test: cover persistent browser navigation
This commit is contained in:
@@ -19,6 +19,7 @@ const FORBIDDEN_PORT = 8788;
|
|||||||
const EXTERNAL_ORIGIN = parseExternalE2eOrigin(process.env.E2E_ORIGIN);
|
const EXTERNAL_ORIGIN = parseExternalE2eOrigin(process.env.E2E_ORIGIN);
|
||||||
const SCREENSHOT_DIR = process.env.E2E_SCREENSHOT_DIR?.trim();
|
const SCREENSHOT_DIR = process.env.E2E_SCREENSHOT_DIR?.trim();
|
||||||
const FLEET_FIXTURE = process.env.E2E_FLEET_FIXTURE !== '0';
|
const FLEET_FIXTURE = process.env.E2E_FLEET_FIXTURE !== '0';
|
||||||
|
const requestPathnames = [];
|
||||||
|
|
||||||
const CHROME_CANDIDATES = [
|
const CHROME_CANDIDATES = [
|
||||||
process.env.CHROME_BIN,
|
process.env.CHROME_BIN,
|
||||||
@@ -77,11 +78,20 @@ const FLEET_FIXTURE_ITEMS = [
|
|||||||
|
|
||||||
async function builtAssetHandler(request, response) {
|
async function builtAssetHandler(request, response) {
|
||||||
const pathname = new URL(request.url ?? '/', 'http://e2e.local').pathname;
|
const pathname = new URL(request.url ?? '/', 'http://e2e.local').pathname;
|
||||||
if (pathname === '/favicon.ico' || pathname === '/api/v1/events') {
|
requestPathnames.push(pathname);
|
||||||
|
if (pathname === '/favicon.ico') {
|
||||||
response.statusCode = 204;
|
response.statusCode = 204;
|
||||||
response.end();
|
response.end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (pathname === '/api/v1/events') {
|
||||||
|
response.writeHead(200, {
|
||||||
|
'content-type': 'text/event-stream',
|
||||||
|
'cache-control': 'no-cache',
|
||||||
|
});
|
||||||
|
response.flushHeaders();
|
||||||
|
return;
|
||||||
|
}
|
||||||
let body;
|
let body;
|
||||||
if (pathname === '/api/v1/auth/status')
|
if (pathname === '/api/v1/auth/status')
|
||||||
body = { configured: false, protectionEnabled: false, authenticated: false };
|
body = { configured: false, protectionEnabled: false, authenticated: false };
|
||||||
@@ -884,7 +894,51 @@ try {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await assertWidePageGutters(cdp, 'Nodes');
|
await assertWidePageGutters(cdp, 'Nodes');
|
||||||
await keyboardNavigate(cdp, '设置', '/settings/instances', '实例');
|
await eventually(
|
||||||
|
cdp,
|
||||||
|
`document.querySelector('.connection-status [data-state="open"]') !== null`,
|
||||||
|
'Event stream did not reach the open state',
|
||||||
|
);
|
||||||
|
await evaluate(cdp, `window.__navigationLifetime = crypto.randomUUID()`);
|
||||||
|
const navigationLifetime = await evaluate(cdp, `window.__navigationLifetime`);
|
||||||
|
const requestCountsBeforeSettings = EXTERNAL_ORIGIN
|
||||||
|
? undefined
|
||||||
|
: {
|
||||||
|
events: requestPathnames.filter((pathname) => pathname === '/api/v1/events').length,
|
||||||
|
fleet: requestPathnames.filter(
|
||||||
|
(pathname) =>
|
||||||
|
pathname === '/api/v1/instances' ||
|
||||||
|
/^\/api\/v1\/instances\/[^/]+\/resources$/u.test(pathname),
|
||||||
|
).length,
|
||||||
|
};
|
||||||
|
await keyboardNavigate(cdp, '设置', '/settings/system', '密码保护');
|
||||||
|
assert.equal(
|
||||||
|
await evaluate(cdp, `window.__navigationLifetime`),
|
||||||
|
navigationLifetime,
|
||||||
|
'Settings navigation reloaded the document',
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
await evaluate(cdp, `document.activeElement?.id`),
|
||||||
|
'main-content',
|
||||||
|
'Settings navigation must focus the main content',
|
||||||
|
);
|
||||||
|
if (requestCountsBeforeSettings) {
|
||||||
|
await delay(100);
|
||||||
|
assert.equal(
|
||||||
|
requestPathnames.filter((pathname) => pathname === '/api/v1/events').length,
|
||||||
|
requestCountsBeforeSettings.events,
|
||||||
|
'Settings navigation recreated the event subscription',
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
requestPathnames.filter(
|
||||||
|
(pathname) =>
|
||||||
|
pathname === '/api/v1/instances' ||
|
||||||
|
/^\/api\/v1\/instances\/[^/]+\/resources$/u.test(pathname),
|
||||||
|
).length,
|
||||||
|
requestCountsBeforeSettings.fleet,
|
||||||
|
'Settings navigation requested Fleet data',
|
||||||
|
);
|
||||||
|
}
|
||||||
await assertWidePageGutters(cdp, 'Settings');
|
await assertWidePageGutters(cdp, 'Settings');
|
||||||
await keyboardNavigate(cdp, '自动化', '/automation', '自动化');
|
await keyboardNavigate(cdp, '自动化', '/automation', '自动化');
|
||||||
await assertWidePageGutters(cdp, 'Automation');
|
await assertWidePageGutters(cdp, 'Automation');
|
||||||
@@ -980,7 +1034,7 @@ try {
|
|||||||
`document.querySelector('[role="tab"][aria-selected="true"]')?.textContent.trim() === '操作审计'`,
|
`document.querySelector('[role="tab"][aria-selected="true"]')?.textContent.trim() === '操作审计'`,
|
||||||
'/audit alias did not select operation audit',
|
'/audit alias did not select operation audit',
|
||||||
);
|
);
|
||||||
await keyboardNavigate(cdp, '设置', '/settings/instances', '实例');
|
await keyboardNavigate(cdp, '设置', '/settings/system', '密码保护');
|
||||||
|
|
||||||
assert.deepEqual(failures, [], `Browser failures detected:\n${failures.join('\n')}`);
|
assert.deepEqual(failures, [], `Browser failures detected:\n${failures.join('\n')}`);
|
||||||
console.log(`PASS real Chrome E2E (${chromeBinary})`);
|
console.log(`PASS real Chrome E2E (${chromeBinary})`);
|
||||||
@@ -990,7 +1044,7 @@ try {
|
|||||||
: `PASS isolated built-asset server on ${origin} (legacy port 8788 untouched)`,
|
: `PASS isolated built-asset server on ${origin} (legacy port 8788 untouched)`,
|
||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
'PASS three-item navigation, Automation drawer and aliases, batch selection, and 390/768/1024/1440/1920 responsive layouts',
|
'PASS persistent navigation, live SSE status, Automation workflows, and 390/768/1024/1440/1920 responsive layouts',
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error instanceof Error ? error.stack : error);
|
console.error(error instanceof Error ? error.stack : error);
|
||||||
|
|||||||
Reference in New Issue
Block a user