@elliemae/smoked-suite 26.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -0
- package/dist/cjs/auth/index.js +153 -0
- package/dist/cjs/base-page/index.js +58 -0
- package/dist/cjs/browserstack/index.js +97 -0
- package/dist/cjs/global-setup/index.js +71 -0
- package/dist/cjs/index.js +47 -0
- package/dist/cjs/monocartCoverage/index.js +125 -0
- package/dist/cjs/package.json +7 -0
- package/dist/cjs/page-setup/index.js +116 -0
- package/dist/cjs/playwright-config/index.js +116 -0
- package/dist/cjs/routes/index.js +27 -0
- package/dist/cjs/types.js +16 -0
- package/dist/esm/auth/index.js +123 -0
- package/dist/esm/base-page/index.js +38 -0
- package/dist/esm/browserstack/index.js +67 -0
- package/dist/esm/global-setup/index.js +41 -0
- package/dist/esm/index.js +20 -0
- package/dist/esm/monocartCoverage/index.js +95 -0
- package/dist/esm/package.json +7 -0
- package/dist/esm/page-setup/index.js +96 -0
- package/dist/esm/playwright-config/index.js +92 -0
- package/dist/esm/routes/index.js +7 -0
- package/dist/esm/types.js +0 -0
- package/dist/types/lib/auth/index.d.ts +41 -0
- package/dist/types/lib/base-page/index.d.ts +27 -0
- package/dist/types/lib/browserstack/index.d.ts +59 -0
- package/dist/types/lib/global-setup/index.d.ts +16 -0
- package/dist/types/lib/index.d.ts +10 -0
- package/dist/types/lib/monocartCoverage/index.d.ts +57 -0
- package/dist/types/lib/page-setup/index.d.ts +39 -0
- package/dist/types/lib/playwright-config/index.d.ts +3 -0
- package/dist/types/lib/routes/index.d.ts +16 -0
- package/dist/types/lib/types.d.ts +77 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
class PageSetup {
|
|
2
|
+
/**
|
|
3
|
+
* Apply all page-level setup. Call once per test — each test
|
|
4
|
+
* receives a fresh Playwright page, so init scripts and route
|
|
5
|
+
* blocks do not carry over.
|
|
6
|
+
* @param page
|
|
7
|
+
*/
|
|
8
|
+
async apply(page) {
|
|
9
|
+
await Promise.all([
|
|
10
|
+
this.stubDiagnostics(page),
|
|
11
|
+
this.suppressErrorOverlays(page)
|
|
12
|
+
]);
|
|
13
|
+
await this.blockThirdPartyScripts(page);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Provide a no-op fallback for the emuiDiagnostics webpack external.
|
|
17
|
+
* @param page
|
|
18
|
+
*/
|
|
19
|
+
async stubDiagnostics(page) {
|
|
20
|
+
await page.addInitScript(() => {
|
|
21
|
+
if (typeof window.emuiDiagnostics === "undefined") {
|
|
22
|
+
const noop = () => {
|
|
23
|
+
};
|
|
24
|
+
const noopTransport = { log: async () => true };
|
|
25
|
+
const fallbackLogger = new Proxy({}, {
|
|
26
|
+
get(_target, prop) {
|
|
27
|
+
if (typeof prop === "string" && typeof console[prop] === "function") {
|
|
28
|
+
return console[prop].bind(console);
|
|
29
|
+
}
|
|
30
|
+
return prop === "setOptions" ? noop : console.log.bind(console);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
window.emuiDiagnostics = {
|
|
34
|
+
http: () => noopTransport,
|
|
35
|
+
logger: () => fallbackLogger,
|
|
36
|
+
Console: () => noopTransport,
|
|
37
|
+
logUnhandledErrors: noop,
|
|
38
|
+
webvitals: noop,
|
|
39
|
+
parentApp: () => noopTransport,
|
|
40
|
+
redactPii: (val) => val,
|
|
41
|
+
LogLevels: { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, FATAL: 4 }
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Auto-hide webpack / react-error-overlay iframes that obscure
|
|
48
|
+
* the page during tests.
|
|
49
|
+
* @param page
|
|
50
|
+
*/
|
|
51
|
+
async suppressErrorOverlays(page) {
|
|
52
|
+
await page.addInitScript(() => {
|
|
53
|
+
const hideOverlayIframes = () => {
|
|
54
|
+
document.querySelectorAll("body > iframe").forEach((el) => {
|
|
55
|
+
el.style.display = "none";
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
const start = () => {
|
|
59
|
+
hideOverlayIframes();
|
|
60
|
+
new MutationObserver(hideOverlayIframes).observe(document.body, {
|
|
61
|
+
childList: true
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
if (document.body) start();
|
|
65
|
+
else document.addEventListener("DOMContentLoaded", start);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/** Domains that are blocked during tests to speed up page loads. */
|
|
69
|
+
static BLOCKED_DOMAINS = [
|
|
70
|
+
"googletagmanager.com",
|
|
71
|
+
"google-analytics.com",
|
|
72
|
+
"fonts.googleapis.com",
|
|
73
|
+
"fonts.gstatic.com",
|
|
74
|
+
"hotjar.com",
|
|
75
|
+
"newrelic.com",
|
|
76
|
+
"nr-data.net",
|
|
77
|
+
"sentry.io",
|
|
78
|
+
"fullstory.com",
|
|
79
|
+
"pendo.io"
|
|
80
|
+
];
|
|
81
|
+
/** Single regex matching all {@link BLOCKED_DOMAINS}. */
|
|
82
|
+
static BLOCKED_PATTERN = new RegExp(
|
|
83
|
+
PageSetup.BLOCKED_DOMAINS.map((d) => d.replace(/\./g, "\\.")).join("|")
|
|
84
|
+
);
|
|
85
|
+
/**
|
|
86
|
+
* Block analytics, fonts, and monitoring scripts that slow page loads.
|
|
87
|
+
* Uses a single route handler instead of one per domain.
|
|
88
|
+
* @param page
|
|
89
|
+
*/
|
|
90
|
+
async blockThirdPartyScripts(page) {
|
|
91
|
+
await page.route(PageSetup.BLOCKED_PATTERN, (route) => route.abort());
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export {
|
|
95
|
+
PageSetup
|
|
96
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
import {
|
|
3
|
+
defineConfig,
|
|
4
|
+
devices
|
|
5
|
+
} from "@playwright/test";
|
|
6
|
+
import { STORAGE_FILE } from "../global-setup/index.js";
|
|
7
|
+
import {
|
|
8
|
+
buildCoverageReporters,
|
|
9
|
+
configureCoverage
|
|
10
|
+
} from "../monocartCoverage/index.js";
|
|
11
|
+
const DEFAULT_ACTION_TIMEOUT = 3e4;
|
|
12
|
+
const DEFAULT_NAVIGATION_TIMEOUT = 45e3;
|
|
13
|
+
const DEFAULT_TEST_TIMEOUT = 12e4;
|
|
14
|
+
const DEFAULT_EXPECT_TIMEOUT = 3e4;
|
|
15
|
+
const FAST_MODE_USE = {
|
|
16
|
+
trace: "off",
|
|
17
|
+
screenshot: "off",
|
|
18
|
+
video: "off"
|
|
19
|
+
};
|
|
20
|
+
const DEFAULT_USE = {
|
|
21
|
+
trace: "retain-on-failure",
|
|
22
|
+
screenshot: "only-on-failure",
|
|
23
|
+
video: "retain-on-failure"
|
|
24
|
+
};
|
|
25
|
+
const CI_CONFIG = {
|
|
26
|
+
workers: "100%",
|
|
27
|
+
forbidOnly: true,
|
|
28
|
+
retries: 2,
|
|
29
|
+
reporter: [
|
|
30
|
+
["list"],
|
|
31
|
+
["junit", { outputFile: "playwright-report/junit.xml" }]
|
|
32
|
+
]
|
|
33
|
+
};
|
|
34
|
+
const LOCAL_CONFIG = {
|
|
35
|
+
workers: "50%",
|
|
36
|
+
forbidOnly: false,
|
|
37
|
+
retries: 0,
|
|
38
|
+
reporter: [
|
|
39
|
+
["html", { outputFolder: "playwright-report" }],
|
|
40
|
+
["list"]
|
|
41
|
+
]
|
|
42
|
+
};
|
|
43
|
+
function createPlaywrightConfig(params = {}) {
|
|
44
|
+
const {
|
|
45
|
+
overrides = {},
|
|
46
|
+
globalAuth = true,
|
|
47
|
+
fastMode = false,
|
|
48
|
+
coverage
|
|
49
|
+
} = params;
|
|
50
|
+
const { use: useOverrides, expect: expectOverrides, ...rest } = overrides;
|
|
51
|
+
const isCoverage = !!coverage;
|
|
52
|
+
if (isCoverage) configureCoverage();
|
|
53
|
+
const globalSetup = path.resolve(__dirname, "../global-setup/index.js");
|
|
54
|
+
const globalAuthConfig = globalAuth ? { globalSetup } : {};
|
|
55
|
+
const storageStateConfig = globalAuth ? { storageState: path.join(process.cwd(), STORAGE_FILE) } : {};
|
|
56
|
+
const envConfig = process.env.CI ? CI_CONFIG : LOCAL_CONFIG;
|
|
57
|
+
const coverageReporter = isCoverage ? { reporter: buildCoverageReporters(coverage) } : {};
|
|
58
|
+
return defineConfig({
|
|
59
|
+
testMatch: "**/*Spec.ts",
|
|
60
|
+
fullyParallel: true,
|
|
61
|
+
...envConfig,
|
|
62
|
+
...coverageReporter,
|
|
63
|
+
projects: [
|
|
64
|
+
{
|
|
65
|
+
name: "chromium",
|
|
66
|
+
use: { ...devices["Desktop Chrome"] }
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
outputDir: "test-results",
|
|
70
|
+
timeout: DEFAULT_TEST_TIMEOUT,
|
|
71
|
+
...globalAuthConfig,
|
|
72
|
+
...rest,
|
|
73
|
+
use: {
|
|
74
|
+
...fastMode ? FAST_MODE_USE : DEFAULT_USE,
|
|
75
|
+
viewport: { width: 1280, height: 720 },
|
|
76
|
+
actionTimeout: DEFAULT_ACTION_TIMEOUT,
|
|
77
|
+
navigationTimeout: DEFAULT_NAVIGATION_TIMEOUT,
|
|
78
|
+
...storageStateConfig,
|
|
79
|
+
...useOverrides,
|
|
80
|
+
...{
|
|
81
|
+
baseURL: process.env.BASE_URL ?? useOverrides?.baseURL ?? "http://localhost:3000"
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
expect: {
|
|
85
|
+
timeout: DEFAULT_EXPECT_TIMEOUT,
|
|
86
|
+
...expectOverrides
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
createPlaywrightConfig
|
|
92
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
import { AuthState, Credentials } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Manages the encw authentication lifecycle.
|
|
5
|
+
*
|
|
6
|
+
* - Performs the Instance ID / User / Password login flow.
|
|
7
|
+
* - Snapshots the full session storage after login.
|
|
8
|
+
* - Injects the snapshot into fresh pages so subsequent tests
|
|
9
|
+
* skip the login form entirely.
|
|
10
|
+
* - Detects expired sessions and forces re-login.
|
|
11
|
+
*/
|
|
12
|
+
export declare class AuthManager {
|
|
13
|
+
private static authState;
|
|
14
|
+
/** Whether a cached session exists and is still valid. */
|
|
15
|
+
hasValidAuth(): boolean;
|
|
16
|
+
/** Expose current auth state (used by global setup to serialise). */
|
|
17
|
+
static getAuthState(): AuthState | null;
|
|
18
|
+
/**
|
|
19
|
+
* Load auth state from the file written by globalSetup.
|
|
20
|
+
* Returns `true` if a valid (non-expired) session was loaded.
|
|
21
|
+
*/
|
|
22
|
+
static loadFromFile(): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Restore every session-storage entry that was captured after
|
|
25
|
+
* the initial login so encw and its micro-apps find the data
|
|
26
|
+
* they need (Authorization, cred, user, userSettings, etc.).
|
|
27
|
+
* @param page
|
|
28
|
+
*/
|
|
29
|
+
inject(page: Page): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Snapshot every session-storage entry after a successful login.
|
|
32
|
+
* @param page
|
|
33
|
+
*/
|
|
34
|
+
capture(page: Page): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Perform the encw login flow (Instance ID -> User / Password).
|
|
37
|
+
* @param page - Playwright page to drive.
|
|
38
|
+
* @param creds - Credentials to use.
|
|
39
|
+
*/
|
|
40
|
+
login(page: Page, creds: Credentials): Promise<void>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Page, Locator } from '@playwright/test';
|
|
2
|
+
import { AppContext, ContextProvider } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Base page object class for encw apps.
|
|
5
|
+
*
|
|
6
|
+
* Accepts a {@link ContextProvider}: either a direct Page or
|
|
7
|
+
* a callback that returns the current one. The callback form
|
|
8
|
+
* lets page objects lazily resolve the context.
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* this.settingsPage = new MyPage(() => this.page);
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare abstract class BasePage {
|
|
15
|
+
private readonly _contextProvider;
|
|
16
|
+
/** The current Page context, resolved lazily. */
|
|
17
|
+
protected get page(): AppContext;
|
|
18
|
+
constructor(context: ContextProvider);
|
|
19
|
+
protected getByTestId(testId: string): Locator;
|
|
20
|
+
protected locator(selector: string): Locator;
|
|
21
|
+
protected getByRole(role: Parameters<Page['getByRole']>[0], options?: Parameters<Page['getByRole']>[1]): Locator;
|
|
22
|
+
protected getByText(text: string | RegExp, options?: Parameters<Page['getByText']>[1]): Locator;
|
|
23
|
+
protected getByLabel(text: string | RegExp, options?: Parameters<Page['getByLabel']>[1]): Locator;
|
|
24
|
+
protected getByPlaceholder(text: string | RegExp, options?: Parameters<Page['getByPlaceholder']>[1]): Locator;
|
|
25
|
+
protected getByAltText(text: string | RegExp, options?: Parameters<Page['getByAltText']>[1]): Locator;
|
|
26
|
+
protected getByTitle(text: string | RegExp, options?: Parameters<Page['getByTitle']>[1]): Locator;
|
|
27
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BrowserStack platform configuration for a single browser/OS combo.
|
|
3
|
+
*/
|
|
4
|
+
export interface BrowserStackPlatform {
|
|
5
|
+
os: string;
|
|
6
|
+
osVersion: string;
|
|
7
|
+
browserName: string;
|
|
8
|
+
browserVersion?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Options for {@link createBrowserStackConfig}.
|
|
12
|
+
* All fields are optional and fall back to sensible defaults.
|
|
13
|
+
*/
|
|
14
|
+
export interface BrowserStackOptions {
|
|
15
|
+
/** Project name shown on the BrowserStack dashboard. */
|
|
16
|
+
projectName?: string;
|
|
17
|
+
/** Build name shown on the dashboard. */
|
|
18
|
+
buildName?: string;
|
|
19
|
+
/** Build identifier template (supports `${BUILD_NUMBER}`). */
|
|
20
|
+
buildIdentifier?: string;
|
|
21
|
+
/** Browser/OS combinations to test on. */
|
|
22
|
+
platforms?: BrowserStackPlatform[];
|
|
23
|
+
/** Number of parallel sessions per platform. */
|
|
24
|
+
parallelsPerPlatform?: number;
|
|
25
|
+
/** Enable the local tunnel for localhost testing. */
|
|
26
|
+
browserstackLocal?: boolean;
|
|
27
|
+
/** Resolve all traffic through the local machine (fixes Host header issues). */
|
|
28
|
+
forceLocal?: boolean;
|
|
29
|
+
/** Capture debug screenshots. */
|
|
30
|
+
debug?: boolean;
|
|
31
|
+
/** Capture HAR network logs. */
|
|
32
|
+
networkLogs?: boolean;
|
|
33
|
+
/** Browser console log level. */
|
|
34
|
+
consoleLogs?: 'disable' | 'errors' | 'warnings' | 'info' | 'verbose';
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Generate the contents of a `browserstack.yml` configuration file.
|
|
38
|
+
*
|
|
39
|
+
* Credentials are always read from environment variables
|
|
40
|
+
* (`BROWSERSTACK_USERNAME` and `BROWSERSTACK_ACCESS_KEY`)
|
|
41
|
+
* and are **never** hardcoded.
|
|
42
|
+
* @param options - Override any default configuration value.
|
|
43
|
+
* @returns The YAML string ready to be written to `browserstack.yml`.
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* import { createBrowserStackConfig, writeBrowserStackConfig } from '@elliemae/smoked-suite';
|
|
47
|
+
*
|
|
48
|
+
* // Generate and write to project root
|
|
49
|
+
* writeBrowserStackConfig({ projectName: 'my-app' });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function createBrowserStackConfig(options?: BrowserStackOptions): string;
|
|
53
|
+
/**
|
|
54
|
+
* Write a `browserstack.yml` file to the specified directory.
|
|
55
|
+
* @param options - BrowserStack configuration options.
|
|
56
|
+
* @param targetDir - Directory to write the file to (defaults to `process.cwd()`).
|
|
57
|
+
* @returns The absolute path of the written file.
|
|
58
|
+
*/
|
|
59
|
+
export declare function writeBrowserStackConfig(options?: BrowserStackOptions, targetDir?: string): string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type FullConfig } from '@playwright/test';
|
|
2
|
+
declare const AUTH_FILE = ".smoked-suite-auth.json";
|
|
3
|
+
declare const STORAGE_FILE = ".smoked-suite-storage.json";
|
|
4
|
+
/**
|
|
5
|
+
* Playwright `globalSetup` function that authenticates once and
|
|
6
|
+
* persists the session for all workers.
|
|
7
|
+
*
|
|
8
|
+
* Writes two files to `process.cwd()`:
|
|
9
|
+
* - `.smoked-suite-auth.json` — serialised `sessionStorage` entries
|
|
10
|
+
* - `.smoked-suite-storage.json` — Playwright `storageState` (cookies + localStorage)
|
|
11
|
+
*
|
|
12
|
+
* Workers load these files at startup so they never need to log in.
|
|
13
|
+
* @param config
|
|
14
|
+
*/
|
|
15
|
+
export default function globalSetup(config: FullConfig): Promise<void>;
|
|
16
|
+
export { AUTH_FILE, STORAGE_FILE };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { BasePage } from './base-page/index.js';
|
|
2
|
+
export { AuthManager } from './auth/index.js';
|
|
3
|
+
export { PageSetup } from './page-setup/index.js';
|
|
4
|
+
export { getRoutePath } from './routes/index.js';
|
|
5
|
+
export { createPlaywrightConfig } from './playwright-config/index.js';
|
|
6
|
+
export { default as globalSetup } from './global-setup/index.js';
|
|
7
|
+
export { createBrowserStackConfig, writeBrowserStackConfig, } from './browserstack/index.js';
|
|
8
|
+
export type { BrowserStackOptions, BrowserStackPlatform, } from './browserstack/index.js';
|
|
9
|
+
export type { AppContext, ContextProvider, AuthState, GotoOptions, Credentials, SmokedSuiteConfig, } from './types.js';
|
|
10
|
+
export type { CoverageConfig } from './monocartCoverage/index.js';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type Page, PlaywrightTestConfig } from '@playwright/test';
|
|
2
|
+
/**
|
|
3
|
+
* Mark coverage as configured. Called by {@link createPlaywrightConfig}
|
|
4
|
+
* when a `coverage` config is provided — no env var needed.
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export declare function configureCoverage(): void;
|
|
8
|
+
/**
|
|
9
|
+
* Enable V8 coverage collection. Hooks into the browser context so that
|
|
10
|
+
* every new page automatically starts JS coverage and every closed page
|
|
11
|
+
* reports its coverage data to monocart.
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export declare function startCoverage(): void;
|
|
15
|
+
/**
|
|
16
|
+
* Collect coverage from any pages still open, then disable collection.
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export declare function stopCoverage(): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Start V8 coverage on a page and track it for collection.
|
|
22
|
+
* Call this after the page is assigned to the test instance.
|
|
23
|
+
* @param page
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export declare function trackPage(page: Page): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Collect and report V8 coverage from a tracked page.
|
|
29
|
+
* Call this before the page is destroyed.
|
|
30
|
+
* @param page
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
export declare function untrackPage(page: Page): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Coverage configuration accepted by {@link createPlaywrightConfig}.
|
|
36
|
+
*/
|
|
37
|
+
export interface CoverageConfig {
|
|
38
|
+
/**
|
|
39
|
+
* Path to the source directory (relative to repo root).
|
|
40
|
+
* All `.ts` / `.tsx` files inside this directory are included in the
|
|
41
|
+
* coverage report — files never loaded by any test appear as 0%.
|
|
42
|
+
* @example './src/features/dashboard'
|
|
43
|
+
*/
|
|
44
|
+
sourceDir: string;
|
|
45
|
+
/**
|
|
46
|
+
* Directory where coverage output files are written.
|
|
47
|
+
* Defaults to `./coverage/<sourceDir-basename>`.
|
|
48
|
+
* @example './coverage/dashboard'
|
|
49
|
+
*/
|
|
50
|
+
outputDir?: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Builds the full reporter array when coverage is enabled.
|
|
54
|
+
* @param configs
|
|
55
|
+
* @internal
|
|
56
|
+
*/
|
|
57
|
+
export declare function buildCoverageReporters(configs: CoverageConfig[]): PlaywrightTestConfig['reporter'];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
/**
|
|
3
|
+
* Registers init scripts and route blocks on a Playwright page.
|
|
4
|
+
*
|
|
5
|
+
* Handles:
|
|
6
|
+
* - `emuiDiagnostics` webpack-external stub (CDN unreachable in test)
|
|
7
|
+
* - Auto-hiding error-overlay iframes (webpack / react-error-overlay)
|
|
8
|
+
* - Blocking non-essential third-party scripts (analytics, tag manager)
|
|
9
|
+
*/
|
|
10
|
+
export declare class PageSetup {
|
|
11
|
+
/**
|
|
12
|
+
* Apply all page-level setup. Call once per test — each test
|
|
13
|
+
* receives a fresh Playwright page, so init scripts and route
|
|
14
|
+
* blocks do not carry over.
|
|
15
|
+
* @param page
|
|
16
|
+
*/
|
|
17
|
+
apply(page: Page): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Provide a no-op fallback for the emuiDiagnostics webpack external.
|
|
20
|
+
* @param page
|
|
21
|
+
*/
|
|
22
|
+
private stubDiagnostics;
|
|
23
|
+
/**
|
|
24
|
+
* Auto-hide webpack / react-error-overlay iframes that obscure
|
|
25
|
+
* the page during tests.
|
|
26
|
+
* @param page
|
|
27
|
+
*/
|
|
28
|
+
private suppressErrorOverlays;
|
|
29
|
+
/** Domains that are blocked during tests to speed up page loads. */
|
|
30
|
+
static readonly BLOCKED_DOMAINS: string[];
|
|
31
|
+
/** Single regex matching all {@link BLOCKED_DOMAINS}. */
|
|
32
|
+
static readonly BLOCKED_PATTERN: RegExp;
|
|
33
|
+
/**
|
|
34
|
+
* Block analytics, fonts, and monitoring scripts that slow page loads.
|
|
35
|
+
* Uses a single route handler instead of one per domain.
|
|
36
|
+
* @param page
|
|
37
|
+
*/
|
|
38
|
+
private blockThirdPartyScripts;
|
|
39
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a route key to a URL path.
|
|
3
|
+
*
|
|
4
|
+
* If `route` is a key in the provided `routes` map, returns the
|
|
5
|
+
* mapped path. Otherwise treats `route` as a raw path and returns
|
|
6
|
+
* it as-is.
|
|
7
|
+
* @param routes
|
|
8
|
+
* @param route
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const ROUTES = { home: '/app/home', settings: '/app/settings' } as const;
|
|
12
|
+
* getRoutePath(ROUTES, 'home'); // '/app/home'
|
|
13
|
+
* getRoutePath(ROUTES, '/raw/path'); // '/raw/path'
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function getRoutePath<T extends Record<string, string>>(routes: T, route: keyof T | string): string;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
/** Page context for element interaction. */
|
|
3
|
+
export type AppContext = Page;
|
|
4
|
+
/**
|
|
5
|
+
* A direct Page or a callback that returns the current Page.
|
|
6
|
+
* The callback form lets page objects lazily resolve the context.
|
|
7
|
+
*/
|
|
8
|
+
export type ContextProvider = AppContext | (() => AppContext);
|
|
9
|
+
/**
|
|
10
|
+
* Full session storage snapshot captured after login.
|
|
11
|
+
* Includes Authorization, cred, user, userSettings, instanceId, etc.
|
|
12
|
+
*/
|
|
13
|
+
export interface AuthState {
|
|
14
|
+
/** All session storage entries needed to restore a logged-in session */
|
|
15
|
+
sessionEntries: Record<string, string>;
|
|
16
|
+
/** Timestamp when auth was captured */
|
|
17
|
+
capturedAt: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Credentials for login
|
|
21
|
+
*/
|
|
22
|
+
export interface Credentials {
|
|
23
|
+
username: string;
|
|
24
|
+
password: string;
|
|
25
|
+
instanceId?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Options for goto navigation
|
|
29
|
+
*/
|
|
30
|
+
export interface GotoOptions {
|
|
31
|
+
/** Wait for specific load state */
|
|
32
|
+
waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';
|
|
33
|
+
/** Custom timeout */
|
|
34
|
+
timeout?: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Configuration for {@link createPlaywrightConfig}.
|
|
38
|
+
*/
|
|
39
|
+
export interface SmokedSuiteConfig {
|
|
40
|
+
/** Partial Playwright config to merge with sensible defaults. */
|
|
41
|
+
overrides?: import('@playwright/test').PlaywrightTestConfig;
|
|
42
|
+
/**
|
|
43
|
+
* When `true` (default), a `globalSetup` function runs once before
|
|
44
|
+
* all workers to authenticate and persist the session to disk.
|
|
45
|
+
* Workers reuse it instead of logging in individually.
|
|
46
|
+
*/
|
|
47
|
+
globalAuth?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* When `true`, disables trace, screenshot, and video recording
|
|
50
|
+
* for faster test execution.
|
|
51
|
+
*/
|
|
52
|
+
fastMode?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* V8 code coverage configuration. When provided, monocart-reporter
|
|
55
|
+
* is automatically added to the reporter array and BaseTest collects
|
|
56
|
+
* V8 coverage per test. No env var needed.
|
|
57
|
+
*
|
|
58
|
+
* Pass a single config or an array for multi-app repos.
|
|
59
|
+
* Only `sourceDir` is required — everything else is derived.
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* // Single app
|
|
63
|
+
* createPlaywrightConfig({
|
|
64
|
+
* coverage: [{ sourceDir: './src/features/dashboard' }],
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* // Multi-app repo
|
|
68
|
+
* createPlaywrightConfig({
|
|
69
|
+
* coverage: [
|
|
70
|
+
* { sourceDir: './src/app-a' },
|
|
71
|
+
* { sourceDir: './src/app-b' },
|
|
72
|
+
* ],
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
coverage?: import('./monocartCoverage/index.js').CoverageConfig[];
|
|
77
|
+
}
|