From 876c20ffb98e4be8a7555ff6ea70ff5a04c61822 Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Tue, 25 Jun 2024 18:32:50 +0900 Subject: [PATCH] refactor(testing): remove dead code and improve test of `testing/mock.ts` (#5137) --- testing/mock.ts | 5 -- testing/mock_test.ts | 131 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 5 deletions(-) diff --git a/testing/mock.ts b/testing/mock.ts index 3d6d6e57e..3684b0697 100644 --- a/testing/mock.ts +++ b/testing/mock.ts @@ -1413,11 +1413,6 @@ export async function assertSpyCallAsync< "do not expect error and return, only one should be expected", ); } - if (call.error) { - throw new AssertionError( - "spy call did not return expected value, an error was thrown.", - ); - } let expectedResolved; try { expectedResolved = await expected.returned; diff --git a/testing/mock_test.ts b/testing/mock_test.ts index fecdc07d0..5b3cc3c47 100644 --- a/testing/mock_test.ts +++ b/testing/mock_test.ts @@ -510,6 +510,51 @@ Deno.test("spy() works on constructor of child class", () => { assertSpyCalls(PointSpy, 1); }); +Deno.test("spy() works with throwing method", () => { + const obj = { + fn() { + throw new Error("failed"); + }, + }; + const spyFn = spy(obj, "fn"); + assertThrows(() => obj.fn(), Error, "failed"); + assertSpyCall(spyFn, 0, { + self: obj, + args: [], + error: { Class: Error, msgIncludes: "failed" }, + }); +}); + +Deno.test("spy() throws when try spying already spied method", () => { + const obj = { fn() {} }; + spy(obj, "fn"); + assertThrows( + () => spy(obj, "fn"), + MockError, + "already spying on instance method", + ); +}); + +Deno.test("spy() throws when the property is not a method", () => { + const obj = {}; + assertThrows( + // deno-lint-ignore no-explicit-any + () => spy(obj as any, "fn"), + MockError, + "property is not an instance method", + ); +}); + +Deno.test("spy() throws when the property is not configurable", () => { + const obj = { fn() {} }; + Object.defineProperty(obj, "fn", { configurable: false }); + assertThrows( + () => spy(obj, "fn"), + MockError, + "cannot spy on non configurable instance method", + ); +}); + Deno.test("stub()", () => { const point = new Point(2, 3); const func = stub(point, "action"); @@ -714,6 +759,53 @@ Deno.test("stub() correctly handles types", () => { }); }); +Deno.test("stub() works with throwing fake implementation", () => { + const obj = { + fn() { + throw new Error("failed"); + }, + }; + const stubFn = stub(obj, "fn", () => { + throw new Error("failed"); + }); + assertThrows(() => obj.fn(), Error, "failed"); + assertSpyCall(stubFn, 0, { + self: obj, + args: [], + error: { Class: Error, msgIncludes: "failed" }, + }); +}); + +Deno.test("stub() throws when the property is not a method", () => { + const obj = { fn: 1 }; + assertThrows( + // deno-lint-ignore no-explicit-any + () => stub(obj as any, "fn"), + MockError, + "property is not an instance method", + ); +}); + +Deno.test("stub() throws when try stubbing already stubbed method", () => { + const obj = { fn() {} }; + stub(obj, "fn"); + assertThrows( + () => stub(obj, "fn"), + MockError, + "already spying on instance method", + ); +}); + +Deno.test("stub() throws then the property is not configurable", () => { + const obj = { fn() {} }; + Object.defineProperty(obj, "fn", { configurable: false }); + assertThrows( + () => stub(obj, "fn"), + MockError, + "cannot spy on non configurable instance method", + ); +}); + Deno.test("mockSession() and mockSessionAsync()", async () => { const points = [ new Point(2, 3), @@ -1228,6 +1320,21 @@ Deno.test("assertSpyCall() works with error", () => { ); }); +Deno.test("assertSpyCall() throws TypeError when returned and error are both provided", () => { + const spyFunc = spy(() => 5); + spyFunc(); + + assertThrows( + () => + assertSpyCall(spyFunc, 0, { + returned: 5, + error: { msgIncludes: "x" }, + }), + TypeError, + "do not expect error and return, only one should be expected", + ); +}); + Deno.test("assertSpyCallAsync() works with function", async () => { const spyFunc = spy((multiplier?: number) => Promise.resolve(5 * (multiplier ?? 1)) @@ -1528,6 +1635,16 @@ Deno.test("assertSpyCallAsync() works with error", async () => { msgIncludes: "fail", }, }); + await assertSpyCallAsync(spyFunc, 0, { + error: { + msgIncludes: "fail", + }, + }); + await assertSpyCallAsync(spyFunc, 0, { + error: { + Class: Error, + }, + }); await assertRejects( () => @@ -1636,6 +1753,20 @@ Deno.test("assertSpyCallAsync() works with error", async () => { ); }); +Deno.test("assertSpyCallAsync() throws type error if expected return value is rejected", async () => { + const spyFunc = spy(() => Promise.resolve(5)); + + spyFunc(); + await assertRejects( + () => + assertSpyCallAsync(spyFunc, 0, { + returned: Promise.reject(new Error("failed")), + }), + TypeError, + "do not expect rejected promise, expect error instead", + ); +}); + Deno.test("assertSpyCallArg()", () => { const spyFunc = spy();