|
1 | 1 | import { expect, it } from 'vitest'; |
2 | | -import { feedbackMetadata, isWireMessage, pickSigning } from '../src/x/wire-extract'; |
| 2 | +import { |
| 3 | + createGate, |
| 4 | + feedbackMetadata, |
| 5 | + isWireMessage, |
| 6 | + isWireSwitch, |
| 7 | + pickSigning, |
| 8 | + type WireMessage, |
| 9 | +} from '../src/x/wire-extract'; |
3 | 10 |
|
4 | 11 | it('reads per-post feedback metadata out of a timeline response', () => { |
5 | 12 | // The shape of HomeTimeline: entries, conversation modules with items, and |
@@ -82,3 +89,51 @@ it('recognises only its own messages', () => { |
82 | 89 | expect(isWireMessage({ kind: 'headers' })).toBe(false); |
83 | 90 | expect(isWireMessage(null)).toBe(false); |
84 | 91 | }); |
| 92 | + |
| 93 | +it('passes nothing on until "Teach X too" is on, and stops reading when it is off', () => { |
| 94 | + const headers: WireMessage = { aitf: 'wire', kind: 'headers', headers: { authorization: 'x' } }; |
| 95 | + const metadata: WireMessage = { aitf: 'wire', kind: 'metadata', entries: [['1', 'AAA=']] }; |
| 96 | + |
| 97 | + // Before the content script has spoken, messages wait; nothing is posted. |
| 98 | + const sent: WireMessage[] = []; |
| 99 | + const gate = createGate((message) => sent.push(message)); |
| 100 | + gate.send(headers); |
| 101 | + gate.send(metadata); |
| 102 | + expect(sent).toEqual([]); |
| 103 | + expect(gate.reading).toBe(true); |
| 104 | + // On: what was held goes out, and the rest follows as it comes. |
| 105 | + gate.set(true); |
| 106 | + expect(sent).toEqual([headers, metadata]); |
| 107 | + gate.send(metadata); |
| 108 | + expect(sent).toHaveLength(3); |
| 109 | + |
| 110 | + // Off: what was held is dropped, nothing is posted, and there is no reading. |
| 111 | + const dropped: WireMessage[] = []; |
| 112 | + const off = createGate((message) => dropped.push(message)); |
| 113 | + off.send(headers); |
| 114 | + off.set(false); |
| 115 | + off.send(metadata); |
| 116 | + expect(dropped).toEqual([]); |
| 117 | + expect(off.reading).toBe(false); |
| 118 | + // Switched on later, it starts clean rather than replaying what it dropped. |
| 119 | + off.set(true); |
| 120 | + expect(dropped).toEqual([]); |
| 121 | + expect(off.reading).toBe(true); |
| 122 | + |
| 123 | + // Held messages are bounded while waiting. |
| 124 | + const bounded: WireMessage[] = []; |
| 125 | + const small = createGate((message) => bounded.push(message), 2); |
| 126 | + for (let i = 0; i < 5; i++) small.send({ ...metadata, entries: [[String(i), 'A']] }); |
| 127 | + small.set(true); |
| 128 | + expect( |
| 129 | + bounded.map((message) => (message.kind === 'metadata' ? message.entries[0]![0] : '')), |
| 130 | + ).toEqual(['3', '4']); |
| 131 | +}); |
| 132 | + |
| 133 | +it('tells a switch apart from what the page script sends', () => { |
| 134 | + expect(isWireSwitch({ aitf: 'wire', kind: 'switch', on: true })).toBe(true); |
| 135 | + expect(isWireSwitch({ aitf: 'wire', kind: 'switch' })).toBe(false); |
| 136 | + expect(isWireSwitch({ aitf: 'wire', kind: 'headers', headers: {} })).toBe(false); |
| 137 | + // The content script's listener never mistakes a switch for data. |
| 138 | + expect(isWireMessage({ aitf: 'wire', kind: 'switch', on: true })).toBe(false); |
| 139 | +}); |
0 commit comments