Skip to content

feat(mock): add override.mock.schemas for per-schema property overrides - #3645

Merged
melloware merged 1 commit into
orval-labs:masterfrom
jakiestfu:feat/mock-schema-overrides
Jun 24, 2026
Merged

feat(mock): add override.mock.schemas for per-schema property overrides#3645
melloware merged 1 commit into
orval-labs:masterfrom
jakiestfu:feat/mock-schema-overrides

Conversation

@jakiestfu

@jakiestfu jakiestfu commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

override.mock.properties matches by property name, so an override for color applies to every schema that has a color property. There was no way to give the same property name different mock values depending on which schema it belongs to.

This adds override.mock.schemas, keyed by schema name, so the same property name can mock differently per schema:

override: {
  mock: {
    schemas: {
      Apple: { properties: { color: () => faker.helpers.arrayElement(['red', 'green']) } },
      Car:   { properties: { color: () => 'midnight black' } },
    },
  },
}

getAppleMock() now mocks color as a fruit color and getCarMock() as a car color, even though both declare color: string.

The keys under properties use the same matching rules as override.mock.properties — bare name, /regex/, or exact #.path.

Precedence (first match wins): override.operationsoverride.tagsoverride.mock.schemasoverride.mock.properties.

Generated output

Given two schemas that both have color: string:

// Apple-scoped override applied
export const getAppleMock = (overrideResponse: Partial<Apple> = {}): Apple => ({
  color: faker.helpers.arrayElement(['red', 'green']),
  ...overrideResponse,
});

// Car-scoped override applied
export const getCarMock = (overrideResponse: Partial<Car> = {}): Car => ({
  color: 'midnight black',
  ...overrideResponse,
});

With schemas: true, a referencing schema keeps delegating to the factory and the override rides along:

export const getBasketMock = (overrideResponse: Partial<Basket> = {}): Basket => ({
  apple: { ...getAppleMock() }, // getAppleMock() already bakes in the Apple-scoped override
  ...overrideResponse,
});

Changes

  • packages/core — add schemas?: Record<string, { properties }> to OverrideMockOptions (user-facing) and MockOptions (serialized form).
  • packages/mock (msw/mocks.ts)getMockWithoutFunc serializes function-valued schema overrides to IIFE strings, mirroring the existing operations/tags handling.
  • packages/mock (faker/getters/scalar.ts)getMockScalar resolves a schema-scoped tier keyed on the property's enclosing schema (item.parentName), between the tag and global-property tiers.
  • Docs — new "Per-schema overrides" section in the Faker guide + an override.mock.schemas reference entry.

Notes

  • Schema-scoped overrides apply to a schema's own properties (matched by immediate parentName). No change to hasOverrideTouchingSchema was needed for schemas: true: each get<Schema>Mock factory is built with the same mock options, so delegation preserves the override (verified by test).
  • Works with both the faker and msw generators.

Tests

  • Added unit tests in scalar.test.ts (override applied per schema; falls through when the schema name doesn't match; precedence vs operation/global).
  • Added end-to-end tests in index.test.ts (different override per schema; preserved through factory delegation).
  • Added serialization tests in mocks.test.ts (function → IIFE, value stringification, omitted when unset).
  • Full suite: mock 293/293, core 2084/2084. Both packages typecheck clean.

Summary by CodeRabbit

  • New Features

    • Added support for schema-scoped mock property overrides, allowing users to customize mock values for specific OpenAPI schemas with clearly defined precedence rules.
  • Documentation

    • Added "Per-schema overrides" guide explaining scoping rules and behavior.
    • Expanded configuration reference with examples and override precedence order.

Property overrides (`override.mock.properties`) match by property name, so
an override for `color` applies to every schema that has a `color` property.
There was no way to give the same property name different mock values per
schema.

Add `override.mock.schemas`, keyed by schema name, each holding a `properties`
map with the same matching rules as `override.mock.properties` (bare name,
`/regex/`, exact `#.path`). It resolves between the tag- and global-property
tiers, so precedence is: operations > tags > schemas > properties.

Example:

  override: {
    mock: {
      schemas: {
        Apple: { properties: { color: () => faker.color.human() } },
        Car:   { properties: { color: () => 'midnight black' } },
      },
    },
  }

When `schemas: true` is enabled, each `get<Schema>Mock` factory bakes its
schema-scoped override in, so references that delegate to the factory keep
the override — no inlining needed.
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds override.mock.schemas support to scope mock property overrides to specific named OpenAPI component schemas. Changes span type definitions in @orval/core, scalar resolution in getMockScalar, function serialization in getMockWithoutFunc, a clarifying comment in the $ref resolver, new tests, and updated documentation.

Changes

Schema-scoped mock overrides

Layer / File(s) Summary
Type contracts for override.mock.schemas
packages/core/src/types.ts
OverrideMockOptions adds schemas?: Record<string, { properties: MockProperties }>. MockOptions omits both properties and schemas from OverrideMockOptions and re-adds schemas with serialized Record<string, unknown> property values.
Schema-scoped resolution in getMockScalar
packages/mock/src/faker/getters/scalar.ts, packages/mock/src/faker/getters/scalar.test.ts
getMockScalar checks safeMockOptions.schemas[item.parentName].properties via resolveMockOverride and returns early when matched, inserting a new stage between operation-scoped and global property overrides. Tests cover matching, non-matching, missing parentName, and precedence rules.
MSW getMockWithoutFunc serialization
packages/mock/src/msw/mocks.ts, packages/mock/src/msw/mocks.test.ts
getMockWithoutFunc builds a schemas field from override.mock.schemas by running getMockPropertiesWithoutFunc per entry. Tests verify function-valued overrides become IIFE strings, non-function values are stringified as-is, and schemas is omitted when absent.
$ref delegation behavior and integration tests
packages/mock/src/faker/resolvers/value.ts, packages/mock/src/faker/index.test.ts
Comment in the $ref handler clarifies schema-scoped overrides need no special inlining since delegated factories already incorporate them. Integration tests verify overrides survive $ref delegation and remain baked into get<X>Mock factories.
Documentation
docs/content/docs/guides/faker.mdx, docs/content/docs/reference/configuration/output.mdx
Faker guide adds a "Per-schema overrides" section covering configuration, factory bake-in, and precedence order (operationstagsschemasproperties). Output reference adds a worked example and expanded schemas field description.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • orval-labs/orval#3569: Changes resolveMockOverride's bare-key vs dotted/regex precedence — the same override-key resolution logic that override.mock.schemas now extends to schema-scoped properties.
  • orval-labs/orval#3585: Modifies generateFakerForSchemas to use getMockWithoutFunc for IIFE serialization of function-valued overrides — the same serialization path this PR extends for the new schemas field.

Suggested labels

mock

Suggested reviewers

  • melloware
  • wadakatu

🐰 A new key in the override map,
schemas now plays the property game!
Per-schema, per-name, the colors align,
Baked into factories — oh how divine!
No $ref can escape the mock's little claim. 🎨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding override.mock.schemas for per-schema property overrides in the mock generation system.
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 unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/mock/src/faker/getters/scalar.test.ts (1)

1139-1168: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the missing tags > schemas precedence assertion.

This suite validates most of the new precedence contract, but it still lacks an explicit tag-scoped-over-schema-scoped test for this feature path.

Proposed test addition
 describe('getMockScalar (schema-scoped overrides)', () => {
@@
   it('prefers an operation-scoped override over a schema-scoped one', () => {
@@
     expect(result.value).toBe("'op-color'");
   });
+
+  it('prefers a tag-scoped override over a schema-scoped one', () => {
+    const result = getMockScalar({
+      ...baseArg,
+      tags: ['vehicle'],
+      item: colorItem('Apple'),
+      mockOptions: {
+        tags: { vehicle: { properties: { color: "'tag-color'" } } },
+        schemas: { Apple: { properties: { color: "'red'" } } },
+      },
+      context: scalarContext(),
+    });
+
+    expect(result.value).toBe("'tag-color'");
+  });
 
   it('prefers a schema-scoped override over a global property override', () => {
🤖 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 `@packages/mock/src/faker/getters/scalar.test.ts` around lines 1139 - 1168, The
test suite for scalar mock overrides is missing a test case that validates the
precedence rule where tag-scoped overrides should take precedence over
schema-scoped overrides. Add a new test case after the existing precedence tests
in the same file that follows the same pattern as the other tests, using
getMockScalar with mockOptions containing both tags and schemas properties for
the same scalar property, and assert that the tag-level override value is
returned instead of the schema-level override value.
🤖 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 `@packages/mock/src/faker/getters/scalar.test.ts`:
- Around line 1139-1168: The test suite for scalar mock overrides is missing a
test case that validates the precedence rule where tag-scoped overrides should
take precedence over schema-scoped overrides. Add a new test case after the
existing precedence tests in the same file that follows the same pattern as the
other tests, using getMockScalar with mockOptions containing both tags and
schemas properties for the same scalar property, and assert that the tag-level
override value is returned instead of the schema-level override value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 41541cc9-f205-4d27-8626-1295097f09e4

📥 Commits

Reviewing files that changed from the base of the PR and between 162a96c and ba43473.

📒 Files selected for processing (9)
  • docs/content/docs/guides/faker.mdx
  • docs/content/docs/reference/configuration/output.mdx
  • packages/core/src/types.ts
  • packages/mock/src/faker/getters/scalar.test.ts
  • packages/mock/src/faker/getters/scalar.ts
  • packages/mock/src/faker/index.test.ts
  • packages/mock/src/faker/resolvers/value.ts
  • packages/mock/src/msw/mocks.test.ts
  • packages/mock/src/msw/mocks.ts

@melloware melloware added the mock Related to mock generation label Jun 24, 2026
@melloware melloware added this to the 8.19.0 milestone Jun 24, 2026
@jakiestfu

Copy link
Copy Markdown
Contributor Author

Thanks for taking a peek @melloware. Do you have any concern or changes you'd like to request?

P.S. We've really been loving the faker mocks <-> Orval at Turo!

@melloware

Copy link
Copy Markdown
Collaborator

@jakiestfu this seems like a slick improvement to me! @wadakatu and @Hypenate any thoughts?

@Hypenate

Copy link
Copy Markdown
Contributor

Nice addition! Thanks

@melloware
melloware merged commit f8673ca into orval-labs:master Jun 24, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mock Related to mock generation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants