mirror of
https://github.com/opengeos/GeoLibre.git
synced 2026-11-04 10:43:36 +00:00
* fix: show startup recovery guidance before app scripts load * Address CodeRabbit review feedback - Assert the JavaScript-disabled message text and visibility by targeting the noscript paragraph directly.
169 lines
7.9 KiB
TypeScript
169 lines
7.9 KiB
TypeScript
import { defineConfig, devices } from "@playwright/test";
|
|
import { DESKTOP_SETTINGS_STORAGE_KEY } from "./apps/geolibre-desktop/src/lib/storage-keys";
|
|
|
|
// `E2E_PORT` moves the preview server off the default, so a second checkout (or
|
|
// a parallel run) can serve its own build without reusing another one's.
|
|
const PORT = Number(process.env.E2E_PORT) || 4173;
|
|
const BASE_URL = `http://localhost:${PORT}`;
|
|
|
|
/**
|
|
* The `core` suite: the app boots and renders a map, and its shared UI surfaces
|
|
* still work. This is the only suite that gates a pull request, so it is kept
|
|
* to the checks that would break *every* user — not per-feature integration.
|
|
*
|
|
* Everything else lands in the `features` project, which runs nightly (see
|
|
* `.github/workflows/e2e-full.yml`). Feature specs are not less valuable — most
|
|
* were written for a specific shipped regression — they are just too slow to
|
|
* charge to every commit: the full suite is ~36 min serial, of which these are
|
|
* ~27 min. Moving a spec between the two lists is the intended way to trade
|
|
* per-commit cost against how fast a regression is caught.
|
|
*/
|
|
const CORE_SPECS = [
|
|
"smoke.spec.ts", // the app loads, a layer renders, the attribute table opens
|
|
"startup.spec.ts", // recovery remains visible if startup scripts cannot load
|
|
"theme.spec.ts",
|
|
"a11y.spec.ts",
|
|
// Add, restyle and export a layer with the keyboard alone: one ~6 s test,
|
|
// so a control dropped from the tab order fails its own PR (#2858). The
|
|
// wider per-dialog axe sweep, a11y-screens.spec.ts, stays nightly (~70 s).
|
|
"keyboard-only.spec.ts",
|
|
"layer-panel.spec.ts",
|
|
"drop-overlay.spec.ts",
|
|
"error-handling.spec.ts",
|
|
"attribute-status.spec.ts",
|
|
"rtl.spec.ts",
|
|
"pwa.spec.ts",
|
|
"deployment-policy.spec.ts",
|
|
// Project -> Save -> reopen. Moved from `features` after an unexpected save
|
|
// prompt broke every saving spec and only the nightly run noticed (#2858).
|
|
"layer-groups.spec.ts",
|
|
// Holds the Plugins docs to the app's deep-link names, so a new built-in
|
|
// plugin fails its own PR instead of the next night's run (#2858). Its
|
|
// registry install flows are in plugin-deep-link-registry.spec.ts, nightly.
|
|
"plugin-deep-link.spec.ts",
|
|
// Moved to `features` once core reached ~11 min wall-clock (~25 min of test
|
|
// time): set-view, paste-style, style-manager and identify-restore. Each
|
|
// covers one dialog or interaction, not something every user hits, and
|
|
// together they were ~40% of core's test time and most of its retries.
|
|
];
|
|
|
|
const coreMatch = CORE_SPECS.map((spec) => `**/${spec}`);
|
|
|
|
/**
|
|
* The per-commit engine smoke pass (`core-engines`): switch to Cesium, then to
|
|
* ArcGIS, add GeoJSON, identify a feature. The deep engine specs stay nightly;
|
|
* this catches an engine that no longer mounts or draws project layers at all.
|
|
*
|
|
* It is its own project because a software-rendered 3D view saturates the CPU
|
|
* on its own. Run beside the `core` workers on a 4-vCPU runner it starved them
|
|
* and itself — clicks and screenshots timing out on both sides — so it runs
|
|
* alone, one worker, after `core` finishes (#2858). ArcGIS loads its SDK from
|
|
* js.arcgis.com, the one network dependency in the per-commit gate.
|
|
*/
|
|
const coreEnginesMatch = ["**/engine-smoke.spec.ts"];
|
|
|
|
// MapLibre needs a WebGL context; force software ANGLE/SwiftShader so the map
|
|
// initializes on headless CI runners without a real GPU.
|
|
const chromium = {
|
|
...devices["Desktop Chrome"],
|
|
launchOptions: { args: ["--use-gl=angle", "--use-angle=swiftshader"] },
|
|
};
|
|
|
|
// End-to-end smoke tests run against the *built* web app served by `vite
|
|
// preview` (matching production output), not the dev server. The webServer
|
|
// command builds first so the suite is self-contained; locally an
|
|
// already-running preview is reused instead of rebuilding.
|
|
export default defineConfig({
|
|
testDir: "./e2e",
|
|
// Measured on a 4-vCPU runner (the GitHub default) with the software
|
|
// renderer, over a 24-test subset: 1 worker 259 s, 3 workers 192 s, 6 workers
|
|
// 165 s, 10 workers 164 s. The speedup is sublinear because SwiftShader is
|
|
// CPU-bound, and at 10 workers contention started failing tests that pass
|
|
// serially. 3 is the conservative point on that curve.
|
|
//
|
|
// Local runs stay serial: dev machines have far more cores, so Playwright's
|
|
// default (half of them) would oversubscribe well past where those flakes
|
|
// began. Pass `--workers=N` to override either way.
|
|
workers: process.env.CI ? 3 : 1,
|
|
forbidOnly: !!process.env.CI,
|
|
retries: process.env.CI ? 1 : 0,
|
|
timeout: 60_000,
|
|
expect: { timeout: 15_000 },
|
|
reporter: process.env.CI ? [["list"], ["html", { open: "never" }]] : [["list"]],
|
|
use: {
|
|
baseURL: BASE_URL,
|
|
// Seed the first-launch UI-profile onboarding (issue #500) as already
|
|
// completed. Otherwise its modal wizard opens on every fresh context and its
|
|
// overlay intercepts pointer events, timing out any spec that clicks through
|
|
// the UI. The partial blob is merged with defaults by the settings loader.
|
|
storageState: {
|
|
cookies: [],
|
|
origins: [
|
|
{
|
|
origin: BASE_URL,
|
|
localStorage: [
|
|
{
|
|
name: DESKTOP_SETTINGS_STORAGE_KEY,
|
|
value: JSON.stringify({ uiProfile: { onboarded: true } }),
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
trace: "on-first-retry",
|
|
screenshot: "only-on-failure",
|
|
video: "off",
|
|
},
|
|
// The projects partition `e2e/` — nothing is listed twice, so a plain
|
|
// `playwright test` still runs every spec exactly once. CI narrows to the
|
|
// per-commit gate with `--project=core --project=core-engines`.
|
|
projects: [
|
|
{ name: "core", testMatch: coreMatch, use: chromium },
|
|
// Depends on `core` so it starts only once those workers are done, and
|
|
// caps itself at one worker. `--no-deps` runs it on its own locally.
|
|
{
|
|
name: "core-engines",
|
|
testMatch: coreEnginesMatch,
|
|
dependencies: ["core"],
|
|
workers: 1,
|
|
use: chromium,
|
|
},
|
|
// `e2e/enterprise-sso/` needs a live API and Keycloak, and `e2e/preview/`
|
|
// a deployed site; each has its own config and job.
|
|
{
|
|
name: "features",
|
|
testIgnore: [...coreMatch, ...coreEnginesMatch, "**/enterprise-sso/**", "**/preview/**"],
|
|
use: chromium,
|
|
},
|
|
],
|
|
webServer: {
|
|
command: `npm run build && npm run preview -w geolibre-desktop -- --port ${PORT} --strictPort`,
|
|
// Build without a Cesium Ion token from the shell. `vite.config.ts` bakes
|
|
// `CESIUM_TOKEN`/`VITE_CESIUM_TOKEN` into the bundle, so a machine with one
|
|
// exported would produce a *different* app than CI builds: the 3D globe
|
|
// would come up with Ion terrain and imagery, and `cesium-globe.spec.ts`
|
|
// could no longer tell the keyless path from the tokened one.
|
|
//
|
|
// This covers the shell only. The bridge in `vite.config.ts` falls through
|
|
// to `loadEnv()` when the prefixed name is falsy, so a token in
|
|
// `apps/geolibre-desktop/.env.local` is still picked up despite these being
|
|
// blanked. That case is not silently tolerated — `cesium-globe.spec.ts`
|
|
// asserts the tokenless hint and fails with a message naming the file.
|
|
env: { CESIUM_TOKEN: "", VITE_CESIUM_TOKEN: "" },
|
|
url: BASE_URL,
|
|
// Reuse locally (the repo's existing DX trade-off), never in CI. Note the
|
|
// interaction with `env` above: Playwright skips the whole command when it
|
|
// reuses a server, so the override is *not* applied to a reused one. That
|
|
// is why `cesium-globe.spec.ts` asserts the tokenless hint rather than
|
|
// trusting this — a reused tokened build fails there with an explanation
|
|
// instead of silently exercising the wrong path. In CI, where determinism
|
|
// actually matters, this is false and the override always applies.
|
|
reuseExistingServer: !process.env.CI,
|
|
// The build (tsc -b + vite build) runs as part of this command, so allow
|
|
// generous startup time on cold CI runners.
|
|
timeout: 300_000,
|
|
stdout: "pipe",
|
|
stderr: "pipe",
|
|
},
|
|
});
|