Skip to content

Commit 67c66bb

Browse files
committed
chore: fix prettier formatting and TypeScript type error in test
1 parent 5f7548c commit 67c66bb

2 files changed

Lines changed: 38 additions & 8 deletions

File tree

src/client/slidingSync.test.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ function makeMockMx(overrides: Record<string, unknown> = {}) {
8989
store: {
9090
setSyncData: vi.fn().mockResolvedValue(undefined),
9191
save: vi.fn().mockResolvedValue(undefined),
92+
removeRoom: vi.fn(),
9293
},
9394
...overrides,
9495
} as unknown as import('$types/matrix-sdk').MatrixClient;
@@ -169,6 +170,24 @@ describe('SlidingSyncManager — timeline pruning on unsubscribe', () => {
169170
expect(payload.rooms.join['!room:example.com'].timeline.limited).toBe(true);
170171
});
171172

173+
it('evicts room from store cache when persist fails', async () => {
174+
const room = makeMockRoom(PRUNE_THRESHOLD + 1);
175+
const mx = makeMockMx({ getRoom: vi.fn().mockReturnValue(room) });
176+
// Make setSyncData reject to simulate an IndexedDB write failure.
177+
(
178+
mx as unknown as { store: { setSyncData: ReturnType<typeof vi.fn> } }
179+
).store.setSyncData.mockRejectedValue(new Error('IndexedDB write failed'));
180+
const manager = makeManager(mx);
181+
182+
manager.unsubscribeFromRoom('!room:example.com');
183+
await flushPromises();
184+
185+
const { store } = mx as unknown as {
186+
store: { removeRoom: ReturnType<typeof vi.fn> };
187+
};
188+
expect(store.removeRoom).toHaveBeenCalledWith('!room:example.com');
189+
});
190+
172191
it('does not reset when event count equals the threshold exactly', () => {
173192
const room = makeMockRoom(PRUNE_THRESHOLD);
174193
const mx = makeMockMx({ getRoom: vi.fn().mockReturnValue(room) });
@@ -205,13 +224,16 @@ describe('SlidingSyncManager — membership leave auto-unsubscribe', () => {
205224
mx: ReturnType<typeof makeMockMx>,
206225
membership: string,
207226
roomId = '!room:example.com',
208-
userId = '@user:example.com',
227+
userId = '@user:example.com'
209228
) {
210229
const onCall = (mx.on as ReturnType<typeof vi.fn>).mock.calls.find(
211-
([event]: [string]) => event === 'RoomMember.membership',
230+
(args: unknown[]) => args[0] === 'RoomMember.membership'
212231
);
213232
if (!onCall) throw new Error('onMembershipLeave listener not registered');
214-
const [, handler] = onCall as [string, (e: unknown, m: { userId: string; roomId: string; membership: string }) => void];
233+
const [, handler] = onCall as [
234+
string,
235+
(e: unknown, m: { userId: string; roomId: string; membership: string }) => void,
236+
];
215237
handler(undefined, { userId, roomId, membership });
216238
}
217239

@@ -275,4 +297,3 @@ describe('SlidingSyncManager — membership leave auto-unsubscribe', () => {
275297
expect(room._resetLiveTimeline).not.toHaveBeenCalled();
276298
});
277299
});
278-

src/client/slidingSync.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,10 @@ export class SlidingSyncManager {
258258

259259
private readonly onLifecycle: (state: SlidingSyncState, resp: unknown, err?: Error) => void;
260260

261-
private readonly onMembershipLeave: (event: unknown, member: { userId: string; roomId: string; membership?: string }) => void;
261+
private readonly onMembershipLeave: (
262+
event: unknown,
263+
member: { userId: string; roomId: string; membership?: string }
264+
) => void;
262265

263266
private presenceExtension!: ExtensionPresence;
264267

@@ -430,7 +433,8 @@ export class SlidingSyncManager {
430433

431434
this.onMembershipLeave = (_event, member) => {
432435
if (member.userId !== this.mx.getUserId()) return;
433-
if (member.membership !== KnownMembership.Leave && member.membership !== KnownMembership.Ban) return;
436+
if (member.membership !== KnownMembership.Leave && member.membership !== KnownMembership.Ban)
437+
return;
434438
if (!this.activeRoomSubscriptions.has(member.roomId)) return;
435439
this.unsubscribeFromRoom(member.roomId);
436440
};
@@ -563,13 +567,18 @@ export class SlidingSyncManager {
563567
room.getUnfilteredTimelineSet().resetLiveTimeline();
564568

565569
// Persist the tail of the timeline to IndexedDB asynchronously.
566-
// If it fails, the events are still available from the server.
570+
// On failure, evict the room from the store so the next open gets a clean
571+
// server fetch rather than potentially stale cached data.
567572
this.persistRoomTimeline(
568573
roomId,
569574
events.map((e) => e.event as IRoomEvent),
570575
prevBatch
571576
).catch((err: unknown) => {
572-
debugLog.warn('timeline', 'Failed to persist pruned room timeline', { roomId, err });
577+
debugLog.warn('timeline', 'Failed to persist pruned room timeline — evicting store cache', {
578+
roomId,
579+
err,
580+
});
581+
this.mx.store.removeRoom(roomId);
573582
});
574583

575584
debugLog.info('timeline', 'Pruned room timeline from memory', {

0 commit comments

Comments
 (0)