deno
deno copied to clipboard
Test step unexpectedly fails due to “leaking async ops“
With this test.mjs module:
import puppeteer from "https://deno.land/x/[email protected]/mod.ts";
Deno.test("A", async (t) => {
const browser = await puppeteer.launch();
try {
await t.step("B", async () => {});
} finally {
await browser.close();
}
});
With this command:
deno test --allow-all
The tests fail with an error:
running 1 test from ./test.mjs
A ...
B ... FAILED (2ms)
error: AssertionError: Test case is leaking async ops.
- 1 async operation to sleep for a duration was started before this test, but was completed during the test. Async operations should not complete in a test if they were not started in that test.
This is often caused by not cancelling a `setTimeout` or `setInterval` call.
To get more details where ops were leaked, run again with --trace-ops flag.
await t.step("B", async () => {});
^
at assert (deno:ext/web/00_infra.js:294:13)
at asyncOpSanitizer (deno:runtime/js/40_testing.js:223:13)
at async resourceSanitizer (deno:runtime/js/40_testing.js:368:7)
at async exitSanitizer (deno:runtime/js/40_testing.js:425:9)
at async TestContext.step (deno:runtime/js/40_testing.js:1328:13)
at async file://[redacted]/test.mjs:7:5
A ... FAILED (341ms)
ERRORS
A => ./test.mjs:3:6
error: Error: 1 test step failed.
at runTest (deno:runtime/js/40_testing.js:835:11)
at async Object.runTests (deno:runtime/js/40_testing.js:1084:22)
FAILURES
A => ./test.mjs:3:6
FAILED | 0 passed | 1 failed (1 step) (397ms)
error: Test failed
With the test step commented out:
import puppeteer from "https://deno.land/x/[email protected]/mod.ts";
Deno.test("A", async (t) => {
const browser = await puppeteer.launch();
try {
// await t.step("B", async () => {});
} finally {
await browser.close();
}
});
The tests pass without error:
running 1 test from ./test.mjs
A ... ok (307ms)
ok | 1 passed | 0 failed (366ms)
GitHub automatically closed this issue based on the unfortunate phrasing of the commit message.
Have you read https://deno.land/[email protected]/testing/sanitizers?
I experienced the same issue before while testing with database connection, even after I manually close the connection after all steps is completed as you did above. Turns out I need to disable sanitizeResources and sanitizeOps on parent Deno.test.
This might solve your issue.
I faced the same problem with Deno v1.29.1.
In my case, I was able to solve it by putting a zero await before the first t.step().
await new Promise((resolve) => setTimeout(resolve, 0));
await t.step("step1", () => {
countAsync("C");
});
Note that this method is based on a comment I found in 40_testing.js.
https://github.com/denoland/deno/blob/2fab4583ef3db0a3d8438ffa07f9e64db8190433/cli/js/40_testing.js#L39-L54 https://github.com/denoland/deno/blob/2fab4583ef3db0a3d8438ffa07f9e64db8190433/cli/js/40_testing.js#L149-L153
So I think we can solve this problem by putting a similar await process before the line below
https://github.com/denoland/deno/blob/2fab4583ef3db0a3d8438ffa07f9e64db8190433/cli/js/40_testing.js#L144
What do you think?
I have similar problem and work around from Chat GPT
The error you are encountering, "Leaking async ops", is likely due to the fact that the logging module is performing asynchronous file operations (such as writing to a file) which are not being awaited or completed before the test ends. This can cause issues with Deno's test runner, which expects all asynchronous operations started during a test to also be completed during the same test.
One way to address this issue is to ensure that the logging module completes all its asynchronous operations before the test ends. This can be done by flushing the logs or waiting for the file operations to complete.
However, since you are using Deno's standard logging module, which does not provide a built-in way to flush logs, you can use a workaround by wrapping your tests in a function that waits for a short period of time before and after running the tests. This will give the logging module time to complete its asynchronous operations.
Here's an example of how you can modify your test file:
// ohlcv_db_test.ts
import { assertEquals } from "./deps.ts";
import { OhlcvDb } from "./ohlcv_db.ts";
import { loadConfig, Config } from "./config.ts";
let testConfig: Config;
async function runTest(testName: string, testFn: () => Promise<void>) {
await new Promise(resolve => setTimeout(resolve, 100)); // Wait before running the test
await testFn();
await new Promise(resolve => setTimeout(resolve, 100)); // Wait after running the test
}
Deno.test("Load Config", async () => {
await runTest("Load Config", async () => {
testConfig = await loadConfig("test", "./"); // replace with your test environment and path
assertEquals(typeof testConfig.POSTGRES_HOST, "string");
});
});
Deno.test("Should connect to the database", async () => {
await runTest("Should connect to the database", async () => {
const ohlcvDb = new OhlcvDb(testConfig);
await ohlcvDb.connect();
assertEquals(ohlcvDb.client !== null, true);
await ohlcvDb.close();
});
});
Deno.test("Should close the database connection", async () => {
await runTest("Should close the database connection", async () => {
const ohlcvDb = new OhlcvDb(testConfig);
await ohlcvDb.connect();
await ohlcvDb.close();
assertEquals(ohlcvDb.client, null);
});
});
This approach introduces a small delay before and after each test, which can help ensure that asynchronous operations have time to complete. However, it's a workaround and not a perfect solution. Ideally, the logging module should provide a way to flush logs or wait for file operations to complete.
I faced the same problem with Deno v1.29.1.
I can confirm the problem is still current in v1.35.3.
In my case, I was able to solve it by putting a zero
awaitbefore the firstt.step().
Adding await new Promise((resolve) => setTimeout(resolve, 0)); before the first step does indeed help in the example mentioned at the beginning of this issue. Thanks for that. Without it, none of my more complicated test were working. I wonder how anyone gets anything done with this problem unfixed wrt testing.
Just in case someone comes here with the same problem, i was able to fix my same issue with the following:
Deno.test({ name: "Test to see if pupeteer can connect to a pre-launched Chrome instance in dev mode", async fn() { const b = await connectToBrowser(); assertExists(b); await b?.disconnect(); }, sanitizeResources: false, });
It was the sanitize that fixed it. Please see : https://deno.land/[email protected]/testing/sanitizers
@zwn Have you upgraded deno? It works well for me (deno 1.38.3 / macosx 12 m1)
Issue is still happening on windows, see https://github.com/denoland/deno/issues/20179
@mmastrac can this issue be closed given the sanitizer rewrite?