BOLL
BOLL•2mo ago

Possible to use Deno.test for callbacks?

I've been implementing tests to make sure the porting of my main project to Deno is working out as expected, coupled with this is a WebSocket server done with Deno.serve. For this the test needs to handle both a server and client session, waiting for callbacks to come through. Right now my test finishes prematurely even if I await the termination of the server, I need to set both sanitizeOps: false and sanitizeResources: false to have the test finish at all, but then it skips any assert defined in the callbacks. My previous experience is with Mocha where we get the done callback to run to finish the current test, but for Deno.test I only see us getting the option to make the test caller asynchronous, which in this case doesn't seem to help me. Basically, is it possible to have something like this working:
Deno.test('ws session', async ()=>{
const srv = new Server()
srv.onOpen = ()=>{ /* send message to client */ }
srv.onMessage = ()=>{ /* confirm then disconnect client */ }
srv.onClose = ()=>{ /* finish test */ }
const cli = new Client()
cli.onMessage(()=>{ /* respond to server */ })
})
Deno.test('ws session', async ()=>{
const srv = new Server()
srv.onOpen = ()=>{ /* send message to client */ }
srv.onMessage = ()=>{ /* confirm then disconnect client */ }
srv.onClose = ()=>{ /* finish test */ }
const cli = new Client()
cli.onMessage(()=>{ /* respond to server */ })
})
My problem now is as mentioned that the callbacks will happen at arbitrary points in time and aren't made to be awaited, so they won't be blocking the test from finishing. I can see adding a few more options to the test options object, like awaitDone and timeout, to enable running until manually marked as done or failing when timing out. To finish a test Deno.TestContext could have a .done() method on it. Unless this already exists, but I haven't found how to achieve this in the docs or in the types, yet. The simulated example but with the above suggestion:
Deno.test('ws session', {awaitDone: true, timeout: 5000}, async (t)=>{
const srv = new Server()
// ...
srv.onClose = ()=>{ t.done() }
// ...
})
Deno.test('ws session', {awaitDone: true, timeout: 5000}, async (t)=>{
const srv = new Server()
// ...
srv.onClose = ()=>{ t.done() }
// ...
})
3 Replies
bartlomieju
bartlomieju•2mo ago
You want to create a Promise.withResolvers(), then you can resolve the promise in one callbacks then await the promise at the end of the test
Deno.test("ws session", async () => {
const r = Promise.withResolvers();
srv.onOpen = () => { r.resolve() };
await r.promise;
});
Deno.test("ws session", async () => {
const r = Promise.withResolvers();
srv.onOpen = () => { r.resolve() };
await r.promise;
});
BOLL
BOLLOP•2mo ago
I wrote this thread before lunch running on fumes, that was clear as I thought of this very solution while eating 🤣 Thanks for giving me an example to work with! Awesome, with this I can even shut down both the server and client so the sanitize options are no longer needed, wohoo 😄 Due to the randomness I also made a resolve function that counted up so I could wait for both the server and client to finish shutting down before resolving, all done now 😄
bartlomieju
bartlomieju•2mo ago
That's great!