| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- import assert from 'node:assert/strict';
- import { readFile } from 'node:fs/promises';
- import { pathToFileURL } from 'node:url';
- import { chromium } from 'playwright';
- // 通过登录 HTTP 响应取得待撤销会话,测试过程中不访问 Vue 状态,不输出凭据。
- export async function checkSessions(page, baseUrl, accounts) {
- const platformAccount = JSON.parse(await readFile(new URL('../../.work/platform-accounts.json', import.meta.url), 'utf8'));
- const results = [];
- async function route(path) {
- await page.evaluate(value => { location.hash = `/${value}`; }, path);
- await page.waitForURL(new RegExp(`#/?${path}$`));
- }
- async function login(product, account) {
- const panel = page.locator('.login-panel');
- await panel.waitFor();
- if (product === 'merchant') await panel.getByLabel('商家标识').fill(accounts.tenant_id);
- await panel.getByLabel('员工账户').fill(account);
- await panel.getByLabel('密码', { exact: true }).fill(product === 'platform' ? platformAccount.password : accounts.password);
- const received = product === 'merchant' ? page.waitForResponse(response => response.url().endsWith('/openapi/v1/auth/sessions') && response.request().method() === 'POST') : null;
- await panel.getByRole('button', { name: '登录', exact: true }).click();
- const token = received ? (await (await received).json()).access_token : null;
- await panel.waitFor({ state: 'hidden' });
- return token;
- }
- async function logout() {
- await page.locator('.admin-session').getByRole('button', { name: '退出登录', exact: true }).click();
- await page.getByRole('dialog').getByRole('button', { name: '确认操作', exact: true }).click();
- await page.locator('.login-panel').waitFor();
- }
- async function revoke(token) {
- const response = await page.context().request.delete(`${baseUrl}/openapi/v1/auth/sessions/current`, { headers: { Authorization: `Bearer ${token}` } });
- assert.equal(response.status(), 204, '独立客户端撤销真实会话');
- }
- await page.goto(`${baseUrl}/#/merchant/service/quick-replies`);
- await page.waitForURL(/#\/?merchant\/login$/);
- assert.equal(await page.locator('.admin-sidebar').count(), 0);
- const panel = page.locator('.login-panel');
- await panel.getByLabel('商家标识').fill(accounts.tenant_id);
- await panel.getByLabel('员工账户').fill('customer01');
- await panel.getByLabel('密码', { exact: true }).fill(accounts.password);
- await panel.getByRole('button', { name: '登录', exact: true }).click();
- await panel.getByRole('alert').waitFor();
- assert.match(await panel.getByRole('alert').innerText(), /无权/);
- assert.equal(await panel.getByLabel('密码', { exact: true }).inputValue(), '');
- results.push('消费者账户无法登录商家后台');
- await login('merchant', 'staff01');
- await page.waitForURL(/#\/?merchant\/service\/quick-replies$/);
- await page.locator('.admin-title').getByRole('heading', { name: '快捷回复' }).waitFor();
- results.push('未登录访问保护页面返回员工原授权目标');
- await route('merchant/approval/review');
- await page.getByRole('heading', { name: '页面不可访问', exact: true }).waitFor();
- assert.equal(await page.getByRole('button', { name: '提交审批决定', exact: true }).count(), 0);
- results.push('客服通过直接地址访问主管审批被阻止');
- await route('platform/login');
- await login('platform', 'platform-admin');
- await logout();
- await route('merchant/service/quick-replies');
- await page.locator('.admin-title').getByRole('heading', { name: '快捷回复' }).waitFor();
- results.push('退出平台后台后商家后台会话保持');
- await route('platform/login');
- await login('platform', 'platform-admin');
- await route('merchant/service/quick-replies');
- await logout();
- await route('platform/dashboard');
- await page.locator('.admin-title').getByRole('heading', { name: '平台概览' }).waitFor();
- results.push('退出商家后台后平台后台会话保持');
- await route('merchant/login');
- let token = await login('merchant', 'admin01');
- await route('merchant/access');
- await page.getByLabel('员工账户', { exact: true }).fill('待保存的管理员邀请');
- await revoke(token);
- await route('merchant/orders');
- await page.waitForURL(/#\/?merchant\/login$/);
- assert.equal(await page.locator('.admin-sidebar').count(), 0);
- token = await login('merchant', 'admin01');
- await page.waitForURL(/#\/?merchant\/orders$/);
- await route('merchant/access');
- assert.equal(await page.getByLabel('员工账户', { exact: true }).inputValue(), '待保存的管理员邀请');
- results.push('真实会话撤销触发重新登录,同身份恢复未提交表单');
- await revoke(token);
- await route('merchant/orders');
- await page.waitForURL(/#\/?merchant\/login$/);
- await login('merchant', 'finance02');
- await page.locator('.admin-title').getByRole('heading', { name: '经营概览' }).waitFor();
- assert.equal(await page.locator('.admin-sidebar').getByRole('button', { name: '店铺与员工', exact: true }).count(), 0);
- assert.equal(await page.locator('.admin-sidebar').getByRole('button', { name: '知识中心', exact: true }).count(), 0);
- assert.equal(await page.locator('.admin-sidebar').getByRole('button', { name: '售后规则', exact: true }).count(), 0);
- await route('merchant/access');
- await page.getByRole('heading', { name: '页面不可访问', exact: true }).waitFor();
- assert.equal(await page.getByLabel('员工账户', { exact: true }).count(), 0);
- assert.equal(await page.getByText('待保存的管理员邀请', { exact: true }).count(), 0);
- results.push('费用账户隐藏配置菜单,直接访问配置页面被阻止');
- return results;
- }
- if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
- const accounts = JSON.parse(await readFile(new URL('../../.work/frontend-accounts.json', import.meta.url), 'utf8'));
- const browser = await chromium.launch({ headless: true, executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE || 'C:/Users/Administrator/AppData/Local/ms-playwright/chromium-1228/chrome-win64/chrome.exe' });
- const page = await browser.newPage();
- page.setDefaultTimeout(12000);
- try { console.log(JSON.stringify(await checkSessions(page, process.env.FRONTEND_URL || 'http://127.0.0.1:18762', accounts), null, 2)); }
- catch (error) { console.error('会话检查页面:', page.url()); console.error(await page.locator('body').innerText()); throw error; }
- finally { await browser.close(); }
- }
|