elvitin
elvitin11mo ago

Strange behavior of the assertRejects() method.

Behavior of the assertRejects() method. assertRejects() fails when a non-stubbed method is called before the stubbed method. Let's look at the following example:
// main.ts
export class MainClass {
async mainFn(): Promise<void> {
await this.foo();
await this.bar();
}

foo(): Promise<string> {
return Promise.resolve("foo");
}

bar(): Promise<string> {
return Promise.resolve("bar");
}
}
// main.ts
export class MainClass {
async mainFn(): Promise<void> {
await this.foo();
await this.bar();
}

foo(): Promise<string> {
return Promise.resolve("foo");
}

bar(): Promise<string> {
return Promise.resolve("bar");
}
}
// main_test.ts
import { describe } from "https://deno.land/std@0.212.0/testing/bdd.ts";
import { stub } from "https://deno.land/std@0.212.0/testing/mock.ts";
import { assertRejects } from "https://deno.land/std@0.212.0/assert/mod.ts";
import { MainClass } from "./main.ts";

describe("unit test", () => {
const mainObj = new MainClass();
const barStub = stub(
mainObj,
"bar",
() => new Promise((_, reject) => reject(new Error())),
);

assertRejects(() => mainObj.mainFn(), "yeah, bar() rejects with Error");
barStub.restore();
});
// main_test.ts
import { describe } from "https://deno.land/std@0.212.0/testing/bdd.ts";
import { stub } from "https://deno.land/std@0.212.0/testing/mock.ts";
import { assertRejects } from "https://deno.land/std@0.212.0/assert/mod.ts";
import { MainClass } from "./main.ts";

describe("unit test", () => {
const mainObj = new MainClass();
const barStub = stub(
mainObj,
"bar",
() => new Promise((_, reject) => reject(new Error())),
);

assertRejects(() => mainObj.mainFn(), "yeah, bar() rejects with Error");
barStub.restore();
});
execute: deno test output:
FAILED | 0 passed | 1 failed (0ms)

error: Test failed
FAILED | 0 passed | 1 failed (0ms)

error: Test failed
Note that bar() is stubbed to reject the promise with an error. However, bar() only rejects with an error if foo() is not called:
// main.ts
export class MainClass {
async mainFn(): Promise<void> {
//await this.foo(); // <-- foo() is not called
await this.bar();
}
//rest of code...
// main.ts
export class MainClass {
async mainFn(): Promise<void> {
//await this.foo(); // <-- foo() is not called
await this.bar();
}
//rest of code...
execute: deno test output:
Check file:///tmp/stdstub/main_test.ts
running 1 test from ./main_test.ts
unit test ... ok (1ms)

ok | 1 passed | 0 failed (4ms)
Check file:///tmp/stdstub/main_test.ts
running 1 test from ./main_test.ts
unit test ... ok (1ms)

ok | 1 passed | 0 failed (4ms)
What am I doing wrong? Is this a bug in the stub() method, or what am I not understanding?
2 Replies
Deno AI Helper
Deno AI Helper11mo ago
I wasn't able to find the answer to your question in the official Deno documentation. However, based on the code you've provided, there is one thing that stands out which might be causing the issue. In your test code, you are not awaiting the assertRejects() call. Since assertRejects() returns a Promise, you should await it to ensure that the test runner waits for the assertion to complete before moving on. Here's the corrected part of your test code:
// main_test.ts
// ... rest of your imports

describe("unit test", () => {
it("should reject when bar is called", async () => {
const mainObj = new MainClass();
const barStub = stub(
mainObj,
"bar",
() => new Promise((_, reject) => reject(new Error())),
);

await assertRejects(() => mainObj.mainFn(), Error, "yeah, bar() rejects with Error");
barStub.restore();
});
});
// main_test.ts
// ... rest of your imports

describe("unit test", () => {
it("should reject when bar is called", async () => {
const mainObj = new MainClass();
const barStub = stub(
mainObj,
"bar",
() => new Promise((_, reject) => reject(new Error())),
);

await assertRejects(() => mainObj.mainFn(), Error, "yeah, bar() rejects with Error");
barStub.restore();
});
});
Please note that the advice provided here is not based on the Deno documentation, and you should double-check the accuracy of the advice given. Additionally, ensure that your test framework supports asynchronous tests and that you are using the correct syntax for defining test cases.
elvitin
elvitinOP11mo ago
Thank you, AI. Yes, that is exactly the problem. You have been extremely helpful now. Congratulations.