75 lines
2.7 KiB
TypeScript
75 lines
2.7 KiB
TypeScript
import { test, expect, Page } from '@playwright/test';
|
|||
|
|
import { HS, ensureUser, hsReachable, loginUI, TestUser, uniq } from './localHs';
|
||
|
|
|
||
|
|
// [Gitea #110, #123] The device-security nudge. A fresh account has no key
|
||
|
|
// backup and no cross-signing → "Set up key backup", but only after the 24 h
|
||
|
|
// grace period on this device; "Not now" snoozes it.
|
||
|
|
const strip = (page: Page) => page.getByRole('status').filter({ hasText: /encryption keys/ });
|
||
|
|
|
||
|
|
/** Back-date this device's first-seen record past the 24 h grace period, then reload. */
|
||
|
|
async function pastGrace(page: Page) {
|
||
|
|
await page.evaluate(() => {
|
||
|
|
const { deviceId } = JSON.parse(localStorage.getItem('cinny_session_v1') ?? '{}');
|
||
|
|
localStorage.setItem(
|
||
|
|
`lotus-security-nudge-${deviceId}`,
|
||
|
|
JSON.stringify({ firstSeen: Date.now() - 2 * 86_400_000, dismissals: {} }),
|
||
|
|
);
|
||
|
|
});
|
||
|
|
await page.reload();
|
||
|
|
}
|
||
|
|
|
||
|
|
/** The nudge waits until sync has settled (after "Connecting…"). */
|
||
|
|
async function settled(page: Page) {
|
||
|
|
await page
|
||
|
|
.getByText('Connecting...')
|
||
|
|
.first()
|
||
|
|
.waitFor({ timeout: 30_000 })
|
||
|
|
.catch(() => undefined);
|
||
|
|
await page.getByText('Connecting...').first().waitFor({ state: 'detached', timeout: 90_000 });
|
||
|
|
await page.waitForTimeout(2000);
|
||
|
|
}
|
||
|
|
|
||
|
|
test.describe('security nudge (#110, #123)', () => {
|
||
|
|
let user: TestUser;
|
||
|
|
|
||
|
|
test.beforeAll(async () => {
|
||
|
|
test.skip(!(await hsReachable()), `no local homeserver at ${HS} (set E2E_LOCAL_HS)`);
|
||
|
|
});
|
||
|
|
|
||
|
|
test.beforeEach(async () => {
|
||
|
|
user = await ensureUser(uniq('e2e_nudge_'));
|
||
|
|
});
|
||
|
|
|
||
|
|
test('nothing during the first 24 h on a device', async ({ page }) => {
|
||
|
|
test.setTimeout(150_000);
|
||
|
|
await loginUI(page, user);
|
||
|
|
await settled(page);
|
||
|
|
// Past the point where the nudge shows once the grace period is over (~5 s).
|
||
|
|
await page.waitForTimeout(8000);
|
||
|
|
await expect(strip(page)).toHaveCount(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('no key backup: "Set up key backup" opens Settings → Devices', async ({ page }) => {
|
||
|
|
test.setTimeout(150_000);
|
||
|
|
await loginUI(page, user);
|
||
|
|
await pastGrace(page);
|
||
|
|
await settled(page);
|
||
|
|
const nudge = strip(page);
|
||
|
|
await expect(nudge).toContainText("Your encryption keys aren't backed up");
|
||
|
|
await nudge.getByRole('button', { name: 'Set up' }).click();
|
||
|
|
await expect(page.getByText('Device Verification').first()).toBeVisible();
|
||
|
|
});
|
||
|
|
|
||
|
|
test('"Not now" snoozes it across a reload', async ({ page }) => {
|
||
|
|
test.setTimeout(200_000);
|
||
|
|
await loginUI(page, user);
|
||
|
|
await pastGrace(page);
|
||
|
|
await settled(page);
|
||
|
|
await strip(page).getByRole('button', { name: 'Not now' }).click();
|
||
|
|
await expect(strip(page)).toHaveCount(0);
|
||
|
|
await page.reload();
|
||
|
|
await settled(page);
|
||
|
|
await expect(strip(page)).toHaveCount(0);
|
||
|
|
});
|
||
|
|
});
|