native-browser: retry the chat probes across stream renewals
Chat is not replayed to a recipient whose stream is renewing, and the gate renews every ten seconds; since the camera steps went in, the chat exchange runs after the first renewal and under load loses a line to the gap. Three tries each way; a chat path that is really broken still fails.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+30
−6
test/browser/native.mjs+30 −6
diff --git a/test/browser/native.mjs b/test/browser/native.mjs| index e7a19b5..e64991e 100644 |
| --- a/test/browser/native.mjs |
| +++ b/test/browser/native.mjs |
| @@ -171,12 +171,36 @@ try { |
| assert.equal(sample.stats.peerConnections, 1, 'recovering the camera keeps the same peer connection'); |
| console.log('PASS a stalled camera was restarted and the far side kept its picture'); |
| } |
| - await page.locator('[data-chat-text]').fill('browser chat probe'); |
| - await page.locator('[data-chat-send]').click(); |
| - await wait(() => sample?.receivedChatProbe === true, 'native displays browser chat'); |
| - native.stdin.write('chat\n'); |
| - await wait(() => chatCommandHandled, 'native handles send-chat command'); |
| - await page.locator('[data-chat-log]').getByText('native chat probe', { exact: true }).waitFor(); |
| + // Chat is not replayed to a recipient whose stream is renewing (§6), and |
| + // in this mode the stream renews every ten seconds, so a line that lands |
| + // in a renewal's gap is lost by design. Since the camera steps above went |
| + // in, chat runs well after the first renewal, and under load the gap is |
| + // wide enough to catch it (2026-09-25: both subtests failed here on an |
| + // unchanged tree, then passed alone and in a full run). Each direction |
| + // gets three tries; a line that never arrives still fails. |
| + for (let attempt = 1; ; attempt++) { |
| + await page.locator('[data-chat-text]').fill('browser chat probe'); |
| + await page.locator('[data-chat-send]').click(); |
| + try { |
| + await wait(() => sample?.receivedChatProbe === true, 'native displays browser chat', 8); |
| + break; |
| + } catch (err) { |
| + if (attempt === 3) throw err; |
| + console.log('RETRY browser chat probe, attempt', attempt + 1); |
| + } |
| + } |
| + for (let attempt = 1; ; attempt++) { |
| + native.stdin.write('chat\n'); |
| + await wait(() => chatCommandHandled, 'native handles send-chat command'); |
| + try { |
| + await page.locator('[data-chat-log]').getByText('native chat probe', { exact: true }).first() |
| + .waitFor({ timeout: 8000 }); |
| + break; |
| + } catch (err) { |
| + if (attempt === 3) throw err; |
| + console.log('RETRY native chat probe, attempt', attempt + 1); |
| + } |
| + } |
| await wait(() => sample?.sentChatProbe === true, 'native displays accepted outgoing chat'); |
| console.log('PASS chat delivered from browser to native and native to browser'); |
| // Spec §15.19 across the two clients: the app's mute reaches the |