async (page) => { const origin = new URL(page.url()).origin; const browser = page.context().browser(); const context = await browser.newContext(); context.setDefaultTimeout(10000); let target = await context.newPage(); const username = `remember_${Date.now()}`; const password = 'Remember-login-smoke-password'; const results = []; async function stored() { return target.evaluate(async () => { const db = await new Promise((resolve, reject) => { const req = indexedDB.open('webdrop-account-local-2'); req.onsuccess = () => resolve(req.result); req.onerror = () => reject(req.error); }); const tx = db.transaction(['sessions', 'credentials'], 'readonly'); const read = (name) => new Promise((resolve, reject) => { const req = tx.objectStore(name).getAll(); req.onsuccess = () => resolve(req.result); req.onerror = () => reject(req.error); }); const [sessions, credentials] = await Promise.all([read('sessions'), read('credentials')]); db.close(); return { sessions: sessions.length, credentials: credentials.length, plaintext: credentials.some((value) => 'password' in value || 'username' in value), exportable: credentials.some((value) => value.key.extractable) }; }); } async function reopen() { await target.close(); target = await context.newPage(); await target.goto(origin); } try { await target.goto(origin); await target.getByLabel('用户名', { exact: true }).fill(username); await target.getByLabel('密码', { exact: true }).fill(password); await target.getByRole('button', { name: '创建账号', exact: true }).click(); await target.getByRole('button', { name: '退出登录', exact: true }).waitFor(); const record = await stored(); if (record.credentials !== 1 || record.plaintext || record.exportable) throw new Error('Login was not stored as non-exportable encrypted data'); await reopen(); await target.getByRole('button', { name: '退出登录', exact: true }).waitFor(); results.push('fresh page restores the remembered account'); await target.getByRole('button', { name: '退出登录', exact: true }).click(); await target.getByRole('button', { name: '登录并同步', exact: true }).waitFor(); if (await target.getByLabel('用户名', { exact: true }).inputValue() !== username || await target.getByLabel('密码', { exact: true }).inputValue() !== password) throw new Error('Saved account/password were not filled'); results.push('normal logout preserves encrypted credentials and fills the login form'); await target.getByRole('checkbox', { name: '记住账号和密码(本机)', exact: true }).uncheck(); await target.getByRole('button', { name: '登录并同步', exact: true }).click(); await target.getByRole('button', { name: '退出登录', exact: true }).waitFor(); await target.getByRole('button', { name: '立即同步', exact: true }).click(); await target.getByText('资源保险库已同步。', { exact: true }).waitFor(); const temporary = await stored(); if (temporary.sessions || temporary.credentials) throw new Error('Unremembered login was persisted by sync'); await reopen(); await target.getByLabel('用户名', { exact: true }).waitFor(); if (await target.getByLabel('用户名', { exact: true }).inputValue() || await target.getByLabel('密码', { exact: true }).inputValue()) throw new Error('Temporary login reappeared'); results.push('unchecked remember only keeps the current page session'); await target.getByRole('button', { name: '已有账号', exact: true }).click(); await target.getByLabel('用户名', { exact: true }).fill(username); await target.getByLabel('密码', { exact: true }).fill(password); await target.getByRole('button', { name: '登录并同步', exact: true }).click(); await target.getByRole('button', { name: '清除本机保存', exact: true }).click(); await target.getByRole('button', { name: '立即同步', exact: true }).click(); await target.getByText('资源保险库已同步。', { exact: true }).waitFor(); const cleared = await stored(); if (cleared.sessions || cleared.credentials) throw new Error('Cleared login was restored by sync'); await reopen(); await target.getByLabel('密码', { exact: true }).waitFor(); if (await target.getByLabel('密码', { exact: true }).inputValue()) throw new Error('Password returned after clearing'); results.push('clearing local saves survives synchronization and page restart'); return { passed: results }; } finally { await context.close(); } }