From 74182221092b259ed9db094dddd31320f0fe6777 Mon Sep 17 00:00:00 2001 From: Jacob Siegle Date: Mon, 18 Aug 2025 21:22:11 -0500 Subject: [PATCH] feat(nested mock): expand PR 884 with tests --- packages/testing/ts-jest/src/mocks.spec.ts | 32 +++++++++++++++++++++- packages/testing/ts-jest/src/mocks.ts | 12 ++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/packages/testing/ts-jest/src/mocks.spec.ts b/packages/testing/ts-jest/src/mocks.spec.ts index eaa595772..ca557d12d 100644 --- a/packages/testing/ts-jest/src/mocks.spec.ts +++ b/packages/testing/ts-jest/src/mocks.spec.ts @@ -10,16 +10,28 @@ interface TestInterface { func: (num: number, str: string) => boolean; func2: (entity: TestClass) => void; func3: () => Promise<{ prop: number }>; + nested: { + someOtherNum: number; + func4: () => boolean; + }; } class TestClass { someProperty!: number; + nested = new NestedTestClass(); + someMethod() { return 42; } } +class NestedTestClass { + someOtherMethod() { + return 24; + } +} + describe('Mocks', () => { const request = { headers: { @@ -200,6 +212,22 @@ describe('Mocks', () => { expect(serviceMock.foo()).toEqual(false); expect(serviceMock.foo()).toEqual(true); }); + + it('should work with nested properties and functions', () => { + const mock = createMock(); + mock.nested.someOtherNum = 99; + mock.nested.func4.mockReturnValueOnce(true); + const result = mock.nested.func4(); + expect(mock.nested.someOtherNum).toBe(99); + expect(result).toBe(true); + }); + + it('should work with classes having nested properties', () => { + const mock = createMock(); + mock.nested.someOtherMethod.mockReturnValueOnce(99); + const result = mock.nested.someOtherMethod(); + expect(result).toBe(99); + }); }); describe('auto mocked', () => { @@ -360,7 +388,9 @@ describe('Mocks', () => { it('should throw error when calling unstubbed method in strict mode', () => { const mock = createMock({}, { strict: true }); - expect(() => mock.func(1, 'test')).toThrow('Method mock.func was called without being explicitly stubbed'); + expect(() => mock.func(1, 'test')).toThrow( + 'Method mock.func was called without being explicitly stubbed', + ); mock.func.mockReturnValue(true); expect(mock.func(1, 'test')).toBe(true); diff --git a/packages/testing/ts-jest/src/mocks.ts b/packages/testing/ts-jest/src/mocks.ts index 439bb44de..f6a905f70 100644 --- a/packages/testing/ts-jest/src/mocks.ts +++ b/packages/testing/ts-jest/src/mocks.ts @@ -21,7 +21,7 @@ export type DeepMocked = { [K in keyof T]: Required[K] extends (...args: any[]) => infer U ? jest.MockInstance[K]>, jest.ArgsType> & ((...args: jest.ArgsType) => DeepMocked) - : T[K]; + : DeepMocked; } & T; const jestFnProps = new Set([ @@ -49,7 +49,11 @@ const jestFnProps = new Set([ const createProxy: { (name: string, strict: boolean, base: T): T; = Mock>(name: string, strict: boolean): T; -} = >(name: string, strict: boolean, base?: T): T => { +} = >( + name: string, + strict: boolean, + base?: T, +): T => { const cache = new Map(); const handler: ProxyHandler = { get: (obj, prop, receiver) => { @@ -105,7 +109,9 @@ const createProxy: { return result; } else { if (strict) { - throw new Error(`Method ${name} was called without being explicitly stubbed`); + throw new Error( + `Method ${name} was called without being explicitly stubbed`, + ); } if (!cache.has('__apply')) { cache.set('__apply', createProxy(name, strict));