Skip to content

test(regression): add regression test for issue #2639#2657

Merged
ymc9 merged 1 commit into
devfrom
regression/issue-2639
May 8, 2026
Merged

test(regression): add regression test for issue #2639#2657
ymc9 merged 1 commit into
devfrom
regression/issue-2639

Conversation

@ymc9
Copy link
Copy Markdown
Member

@ymc9 ymc9 commented May 8, 2026

Summary

  • Adds a regression test for #2639: factory.makeModelSchema(...)-inferred type not assignable to the ORM-inferred model type because of null mismatch on required Json fields.
  • Mirrors the user's reproduction (type BasicFields mixin + model Test with BasicFields, including metaData Json @default("{}")) and asserts that z.infer<typeof zodSchema> extends the ORM model type.
  • The bug was already fixed by fix(zod): top-level null mismatch in makeJsonSchema() for required Json fields #2647 (widened TypeMap.Json to JsonValue | null); this test guards against regression.

Test plan

  • pnpm test:generate produces tests/regression/test/issue-2639/schema.ts
  • tsc --noEmit passes (the type-level expectTypeOf().toExtend() assertions are checked at compile time)
  • vitest run test/issue-2639/regression.test.ts — 2/2 pass

🤖 Generated with Claude Code

Summary by CodeRabbit

Verifies that the type inferred from `factory.makeModelSchema('Test')`
is assignable to the ORM-inferred model type for a required `Json` field
with a default. The bug was fixed by #2647 widening `TypeMap.Json` to
`JsonValue | null`; this test guards against regressions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a regression test suite for GitHub issue #2639 to validate that ZenStack's Zod schema generation produces TypeScript types compatible with ORM-inferred types, particularly for JSON fields with null defaults.

Changes

Issue #2639 Regression Test

Layer / File(s) Summary
ZenStack Schema Definition
tests/regression/test/issue-2639/schema.zmodel
Defines PostgreSQL datasource, BasicFields composite type with id, createdAt, updatedAt, and metaData JSON field with null default, and Test model composing BasicFields plus a name field.
Auto-Generated Schema Implementation
tests/regression/test/issue-2639/schema.ts
Exports SchemaType class implementing SchemaDef with PostgreSQL provider config, field definitions, defaults, and attributes; provides singleton schema instance.
Type Compatibility Assertions
tests/regression/test/issue-2639/regression.test.ts
Constructs test client and schema factory; validates that Zod-inferred model type extends ORM model type; asserts metaData field null assignability across both type systems.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

  • zenstackhq/zenstack#2647: The regression test directly validates the fix for makeJsonSchema() removing top-level z.null() wrapper to resolve null handling mismatch for required JSON fields between Zod and ORM type inference.

Poem

🐰 A schema test hops into the light,
Checking Zod types match ORM just right,
Where metaData dances with null so keen,
Type compatibility, a hop-tastic scene!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a regression test for issue #2639, which directly matches the changeset content across all three files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch regression/issue-2639

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 8, 2026

Claude finished @ymc9's task —— View job


📋 Code Review Tasks

  • Read and analyze changed files
  • Review test implementation approach
  • Check code quality and best practices
  • Evaluate test coverage
  • Provide comprehensive feedback

🔍 Code Review for PR #2657

This PR adds a regression test for issue #2639, which addresses type inference problems with Json fields. Here's my analysis:

Strengths

Test Implementation:

  • Excellent reproduction of user scenario: The test accurately mirrors the reported issue with type BasicFields mixin pattern and model Test with BasicFields
  • Proper use of type-level assertions: Using expectTypeOf<ZodTest>().toExtend<OrmTest>() is the correct approach for compile-time type checking
  • Comprehensive coverage: Two test cases cover both the general type assignability issue and the specific metaData field null handling

Code Quality:

  • Clear test structure: Well-organized with descriptive test names and inline documentation referencing the GitHub issue
  • Consistent with existing patterns: Follows the same structure as other regression tests (e.g., issue-2647, issue-422)
  • Minimal and focused: The ZModel schema is minimal but sufficient to reproduce the bug

File Organization:

  • Correct placement: Files are properly organized in tests/regression/test/issue-2639/ following project conventions
  • Generated schema included: The generated schema.ts shows the expected output after compilation

🟡 Minor Improvements

Test Coverage:

  • The test focuses on type-level assertions but doesn't include runtime validation tests. Consider adding a test like:
    it('zod schema parses metaData with null at runtime', () => {
        const _schema = factory.makeModelSchema('Test');
        const result = _schema.safeParse({ id: 'test', name: 'test', metaData: null });
        expect(result.success).toBe(true);
    });

Code Comments:

  • While the issue reference is clear, a brief comment explaining what the bug actually was would help future maintainers:
    // Bug: zod-inferred `metaData` included `null` while ORM `JsonValue` did not,
    // causing type incompatibility for required Json fields with defaults

🔒 Security & Performance

  • No security concerns: Test code uses standard testing patterns with no external inputs or sensitive operations
  • No performance issues: Type-level assertions have zero runtime cost; tests are lightweight

📊 Test Coverage Assessment

  • Adequate for regression testing: Successfully prevents the specific type inference bug from returning
  • Complements existing tests: Works well alongside issue-2647 tests which focus on the underlying Json type fix
  • Type safety focus: Appropriately uses compile-time checks since this was a TypeScript inference issue

🎯 Overall Assessment

This is a high-quality regression test that:

The test is well-implemented and ready for merge. The minor suggestions above would enhance completeness but are not blocking issues.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
tests/regression/test/issue-2639/regression.test.ts (2)

16-37: 💤 Low value

Deduplicate createTestClient across tests

await createTestClient(schema) is called independently in each test (lines 17 and 29), but db is used only for typeof db.test.findFirstOrThrow type extraction. Consider hoisting it to beforeAll or a shared outer variable to avoid spinning up the client twice.

♻️ Proposed refactor
+import { beforeAll } from 'vitest';
 import { createTestClient } from '@zenstackhq/testtools';
 import { createSchemaFactory } from '@zenstackhq/zod';
-import { describe, expectTypeOf, it } from 'vitest';
+import { beforeAll, describe, expectTypeOf, it } from 'vitest';
 import z from 'zod';
 import { schema } from './schema';
 
 const factory = createSchemaFactory(schema);
+const _schema = factory.makeModelSchema('Test');
+type ZodTest = z.infer<typeof _schema>;
+let db: Awaited<ReturnType<typeof createTestClient>>;
+
+beforeAll(async () => {
+    db = await createTestClient(schema);
+});
 
 describe('Regression for issue `#2639`', () => {
     it('zod-inferred model type is assignable to the ORM model type', async () => {
-        const db = await createTestClient(schema);
-        const _schema = factory.makeModelSchema('Test');
-        type ZodTest = z.infer<typeof _schema>;
         type OrmTest = Awaited<ReturnType<typeof db.test.findFirstOrThrow>>;
         expectTypeOf<ZodTest>().toExtend<OrmTest>();
     });
 
     it('zod-inferred metaData allows null and is assignable to the ORM metaData', async () => {
-        const db = await createTestClient(schema);
-        const _schema = factory.makeModelSchema('Test');
-        type ZodTest = z.infer<typeof _schema>;
         type OrmTest = Awaited<ReturnType<typeof db.test.findFirstOrThrow>>;
         expectTypeOf<null>().toExtend<ZodTest['metaData']>();
         expectTypeOf<null>().toExtend<OrmTest['metaData']>();
         expectTypeOf<ZodTest['metaData']>().toExtend<OrmTest['metaData']>();
     });
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/regression/test/issue-2639/regression.test.ts` around lines 16 - 37,
The tests call await createTestClient(schema) twice just to extract types from
typeof db.test.findFirstOrThrow; hoist the client creation to a single shared
variable by creating a top-level let db (or const) and initializing it in a
beforeAll block (or once outside the it blocks) so both tests reuse the same db
value; update references to use that shared db and remove the duplicate await
createTestClient(schema) calls in the two it blocks to avoid spinning up the
client twice (symbols: createTestClient, db, db.test.findFirstOrThrow,
beforeAll).

16-38: ⚡ Quick win

Type assertions are no-ops at runtime — rename to .test-d.ts or run with --typecheck

During runtime, expectTypeOf doesn't do anything. To enable typechecking, the --typecheck flag must be passed. Because this file uses the .test.ts extension, only tests inside *.test-d.ts files are considered type tests by default. The two tests currently pass trivially via vitest run regardless of any type mismatch, meaning the regression guard is only enforced by the separately-run tsc --noEmit step.

Renaming to regression.test-d.ts makes Vitest itself enforce the type assertions, ensuring the test fails automatically if the bug regresses:

♻️ Proposed rename
-tests/regression/test/issue-2639/regression.test.ts
+tests/regression/test/issue-2639/regression.test-d.ts

Alternatively, ensure the CI step that runs these regression tests includes the --typecheck flag.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/regression/test/issue-2639/regression.test.ts` around lines 16 - 38,
The file contains runtime no-op type assertions using expectTypeOf (e.g., types
ZodTest and OrmTest derived from db.test.findFirstOrThrow) so Vitest won't
enforce them as the file currently ends with .test.ts; either rename this test
file to use the type-test suffix (e.g., change the filename so it ends with
.test-d.ts) so Vitest will run expectTypeOf checks, or modify the test-run
invocation to include the --typecheck flag so expectTypeOf assertions are
validated at test time.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/regression/test/issue-2639/regression.test.ts`:
- Around line 16-37: The tests call await createTestClient(schema) twice just to
extract types from typeof db.test.findFirstOrThrow; hoist the client creation to
a single shared variable by creating a top-level let db (or const) and
initializing it in a beforeAll block (or once outside the it blocks) so both
tests reuse the same db value; update references to use that shared db and
remove the duplicate await createTestClient(schema) calls in the two it blocks
to avoid spinning up the client twice (symbols: createTestClient, db,
db.test.findFirstOrThrow, beforeAll).
- Around line 16-38: The file contains runtime no-op type assertions using
expectTypeOf (e.g., types ZodTest and OrmTest derived from
db.test.findFirstOrThrow) so Vitest won't enforce them as the file currently
ends with .test.ts; either rename this test file to use the type-test suffix
(e.g., change the filename so it ends with .test-d.ts) so Vitest will run
expectTypeOf checks, or modify the test-run invocation to include the
--typecheck flag so expectTypeOf assertions are validated at test time.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 03e23cbd-45b8-48b6-8bbb-785e5adb58ff

📥 Commits

Reviewing files that changed from the base of the PR and between d1db37c and db66a36.

📒 Files selected for processing (3)
  • tests/regression/test/issue-2639/regression.test.ts
  • tests/regression/test/issue-2639/schema.ts
  • tests/regression/test/issue-2639/schema.zmodel

@ymc9 ymc9 merged commit 899e74d into dev May 8, 2026
9 checks passed
@ymc9 ymc9 deleted the regression/issue-2639 branch May 8, 2026 04:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant