49 lines
4.2 KiB
JavaScript
49 lines
4.2 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { chromium } from 'playwright';
|
|
import { classifyLoginSignals, detectSession, inspectVisibleSessionSignals } from './session-detection.mjs';
|
|
|
|
// New empty browser + synthetic documents only; never any user account/profile.
|
|
const browser = await chromium.launch({ headless: true, channel: process.env.ASSISTANT_TEST_BROWSER_CHANNEL || (process.platform === 'win32' ? 'msedge' : 'chromium') });
|
|
const page = await browser.newPage({ viewport: { width: 1280, height: 840 } });
|
|
const navigation = '<nav><ul><li><a href="https://www.xiaohongshu.com/explore">首页</a></li><li><a href="https://www.xiaohongshu.com/notification">通知</a></li><li><a href="https://www.xiaohongshu.com/user/profile/fakeaccount123">我<img alt="avatar"></a></li></ul></nav>';
|
|
const results = [];
|
|
async function check(name, html, state) {
|
|
await page.setContent(`<style>body{font:18px sans-serif}nav{display:block;width:180px;height:240px}a,button{display:block;padding:8px}</style>${html}`);
|
|
// Reading input values or local session data would make the fixture fail.
|
|
await page.evaluate(() => {
|
|
Object.defineProperty(HTMLInputElement.prototype, 'value', { get() { throw Error('form value read'); }, configurable: true });
|
|
Object.defineProperty(document, 'cookie', { get() { throw Error('cookie read'); }, configurable: true });
|
|
});
|
|
const signals = await inspectVisibleSessionSignals(page);
|
|
assert.equal(classifyLoginSignals(signals).state, state, name);
|
|
assert.ok(!JSON.stringify(signals).includes('FakePrivateValue91'));
|
|
results.push(name);
|
|
}
|
|
try {
|
|
await check('visible account in main navigation', navigation, 'logged_in');
|
|
await check('public note author is not viewer login', '<article><a href="https://www.xiaohongshu.com/user/profile/fakeauthor123">笔记作者</a></article>', 'unknown');
|
|
await check('visible login entry', '<button>登录</button>', 'logged_out');
|
|
await check('hidden login dialog ignored', navigation + '<div role="dialog" style="display:none">扫码登录<input value="FakePrivateValue91"></div>', 'logged_in');
|
|
await check('hidden ancestor ignored', navigation + '<div style="display:none"><div role="dialog">手机号登录</div></div>', 'logged_in');
|
|
await check('offscreen login ignored', navigation + '<div role="dialog" style="position:absolute;top:1800px">扫码登录</div>', 'logged_in');
|
|
await check('active login dialog wins over old navigation', navigation + '<div role="dialog">扫码登录<input value="FakePrivateValue91"></div>', 'logged_out');
|
|
await check('verification widget wins', navigation + '<div class="captcha-container">请完成安全验证</div>', 'verification_required');
|
|
await check('hidden verification ignored', navigation + '<div class="captcha-container" hidden>请完成安全验证</div>', 'logged_in');
|
|
await check('hidden login text inside visible dialog ignored', navigation + '<div role="dialog"><span hidden>扫码登录</span><p>其他说明</p></div>', 'logged_in');
|
|
await check('hidden challenge text inside visible widget ignored', navigation + '<div class="captcha-container" style="height:30px"><span hidden>请完成安全验证</span></div>', 'logged_in');
|
|
await check('contradictory entry remains unknown', navigation + '<button>登录</button>', 'unknown');
|
|
await check('no stored-login inference', '<h1>欢迎</h1>', 'unknown');
|
|
assert.equal((await detectSession(page)).state, 'unknown');
|
|
assert.deepEqual((await detectSession(page)).evidence, ['unsupported_platform']);
|
|
// The URL facade tests official-host gating against the same synthetic DOM;
|
|
// there is no network navigation to a real platform.
|
|
await page.setContent(navigation);
|
|
const facade = { url: () => 'https://www.xiaohongshu.com/explore', evaluate: (...args) => page.evaluate(...args) };
|
|
const detected = await detectSession(facade);
|
|
assert.equal(detected.state, 'logged_in');
|
|
assert.equal(detected.basis, 'visible_page');
|
|
assert.ok(Number.isFinite(Date.parse(detected.observed_at)));
|
|
assert.equal((await detectSession({ ...facade, url: () => 'https://xiaohongshu.com.evil.invalid/' })).state, 'unknown');
|
|
console.log(JSON.stringify({ result: 'passed', visible_page_cases: results.length, host_boundary: true, no_cookies_or_form_values: true, real_platform: false }));
|
|
} finally { await browser.close(); }
|