Unify Playwright route base selection

This commit is contained in:
rcourtman 2026-04-10 17:33:18 +01:00
parent 8d97bc3995
commit 259285ad40
8 changed files with 84 additions and 27 deletions

View file

@ -451,6 +451,11 @@ browser helper must treat `PLAYWRIGHT_BASE_URL` as the browser truth and leave
`PULSE_BASE_URL` available for backend-oriented health checks and setup
traffic, so split browser/backend proof can target fresh frontend code without
rewiring the API-side contract.
Playwright-driven public/commercial specs that support scenario-specific
endpoint overrides such as `PULSE_CLOUD_BASE_URL` or
`PULSE_COMMERCIAL_BASE_URL` must layer those values through that same shared
route helper instead of duplicating `PLAYWRIGHT_BASE_URL` versus
`PULSE_BASE_URL` precedence locally.
That defaulting rule must live in one shared integration helper rather than
being duplicated between config and helper files, so future browser-target
changes cannot leave Playwright navigation and browser/API helper calls

View file

@ -757,10 +757,11 @@ test_integration_helpers_prefer_managed_hot_dev_runtime() {
local output
output="$(cat "${ROOT_DIR}/tests/integration/tests/helpers.ts")"
assert_contains "integration helpers import preferred browser helper" "${output}" "preferredBrowserBaseURL, readRuntimeState"
assert_contains "integration helpers import preferred browser helper" "${output}" "preferredBrowserBaseURL"
assert_contains "integration helpers import shared route helper" "${output}" "preferredPlaywrightRouteBaseURL"
assert_contains "integration helpers import shared browser defaults" "${output}" "runtime-defaults"
assert_contains "integration helpers delegate browser context base url to shared helper" "${output}" "baseURL: preferredBrowserBaseURL(),"
assert_contains "integration helpers delegate api request base url to shared helper" "${output}" "const baseURL = preferredBrowserBaseURL().replace"
assert_contains "integration helpers delegate api request base url to shared route helper" "${output}" "const baseURL = preferredPlaywrightRouteBaseURL()"
}
test_integration_runtime_defaults_centralize_managed_browser_detection() {
@ -771,6 +772,7 @@ test_integration_runtime_defaults_centralize_managed_browser_detection() {
assert_contains "runtime defaults expose runtime-state reader" "${output}" "export const readRuntimeState ="
assert_contains "runtime defaults expose managed browser detection" "${output}" "export const managedDevBrowserBaseURL ="
assert_contains "runtime defaults expose preferred browser base url" "${output}" "export const preferredBrowserBaseURL ="
assert_contains "runtime defaults expose normalized Playwright route helper" "${output}" "export const preferredPlaywrightRouteBaseURL ="
}
test_integration_runtime_defaults_prefer_explicit_browser_override() {
@ -835,6 +837,25 @@ EOF
assert_contains "runtime defaults resolve managed dev browser url from overridden repo root" "${output}" "managed=http://127.0.0.1:4174"
}
test_cloud_and_commercial_specs_use_shared_route_defaults() {
local output
output="$(cat "${ROOT_DIR}/tests/integration/tests/08-cloud-hosting.spec.ts")"
assert_contains "cloud hosting spec imports shared route helper" "${output}" "preferredPlaywrightRouteBaseURL"
assert_contains "cloud hosting spec uses cloud override through shared route helper" "${output}" "process.env.PULSE_CLOUD_BASE_URL"
assert_not_contains "cloud hosting spec no longer duplicates Pulse-vs-Playwright precedence" "${output}" "process.env.PULSE_BASE_URL ||"
output="$(cat "${ROOT_DIR}/tests/integration/tests/09-cloud-billing-lifecycle.spec.ts")"
assert_contains "cloud billing spec imports shared route helper" "${output}" "preferredPlaywrightRouteBaseURL"
assert_contains "cloud billing spec uses cloud override through shared route helper" "${output}" "process.env.PULSE_CLOUD_BASE_URL"
assert_not_contains "cloud billing spec no longer duplicates Pulse-vs-Playwright precedence" "${output}" "process.env.PULSE_BASE_URL ||"
output="$(cat "${ROOT_DIR}/tests/integration/tests/14-commercial-cancellation-reactivation.spec.ts")"
assert_contains "commercial cancellation spec imports shared route helper" "${output}" "preferredPlaywrightRouteBaseURL"
assert_contains "commercial cancellation spec uses commercial override through shared route helper" "${output}" "process.env.PULSE_COMMERCIAL_BASE_URL"
assert_not_contains "commercial cancellation spec no longer duplicates Pulse-vs-Playwright precedence" "${output}" "process.env.PULSE_BASE_URL ||"
}
test_clean_mock_alerts_prefers_managed_runtime() {
local test_dir fake_bin alert_history fake_hot_dev_bg action_log output
test_dir="$(mktemp -d)"
@ -1086,6 +1107,7 @@ main() {
test_integration_runtime_defaults_centralize_managed_browser_detection
test_integration_runtime_defaults_prefer_explicit_browser_override
test_integration_runtime_defaults_honor_repo_root_override
test_cloud_and_commercial_specs_use_shared_route_defaults
test_clean_mock_alerts_prefers_managed_runtime
test_dev_check_uses_managed_runtime_status
test_backend_restart_requires_managed_runtime

View file

@ -7,6 +7,7 @@ import test from 'node:test';
import {
managedDevBrowserBaseURL,
preferredBrowserBaseURL,
preferredPlaywrightRouteBaseURL,
runtimeStatePath,
} from '../tests/runtime-defaults.ts';
@ -27,6 +28,26 @@ test('preferredBrowserBaseURL still falls back to PULSE_BASE_URL when no browser
assert.equal(resolved, 'http://127.0.0.1:7655');
});
test('preferredPlaywrightRouteBaseURL honors explicit per-scenario overrides before shared browser defaults', () => {
const resolved = preferredPlaywrightRouteBaseURL(
{
PLAYWRIGHT_BASE_URL: 'http://127.0.0.1:4174',
PULSE_BASE_URL: 'http://127.0.0.1:7655',
},
['https://cloud.example.test///'],
);
assert.equal(resolved, 'https://cloud.example.test');
});
test('preferredPlaywrightRouteBaseURL normalizes the selected browser target for route concatenation', () => {
const resolved = preferredPlaywrightRouteBaseURL({
PLAYWRIGHT_BASE_URL: 'http://127.0.0.1:4174///',
});
assert.equal(resolved, 'http://127.0.0.1:4174');
});
test('runtimeStatePath resolves the default path from an overridden integration repo root', () => {
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'pulse-runtime-defaults-'));

View file

@ -1,13 +1,11 @@
import { expect, test } from '@playwright/test';
import { completeStripeSandboxCheckout } from './stripe-sandbox';
import { preferredPlaywrightRouteBaseURL } from './runtime-defaults';
function cloudBaseURL(): string {
const base =
process.env.PULSE_CLOUD_BASE_URL ||
process.env.PULSE_BASE_URL ||
process.env.PLAYWRIGHT_BASE_URL ||
'http://localhost:7655';
return base.replace(/\/+$/, '');
return preferredPlaywrightRouteBaseURL(process.env, [
process.env.PULSE_CLOUD_BASE_URL,
]);
}
function signupIdentity() {

View file

@ -1,6 +1,7 @@
import { expect, test } from '@playwright/test';
import { completeStripeSandboxCheckout } from './stripe-sandbox';
import { sendStripeWebhook } from './stripe-webhooks';
import { preferredPlaywrightRouteBaseURL } from './runtime-defaults';
type Tenant = {
id: string;
@ -29,12 +30,9 @@ type StripeSubscriptionResponse = {
};
function cloudBaseURL(): string {
const base =
process.env.PULSE_CLOUD_BASE_URL ||
process.env.PULSE_BASE_URL ||
process.env.PLAYWRIGHT_BASE_URL ||
'http://localhost:7655';
return base.replace(/\/+$/, '');
return preferredPlaywrightRouteBaseURL(process.env, [
process.env.PULSE_CLOUD_BASE_URL,
]);
}
function requiredEnv(name: string): string {

View file

@ -6,6 +6,7 @@ import { expect, test, type APIRequestContext, type Page } from '@playwright/tes
import { apiRequest, ensureAuthenticated, navigateToSettings } from './helpers';
import { completeStripeSandboxCheckout } from './stripe-sandbox';
import { sendStripeWebhook } from './stripe-webhooks';
import { preferredPlaywrightRouteBaseURL } from './runtime-defaults';
type StripeSubscription = {
id: string;
@ -75,12 +76,9 @@ function requiredEnv(name: string): string {
}
function commercialBaseURL(): string {
const base =
process.env.PULSE_COMMERCIAL_BASE_URL ||
process.env.PULSE_BASE_URL ||
process.env.PLAYWRIGHT_BASE_URL ||
'http://localhost:7655';
return base.replace(/\/+$/, '');
return preferredPlaywrightRouteBaseURL(process.env, [
process.env.PULSE_COMMERCIAL_BASE_URL,
]);
}
function commercialWebhookBaseURL(): string {

View file

@ -1,5 +1,9 @@
import { Browser, Page, Request, expect } from "@playwright/test";
import { preferredBrowserBaseURL, readRuntimeState } from "./runtime-defaults";
import {
preferredBrowserBaseURL,
preferredPlaywrightRouteBaseURL,
readRuntimeState,
} from "./runtime-defaults";
const runtimePrimaryAPIToken = (): string => {
const parsed = readRuntimeState();
@ -812,7 +816,7 @@ export async function apiRequest(
endpoint: string,
options: any = {},
) {
const baseURL = preferredBrowserBaseURL().replace(/\/+$/, "");
const baseURL = preferredPlaywrightRouteBaseURL();
const method = String(options.method || "GET").toUpperCase();
const headers = { ...(options.headers || {}) } as Record<string, string>;

View file

@ -10,6 +10,8 @@ export type RuntimeState = {
};
const trim = (value: unknown): string => String(value ?? '').trim();
const firstNonEmpty = (...values: readonly unknown[]): string =>
values.map(trim).find((value) => value !== '') || '';
const repoRootFromEnv = (env: NodeJS.ProcessEnv = process.env): string =>
trim(env.PULSE_E2E_REPO_ROOT) || path.resolve(__dirname, '..', '..', '..');
@ -66,9 +68,18 @@ export const managedDevBrowserBaseURL = (
export const preferredBrowserBaseURL = (
env: NodeJS.ProcessEnv = process.env,
overrides: readonly unknown[] = [],
): string =>
trim(env.PLAYWRIGHT_BASE_URL) ||
trim(env.PULSE_BASE_URL) ||
loadRuntimeBaseURL(env) ||
managedDevBrowserBaseURL(env) ||
'http://localhost:7655';
firstNonEmpty(
...overrides,
env.PLAYWRIGHT_BASE_URL,
env.PULSE_BASE_URL,
loadRuntimeBaseURL(env),
managedDevBrowserBaseURL(env),
'http://localhost:7655',
);
export const preferredPlaywrightRouteBaseURL = (
env: NodeJS.ProcessEnv = process.env,
overrides: readonly unknown[] = [],
): string => preferredBrowserBaseURL(env, overrides).replace(/\/+$/, '');