From 20ffef7cc62781a88d840f8fab3f7281620dd767 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 23 Sep 2026 17:29:27 +0200 Subject: [PATCH] Apply the same assertRejectsAndDisposes guard to the new provider test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "dispose() evicts a connection still mid-handshake" test (previous commit) used a bare assert.rejects(connector.connect(...)) to force the handshake-rejection path it needs, which is exactly the pattern that hung realtime-quic-consumer.test.ts under M1: found re-running M1 against the full workspace after the previous fix — it hung again, this time in realtime-quic-provider.test.ts, at this new test, for the same reason. Ported the same assertRejectsAndDisposes() helper into this file rather than importing it across test files (each file already keeps its own small helpers). Co-Authored-By: Claude Sonnet 5 --- .../test/realtime-quic-provider.test.ts | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/cultmesh-ts/test/realtime-quic-provider.test.ts b/packages/cultmesh-ts/test/realtime-quic-provider.test.ts index c3d6fc42..7c879a3f 100644 --- a/packages/cultmesh-ts/test/realtime-quic-provider.test.ts +++ b/packages/cultmesh-ts/test/realtime-quic-provider.test.ts @@ -31,6 +31,28 @@ import { nativeBridgeAvailable } from "./support/native-bridge"; // levels up. const FIXTURE_P12 = join(__dirname, "..", "..", "test", "fixtures", "quic-test.p12"); +/** + * `assert.rejects`, but safe against a mutant or a real regression that + * makes the promise resolve instead: a transport that unexpectedly connects + * is disposed before the assertion fails, so a broken certificate check + * cannot hang this file the way M1 did before realtime-quic-consumer.test.ts + * gained this same helper. + */ +async function assertRejectsAndDisposes( + promise: Promise<{ dispose(): void }>, + match?: RegExp, +): Promise { + let resolved: { dispose(): void } | undefined; + try { + resolved = await promise; + } catch (error) { + if (match) assert.match(error instanceof Error ? error.message : String(error), match); + return; + } + resolved.dispose(); + assert.fail("expected the promise to reject, but it resolved (the resolved value has been disposed)"); +} + function testFrame(overrides: Partial = {}): CultMeshRealtimeFrame { return { channelId: "aetheria.entities", @@ -387,7 +409,7 @@ test( generation: "gen-1", }; const connector = new CultMeshQuicRealtimeConnector(); - await assert.rejects(connector.connect(candidate, target), /certificate|rejected/i); + await assertRejectsAndDisposes(connector.connect(candidate, target), /certificate|rejected/i); // The provider's own accept flow is asynchronous (attachPeer awaits a // runtime reference before it can even see the rejection); give it a