feat: add Keycloak authentication

This commit is contained in:
2026-08-19 12:11:18 +08:00
parent bdd5eff776
commit d08cf2abc1
27 changed files with 533 additions and 128 deletions
+1
View File
@@ -151,6 +151,7 @@ async function prepareWorkbench(page: Page) {
await route.fulfill({
contentType: "application/javascript",
body: `globalThis.__TJWATER_CONFIG__ = {
TJWATER_AUTH_MODE: "disabled",
TJWATER_MAPBOX_ACCESS_TOKEN: "",
TJWATER_MAP_URL: "https://button-system.invalid/geoserver",
TJWATER_GEOSERVER_WORKSPACE: "tjwater",
+14 -9
View File
@@ -1,10 +1,22 @@
import type { Page } from "@playwright/test";
type MockAgentApiOptions = {
model?: {
id: string;
label: string;
description: string;
icon: "bolt" | "sparkle";
};
sessions?: Array<Record<string, unknown>>;
};
export async function mockAgentApi(page: Page, options: MockAgentApiOptions = {}) {
const model = options.model ?? {
id: "test/model",
label: "测试模型",
description: "Playwright 浏览器测试",
icon: "bolt" as const
};
await page.route("**/api/v1/agent/chat/**", async (route) => {
const pathname = new URL(route.request().url()).pathname;
@@ -37,15 +49,8 @@ export async function mockAgentApi(page: Page, options: MockAgentApiOptions = {}
if (pathname.endsWith("/models")) {
await route.fulfill({
json: {
default_model: "test/model",
models: [
{
id: "test/model",
label: "测试模型",
description: "Playwright 浏览器测试",
icon: "bolt"
}
]
default_model: model.id,
models: [model]
}
});
return;
+13 -1
View File
@@ -1,4 +1,5 @@
import { expect, test, type Locator, type Page } from "@playwright/test";
import { mockAgentApi } from "./support/mock-agent-api";
const EMPTY_RASTER_TILE = Buffer.from(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=",
@@ -116,10 +117,19 @@ test.describe("neutral blue mist workbench", () => {
});
async function prepareDeterministicWorkbench(page: Page) {
await mockAgentApi(page, {
model: {
id: "deepseek/deepseek-v4-flash",
label: "快速",
description: "快速响应",
icon: "bolt"
}
});
await page.route("**/runtime-config.js", async (route) => {
await route.fulfill({
contentType: "application/javascript",
body: `globalThis.__TJWATER_CONFIG__ = {
TJWATER_AUTH_MODE: "disabled",
TJWATER_MAPBOX_ACCESS_TOKEN: "visual-test-token",
TJWATER_MAP_URL: "https://visual-map.invalid/geoserver",
TJWATER_GEOSERVER_WORKSPACE: "tjwater",
@@ -148,7 +158,9 @@ async function prepareDeterministicWorkbench(page: Page) {
async function openWorkbench(page: Page) {
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.locator("main").evaluate((element) => {
const workbench = page.locator("main[data-basemap-tone]");
await workbench.waitFor();
await workbench.evaluate((element) => {
element.setAttribute("data-visual-test", "true");
});
await page.addStyleTag({