Skip to content

Commit 3d8649b

Browse files
committed
fix(mock): treat leading [] segment transparently in override key
Initial implementation in the previous commit normalized `.[]` substrings only, which broke previously-working override keys with a leading `[]` (no preceding dot) — e.g. `properties: { '[].id': ... }` at the operation level, as used in `samples/vue-query/vue-query-basic`. Switch to segment-based stripping: split on `.`, drop `[]` segments, rejoin. Now `[].id`, `foo.[].id`, `foo.[].bar.[].id`, etc. all normalize equivalently to the corresponding `.[]`-free form. Regression test added in `resolveMockOverride` unit suite covering the leading-bracket case explicitly. Sample snapshot updates surface the #2465 fix correctly applying operation-level `id` overrides for array-of-object responses in `angular-app`, `angular-query`, and `basic` (previously the override was silently dropped, so the snapshots stored the default `faker.number.int(...)`). The `basic` sample's `orval.config.ts` also wraps its `id` override in a thunk so the generated value is stable across regenerations (matches the pattern already used by `angular-app`, `angular-query`, and `vue-query-basic`).
1 parent c3ee58e commit 3d8649b

19 files changed

Lines changed: 62 additions & 36 deletions

File tree

packages/mock/src/faker/resolvers/value.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,22 @@ describe('resolveMockOverride (#2465 — bare-key matching across array boundari
5151
expect(result?.value).toBe('() => faker.person.firstName()');
5252
});
5353

54+
it('matches a key with a leading `[].` segment (operation-level array-items syntax)', () => {
55+
// The vue-query-basic sample uses `properties: { '[].id': ... }` at the
56+
// operation level to target the `id` of items returned by an
57+
// array-of-objects endpoint. Path arriving here is `#.[].id`.
58+
const item: Item = { name: 'id', path: '#.[].id' };
59+
60+
const result = resolveMockOverride(
61+
{ '[].id': '() => faker.number.int({ min: 1, max: 99999 })' },
62+
item,
63+
);
64+
65+
expect(result?.value).toBe(
66+
'() => faker.number.int({ min: 1, max: 99999 })',
67+
);
68+
});
69+
5470
it('still does not match bare keys against non-array nested paths (semantic preserved)', () => {
5571
// The non-array nested case (`#.user.firstName` produced by an object
5672
// property `user` containing baseUser) was never matched by a bare key

packages/mock/src/faker/resolvers/value.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,26 @@ function isRegex(key: string) {
1919
return key.startsWith('/') && key.endsWith('/');
2020
}
2121

22+
// Drop `[]` array-items segments from a dotted JSON-pointer-ish path. Treating
23+
// the marker as transparent for property override matching lets a bare
24+
// property-name override apply wherever the property literally appears, even
25+
// inside arrays (#2465). Segment-based so both leading (`[].id`) and embedded
26+
// (`foo.[].id`) markers normalize equivalently.
27+
function stripArrayMarkerSegments(s: string): string {
28+
return s
29+
.split('.')
30+
.filter((seg) => seg !== '[]')
31+
.join('.');
32+
}
33+
2234
export function resolveMockOverride(
2335
properties: Record<string, unknown> | undefined = {},
2436
item: OpenApiSchemaObject & { name: string; path?: string },
2537
) {
2638
const path = item.path ?? `#.${item.name}`;
27-
// Strip `.[]` array-items markers so a bare property-name override applies
28-
// wherever the property literally appears, including inside arrays (#2465).
29-
// Regex keys still match against the original (un-stripped) path so users
39+
// Regex keys still match against the original (un-normalized) path so users
3040
// can opt into array-scoped targeting explicitly if ever needed.
31-
const pathWithoutArrayMarkers = path.replaceAll('.[]', '');
41+
const normalizedPath = stripArrayMarkerSegments(path);
3242
const property = Object.entries(properties).find(([key]) => {
3343
if (isRegex(key)) {
3444
const regex = new RegExp(key.slice(1, -1));
@@ -37,7 +47,7 @@ export function resolveMockOverride(
3747
}
3848
}
3949

40-
if (`#.${key.replaceAll('.[]', '')}` === pathWithoutArrayMarkers) {
50+
if (`#.${stripArrayMarkerSegments(key)}` === normalizedPath) {
4151
return true;
4252
}
4353

samples/angular-app/__snapshots__/api/endpoints-zod/pets/pets.msw.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const getListPetsResponseMock = (): Pets =>
6060
{ length: faker.number.int({ min: 1, max: 100 }) },
6161
(_, i) => i + 1,
6262
).map(() => ({
63-
id: faker.number.int({ min: 1 }),
63+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
6464
name: (() => faker.person.lastName())(),
6565
tag: (() => faker.person.lastName())(),
6666
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),
@@ -101,7 +101,7 @@ export const getListPetsResponseMock = (): Pets =>
101101
{ length: faker.number.int({ min: 1, max: 100 }) },
102102
(_, i) => i + 1,
103103
).map(() => ({
104-
id: faker.number.int({ min: 1 }),
104+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
105105
name: (() => faker.person.lastName())(),
106106
tag: (() => faker.person.lastName())(),
107107
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),

samples/angular-app/__snapshots__/api/http-both/pets/pets.msw.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const getListPetsResponseMock = (): Pets =>
6060
{ length: faker.number.int({ min: 1, max: 100 }) },
6161
(_, i) => i + 1,
6262
).map(() => ({
63-
id: faker.number.int({ min: 1 }),
63+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
6464
name: (() => faker.person.lastName())(),
6565
tag: (() => faker.person.lastName())(),
6666
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),
@@ -101,7 +101,7 @@ export const getListPetsResponseMock = (): Pets =>
101101
{ length: faker.number.int({ min: 1, max: 100 }) },
102102
(_, i) => i + 1,
103103
).map(() => ({
104-
id: faker.number.int({ min: 1 }),
104+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
105105
name: (() => faker.person.lastName())(),
106106
tag: (() => faker.person.lastName())(),
107107
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),

samples/angular-app/__snapshots__/api/http-client-custom-params/pets/pets.msw.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const getListPetsResponseMock = (): Pets =>
6060
{ length: faker.number.int({ min: 1, max: 100 }) },
6161
(_, i) => i + 1,
6262
).map(() => ({
63-
id: faker.number.int({ min: 1 }),
63+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
6464
name: (() => faker.person.lastName())(),
6565
tag: (() => faker.person.lastName())(),
6666
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),
@@ -101,7 +101,7 @@ export const getListPetsResponseMock = (): Pets =>
101101
{ length: faker.number.int({ min: 1, max: 100 }) },
102102
(_, i) => i + 1,
103103
).map(() => ({
104-
id: faker.number.int({ min: 1 }),
104+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
105105
name: (() => faker.person.lastName())(),
106106
tag: (() => faker.person.lastName())(),
107107
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),

samples/angular-app/__snapshots__/api/http-client/pets/pets.msw.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const getListPetsResponseMock = (): Pets =>
6060
{ length: faker.number.int({ min: 1, max: 100 }) },
6161
(_, i) => i + 1,
6262
).map(() => ({
63-
id: faker.number.int({ min: 1 }),
63+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
6464
name: (() => faker.person.lastName())(),
6565
tag: (() => faker.person.lastName())(),
6666
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),
@@ -101,7 +101,7 @@ export const getListPetsResponseMock = (): Pets =>
101101
{ length: faker.number.int({ min: 1, max: 100 }) },
102102
(_, i) => i + 1,
103103
).map(() => ({
104-
id: faker.number.int({ min: 1 }),
104+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
105105
name: (() => faker.person.lastName())(),
106106
tag: (() => faker.person.lastName())(),
107107
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),

samples/angular-app/__snapshots__/api/http-resource-zod/pets/pets.msw.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const getListPetsResponseMock = (): Pets =>
6060
{ length: faker.number.int({ min: 1, max: 100 }) },
6161
(_, i) => i + 1,
6262
).map(() => ({
63-
id: faker.number.int({ min: 1 }),
63+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
6464
name: (() => faker.person.lastName())(),
6565
tag: (() => faker.person.lastName())(),
6666
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),
@@ -101,7 +101,7 @@ export const getListPetsResponseMock = (): Pets =>
101101
{ length: faker.number.int({ min: 1, max: 100 }) },
102102
(_, i) => i + 1,
103103
).map(() => ({
104-
id: faker.number.int({ min: 1 }),
104+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
105105
name: (() => faker.person.lastName())(),
106106
tag: (() => faker.person.lastName())(),
107107
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),

samples/angular-app/__snapshots__/api/http-resource/pets/pets.msw.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const getListPetsResponseMock = (): Pets =>
6060
{ length: faker.number.int({ min: 1, max: 100 }) },
6161
(_, i) => i + 1,
6262
).map(() => ({
63-
id: faker.number.int({ min: 1 }),
63+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
6464
name: (() => faker.person.lastName())(),
6565
tag: (() => faker.person.lastName())(),
6666
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),
@@ -101,7 +101,7 @@ export const getListPetsResponseMock = (): Pets =>
101101
{ length: faker.number.int({ min: 1, max: 100 }) },
102102
(_, i) => i + 1,
103103
).map(() => ({
104-
id: faker.number.int({ min: 1 }),
104+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
105105
name: (() => faker.person.lastName())(),
106106
tag: (() => faker.person.lastName())(),
107107
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),

samples/angular-app/src/api/endpoints-zod/pets/pets.msw.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const getListPetsResponseMock = (): Pets =>
6060
{ length: faker.number.int({ min: 1, max: 100 }) },
6161
(_, i) => i + 1,
6262
).map(() => ({
63-
id: faker.number.int({ min: 1 }),
63+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
6464
name: (() => faker.person.lastName())(),
6565
tag: (() => faker.person.lastName())(),
6666
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),
@@ -101,7 +101,7 @@ export const getListPetsResponseMock = (): Pets =>
101101
{ length: faker.number.int({ min: 1, max: 100 }) },
102102
(_, i) => i + 1,
103103
).map(() => ({
104-
id: faker.number.int({ min: 1 }),
104+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
105105
name: (() => faker.person.lastName())(),
106106
tag: (() => faker.person.lastName())(),
107107
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),

samples/angular-app/src/api/http-both/pets/pets.msw.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const getListPetsResponseMock = (): Pets =>
6060
{ length: faker.number.int({ min: 1, max: 100 }) },
6161
(_, i) => i + 1,
6262
).map(() => ({
63-
id: faker.number.int({ min: 1 }),
63+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
6464
name: (() => faker.person.lastName())(),
6565
tag: (() => faker.person.lastName())(),
6666
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),
@@ -101,7 +101,7 @@ export const getListPetsResponseMock = (): Pets =>
101101
{ length: faker.number.int({ min: 1, max: 100 }) },
102102
(_, i) => i + 1,
103103
).map(() => ({
104-
id: faker.number.int({ min: 1 }),
104+
id: (() => faker.number.int({ min: 1, max: 99999 }))(),
105105
name: (() => faker.person.lastName())(),
106106
tag: (() => faker.person.lastName())(),
107107
email: faker.helpers.arrayElement([faker.internet.email(), undefined]),

0 commit comments

Comments
 (0)