Skip to content

Commit 04700ea

Browse files
fredericooclaude
andcommitted
test(hydrogen-api): assert checked-in generated types match declared API versions
Adds a unit test that fails if SF_API_VERSION or CA_API_VERSION in api-versions.ts doesn't match the version the checked-in .d.ts files were generated against — i.e. someone bumped a version constant without running `pnpm graphql-types` to regenerate. Why: the generated .d.ts files are committed to the repo so consumers and CI get deterministic installs. That's only safe if what ships matches what's declared. Without this check, a version bump in isolation silently ships stale types, and `storefront.query()` calls typecheck against the wrong schema shape. How: extracted SF_API_VERSION and CA_API_VERSION from codegen.ts into src/api-versions.ts as a single source of truth imported by both codegen.ts (the writer) and src/generated-files.test.ts (the verifier). The test reads the "Based on <API> API <version>" header codegen.ts embeds on line 3 of each .d.ts and asserts the parsed version equals the declared one. Uses parametrized `it.each` so each API gets its own named test; the failure message names the file, both versions, and the remediation command. Unit test rather than a tsdown hook: this is an invariant on repo state (are checked-in files fresh?), not on build output (did bundling produce correct JS?) — it belongs with the other `pnpm test` assertions where failures are discoverable and compose with other invariants. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 85db71e commit 04700ea

3 files changed

Lines changed: 57 additions & 3 deletions

File tree

packages/hydrogen-api/codegen.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ import {
33
storefrontApiCustomScalars,
44
customerAccountApiCustomScalars,
55
} from './src/codegen-helpers';
6-
7-
const SF_API_VERSION = '2026-04';
8-
const CA_API_VERSION = '2026-04';
6+
import {SF_API_VERSION, CA_API_VERSION} from './src/api-versions';
97

108
const storefrontAPISchema: CodegenConfig['schema'] = {
119
[`https://hydrogen-preview.myshopify.com/api/${SF_API_VERSION}/graphql.json`]:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Single source of truth for the Shopify API versions this package
3+
* generates types against. Imported by `codegen.ts` (the writer) and by
4+
* `generated-files.test.ts` (the verifier that ensures the checked-in
5+
* generated files were produced against these same versions).
6+
*
7+
* Bumping a version here without running `pnpm graphql-types` will cause
8+
* `pnpm test` to fail.
9+
*/
10+
export const SF_API_VERSION = '2026-04';
11+
export const CA_API_VERSION = '2026-04';
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import {readFileSync} from 'node:fs';
2+
import {fileURLToPath} from 'node:url';
3+
import {dirname, join} from 'node:path';
4+
import {describe, it, expect} from 'vitest';
5+
import {SF_API_VERSION, CA_API_VERSION} from './api-versions';
6+
7+
const here = dirname(fileURLToPath(import.meta.url));
8+
9+
// codegen.ts emits a header comment on line 3 of each generated .d.ts
10+
// like `* Based on Storefront API 2026-04`. If that version doesn't
11+
// match what api-versions.ts declares, someone bumped the constant
12+
// without running `pnpm graphql-types`.
13+
const cases = [
14+
{
15+
file: 'generated/storefront-api-types.d.ts',
16+
apiName: 'Storefront',
17+
declaredVersion: SF_API_VERSION,
18+
},
19+
{
20+
file: 'generated/customer-account-api-types.d.ts',
21+
apiName: 'Customer Account',
22+
declaredVersion: CA_API_VERSION,
23+
},
24+
] as const;
25+
26+
describe('checked-in generated types', () => {
27+
it.each(cases)(
28+
'$file matches declared $apiName API version ($declaredVersion)',
29+
({file, apiName, declaredVersion}) => {
30+
const contents = readFileSync(join(here, file), 'utf8');
31+
const match = contents.match(
32+
new RegExp(`Based on ${apiName} API (\\S+)`),
33+
);
34+
expect(
35+
match,
36+
`"Based on ${apiName} API <version>" header not found in ${file}. Run \`pnpm graphql-types\` to regenerate.`,
37+
).not.toBeNull();
38+
const [, generatedVersion] = match!;
39+
expect(
40+
generatedVersion,
41+
`${file} is stale: generated against ${apiName} API ${generatedVersion}, but api-versions.ts declares ${declaredVersion}. Run \`pnpm graphql-types\` to regenerate.`,
42+
).toBe(declaredVersion);
43+
},
44+
);
45+
});

0 commit comments

Comments
 (0)