Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 41 additions & 23 deletions tests/Unit/RemoteNotifications.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,16 @@ beforeEach(() => {
},
});
vi.stubGlobal('document', { addEventListener() {}, removeEventListener() {} });
let lock = Promise.resolve();
vi.stubGlobal('navigator', { locks: { request: (_name: string, run: () => Promise<void>) => (lock = lock.then(run)) } });
const locks = new Map<string, Promise<void>>();
vi.stubGlobal('navigator', { locks: { request: (name: string, options: LockOptions | (() => Promise<void>), run?: () => Promise<void>) => {
const callback = typeof options === 'function' ? options : () => {
options.signal?.throwIfAborted();
return run!();
};
const lock = (locks.get(name) ?? Promise.resolve()).then(callback, callback);
locks.set(name, lock);
return lock;
} } });
});

afterEach(() => {
Expand Down Expand Up @@ -378,10 +386,17 @@ test.each([true, false])('background inbox polling alerts without consuming unre
const stop = watchRemoteAlerts('me');

try {
await vi.advanceTimersByTimeAsync(0);
await vi.advanceTimersByTimeAsync(59_999);
assert.deepEqual(requestedBaselines, []);
await vi.advanceTimersByTimeAsync(1);
assert.deepEqual(requestedBaselines, [true]);
assert.equal(shown.length, 0);
messages = [conversation(31, { kind: 'org' })];
await vi.advanceTimersByTimeAsync(15_000);
await vi.advanceTimersByTimeAsync(59_999);
assert.deepEqual(requestedBaselines, [true]);
assert.equal(shown.length, 0);
assert.equal(play.mock.calls.length, 0);
await vi.advanceTimersByTimeAsync(1);
assert.equal(shown.length, Number(banners));
assert.equal(play.mock.calls.length, 1);
assert.equal(chatSnapshot().unread, 1);
Expand All @@ -391,22 +406,22 @@ test.each([true, false])('background inbox polling alerts without consuming unre

unread = 4;
messages = [conversation(32, { kind: 'org', ahead: 4 })];
await vi.advanceTimersByTimeAsync(15_000);
await vi.advanceTimersByTimeAsync(60_000);
assert.equal(pageTitle('Settings', page), '(6) Settings - /dev/null');
assert.equal(shown.length, 2 * Number(banners));
assert.equal(play.mock.calls.length, 2);

unread = 97;
await vi.advanceTimersByTimeAsync(15_000);
await vi.advanceTimersByTimeAsync(60_000);
assert.equal(pageTitle('Settings', page), '(99) Settings - /dev/null');

unread = 98;
await vi.advanceTimersByTimeAsync(15_000);
await vi.advanceTimersByTimeAsync(60_000);
assert.equal(pageTitle('', page), '(99+) /dev/null');

unread = 0;
messages = [conversation(32, { kind: 'org', ahead: 0 })];
await vi.advanceTimersByTimeAsync(15_000);
await vi.advanceTimersByTimeAsync(60_000);
assert.equal(pageTitle('', page), '(2) /dev/null');
page.props.auth.unreadNotificationsCount = 0;
assert.equal(pageTitle('Remotes', page), 'Remotes - /dev/null');
Expand Down Expand Up @@ -563,7 +578,7 @@ test('native broadcasts only acknowledge the receiving remote, without extra sou
test('restarting alerts during an inbox request waits for its own baseline without replaying old messages', async () => {
vi.useFakeTimers();
Object.assign(window, { setTimeout, clearTimeout });
Object.assign(document, { hidden: true, cookie: '' });
Object.assign(document, { hidden: false, hasFocus: () => false, cookie: '' });
let resolveOld: ((response: Response) => void) | undefined;
let id = 80;
const requestedBaselines: boolean[] = [];
Expand Down Expand Up @@ -610,9 +625,9 @@ test('an inbox response from before a successful mute cannot alert or replay aft
});
const stop = watchRemoteAlerts('me');
try {
await vi.advanceTimersByTimeAsync(0);
await vi.advanceTimersByTimeAsync(60_000);
delayInbox = true;
await vi.advanceTimersByTimeAsync(15_000);
await vi.advanceTimersByTimeAsync(60_000);
assert.ok(resolveInbox);
await setConversationMute(target, 'forever');
messages = [conversation(70, { id: 'mute-race', kind: 'org' })];
Expand All @@ -623,10 +638,10 @@ test('an inbox response from before a successful mute cannot alert or replay aft

delayInbox = false;
await setConversationMute(target, 'off');
await vi.advanceTimersByTimeAsync(15_000);
await vi.advanceTimersByTimeAsync(60_000);
assert.equal(shown.length, 0);
messages = [conversation(71, { id: 'mute-race', kind: 'org' })];
await vi.advanceTimersByTimeAsync(15_000);
await vi.advanceTimersByTimeAsync(60_000);
assert.equal(shown.length, 1);
assert.equal(play.mock.calls.length, 1);
} finally {
Expand All @@ -642,18 +657,21 @@ test('muting while an alert waits for the cross-tab lock suppresses it', async (
const target = { kind: 'org' as const, org: { id: 'lock-mute', name: 'Team' } };
let messages: ConversationSummary[] = [];
let releaseAlert: (() => Promise<void>) | undefined;
vi.stubGlobal('navigator', { locks: { request: (_name: string, notify: () => Promise<void>) => {
releaseAlert = notify;
vi.stubGlobal('navigator', { locks: { request: (_name: string, options: LockOptions | (() => Promise<void>), run?: () => Promise<void>) => {
if (typeof options !== 'function') return run!();
return new Promise<void>((resolve) => {
releaseAlert = async () => { await options(); resolve(); };
});
} } });
vi.stubGlobal('fetch', async (_url: string, options?: RequestInit) => {
if (options?.method === 'PUT') return Response.json({ muted_until_at: '9999-12-31T00:00:00Z' });
return Response.json({ conversations: messages, notification_baseline: {}, has_more: false, unread: messages.length, requests: 0 });
});
const stop = watchRemoteAlerts('me');
try {
await vi.advanceTimersByTimeAsync(0);
await vi.advanceTimersByTimeAsync(60_000);
messages = [conversation(75, { id: 'lock-mute', kind: 'org' })];
await vi.advanceTimersByTimeAsync(15_000);
await vi.advanceTimersByTimeAsync(60_000);
assert.ok(releaseAlert);
await setConversationMute(target, 'forever');
await releaseAlert();
Expand Down Expand Up @@ -686,17 +704,17 @@ test('popping an unread stash without opening its thread does not replay old mes
});
const stop = watchRemoteAlerts('me');
try {
await vi.advanceTimersByTimeAsync(0);
await vi.advanceTimersByTimeAsync(60_000);
await loadTab('stashed');
assert.equal(await setConversationArchived(target, false), true);
await vi.advanceTimersByTimeAsync(15_000);
await vi.advanceTimersByTimeAsync(60_000);
assert.equal(chatSnapshot().threads['org:old-stash'], undefined);
assert.equal(chatSnapshot().unread, 1);
assert.equal(shown.length, 0);
assert.equal(play.mock.calls.length, 0);

id = 81;
await vi.advanceTimersByTimeAsync(15_000);
await vi.advanceTimersByTimeAsync(60_000);
assert.equal(shown.length, 1);
assert.equal(play.mock.calls.length, 1);
} finally {
Expand Down Expand Up @@ -744,7 +762,7 @@ test.each(['blur', 'hidden', 'leave'] as const)('viewing one remote allows alert
assert.equal(shown.length, 2);
await vi.advanceTimersByTimeAsync(10_000);
id = 94;
await vi.advanceTimersByTimeAsync(15_000);
await vi.advanceTimersByTimeAsync(release === 'hidden' ? 60_000 : 15_000);
assert.equal(shown.length, 3);
assert.equal(play.mock.calls.length, 2);
} finally {
Expand Down Expand Up @@ -816,9 +834,9 @@ test('alerts from recent activity even when older pins occupy the visible first
});
const stop = watchRemoteAlerts('me');
try {
await vi.advanceTimersByTimeAsync(0);
await vi.advanceTimersByTimeAsync(60_000);
incoming = conversation(101, { id: 'recent-unpinned', kind: 'org' });
await vi.advanceTimersByTimeAsync(15_000);
await vi.advanceTimersByTimeAsync(60_000);
assert.equal(shown.length, 1);
assert.equal(play.mock.calls.length, 1);
assert.equal(chatSnapshot().conversations?.[0].id, 'old-pinned');
Expand Down
Loading