test(e2e): add frontend smoke coverage
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
import { mockBackend } from "./support/mockBackend";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await mockBackend(page);
|
||||
});
|
||||
|
||||
test("已登录管理员可以打开审计日志页面", async ({ page }) => {
|
||||
await page.goto("/audit-logs");
|
||||
|
||||
await expect(
|
||||
page.getByRole("heading", { name: "审计日志", exact: true }),
|
||||
).toBeVisible();
|
||||
await expect(page.getByText("系统管理员权限已验证")).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "查询结果" })).toBeVisible();
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { encode } from "next-auth/jwt";
|
||||
|
||||
import {
|
||||
AUTH_STATE_PATH,
|
||||
E2E_AUTH_SECRET,
|
||||
E2E_BASE_URL,
|
||||
} from "./support/environment";
|
||||
|
||||
const SESSION_MAX_AGE_SECONDS = 12 * 60 * 60;
|
||||
|
||||
export default async function globalSetup() {
|
||||
if (process.env.E2E_STORAGE_STATE) return;
|
||||
|
||||
const now = Date.now();
|
||||
const baseUrl = new URL(E2E_BASE_URL);
|
||||
const secure = baseUrl.protocol === "https:";
|
||||
const token = await encode({
|
||||
secret: E2E_AUTH_SECRET,
|
||||
maxAge: SESSION_MAX_AGE_SECONDS,
|
||||
token: {
|
||||
sub: "playwright-user",
|
||||
username: "playwright",
|
||||
name: "E2E 测试用户",
|
||||
email: "playwright@example.invalid",
|
||||
accessToken: "playwright-access-token",
|
||||
accessTokenIssuedAt: now,
|
||||
accessTokenExpires: now + SESSION_MAX_AGE_SECONDS * 1000,
|
||||
sessionExpiresAt: now + SESSION_MAX_AGE_SECONDS * 1000,
|
||||
},
|
||||
});
|
||||
|
||||
await fs.mkdir(path.dirname(AUTH_STATE_PATH), { recursive: true });
|
||||
await fs.writeFile(
|
||||
AUTH_STATE_PATH,
|
||||
JSON.stringify(
|
||||
{
|
||||
cookies: [
|
||||
{
|
||||
name: secure
|
||||
? "__Secure-next-auth.session-token"
|
||||
: "next-auth.session-token",
|
||||
value: token,
|
||||
domain: baseUrl.hostname,
|
||||
path: "/",
|
||||
expires: Math.floor(now / 1000) + SESSION_MAX_AGE_SECONDS,
|
||||
httpOnly: true,
|
||||
secure,
|
||||
sameSite: "Lax",
|
||||
},
|
||||
],
|
||||
origins: [
|
||||
{
|
||||
origin: baseUrl.origin,
|
||||
localStorage: [
|
||||
{ name: "active_project", value: "playwright-project" },
|
||||
{ name: "MAP_WORKSPACE", value: "tjwater_e2e" },
|
||||
{ name: "NETWORK_NAME", value: "tjwater_e2e" },
|
||||
{
|
||||
name: "MAP_EXTENT",
|
||||
value: "13508801.93,3608163.35,13555650.64,3633685.14",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import path from "node:path";
|
||||
|
||||
export const E2E_BASE_URL =
|
||||
process.env.E2E_BASE_URL || "http://127.0.0.1:3100";
|
||||
|
||||
export const E2E_AUTH_SECRET =
|
||||
process.env.E2E_NEXTAUTH_SECRET ||
|
||||
"tjwater-playwright-local-secret-at-least-32-characters";
|
||||
|
||||
export const AUTH_STATE_PATH = path.join(
|
||||
process.cwd(),
|
||||
"e2e",
|
||||
".auth",
|
||||
"user.json",
|
||||
);
|
||||
@@ -0,0 +1,63 @@
|
||||
import type { Page, Route } from "@playwright/test";
|
||||
|
||||
const json = (route: Route, body: unknown) =>
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
export const mockBackend = async (page: Page) => {
|
||||
if (process.env.E2E_USE_REAL_SERVICES === "true") return;
|
||||
|
||||
await page.route("**/api/v1/**", async (route) => {
|
||||
const url = new URL(route.request().url());
|
||||
|
||||
if (url.pathname === "/api/v1/access-context") {
|
||||
return json(route, {
|
||||
user_id: "playwright-user",
|
||||
username: "playwright",
|
||||
system_role: "system_admin",
|
||||
is_system_admin: true,
|
||||
project_id: "playwright-project",
|
||||
project_role: "project_admin",
|
||||
permissions: [
|
||||
"webgis.view",
|
||||
"simulation.view",
|
||||
"simulation.run",
|
||||
"scada.clean",
|
||||
"risk.run",
|
||||
"optimization.run",
|
||||
"burst.run",
|
||||
"audit.view",
|
||||
"environment.manage",
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
if (url.pathname === "/api/v1/projects/current") {
|
||||
return json(route, {
|
||||
project_id: "playwright-project",
|
||||
code: "tjwater_e2e",
|
||||
gs_workspace: "tjwater_e2e",
|
||||
map_extent: {
|
||||
bbox: [13508801.93, 3608163.35, 13555650.64, 3633685.14],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (url.pathname === "/api/v1/audit-logs/count") {
|
||||
return json(route, { count: 0 });
|
||||
}
|
||||
|
||||
if (
|
||||
url.pathname === "/api/v1/audit-logs" ||
|
||||
url.pathname === "/api/v1/admin/users" ||
|
||||
url.pathname === "/api/v1/admin/projects"
|
||||
) {
|
||||
return json(route, []);
|
||||
}
|
||||
|
||||
return json(route, {});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
test("未登录访问受保护页面时返回登录重定向", async ({ request }) => {
|
||||
const sessionResponse = await request.get("/api/auth/session");
|
||||
expect(await sessionResponse.json()).toEqual({});
|
||||
|
||||
const response = await request.get("/audit-logs", { maxRedirects: 0 });
|
||||
const body = await response.text();
|
||||
|
||||
expect(response.status()).toBe(200);
|
||||
expect(body).toContain("NEXT_REDIRECT;replace;/login;307;");
|
||||
});
|
||||
Reference in New Issue
Block a user