@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
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# smoked-suite
|
|
2
|
+
|
|
3
|
+
> Shared Playwright test infrastructure for ICE micro-frontend apps running inside encw (Encompass Web).
|
|
4
|
+
|
|
5
|
+
Part of the [encw-libraries](https://git.elliemae.io/EncompassWeb/encw-libraries) monorepo.
|
|
6
|
+
|
|
7
|
+
Previously maintained at [EncompassWeb/smoked-suite](https://git.elliemae.io/EncompassWeb/smoked-suite) (now archived).
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add -D @elliemae/smoked-suite @playwright/test
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { BaseTest } from '@elliemae/smoked-suite';
|
|
19
|
+
import { SelectSettingsPage } from '../page-objects';
|
|
20
|
+
|
|
21
|
+
class SelectSettingsSpec extends BaseTest {
|
|
22
|
+
private settingsPage!: SelectSettingsPage;
|
|
23
|
+
|
|
24
|
+
async beforeEach() {
|
|
25
|
+
await this.goToEmAdminUI();
|
|
26
|
+
this.settingsPage = new SelectSettingsPage(() => this.appFrame);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async testPageLoads() {
|
|
30
|
+
await this.goto('/admin/oneadmin/migrate');
|
|
31
|
+
await this.expect(this.settingsPage.container).toBeVisible();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
SelectSettingsSpec.run();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## What It Provides
|
|
39
|
+
|
|
40
|
+
- **BaseTest** — Test runner orchestrator with auth, iframe resolution, micro-app navigation
|
|
41
|
+
- **BasePage** — Page object base class with ContextProvider pattern and locator helpers
|
|
42
|
+
- **AuthManager** — encw login, session-storage capture/inject, TTL caching
|
|
43
|
+
- **PageSetup** — Init scripts, error-overlay suppression, analytics blocking
|
|
44
|
+
- **createPlaywrightConfig** — Config factory with sensible defaults, coverage support
|
|
45
|
+
- **globalSetup** — Worker-level auth setup function
|
|
46
|
+
- **getRoutePath** — Route resolution utility
|
|
47
|
+
- **BrowserStack** — Integration utilities for BrowserStack cloud testing
|
|
48
|
+
- **Coverage** — V8 code coverage collection via monocart-reporter
|
|
49
|
+
|
|
50
|
+
## Development
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# From monorepo root
|
|
54
|
+
pnpm --filter @elliemae/smoked-suite build # Production build
|
|
55
|
+
pnpm --filter @elliemae/smoked-suite test # Run unit tests
|
|
56
|
+
pnpm --filter @elliemae/smoked-suite lint # Lint
|
|
57
|
+
pnpm --filter @elliemae/smoked-suite tscheck # TypeScript check
|
|
58
|
+
```
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var auth_exports = {};
|
|
30
|
+
__export(auth_exports, {
|
|
31
|
+
AuthManager: () => AuthManager
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(auth_exports);
|
|
34
|
+
var fs = __toESM(require("fs"), 1);
|
|
35
|
+
var path = __toESM(require("path"), 1);
|
|
36
|
+
const AUTH_CAPTURE_TIMEOUT = 3e4;
|
|
37
|
+
const LOGIN_PAGE_TIMEOUT = 9e4;
|
|
38
|
+
const LOGIN_FIELD_TIMEOUT = 6e4;
|
|
39
|
+
const LOGIN_BUTTON_TIMEOUT = 3e4;
|
|
40
|
+
const AUTH_SHELL_TIMEOUT = 12e4;
|
|
41
|
+
const AUTH_TTL_MS = 25 * 60 * 1e3;
|
|
42
|
+
const AUTH_FILE = ".smoked-suite-auth.json";
|
|
43
|
+
class AuthManager {
|
|
44
|
+
static authState = null;
|
|
45
|
+
/** Whether a cached session exists and is still valid. */
|
|
46
|
+
hasValidAuth() {
|
|
47
|
+
const state = AuthManager.authState;
|
|
48
|
+
if (!state) return false;
|
|
49
|
+
return Date.now() - state.capturedAt < AUTH_TTL_MS;
|
|
50
|
+
}
|
|
51
|
+
/** Expose current auth state (used by global setup to serialise). */
|
|
52
|
+
static getAuthState() {
|
|
53
|
+
return AuthManager.authState;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Load auth state from the file written by globalSetup.
|
|
57
|
+
* Returns `true` if a valid (non-expired) session was loaded.
|
|
58
|
+
*/
|
|
59
|
+
static loadFromFile() {
|
|
60
|
+
const filePath = path.join(process.cwd(), AUTH_FILE);
|
|
61
|
+
try {
|
|
62
|
+
if (!fs.existsSync(filePath)) return false;
|
|
63
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
64
|
+
const state = JSON.parse(raw);
|
|
65
|
+
if (!state?.sessionEntries || !state?.capturedAt) return false;
|
|
66
|
+
if (Date.now() - state.capturedAt >= AUTH_TTL_MS) return false;
|
|
67
|
+
AuthManager.authState = state;
|
|
68
|
+
return true;
|
|
69
|
+
} catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Restore every session-storage entry that was captured after
|
|
75
|
+
* the initial login so encw and its micro-apps find the data
|
|
76
|
+
* they need (Authorization, cred, user, userSettings, etc.).
|
|
77
|
+
* @param page
|
|
78
|
+
*/
|
|
79
|
+
async inject(page) {
|
|
80
|
+
const state = AuthManager.authState;
|
|
81
|
+
if (!state) {
|
|
82
|
+
throw new Error("No auth state available to inject");
|
|
83
|
+
}
|
|
84
|
+
await page.evaluate((entries) => {
|
|
85
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
86
|
+
sessionStorage.setItem(key, value);
|
|
87
|
+
}
|
|
88
|
+
}, state.sessionEntries);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Snapshot every session-storage entry after a successful login.
|
|
92
|
+
* @param page
|
|
93
|
+
*/
|
|
94
|
+
async capture(page) {
|
|
95
|
+
await page.waitForFunction(
|
|
96
|
+
() => sessionStorage.getItem("Authorization") !== null,
|
|
97
|
+
{ timeout: AUTH_CAPTURE_TIMEOUT }
|
|
98
|
+
);
|
|
99
|
+
const sessionEntries = await page.evaluate(() => {
|
|
100
|
+
const entries = {};
|
|
101
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
102
|
+
const key = sessionStorage.key(i);
|
|
103
|
+
if (key) entries[key] = sessionStorage.getItem(key) ?? "";
|
|
104
|
+
}
|
|
105
|
+
return entries;
|
|
106
|
+
});
|
|
107
|
+
if (sessionEntries?.Authorization) {
|
|
108
|
+
AuthManager.authState = { sessionEntries, capturedAt: Date.now() };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Perform the encw login flow (Instance ID -> User / Password).
|
|
113
|
+
* @param page - Playwright page to drive.
|
|
114
|
+
* @param creds - Credentials to use.
|
|
115
|
+
*/
|
|
116
|
+
async login(page, creds) {
|
|
117
|
+
await page.goto("", { waitUntil: "load", timeout: LOGIN_PAGE_TIMEOUT });
|
|
118
|
+
const instanceIdField = page.getByPlaceholder("Instance ID");
|
|
119
|
+
await instanceIdField.waitFor({
|
|
120
|
+
state: "visible",
|
|
121
|
+
timeout: LOGIN_PAGE_TIMEOUT
|
|
122
|
+
});
|
|
123
|
+
await instanceIdField.click();
|
|
124
|
+
await instanceIdField.fill(creds.instanceId ?? "BE11226875");
|
|
125
|
+
const userIdField = page.getByPlaceholder("User ID");
|
|
126
|
+
await userIdField.waitFor({
|
|
127
|
+
state: "visible",
|
|
128
|
+
timeout: LOGIN_FIELD_TIMEOUT
|
|
129
|
+
});
|
|
130
|
+
await userIdField.click();
|
|
131
|
+
await userIdField.fill(creds.username);
|
|
132
|
+
await userIdField.press("Tab");
|
|
133
|
+
const passwordField = page.getByRole("textbox", { name: "Password" });
|
|
134
|
+
await passwordField.waitFor({
|
|
135
|
+
state: "visible",
|
|
136
|
+
timeout: LOGIN_BUTTON_TIMEOUT
|
|
137
|
+
});
|
|
138
|
+
await passwordField.fill(creds.password);
|
|
139
|
+
const loginButton = page.getByRole("button", { name: "Log In" });
|
|
140
|
+
await loginButton.waitFor({
|
|
141
|
+
state: "visible",
|
|
142
|
+
timeout: LOGIN_BUTTON_TIMEOUT
|
|
143
|
+
});
|
|
144
|
+
await loginButton.click();
|
|
145
|
+
await page.waitForLoadState("domcontentloaded", {
|
|
146
|
+
timeout: AUTH_SHELL_TIMEOUT
|
|
147
|
+
});
|
|
148
|
+
await page.waitForFunction(
|
|
149
|
+
() => sessionStorage.getItem("Authorization") !== null,
|
|
150
|
+
{ polling: 1e3, timeout: AUTH_SHELL_TIMEOUT }
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var base_page_exports = {};
|
|
20
|
+
__export(base_page_exports, {
|
|
21
|
+
BasePage: () => BasePage
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(base_page_exports);
|
|
24
|
+
class BasePage {
|
|
25
|
+
_contextProvider;
|
|
26
|
+
/** The current Page context, resolved lazily. */
|
|
27
|
+
get page() {
|
|
28
|
+
return typeof this._contextProvider === "function" ? this._contextProvider() : this._contextProvider;
|
|
29
|
+
}
|
|
30
|
+
constructor(context) {
|
|
31
|
+
this._contextProvider = context;
|
|
32
|
+
}
|
|
33
|
+
// ─── Locator helpers ─────────────────────────────────────────────────────────
|
|
34
|
+
getByTestId(testId) {
|
|
35
|
+
return this.page.getByTestId(testId);
|
|
36
|
+
}
|
|
37
|
+
locator(selector) {
|
|
38
|
+
return this.page.locator(selector);
|
|
39
|
+
}
|
|
40
|
+
getByRole(role, options) {
|
|
41
|
+
return this.page.getByRole(role, options);
|
|
42
|
+
}
|
|
43
|
+
getByText(text, options) {
|
|
44
|
+
return this.page.getByText(text, options);
|
|
45
|
+
}
|
|
46
|
+
getByLabel(text, options) {
|
|
47
|
+
return this.page.getByLabel(text, options);
|
|
48
|
+
}
|
|
49
|
+
getByPlaceholder(text, options) {
|
|
50
|
+
return this.page.getByPlaceholder(text, options);
|
|
51
|
+
}
|
|
52
|
+
getByAltText(text, options) {
|
|
53
|
+
return this.page.getByAltText(text, options);
|
|
54
|
+
}
|
|
55
|
+
getByTitle(text, options) {
|
|
56
|
+
return this.page.getByTitle(text, options);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var browserstack_exports = {};
|
|
30
|
+
__export(browserstack_exports, {
|
|
31
|
+
createBrowserStackConfig: () => createBrowserStackConfig,
|
|
32
|
+
writeBrowserStackConfig: () => writeBrowserStackConfig
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(browserstack_exports);
|
|
35
|
+
var fs = __toESM(require("fs"), 1);
|
|
36
|
+
var path = __toESM(require("path"), 1);
|
|
37
|
+
const DEFAULT_PLATFORMS = [
|
|
38
|
+
{
|
|
39
|
+
os: "OS X",
|
|
40
|
+
osVersion: "Sequoia",
|
|
41
|
+
browserName: "chrome",
|
|
42
|
+
browserVersion: "latest"
|
|
43
|
+
}
|
|
44
|
+
];
|
|
45
|
+
function createBrowserStackConfig(options = {}) {
|
|
46
|
+
const {
|
|
47
|
+
projectName = "encw-app",
|
|
48
|
+
buildName = "playwright-tests",
|
|
49
|
+
// eslint-disable-next-line no-template-curly-in-string
|
|
50
|
+
buildIdentifier = "#${BUILD_NUMBER}",
|
|
51
|
+
platforms = DEFAULT_PLATFORMS,
|
|
52
|
+
parallelsPerPlatform = 1,
|
|
53
|
+
browserstackLocal = true,
|
|
54
|
+
forceLocal = true,
|
|
55
|
+
debug = true,
|
|
56
|
+
networkLogs = true,
|
|
57
|
+
consoleLogs = "info"
|
|
58
|
+
} = options;
|
|
59
|
+
const platformsYaml = platforms.map((p) => {
|
|
60
|
+
const lines = [
|
|
61
|
+
` - os: ${p.os}`,
|
|
62
|
+
` osVersion: ${p.osVersion}`,
|
|
63
|
+
` browserName: ${p.browserName}`
|
|
64
|
+
];
|
|
65
|
+
if (p.browserVersion) {
|
|
66
|
+
lines.push(` browserVersion: ${p.browserVersion}`);
|
|
67
|
+
}
|
|
68
|
+
return lines.join("\n");
|
|
69
|
+
}).join("\n");
|
|
70
|
+
return `userName: "\${BROWSERSTACK_USERNAME}"
|
|
71
|
+
accessKey: "\${BROWSERSTACK_ACCESS_KEY}"
|
|
72
|
+
|
|
73
|
+
projectName: ${projectName}
|
|
74
|
+
buildName: ${buildName}
|
|
75
|
+
buildIdentifier: "${buildIdentifier}"
|
|
76
|
+
framework: playwright
|
|
77
|
+
|
|
78
|
+
platforms:
|
|
79
|
+
${platformsYaml}
|
|
80
|
+
|
|
81
|
+
parallelsPerPlatform: ${parallelsPerPlatform}
|
|
82
|
+
|
|
83
|
+
browserstackLocal: ${String(browserstackLocal)}
|
|
84
|
+
browserStackLocalOptions:
|
|
85
|
+
forceLocal: ${String(forceLocal)}
|
|
86
|
+
|
|
87
|
+
debug: ${String(debug)}
|
|
88
|
+
networkLogs: ${String(networkLogs)}
|
|
89
|
+
consoleLogs: ${consoleLogs}
|
|
90
|
+
`;
|
|
91
|
+
}
|
|
92
|
+
function writeBrowserStackConfig(options = {}, targetDir = process.cwd()) {
|
|
93
|
+
const content = createBrowserStackConfig(options);
|
|
94
|
+
const filePath = path.join(targetDir, "browserstack.yml");
|
|
95
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
96
|
+
return filePath;
|
|
97
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var global_setup_exports = {};
|
|
30
|
+
__export(global_setup_exports, {
|
|
31
|
+
AUTH_FILE: () => AUTH_FILE,
|
|
32
|
+
STORAGE_FILE: () => STORAGE_FILE,
|
|
33
|
+
default: () => globalSetup
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(global_setup_exports);
|
|
36
|
+
var fs = __toESM(require("fs"), 1);
|
|
37
|
+
var path = __toESM(require("path"), 1);
|
|
38
|
+
var import_test = require("@playwright/test");
|
|
39
|
+
var import_auth = require("../auth/index.js");
|
|
40
|
+
var import_page_setup = require("../page-setup/index.js");
|
|
41
|
+
const AUTH_FILE = ".smoked-suite-auth.json";
|
|
42
|
+
const STORAGE_FILE = ".smoked-suite-storage.json";
|
|
43
|
+
async function globalSetup(config) {
|
|
44
|
+
const baseURL = config.projects[0]?.use?.baseURL ?? process.env.BASE_URL;
|
|
45
|
+
if (!baseURL) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
"smoked-suite globalSetup: baseURL is required. Set BASE_URL env var or configure use.baseURL in createPlaywrightConfig."
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
const browser = await import_test.chromium.launch();
|
|
51
|
+
const context = await browser.newContext({ baseURL });
|
|
52
|
+
const page = await context.newPage();
|
|
53
|
+
const pageSetup = new import_page_setup.PageSetup();
|
|
54
|
+
await pageSetup.apply(page);
|
|
55
|
+
const auth = new import_auth.AuthManager();
|
|
56
|
+
const credentials = {
|
|
57
|
+
instanceId: process.env.ENCW_INSTANCE_ID ?? "BE11226875",
|
|
58
|
+
username: process.env.ENCW_USER_ID ?? "admin",
|
|
59
|
+
password: process.env.ENCW_PASSWORD ?? "Password#!23"
|
|
60
|
+
};
|
|
61
|
+
await auth.login(page, credentials);
|
|
62
|
+
await auth.capture(page);
|
|
63
|
+
const authState = import_auth.AuthManager.getAuthState();
|
|
64
|
+
if (authState) {
|
|
65
|
+
const authPath = path.join(process.cwd(), AUTH_FILE);
|
|
66
|
+
fs.writeFileSync(authPath, JSON.stringify(authState), "utf-8");
|
|
67
|
+
}
|
|
68
|
+
const storagePath = path.join(process.cwd(), STORAGE_FILE);
|
|
69
|
+
await context.storageState({ path: storagePath });
|
|
70
|
+
await browser.close();
|
|
71
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var index_exports = {};
|
|
30
|
+
__export(index_exports, {
|
|
31
|
+
AuthManager: () => import_auth.AuthManager,
|
|
32
|
+
BasePage: () => import_base_page.BasePage,
|
|
33
|
+
PageSetup: () => import_page_setup.PageSetup,
|
|
34
|
+
createBrowserStackConfig: () => import_browserstack.createBrowserStackConfig,
|
|
35
|
+
createPlaywrightConfig: () => import_playwright_config.createPlaywrightConfig,
|
|
36
|
+
getRoutePath: () => import_routes.getRoutePath,
|
|
37
|
+
globalSetup: () => import_global_setup.default,
|
|
38
|
+
writeBrowserStackConfig: () => import_browserstack.writeBrowserStackConfig
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(index_exports);
|
|
41
|
+
var import_base_page = require("./base-page/index.js");
|
|
42
|
+
var import_auth = require("./auth/index.js");
|
|
43
|
+
var import_page_setup = require("./page-setup/index.js");
|
|
44
|
+
var import_routes = require("./routes/index.js");
|
|
45
|
+
var import_playwright_config = require("./playwright-config/index.js");
|
|
46
|
+
var import_global_setup = __toESM(require("./global-setup/index.js"), 1);
|
|
47
|
+
var import_browserstack = require("./browserstack/index.js");
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var monocartCoverage_exports = {};
|
|
30
|
+
__export(monocartCoverage_exports, {
|
|
31
|
+
buildCoverageReporters: () => buildCoverageReporters,
|
|
32
|
+
configureCoverage: () => configureCoverage,
|
|
33
|
+
startCoverage: () => startCoverage,
|
|
34
|
+
stopCoverage: () => stopCoverage,
|
|
35
|
+
trackPage: () => trackPage,
|
|
36
|
+
untrackPage: () => untrackPage
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(monocartCoverage_exports);
|
|
39
|
+
var import_test = require("@playwright/test");
|
|
40
|
+
let coverageConfigured = false;
|
|
41
|
+
let coverageEnabled = false;
|
|
42
|
+
const trackedPages = /* @__PURE__ */ new Set();
|
|
43
|
+
function configureCoverage() {
|
|
44
|
+
coverageConfigured = true;
|
|
45
|
+
}
|
|
46
|
+
function startCoverage() {
|
|
47
|
+
if (!coverageConfigured) return;
|
|
48
|
+
coverageEnabled = true;
|
|
49
|
+
trackedPages.clear();
|
|
50
|
+
}
|
|
51
|
+
async function stopCoverage() {
|
|
52
|
+
if (!coverageEnabled) return;
|
|
53
|
+
await Promise.allSettled(
|
|
54
|
+
[...trackedPages].map((page) => flushPageCoverage(page))
|
|
55
|
+
);
|
|
56
|
+
trackedPages.clear();
|
|
57
|
+
coverageEnabled = false;
|
|
58
|
+
}
|
|
59
|
+
async function trackPage(page) {
|
|
60
|
+
if (!coverageEnabled) return;
|
|
61
|
+
trackedPages.add(page);
|
|
62
|
+
await page.coverage.startJSCoverage({ resetOnNavigation: false });
|
|
63
|
+
}
|
|
64
|
+
async function untrackPage(page) {
|
|
65
|
+
if (!coverageEnabled || !trackedPages.has(page)) return;
|
|
66
|
+
await flushPageCoverage(page);
|
|
67
|
+
trackedPages.delete(page);
|
|
68
|
+
}
|
|
69
|
+
async function flushPageCoverage(page) {
|
|
70
|
+
const entries = await page.coverage.stopJSCoverage();
|
|
71
|
+
const { addCoverageReport } = await import("monocart-reporter");
|
|
72
|
+
await addCoverageReport(entries, import_test.test.info());
|
|
73
|
+
}
|
|
74
|
+
function buildCoverageReporter(configs) {
|
|
75
|
+
const repoName = process.cwd().split("/").pop() ?? "";
|
|
76
|
+
const segments = configs.map(
|
|
77
|
+
(c) => c.sourceDir.replace(/^\.\//, "").replace(/\/$/, "")
|
|
78
|
+
);
|
|
79
|
+
const firstBase = configs[0].sourceDir.split("/").filter(Boolean).pop() ?? "app";
|
|
80
|
+
const reportName = configs.length === 1 ? `${toTitleCase(firstBase)} Coverage Report` : "Coverage Report";
|
|
81
|
+
const outputDir = configs[0].outputDir ?? `./coverage/${firstBase}`;
|
|
82
|
+
const fileFilter = {
|
|
83
|
+
"**/*.{ts,tsx}": true,
|
|
84
|
+
"**/*.test.*": false,
|
|
85
|
+
"**/*.spec.*": false,
|
|
86
|
+
"**/tests/**": false
|
|
87
|
+
};
|
|
88
|
+
const allEntries = configs.map((c) => ({
|
|
89
|
+
dir: c.sourceDir,
|
|
90
|
+
filter: fileFilter
|
|
91
|
+
}));
|
|
92
|
+
return [
|
|
93
|
+
"monocart-reporter",
|
|
94
|
+
{
|
|
95
|
+
name: reportName,
|
|
96
|
+
outputFile: `${outputDir}/report.html`,
|
|
97
|
+
coverage: {
|
|
98
|
+
reports: ["v8", "console-details", "lcovonly"],
|
|
99
|
+
all: allEntries.length === 1 ? allEntries[0] : allEntries,
|
|
100
|
+
sourcePath: (filePath) => {
|
|
101
|
+
let p = filePath;
|
|
102
|
+
if (repoName) {
|
|
103
|
+
p = p.replace(new RegExp(`^${repoName}/`), "");
|
|
104
|
+
}
|
|
105
|
+
p = p.replace(/-[0-9a-f]{4}$/, "");
|
|
106
|
+
return p;
|
|
107
|
+
},
|
|
108
|
+
sourceFilter: (sourcePath) => {
|
|
109
|
+
if (sourcePath.includes("node_modules")) return false;
|
|
110
|
+
return segments.some((seg) => sourcePath.includes(seg));
|
|
111
|
+
},
|
|
112
|
+
entryFilter: (entry) => {
|
|
113
|
+
if (entry.url.startsWith("http")) return false;
|
|
114
|
+
return segments.some((seg) => entry.url.includes(seg));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
function toTitleCase(s) {
|
|
121
|
+
return s.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
122
|
+
}
|
|
123
|
+
function buildCoverageReporters(configs) {
|
|
124
|
+
return [["list"], buildCoverageReporter(configs)];
|
|
125
|
+
}
|