Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
"lint-fix": "pnpm run eslint -- --fix",
"oxlint": "oxlint --type-aware",
"eslint": "eslint .",
"check": "pnpm run format:check && pnpm run type-check && pnpm run lint",
"test": "vitest run",
"test:discogs": "vitest run tests/discogs",
"test:discogs:update-snapshots": "node --strip-types tests/discogs/update-snapshots.ts && oxfmt tests/discogs/snapshots",
"test:discogs:update-fixtures": "node --strip-types tests/discogs/fetch-fixtures.ts && pnpm run format tests/discogs/fixtures",
"test:watch": "vitest",
"generate-readme": "node --strip-types ./tools/generate-readme.ts > README.md",
Expand Down
13 changes: 7 additions & 6 deletions tests/discogs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ A **fixture** is the JSON returned by the Discogs API for a release (e.g. `fixtu

A **snapshot** is the JSON produced by running `parseDiscogsRelease` on that fixture (e.g. `snapshots/1996829.json`). It is the expected MusicBrainz import data: artist credits, labels, discs, tracks, durations, and so on.

Snapshot files are regenerated by the tests with stable key ordering when `pnpm test:discogs -u` is used.
Snapshot files are formatted by oxfmt. Regeneration is a separate command from the tests because the tests compare parsed JSON rather than serialized text.

When you change the parser, tests re-parse the fixtures and compare the result to the snapshots.

Expand Down Expand Up @@ -48,8 +48,9 @@ CI runs `pnpm test:discogs` on every pull request. No Discogs API calls are made
Use the API URL (`https://api.discogs.com/releases/<id>`), not the website URL.

3. Fetch the fixture.
4. Run all tests. Missing snapshot will be automatically created.
5. Commit the new fixture, snapshot, and config change.
4. Regenerate the snapshots.
5. Run all tests.
6. Commit the new fixture, snapshot, and config change.

Pick releases that cover distinct edge cases (multi-disc tracklists, unusual side numbering, nested sub-tracks, etc.) rather than many similar ones.

Expand All @@ -70,9 +71,9 @@ pnpm test:discogs:update-fixtures
Regenerate snapshots after an intentional parser change (no network request):

```bash
pnpm test:discogs -u
pnpm test:discogs:update-snapshots
```

After adding an entry to `config.ts`, run `pnpm test:discogs:update-fixtures` once to create its fixture, then `pnpm test:discogs` to initialize its snapshot and confirm everything passes.
After adding an entry to `config.ts`, run `pnpm test:discogs:update-fixtures` once to create its fixture, then regenerate the snapshots and run the tests.

If a test fails after a parser change you intended, review the diff, then run `pnpm test:discogs -u` to approve the new snapshots and commit the updated files.
If a test fails after a parser change you intended, review the failure, regenerate the snapshots, inspect the file diff, and commit the updated files.
37 changes: 3 additions & 34 deletions tests/discogs/discogs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,47 +13,16 @@ const SNAPSHOTS_DIR = path.join(DIR, 'snapshots');

const parseDiscogsRelease = loadParseDiscogsRelease();

function sortJsonValue(value: unknown): unknown {
if (Array.isArray(value)) {
return value.map(sortJsonValue);
}

if (value !== null && typeof value === 'object') {
return Object.fromEntries(
Object.entries(value)
.sort(([left], [right]) => left.localeCompare(right))
.map(([key, child]) => [key, sortJsonValue(child)]),
);
}

return value;
}

function stableStringify(value: unknown): string {
return `${JSON.stringify(sortJsonValue(JSON.parse(JSON.stringify(value))), null, 4)}\n`;
}

// These tests compare parsed JSON structurally, so mirror Vitest's snapshot update flags explicitly.
function shouldUpdateSnapshots(): boolean {
return process.argv.some(arg => arg === '-u' || arg === '--update' || arg === '--updateSnapshot');
}

const releases = RELEASES.map(({ url, description }) => ({
id: path.basename(new URL(url).pathname),
description,
}));

test.each(releases)('$id: $description', ({ id }) => {
const fixture = JSON.parse(fs.readFileSync(path.join(FIXTURES_DIR, `${id}.json`), 'utf8')) as Record<string, unknown>;
const snapshotPath = path.join(SNAPSHOTS_DIR, `${id}.json`);
const result = parseDiscogsRelease(fixture);
const serializedResult = stableStringify(result);
const snapshot = JSON.parse(fs.readFileSync(path.join(SNAPSHOTS_DIR, `${id}.json`), 'utf8')) as Record<string, unknown>;

if (shouldUpdateSnapshots() || !fs.existsSync(snapshotPath)) {
fs.writeFileSync(snapshotPath, serializedResult, 'utf8');
return;
}
const result = JSON.parse(JSON.stringify(parseDiscogsRelease(fixture))) as Record<string, unknown>;

const snapshot = JSON.parse(fs.readFileSync(snapshotPath, 'utf8')) as Record<string, unknown>;
expect(JSON.parse(serializedResult)).toEqual(snapshot);
expect(result).toEqual(snapshot);
});
22 changes: 22 additions & 0 deletions tests/discogs/update-snapshots.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as fs from 'node:fs';
import * as path from 'node:path';
import { fileURLToPath } from 'node:url';

import { RELEASES } from './config.ts';
import { loadParseDiscogsRelease } from './load-parser.ts';

const DIR = path.dirname(fileURLToPath(import.meta.url));
const FIXTURES_DIR = path.join(DIR, 'fixtures');
const SNAPSHOTS_DIR = path.join(DIR, 'snapshots');

const parseDiscogsRelease = loadParseDiscogsRelease();

fs.mkdirSync(SNAPSHOTS_DIR, { recursive: true });

for (const { url } of RELEASES) {
const id = path.basename(new URL(url).pathname);
const fixture = JSON.parse(fs.readFileSync(path.join(FIXTURES_DIR, `${id}.json`), 'utf8')) as Record<string, unknown>;
const result = parseDiscogsRelease(fixture);

fs.writeFileSync(path.join(SNAPSHOTS_DIR, `${id}.json`), `${JSON.stringify(result, null, 4)}\n`);
}
Loading