mirror of
https://github.com/obra/superpowers.git
synced 2026-06-15 15:19:04 +08:00
Harden brainstorm companion auth regressions
This commit is contained in:
@@ -85,7 +85,7 @@ console.log('\n--- Reconnect state machine (mocked browser) ---');
|
||||
// Drive helper.js's browser code against mocked DOM/WebSocket/timers/clock so we
|
||||
// can exercise the actual reconnect/status/tombstone behaviour, not just grep it.
|
||||
function makeEnv() {
|
||||
const state = { now: 1000, timers: [], reloads: 0, appended: [] };
|
||||
const state = { now: 1000, timers: [], reloads: 0, replacements: [], appended: [], sessionKey: 'stored-key-abc' };
|
||||
const sockets = [];
|
||||
const statusEl = { textContent: '', style: { setProperty() {} } };
|
||||
class FakeWS {
|
||||
@@ -97,7 +97,14 @@ function makeEnv() {
|
||||
FakeWS.OPEN = 1;
|
||||
const env = {
|
||||
module: { exports: {} },
|
||||
window: { location: { host: 'localhost:7777', reload() { state.reloads++; } } },
|
||||
window: {
|
||||
location: {
|
||||
host: 'localhost:7777',
|
||||
reload() { state.reloads++; },
|
||||
replace(url) { state.replacements.push(url); }
|
||||
},
|
||||
sessionStorage: { getItem: (key) => key === 'brainstorm-session-key' ? state.sessionKey : null }
|
||||
},
|
||||
document: {
|
||||
querySelector: (s) => s === '.status' ? statusEl : null,
|
||||
getElementById: () => null,
|
||||
@@ -124,6 +131,20 @@ function makeEnv() {
|
||||
};
|
||||
}
|
||||
|
||||
test('uses sessionStorage key in the WebSocket URL when present', () => {
|
||||
const e = makeEnv();
|
||||
e.state.sessionKey = 'stored-key-abc';
|
||||
e.boot();
|
||||
assert.strictEqual(e.sockets[0].url, 'ws://localhost:7777/?key=stored-key-abc');
|
||||
});
|
||||
|
||||
test('uses cookie-only WebSocket URL when no sessionStorage key is present', () => {
|
||||
const e = makeEnv();
|
||||
e.state.sessionKey = null;
|
||||
e.boot();
|
||||
assert.strictEqual(e.sockets[0].url, 'ws://localhost:7777');
|
||||
});
|
||||
|
||||
test('on disconnect shows Reconnecting and schedules a 500ms reconnect', () => {
|
||||
const e = makeEnv(); e.boot();
|
||||
e.last().open();
|
||||
@@ -150,13 +171,26 @@ test('shows the tombstone and Disconnected after the grace period', () => {
|
||||
assert.strictEqual(e.state.appended.length, 1, 'tombstone appended exactly once');
|
||||
});
|
||||
|
||||
test('reloads to recover when a tombstoned connection comes back', () => {
|
||||
test('rebootstraps with stored key when a tombstoned connection comes back', () => {
|
||||
const e = makeEnv(); e.boot();
|
||||
e.last().open(); e.last().close();
|
||||
e.advance(20000); e.fireReconnect(); e.last().close(); // tombstone now shown
|
||||
assert.strictEqual(e.state.reloads, 0);
|
||||
assert.deepStrictEqual(e.state.replacements, []);
|
||||
e.fireReconnect(); e.last().open(); // server back (e.g. same-port restart)
|
||||
assert.strictEqual(e.state.reloads, 0, 'stored-key recovery should not reload bare /');
|
||||
assert.deepStrictEqual(e.state.replacements, ['/?key=stored-key-abc']);
|
||||
});
|
||||
|
||||
test('reloads to recover when tombstoned and no sessionStorage key is present', () => {
|
||||
const e = makeEnv();
|
||||
e.state.sessionKey = null;
|
||||
e.boot();
|
||||
e.last().open(); e.last().close();
|
||||
e.advance(20000); e.fireReconnect(); e.last().close(); // tombstone now shown
|
||||
assert.strictEqual(e.state.reloads, 0);
|
||||
e.fireReconnect(); e.last().open(); // server back (e.g. cookie-only page)
|
||||
assert.strictEqual(e.state.reloads, 1, 'reloads once on recovery');
|
||||
assert.deepStrictEqual(e.state.replacements, []);
|
||||
});
|
||||
|
||||
console.log(`\n--- Results: ${passed} passed, ${failed} failed ---`);
|
||||
|
||||
Reference in New Issue
Block a user