diff --git a/package-lock.json b/package-lock.json index 4751619..c29d49a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "@athenna/test", - "version": "4.12.0", + "version": "4.13.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@athenna/test", - "version": "4.12.0", + "version": "4.13.0", "license": "MIT", "dependencies": { "@japa/assert": "^1.4.1", "@japa/run-failed-tests": "^1.1.0", "@japa/runner": "^2.2.2", "@japa/spec-reporter": "^1.3.3", - "@types/sinon": "^10.0.16", + "@types/sinon": "^10.0.17", "c8": "^8.0.1", "sinon": "^15.1.0" }, @@ -1186,9 +1186,9 @@ "dev": true }, "node_modules/@types/sinon": { - "version": "10.0.16", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.16.tgz", - "integrity": "sha512-j2Du5SYpXZjJVJtXBokASpPRj+e2z+VUhCPHmM6WMfe3dpHu6iVKJMU6AiBcMp/XTAYnEj6Wc1trJUWwZ0QaAQ==", + "version": "10.0.17", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.17.tgz", + "integrity": "sha512-+6ILpcixQ0Ma3dHMTLv4rSycbDXkDljgKL+E0nI2RUxxhYTFyPSjt6RVMxh7jUshvyVcBvicb0Ktj+lAJcjgeA==", "dependencies": { "@types/sinonjs__fake-timers": "*" } diff --git a/package.json b/package.json index e175d6b..b81957f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@athenna/test", - "version": "4.12.0", + "version": "4.13.0", "description": "The Athenna test runner. Built on top of Japa.", "license": "MIT", "author": "João Lenon ", @@ -60,7 +60,7 @@ "@japa/run-failed-tests": "^1.1.0", "@japa/runner": "^2.2.2", "@japa/spec-reporter": "^1.3.3", - "@types/sinon": "^10.0.16", + "@types/sinon": "^10.0.17", "c8": "^8.0.1", "sinon": "^15.1.0" }, diff --git a/src/mocks/Mock.ts b/src/mocks/Mock.ts index 0308c66..6ca1c5c 100644 --- a/src/mocks/Mock.ts +++ b/src/mocks/Mock.ts @@ -82,6 +82,27 @@ export class Mock { return Mock.sandbox.match(value) } + /** + * Restore a mock to default behavior. + * + * @example + * ```ts + * Mock.when(console, 'log').return(undefined) + * + * Mock.restore(console.log) + * ``` + */ + public static restore(value: any): void { + if (!value.restore) { + return + } + + value.restore() + value.resetHistory() + value.resetBehavior() + value.reset() + } + /** * Restore all mocks to default. */ diff --git a/src/mocks/MockBuilder.ts b/src/mocks/MockBuilder.ts index 0062801..636b7f8 100644 --- a/src/mocks/MockBuilder.ts +++ b/src/mocks/MockBuilder.ts @@ -18,6 +18,26 @@ export class MockBuilder { private sandbox: SinonSandbox ) {} + /** + * Mock a property changing it value. + * + * @example + * ```ts + * import { Mock } from '@athenna/test' + * + * const mock = Mock.when(console, 'log').value(() => {}) + * + * mock.called // false + * ``` + */ + public value(value: T): Stub { + const stub = this.sandbox.stub(this.object, this.method) + + stub.value(value) + + return stub + } + /** * Mock the method to return the given value. * diff --git a/tests/unit/mocks/MockTest.ts b/tests/unit/mocks/MockTest.ts index 84aaa6e..a918369 100644 --- a/tests/unit/mocks/MockTest.ts +++ b/tests/unit/mocks/MockTest.ts @@ -52,6 +52,17 @@ export default class MockTest { assert.calledWith(spy, 1) } + @Test() + public async shouldBeAbleToMockObjectPropertyWithDifferentValues({ assert }: Context) { + const userService = new UserService() + + Mock.when(userService, 'findById').value(() => ({ id: 2 })) + + const value = userService.findById(1) + + assert.deepEqual(value, { id: 2 }) + } + @Test() public async shouldBeAbleToMockObjectMethodsToReturnValue({ assert }: Context) { const userService = new UserService() @@ -121,4 +132,42 @@ export default class MockTest { await assert.doesNotRejects(() => userService.find()) await assert.doesNotRejects(() => userService.findById(1)) } + + @Test() + public async shouldBeAbleToRestoreASingleMockedMethod({ assert }: Context) { + const userService = new UserService() + + Mock.when(userService, 'find').reject(new Error('ERROR_MOCK')) + Mock.when(userService, 'findById').reject(new Error('ERROR_MOCK')) + + await assert.rejects(() => userService.find(), Error) + await assert.rejects(() => userService.findById(1), Error) + + Mock.restore(userService.find) + Mock.restore(userService.findById) + + await assert.doesNotRejects(() => userService.find()) + await assert.doesNotRejects(() => userService.findById(1)) + } + + @Test() + public async shouldBeAbleToRestoreASingleMockedProperty({ assert }: Context) { + const userService = new UserService() + + const mockFind = Mock.when(userService, 'find').value(() => { + throw new Error('ERROR_MOCK') + }) + const mockFindById = Mock.when(userService, 'findById').value(() => { + throw new Error('ERROR_MOCK') + }) + + await assert.rejects(() => userService.find(), Error) + await assert.rejects(() => userService.findById(1), Error) + + Mock.restore(mockFind) + Mock.restore(mockFindById) + + await assert.doesNotRejects(() => userService.find()) + await assert.doesNotRejects(() => userService.findById(1)) + } }