Files
dockhand-upstream/tests/compose-validate/apply-quick-fix.test.ts
T

70 lines
3.3 KiB
TypeScript

// @ts-expect-error -- bun:test is a runtime built-in with no types installed
import { describe, expect, test } from 'bun:test';
import { applyQuickFix } from '../../src/lib/utils/compose-quick-fix';
describe('applyQuickFix', () => {
test('delete-line removes exactly that 1-based line', () => {
const src = `version: "3.8"\nservices:\n web:\n image: nginx:1.27\n`;
expect(applyQuickFix(src, { kind: 'delete-line', line: 1 })).toBe(
`services:\n web:\n image: nginx:1.27\n`
);
});
test('replace-in-line swaps the first occurrence, keeping indentation', () => {
const src = `services:\n web:\n image: nginx:1.27\n restar: always\n`;
expect(applyQuickFix(src, { kind: 'replace-in-line', line: 4, find: 'restar', replace: 'restart' })).toBe(
`services:\n web:\n image: nginx:1.27\n restart: always\n`
);
});
test('replace-in-line prefixes a port binding without touching quotes', () => {
const src = `services:\n db:\n ports:\n - "5432:5432"\n`;
expect(
applyQuickFix(src, { kind: 'replace-in-line', line: 4, find: '5432:5432', replace: '127.0.0.1:5432:5432' })
).toBe(`services:\n db:\n ports:\n - "127.0.0.1:5432:5432"\n`);
});
test('a fix whose text no longer matches leaves the source unchanged (stale)', () => {
const src = `services:\n web:\n image: nginx:1.27\n`;
expect(applyQuickFix(src, { kind: 'replace-in-line', line: 3, find: 'gone', replace: 'x' })).toBe(src);
});
test('an out-of-range line leaves the source unchanged', () => {
const src = `services:\n web:\n image: nginx:1.27\n`;
expect(applyQuickFix(src, { kind: 'delete-line', line: 99 })).toBe(src);
});
test('insert-after adds the text as the next line, verbatim (indent in text)', () => {
const src = `services:\n web:\n image: nginx:1.27\n`;
expect(applyQuickFix(src, { kind: 'insert-after', line: 2, text: ' restart: unless-stopped' })).toBe(
`services:\n web:\n restart: unless-stopped\n image: nginx:1.27\n`
);
});
test('CRLF line endings on other lines are preserved', () => {
const src = `version: "3.8"\r\nservices:\r\n web:\r\n image: nginx:1.27\r\n`;
// delete the version line; the remaining \r stay intact.
expect(applyQuickFix(src, { kind: 'delete-line', line: 1 })).toBe(
`services:\r\n web:\r\n image: nginx:1.27\r\n`
);
});
});
describe('replace-in-line anchoring (review regression)', () => {
test("`at` anchors to the intended occurrence, not the first substring", () => {
// The short "80:80" token is a substring of the earlier "8080:80" token.
const line = ' ports: ["8080:80", "80:80"]';
const src = `services:\n db:\n${line}\n`;
const at = line.indexOf('"80:80"') + 1; // column of the 2nd token
const out = applyQuickFix(src, { kind: 'replace-in-line', line: 3, find: '80:80', replace: '127.0.0.1:80:80', at });
expect(out).toContain('"8080:80"'); // earlier token intact
expect(out).toContain('"127.0.0.1:80:80"'); // correct token rewritten
expect(out).not.toContain('80127.0.0.1'); // no corruption
});
test('without `at`, falls back to first occurrence (unchanged behavior)', () => {
const src = `services:\n a:\n restar: always\n`;
const out = applyQuickFix(src, { kind: 'replace-in-line', line: 3, find: 'restar', replace: 'restart' });
expect(out).toContain('restart: always');
});
});