Skip to content

Add support for deterministic mock generation#7629

Merged
ardatan merged 4 commits intoardatan:masterfrom
sanniassin:deterministic-mocks
Oct 26, 2025
Merged

Add support for deterministic mock generation#7629
ardatan merged 4 commits intoardatan:masterfrom
sanniassin:deterministic-mocks

Conversation

@sanniassin
Copy link
Contributor

@sanniassin sanniassin commented Oct 25, 2025

Description

This PR implements mockGenerationBehavior option in addMocksToSchema, which gives control over randomness in autogenerated mocks. By default the current random behavior is preserved, but now it's also possible to pass mockGenerationBehavior: 'deterministic' option.

It aims to reduce risks of flakiness in apps with large sophisticated GraphQL schemas, where app's behavior may change because of some specific combination of boolean flag and status enums and the test's author may not be aware of all such combinations. With random generation this may cause flakiness in tests, because a specific non-working combination of flags and enums may only occur randomly once per 100 test runs.

Though this issue could already be worked around by passing explicit mocks for all types affected by randomness, this only works well for scalar types and simple schemas. In large codebases with hundreds of union and enum fields this can hardly be done well and maintained.

Related # (issue)

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

How Has This Been Tested?

  • Added tests for both deterministic and random behaviors in packages/mock/tests/store.spec.ts.
  • Tested local build on an app with a complicated schema, which now requires a lot of manual mocking for enums and booleans to mitigate flakiness. Both by passing to mockGenerationBehavior option directly to createMockStore and via addMocksToSchema.

Test Environment:

  • OS: macOS Sequoia 15.6.1 (24G90)
  • Node.js 24.8.0

Checklist:

  • I have followed the
    CONTRIBUTING doc and the
    style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests and linter rules pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

@changeset-bot
Copy link

changeset-bot bot commented Oct 25, 2025

🦋 Changeset detected

Latest commit: b7ac1ba

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@graphql-tools/mock Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 25, 2025

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added mockGenerationBehavior option to control mock generation mode across all mocking functions ('random' for varied values, 'deterministic' for consistent fixed values).
  • Tests

    • Added comprehensive test coverage for random and deterministic mock generation behaviors, including scalars, enums, unions, interfaces, and lists.
  • Documentation

    • Updated documentation to describe the new mockGenerationBehavior option and its effects on mock data generation.

Walkthrough

A new option mockGenerationBehavior ('random' | 'deterministic') is added and threaded through mockServer → addMocksToSchema → MockStore. MockStore now composes defaultCommonMocks with either defaultRandomMocks or defaultDeterministicMocks and uses takeOneOf(values, mockGenerationBehavior) for selections.

Changes

Cohort / File(s) Summary
Type Definition
packages/mock/src/types.ts
Added exported type MockGenerationBehavior = 'random' | 'deterministic'.
Utilities
packages/mock/src/utils.ts
Replaced takeRandom with takeOneOf(arr, behavior); deterministic returns first element, random returns a random element.
MockStore Core
packages/mock/src/MockStore.ts
Added mockGenerationBehavior field and constructor option; introduced defaultRandomMocks, defaultDeterministicMocks, and defaultCommonMocks; replaced takeRandom uses with takeOneOf(..., mockGenerationBehavior) across scalar/enum/union/array generation.
API Integration
packages/mock/src/addMocksToSchema.ts
IMockOptions now includes mockGenerationBehavior?: MockGenerationBehavior; option forwarded to createMockStore.
Public API Surface
packages/mock/src/mockServer.ts
mockServer gains optional mockGenerationBehavior?: MockGenerationBehavior parameter and passes it to addMocksToSchema.
Tests & Docs
packages/mock/tests/store.spec.ts,
website/src/content/mocking.mdx
Tests: added verified: Boolean on User and rating: Float on Book implementations; new tests cover 'random' vs 'deterministic' behaviors. Docs: examples updated to show mockGenerationBehavior option and default behavior.
Release
.changeset/quiet-turtles-appear.md
Bumped package version and added changeset entry documenting new mockGenerationBehavior option.

Sequence Diagram

sequenceDiagram
    participant User
    participant mockServer
    participant addMocksToSchema
    participant MockStore
    participant takeOneOf

    User->>mockServer: mockServer(schema, mocks, ..., mockGenerationBehavior?)
    mockServer->>addMocksToSchema: addMocksToSchema({... mockGenerationBehavior})
    addMocksToSchema->>MockStore: createMockStore({... mockGenerationBehavior})
    MockStore->>MockStore: merge defaults (defaultCommon + (deterministic?deterministicMocks:randomMocks))

    rect rgba(100,150,200,0.12)
    Note over MockStore,takeOneOf: value selection during mock generation
    MockStore->>takeOneOf: takeOneOf(values, mockGenerationBehavior)
    alt deterministic
        takeOneOf-->>MockStore: return first value
    else random
        takeOneOf-->>MockStore: return random value
    end
    end

    MockStore-->>User: resolved mock values
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Pay special attention to:
    • MockStore merging logic for defaultCommonMocks vs behavior-specific defaults.
    • Correct and complete replacement of takeRandom with takeOneOf across all generation paths (scalars, enums, unions, arrays).
    • Propagation and typing of MockGenerationBehavior across public APIs (mockServer, addMocksToSchema, createMockStore).
    • Expanded tests in packages/mock/tests/store.spec.ts validating both behaviors and new schema fields.

Suggested reviewers

  • ardatan

Poem

🐰 I hop through defaults, choose first or roam,

Determined I settle, or randomly comb.
From server to store I carry the play,
Mocks bloom predictable or stray. 🎋

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "Add support for deterministic mock generation" directly and accurately reflects the main change implemented in the changeset. The title is concise, specific, and highlights the primary feature being added—the ability to control mock generation behavior between random (default) and deterministic modes. A teammate reviewing git history would immediately understand that this PR introduces deterministic mock generation capabilities to the mock library. The title is neither overly broad nor vague, making it a clear summary of the changeset's primary objective.
Description Check ✅ Passed The PR description is clearly related to the changeset and provides substantial, meaningful information. It explains the implementation of the mockGenerationBehavior option, describes the problem being solved (test flakiness in complex schemas), specifies testing approaches (tests added for both behaviors), and includes references to related issues and environment details. The description demonstrates awareness of backward compatibility (default behavior preserved) and explains why this feature matters at scale. This level of detail and relevance easily satisfies the lenient criteria for the description check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8b32baa and b7ac1ba.

📒 Files selected for processing (1)
  • .changeset/quiet-turtles-appear.md (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
  • GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Full Check on GraphQL v16
🔇 Additional comments (1)
.changeset/quiet-turtles-appear.md (1)

1-5: Changeset correctly formatted and addresses reviewer feedback.

The changeset is properly structured with the correct package name, appropriate minor version bump for a new optional feature, and a clear description. This successfully addresses the request for a changeset so a release can be cut.

Consider enriching the changelog entry to mention that the default behavior remains random (backward-compatible) for clarity in release notes:

- New `mockGenerationBehavior` option to enable deterministic mock generation
+ New `mockGenerationBehavior` option to enable deterministic mock generation (defaults to 'random' for backward compatibility)

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.

Copy link
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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/mock/src/MockStore.ts (1)

748-768: Consider clarifying array length behavior in documentation.

The JSDoc states "For Arrays an array of random length will be generated" in random mode, but randomListLength() (line 14 of utils.ts) always returns 2. Consider either:

  • Updating the documentation to reflect that arrays have a fixed length of 2
  • Implementing actual random-length arrays for random mode (though this might introduce more flakiness)

The current behavior (always length 2) is actually less flaky, so updating the documentation might be the better approach.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd3b458 and 1e0fd8e.

📒 Files selected for processing (7)
  • packages/mock/src/MockStore.ts (7 hunks)
  • packages/mock/src/addMocksToSchema.ts (3 hunks)
  • packages/mock/src/mockServer.ts (3 hunks)
  • packages/mock/src/types.ts (1 hunks)
  • packages/mock/src/utils.ts (2 hunks)
  • packages/mock/tests/store.spec.ts (3 hunks)
  • website/src/content/mocking.mdx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
packages/mock/src/mockServer.ts (2)
packages/utils/src/Interfaces.ts (1)
  • TypeSource (272-279)
packages/mock/src/types.ts (2)
  • IMocks (10-22)
  • MockGenerationBehavior (24-24)
packages/mock/src/utils.ts (1)
packages/mock/src/types.ts (1)
  • MockGenerationBehavior (24-24)
packages/mock/tests/store.spec.ts (1)
packages/mock/src/MockStore.ts (1)
  • MockStore (57-678)
packages/mock/src/MockStore.ts (2)
packages/mock/src/types.ts (3)
  • MockGenerationBehavior (24-24)
  • IMocks (10-22)
  • TypePolicy (28-37)
packages/mock/src/utils.ts (1)
  • takeOneOf (20-26)
packages/mock/src/addMocksToSchema.ts (1)
packages/mock/src/types.ts (3)
  • IMockStore (84-216)
  • IMocks (10-22)
  • MockGenerationBehavior (24-24)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Unit Test on Bun
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
  • GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Full Check on GraphQL v16
🔇 Additional comments (17)
packages/mock/src/types.ts (1)

24-24: LGTM!

The new MockGenerationBehavior type is cleanly defined and appropriately exported for use across the mocking system.

packages/mock/src/utils.ts (2)

3-3: LGTM!

Import correctly adds the new MockGenerationBehavior type to support the behavior-aware selection logic.


20-26: LGTM!

The refactored takeOneOf function cleanly implements deterministic selection (first element) and random selection based on the behavior parameter.

website/src/content/mocking.mdx (1)

415-428: LGTM!

The documentation clearly explains the new mockGenerationBehavior option, its default value, and when to use the deterministic mode to reduce test flakiness.

packages/mock/src/addMocksToSchema.ts (3)

14-14: LGTM!

Import correctly adds the MockGenerationBehavior type for use in the options interface.


21-21: LGTM!

The optional mockGenerationBehavior parameter properly extends IMockOptions while maintaining backward compatibility.


97-97: LGTM!

The parameter is correctly destructured from options and properly forwarded to createMockStore, enabling the behavior to affect mock generation throughout the system.

Also applies to: 117-117

packages/mock/src/mockServer.ts (3)

5-5: LGTM!

Import correctly adds the MockGenerationBehavior type for the public API.


18-26: LGTM!

The function signature is properly extended with the optional mockGenerationBehavior parameter, and the JSDoc clearly documents its purpose.


34-34: LGTM!

The parameter is correctly forwarded to addMocksToSchema, completing the integration through the public API surface.

packages/mock/src/MockStore.ts (4)

82-86: Verify the variable name reference after fixing the typo.

Once the typo in defaultDeteministicMocks is fixed to defaultDeterministicMocks on line 40, ensure this reference is also updated.


60-60: LGTM!

The mockGenerationBehavior field is properly added as a private member, correctly initialized in the constructor with a sensible default of 'random', and the constructor signature properly extends the options to accept this parameter.

Also applies to: 70-70, 75-75, 81-81


570-570: LGTM!

The enum value generation correctly uses takeOneOf with the instance's mockGenerationBehavior, enabling deterministic first-value selection when configured.


584-587: LGTM!

Abstract type resolution correctly uses takeOneOf with the instance's mockGenerationBehavior to select from possible types, enabling deterministic behavior when configured.

packages/mock/tests/store.spec.ts (3)

20-20: LGTM!

The schema additions (verified: Boolean on User, rating: Float on Book interface and implementations) provide the necessary fields to test the new mock generation behaviors comprehensively.

Also applies to: 44-44, 50-50, 57-57


677-758: LGTM!

The random behavior test suite comprehensively validates that the random mode produces varied values across Int, Float, Boolean, Enum, and Union types. The approach of generating 100 samples and checking for variation is robust.


760-832: LGTM!

The deterministic behavior test suite thoroughly validates that the deterministic mode produces consistent, predictable values (1 for Int, 1.5 for Float, true for Boolean, first enum value, first union type, etc.). This provides strong confidence that the feature works as intended.

Copy link
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.

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/mock/tests/store.spec.ts (2)

677-758: Strong coverage for random behavior; fix misleading test title.

The suite thoroughly validates randomness for Int, Float, Enum, Union, and Boolean. One nit: the test named “should return random values for Boolean scalars” actually checks Union variant randomness.

Apply this rename:

-    it('should return random values for Boolean scalars', () => {
+    it('should return random union variants for UserImage', () => {

760-844: Deterministic suite is comprehensive; consider one extra assertion path.

All key types are validated, including arrays length=2. Optionally add a companion test using createMockStore({ mockGenerationBehavior: 'deterministic' }) to ensure the factory path also enforces determinism (not just new MockStore).

packages/mock/src/MockStore.ts (1)

748-771: Clarify JSDoc for String behavior in random mode (nit).

Doc specifies deterministic String = "Hello World"; it doesn’t state random mode explicitly. Since String comes from defaultCommonMocks, it’s "Hello World" in both modes. Consider an extra sentence to avoid confusion.

Apply:

  * - For String scalars we'll always return "Hello World"
+ *   (Strings use the same default in both modes.)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ad3d52 and 8b32baa.

📒 Files selected for processing (2)
  • packages/mock/src/MockStore.ts (7 hunks)
  • packages/mock/tests/store.spec.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/mock/src/MockStore.ts (2)
packages/mock/src/types.ts (3)
  • MockGenerationBehavior (24-24)
  • IMocks (10-22)
  • TypePolicy (28-37)
packages/mock/src/utils.ts (1)
  • takeOneOf (20-26)
packages/mock/tests/store.spec.ts (1)
packages/mock/src/MockStore.ts (1)
  • MockStore (57-678)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: Unit Test on Bun
  • GitHub Check: Full Check on GraphQL v16
🔇 Additional comments (6)
packages/mock/tests/store.spec.ts (2)

19-21: Schema field addition looks good.

The new verified: Boolean field is consistent with later tests. No issues.


44-44: Rating field alignment across interface and implementors.

Adding rating: Float to Book, TextBook, and ColoringBook keeps the schema coherent for interface field resolution. Looks good.

Also applies to: 50-50, 57-57

packages/mock/src/MockStore.ts (4)

569-571: Enum selection correctly respects behavior.

Switch to takeOneOf(values, this.mockGenerationBehavior) is correct and minimal.


584-587: Abstract type resolution wired to behavior.

Using takeOneOf over possible types matches the new option; good change.


82-86: Mocks merge order is sensible.

defaultCommonMocks → behavior-specific defaults → user mocks ensures user overrides win. LGTM.


574-578: No change required—randomListLength() already returns 2 deterministically.

The review comment assumes randomListLength() generates varying lengths in random mode. In reality, randomListLength() (defined in packages/mock/src/utils.ts:14-18) is hardcoded to always return 2. The commented-out code at line 16 shows a prior random implementation, but the current version is deterministic. Both 'random' and 'deterministic' modes already produce arrays of length 2, matching the expected behavior.

Likely an incorrect or invalid review comment.

@ardatan
Copy link
Owner

ardatan commented Oct 26, 2025

Thanks for the PR @sanniassin ! Could you add a changeset with npx changeset then we can cut a new release?

@sanniassin
Copy link
Contributor Author

@ardatan Sure, added a changeset 🙌

@ardatan ardatan merged commit 252f142 into ardatan:master Oct 26, 2025
15 checks passed
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.

3 participants