@owlmeans/test-ui 0.1.18-rc.48 → 0.1.18-rc.49
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 +8 -6
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/testing-ui/SKILL.md +29 -29
- package/build/browser/types.d.ts +22 -0
- package/build/browser/types.d.ts.map +1 -0
- package/build/browser/types.js +2 -0
- package/build/browser/types.js.map +1 -0
- package/build/browser.d.ts +8 -16
- package/build/browser.d.ts.map +1 -1
- package/build/browser.js +38 -41
- package/build/browser.js.map +1 -1
- package/build/index.d.ts +4 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/marketing-consent.d.ts +2 -22
- package/build/marketing-consent.d.ts.map +1 -1
- package/build/marketing-consent.js +3 -106
- package/build/marketing-consent.js.map +1 -1
- package/build/mount.d.ts +1 -1
- package/build/mount.js +3 -3
- package/build/mount.js.map +1 -1
- package/build/page/types.d.ts +134 -0
- package/build/page/types.d.ts.map +1 -0
- package/build/page/types.js +2 -0
- package/build/page/types.js.map +1 -0
- package/build/page.d.ts +4 -0
- package/build/page.d.ts.map +1 -0
- package/build/page.js +160 -0
- package/build/page.js.map +1 -0
- package/build/supervisor/types.d.ts +56 -0
- package/build/supervisor/types.d.ts.map +1 -0
- package/build/supervisor/types.js +2 -0
- package/build/supervisor/types.js.map +1 -0
- package/build/supervisor.d.ts +9 -67
- package/build/supervisor.d.ts.map +1 -1
- package/build/supervisor.js +65 -177
- package/build/supervisor.js.map +1 -1
- package/build/types.d.ts +0 -86
- package/build/types.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/browser/types.ts +22 -0
- package/src/browser.ts +43 -40
- package/src/index.ts +4 -0
- package/src/marketing-consent.ts +4 -115
- package/src/mount.ts +3 -3
- package/src/page/types.ts +137 -0
- package/src/page.ts +184 -0
- package/src/supervisor/types.ts +55 -0
- package/src/supervisor.ts +82 -207
- package/src/types.ts +0 -86
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
export interface AnswerMarketingConsentOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Which choice to save when the step is shown. `'all'` (the default) ticks the "select all"
|
|
4
|
+
* checkbox (every consent, and the Terms row while it is up — see {@link terms} for what is left
|
|
5
|
+
* of that) before saving; `'none'` saves with every item left unchecked, which is a valid,
|
|
6
|
+
* fully-compliant state on its own; `'skip'` clicks "Skip for now" instead of saving anything —
|
|
7
|
+
* only valid when a Terms box is not on screen (nothing calls it there; see {@link terms}).
|
|
8
|
+
*/
|
|
9
|
+
accept?: 'none' | 'all' | 'skip';
|
|
10
|
+
/**
|
|
11
|
+
* When a Terms row is on screen (`appendMarketingConsent({ terms: 'step' })`), `'accept'` (the
|
|
12
|
+
* default) ends with it ticked. `'leave'` ends with it unticked, even after a select-all — for a
|
|
13
|
+
* spec that means to drive the blocked state itself; the confirm click below still fires (with `{ force: true }`, since
|
|
14
|
+
* the control is never truly `disabled`), and this helper then EXPECTS the box to still be up
|
|
15
|
+
* afterward rather than treating that as a failure.
|
|
16
|
+
*/
|
|
17
|
+
terms?: 'accept' | 'leave';
|
|
18
|
+
timeout?: number;
|
|
19
|
+
}
|
|
20
|
+
/** What {@link PageHelper.acceptConsent} waits for. */
|
|
21
|
+
export interface AcceptConsentOptions {
|
|
22
|
+
/** How long the dialog may take to appear, and then to go away. Defaults to 5s. */
|
|
23
|
+
timeout?: number;
|
|
24
|
+
}
|
|
25
|
+
export interface DispatcherLoginOptions {
|
|
26
|
+
dispatcherPath?: string;
|
|
27
|
+
/** What counts as "arrived" for the navigation. Defaults to `domcontentloaded` — see `MountOptions.waitUntil`. */
|
|
28
|
+
waitUntil?: 'commit' | 'domcontentloaded' | 'load' | 'networkidle';
|
|
29
|
+
/**
|
|
30
|
+
* Answer the marketing-consent step if it is shown right after the dispatcher navigates away.
|
|
31
|
+
* Defaults to `'save'` (select-all and save) — see {@link PageHelper.answerMarketingConsent}. Pass
|
|
32
|
+
* `'ignore'` to skip the call entirely, e.g. in a spec that answers the step itself.
|
|
33
|
+
*/
|
|
34
|
+
marketingConsent?: 'save' | 'ignore';
|
|
35
|
+
}
|
|
36
|
+
export interface SupervisorFormLoginOptions {
|
|
37
|
+
baseUrl: string;
|
|
38
|
+
/** Target user id / email. */
|
|
39
|
+
userId: string;
|
|
40
|
+
/** Supervisor private key (e.g. `ed25519:<base64>` from `.env.dev.secrets`). */
|
|
41
|
+
pk: string;
|
|
42
|
+
/** Login path; defaults to the standard supervisor route. */
|
|
43
|
+
path?: string;
|
|
44
|
+
/** Predicate/URL fragment that signals a successful landing (default: leaving the login path). */
|
|
45
|
+
expectPath?: string;
|
|
46
|
+
timeout?: number;
|
|
47
|
+
/**
|
|
48
|
+
* What counts as "arrived" for the initial navigation. Defaults to `domcontentloaded`.
|
|
49
|
+
*
|
|
50
|
+
* See the note on `MountOptions.waitUntil`: `load` is playwright's default and is wrong for a
|
|
51
|
+
* real application, because it waits for every subresource — a tag manager, an analytics beacon
|
|
52
|
+
* or any pixel that never settles holds it open until the navigation times out, with the login
|
|
53
|
+
* form rendered and fillable the whole time.
|
|
54
|
+
*/
|
|
55
|
+
waitUntil?: 'commit' | 'domcontentloaded' | 'load' | 'networkidle';
|
|
56
|
+
/**
|
|
57
|
+
* What to do about a cookie-consent dialog covering the form. Defaults to `accept`, because an
|
|
58
|
+
* OwlMeans app will not start an authentication flow until consent is answered — see
|
|
59
|
+
* {@link PageHelper.acceptConsent}. Pass `ignore` only in a spec that answers the dialog itself.
|
|
60
|
+
*/
|
|
61
|
+
consent?: 'accept' | 'ignore';
|
|
62
|
+
/** When set, capture the filled login form (`supervisor-login-form.png`) before submit. */
|
|
63
|
+
screenshotDir?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Answer the marketing-consent step if it is shown right after landing. Defaults to `'save'`
|
|
66
|
+
* (select-all and save) — see {@link PageHelper.answerMarketingConsent}. Pass `'ignore'` to skip the call
|
|
67
|
+
* entirely, e.g. in a spec that answers the step itself.
|
|
68
|
+
*/
|
|
69
|
+
marketingConsent?: 'save' | 'ignore';
|
|
70
|
+
}
|
|
71
|
+
/** Driving one page of an OwlMeans app: consent dialogs, the login flows, screenshots. */
|
|
72
|
+
export interface PageHelper {
|
|
73
|
+
/**
|
|
74
|
+
* Answer the marketing-consent full-page step (`@owlmeans/web-marketing-consent`) if it is shown
|
|
75
|
+
* right after login, so a spec driving {@link PageHelper.loginViaSupervisorForm} or
|
|
76
|
+
* {@link PageHelper.loginViaDispatcher} is never blocked behind it.
|
|
77
|
+
*
|
|
78
|
+
* The screen is opt-in per app, and most apps/environments will not have it wired in — that makes
|
|
79
|
+
* detecting its ABSENCE cheaply the whole point. A plain `waitFor` on `[data-marketing-consent]`
|
|
80
|
+
* alone would cost the full `timeout` on every login of every app that never renders it (the same
|
|
81
|
+
* caveat `acceptConsent` documents for the cookie dialog). Instead this races the step's own root
|
|
82
|
+
* against the generic OwlMeans "the app has already landed" / "still on the login screen" markers
|
|
83
|
+
* this helper's own login flows already wait on (`#app-prompt`, `[data-login-method]`) — by the
|
|
84
|
+
* time a login flow calls this, one of those has typically already rendered, so the race resolves
|
|
85
|
+
* as soon as it does: no fixed sleep, and in the common "step absent" case, no material added
|
|
86
|
+
* latency over what the login flow already paid to get here.
|
|
87
|
+
*
|
|
88
|
+
* @returns whether the step was actually shown and answered (including the error/skip fallback);
|
|
89
|
+
* `false` when it never appeared within `timeout`, which is the expected result everywhere
|
|
90
|
+
* the screen is not yet configured or the visitor already has saved consents.
|
|
91
|
+
* @throws if a Terms box could not be confirmed (a `[data-marketing-consent-terms-error]`, or the
|
|
92
|
+
* box is still up with nowhere left to go — Skip is never offered there on purpose).
|
|
93
|
+
*/
|
|
94
|
+
answerMarketingConsent: (opts?: AnswerMarketingConsentOptions) => Promise<boolean>;
|
|
95
|
+
/**
|
|
96
|
+
* Inject a pre-generated bearer into an app that uses the standard owlmeans
|
|
97
|
+
* dispatcher: navigate to `/dispatcher?token=...` so the web app authenticates
|
|
98
|
+
* and redirects home natively. Note: apps that override the DISPATCHER route
|
|
99
|
+
* (e.g. to force an external IdP) should use {@link PageHelper.loginViaSupervisorForm}.
|
|
100
|
+
*/
|
|
101
|
+
loginViaDispatcher: (baseUrl: string, token: string, opts?: DispatcherLoginOptions) => Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Save a full-page screenshot to `<dir>/<name>.png`, creating `dir` if needed.
|
|
104
|
+
* Returns the absolute file path. Use a host-backed folder (e.g. the project's
|
|
105
|
+
* `tmp/tests/screenshots`) so the file is visible whether the test runs on the
|
|
106
|
+
* host or inside a dev container.
|
|
107
|
+
*/
|
|
108
|
+
saveScreenshot: (dir: string, name: string) => Promise<string>;
|
|
109
|
+
/**
|
|
110
|
+
* Answer the cookie-consent dialog if one is up, so the page underneath can be driven.
|
|
111
|
+
*
|
|
112
|
+
* An OwlMeans app asks for consent BEFORE it will start an authentication flow, and the dialog is
|
|
113
|
+
* a modal with no dismissal — by design, since a decision is what the gate is waiting for. For a
|
|
114
|
+
* test that means the login form renders, resolves, reports itself "visible, enabled and stable"
|
|
115
|
+
* and still cannot be clicked, because the overlay intercepts the pointer. Playwright retries for
|
|
116
|
+
* the full timeout and then blames the button, which is the most misleading failure in this
|
|
117
|
+
* helper: nothing is wrong with the form.
|
|
118
|
+
*
|
|
119
|
+
* Accepting is the honest default for a login helper — the flow it is about to drive is exactly
|
|
120
|
+
* what the dialog is gating — but it is best-effort: an app without the widget, or one where the
|
|
121
|
+
* visitor already decided, simply has no dialog and this returns at once.
|
|
122
|
+
*
|
|
123
|
+
* @returns whether a dialog was actually answered.
|
|
124
|
+
*/
|
|
125
|
+
acceptConsent: (opts?: AcceptConsentOptions) => Promise<boolean>;
|
|
126
|
+
/**
|
|
127
|
+
* Drive the PK-based supervisor login FORM end-to-end (the faithful path that
|
|
128
|
+
* exercises the real supervisor plugin + registration): navigate to the
|
|
129
|
+
* supervisor login route, fill the user id + private key, submit, and wait for
|
|
130
|
+
* the app to leave the login screen.
|
|
131
|
+
*/
|
|
132
|
+
loginViaSupervisorForm: (opts: SupervisorFormLoginOptions) => Promise<void>;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/page/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,6BAA6B;IAC5C;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAA;IAChC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAA;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,uDAAuD;AACvD,MAAM,WAAW,oBAAoB;IACnC,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,kHAAkH;IAClH,SAAS,CAAC,EAAE,QAAQ,GAAG,kBAAkB,GAAG,MAAM,GAAG,aAAa,CAAA;IAClE;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;CACrC;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAA;IACf,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,EAAE,EAAE,MAAM,CAAA;IACV,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,kGAAkG;IAClG,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,QAAQ,GAAG,kBAAkB,GAAG,MAAM,GAAG,aAAa,CAAA;IAClE;;;;OAIG;IACH,OAAO,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC7B,2FAA2F;IAC3F,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;CACrC;AAED,0FAA0F;AAC1F,MAAM,WAAW,UAAU;IACzB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,sBAAsB,EAAE,CAAC,IAAI,CAAC,EAAE,6BAA6B,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAClF;;;;;OAKG;IACH,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,sBAAsB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACpG;;;;;OAKG;IACH,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC9D;;;;;;;;;;;;;;;OAeG;IACH,aAAa,EAAE,CAAC,IAAI,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAChE;;;;;OAKG;IACH,sBAAsB,EAAE,CAAC,IAAI,EAAE,0BAA0B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/page/types.ts"],"names":[],"mappings":""}
|
package/build/page.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../src/page.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEtC,OAAO,KAAK,EACmE,UAAU,EACxF,MAAM,iBAAiB,CAAA;AAExB,eAAO,MAAM,cAAc,SAAU,IAAI,KAAG,UA+K3C,CAAA"}
|
package/build/page.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { mkdir } from 'node:fs/promises';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
import { DEFAULT_MARKETING_CONSENT_TIMEOUT, DEFAULT_SUPERVISOR_PATH } from './consts.local.js';
|
|
4
|
+
export const makePageHelper = (page) => {
|
|
5
|
+
const answerMarketingConsent = async (opts) => {
|
|
6
|
+
const timeout = opts?.timeout ?? DEFAULT_MARKETING_CONSENT_TIMEOUT;
|
|
7
|
+
const step = page.locator('[data-marketing-consent]');
|
|
8
|
+
try {
|
|
9
|
+
await page.locator('[data-marketing-consent], #app-prompt, [data-login-method]')
|
|
10
|
+
.first().waitFor({ state: 'visible', timeout });
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
if (await step.count() === 0)
|
|
16
|
+
return false;
|
|
17
|
+
// The step's own status read may still be outstanding (`data-state="loading"`) — wait past it,
|
|
18
|
+
// OR notice it already auto-continued (nothing was pending) and detached on its own. An older
|
|
19
|
+
// `web-marketing-consent` that predates `data-state` entirely satisfies the first selector
|
|
20
|
+
// immediately (a missing attribute is never `"loading"`), so this costs nothing there.
|
|
21
|
+
await Promise.race([
|
|
22
|
+
page.waitForSelector('[data-marketing-consent]:not([data-state="loading"])', { timeout }),
|
|
23
|
+
page.waitForSelector('[data-marketing-consent]', { state: 'detached', timeout }),
|
|
24
|
+
]).catch(() => undefined);
|
|
25
|
+
// Nothing was pending — it already auto-continued while this waited.
|
|
26
|
+
if (await step.count() === 0)
|
|
27
|
+
return true;
|
|
28
|
+
const terms = page.locator('[data-marketing-consent-terms]');
|
|
29
|
+
const hasTerms = await terms.count() > 0;
|
|
30
|
+
if (!hasTerms && opts?.accept === 'skip') {
|
|
31
|
+
await page.locator('[data-marketing-consent-skip]').click();
|
|
32
|
+
await step.waitFor({ state: 'detached', timeout });
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
if ((opts?.accept ?? 'all') === 'all') {
|
|
36
|
+
// The step draws "Select all" only when there is more than one row to select; a lone consent
|
|
37
|
+
// is ticked itself. Select all speaks for the Terms row too while it is up, which the choice
|
|
38
|
+
// below then settles either way.
|
|
39
|
+
const all = page.locator('[data-marketing-consent-all]');
|
|
40
|
+
if (await all.count() > 0) {
|
|
41
|
+
await all.click();
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
for (const item of await page.locator('[data-marketing-consent-item]').all()) {
|
|
45
|
+
await item.check();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// 'none' leaves every item unchecked and clicks nothing else before saving.
|
|
50
|
+
if (hasTerms) {
|
|
51
|
+
const wanted = (opts?.terms ?? 'accept') === 'accept';
|
|
52
|
+
if (wanted && !(await terms.isChecked())) {
|
|
53
|
+
await terms.check();
|
|
54
|
+
}
|
|
55
|
+
else if (!wanted && await terms.isChecked()) {
|
|
56
|
+
await terms.uncheck();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// `{ force: true }`: the confirm is never the native `disabled` — only `aria-disabled` while a
|
|
60
|
+
// Terms box is unticked, or merely styled muted with nothing changed yet — and Playwright's own
|
|
61
|
+
// actionability check honours `aria-disabled`, which this helper deliberately does not.
|
|
62
|
+
await page.locator('[data-marketing-consent-save]').click({ force: true });
|
|
63
|
+
const outcome = await Promise.race([
|
|
64
|
+
step.waitFor({ state: 'detached', timeout }).then(() => 'saved'),
|
|
65
|
+
page.locator('[data-marketing-consent-error]').waitFor({ state: 'visible', timeout })
|
|
66
|
+
.then(() => 'error'),
|
|
67
|
+
page.locator('[data-marketing-consent-terms-error]').waitFor({ state: 'visible', timeout })
|
|
68
|
+
.then(() => 'terms-error'),
|
|
69
|
+
]).catch(() => 'error');
|
|
70
|
+
if (outcome === 'terms-error') {
|
|
71
|
+
throw new Error('[@owlmeans/test-ui] the marketing-consent step could not confirm the Terms');
|
|
72
|
+
}
|
|
73
|
+
if (outcome !== 'saved') {
|
|
74
|
+
const skip = page.locator('[data-marketing-consent-skip]');
|
|
75
|
+
if (await skip.count() > 0) {
|
|
76
|
+
console.warn('[@owlmeans/test-ui] marketing consent save did not complete; using the skip link instead');
|
|
77
|
+
await skip.click();
|
|
78
|
+
await step.waitFor({ state: 'detached', timeout }).catch(() => undefined);
|
|
79
|
+
}
|
|
80
|
+
else if (await terms.count() > 0) {
|
|
81
|
+
// No Skip is ever offered while the Terms box is up — a failed/blocked confirm here has no
|
|
82
|
+
// fallback, and silently returning would hide a caller stuck behind a real requirement.
|
|
83
|
+
throw new Error('[@owlmeans/test-ui] the marketing-consent step is still showing its Terms box');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Answered either way: saved, or skipped past a flaky save. Never leaves the caller blocked.
|
|
87
|
+
return true;
|
|
88
|
+
};
|
|
89
|
+
const loginViaDispatcher = async (baseUrl, token, opts) => {
|
|
90
|
+
const path = opts?.dispatcherPath ?? '/dispatcher';
|
|
91
|
+
const url = new URL(path, baseUrl);
|
|
92
|
+
url.searchParams.set('token', token);
|
|
93
|
+
// `domcontentloaded`, not playwright's `load` default — see the note on `MountOptions.waitUntil`.
|
|
94
|
+
await page.goto(url.toString(), { waitUntil: opts?.waitUntil ?? 'domcontentloaded' });
|
|
95
|
+
// Wait until the dispatcher has navigated away (token consumed).
|
|
96
|
+
await page.waitForURL(u => !u.pathname.startsWith(path), { timeout: 30_000 });
|
|
97
|
+
if (opts?.marketingConsent !== 'ignore') {
|
|
98
|
+
await answerMarketingConsent({ accept: 'all', timeout: 30_000 });
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const saveScreenshot = async (dir, name) => {
|
|
102
|
+
const target = resolve(dir);
|
|
103
|
+
await mkdir(target, { recursive: true });
|
|
104
|
+
const file = join(target, `${name}.png`);
|
|
105
|
+
await page.screenshot({ path: file, fullPage: true });
|
|
106
|
+
return file;
|
|
107
|
+
};
|
|
108
|
+
const acceptConsent = async (opts) => {
|
|
109
|
+
const dialog = page.locator('[data-consent-dialog]');
|
|
110
|
+
try {
|
|
111
|
+
await dialog.waitFor({ state: 'visible', timeout: opts?.timeout ?? 5_000 });
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
// Accept-all rather than essential-only: a test asserting a narrower decision should make that
|
|
117
|
+
// decision itself, and silently choosing the minimum here would hide it from the spec.
|
|
118
|
+
await page.locator('[data-consent-accept-all]').click();
|
|
119
|
+
await dialog.waitFor({ state: 'detached', timeout: opts?.timeout ?? 5_000 });
|
|
120
|
+
return true;
|
|
121
|
+
};
|
|
122
|
+
const loginViaSupervisorForm = async (opts) => {
|
|
123
|
+
const path = opts.path ?? DEFAULT_SUPERVISOR_PATH;
|
|
124
|
+
const timeout = opts.timeout ?? 60_000;
|
|
125
|
+
await page.goto(new URL(path, opts.baseUrl).toString(), {
|
|
126
|
+
waitUntil: opts.waitUntil ?? 'domcontentloaded', timeout
|
|
127
|
+
});
|
|
128
|
+
// Wait for the app to MOUNT before deciding whether there is a dialog to answer. `domcontentloaded`
|
|
129
|
+
// returns while the SPA is still booting, and on a dev server that boot is occasionally tens of
|
|
130
|
+
// seconds — so a short consent probe reports "no dialog", the dialog then mounts over the form,
|
|
131
|
+
// and the fill below waits out its own timeout on a field that is present but covered. Either
|
|
132
|
+
// marker proves the app is up: the dialog, or the form itself when consent was already given.
|
|
133
|
+
await page.locator('[data-consent-dialog], [data-testid="supervisor-user-id"]')
|
|
134
|
+
.first().waitFor({ state: 'visible', timeout });
|
|
135
|
+
if (opts.consent !== 'ignore')
|
|
136
|
+
await acceptConsent({ timeout });
|
|
137
|
+
// The form renders only AFTER the dialog is dismissed, so these carry the caller's budget rather
|
|
138
|
+
// than playwright's 30s default — the whole point of accepting an explicit `timeout` here.
|
|
139
|
+
await page.getByTestId('supervisor-user-id').fill(opts.userId, { timeout });
|
|
140
|
+
await page.getByTestId('supervisor-pk').fill(opts.pk, { timeout });
|
|
141
|
+
if (opts.screenshotDir != null) {
|
|
142
|
+
await saveScreenshot(opts.screenshotDir, 'supervisor-login-form');
|
|
143
|
+
}
|
|
144
|
+
await page.getByTestId('supervisor-submit').click({ timeout });
|
|
145
|
+
if (opts.expectPath != null) {
|
|
146
|
+
await page.waitForURL(url => url.toString().includes(opts.expectPath), { timeout });
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
await page.waitForURL(url => !url.pathname.startsWith(path), { timeout });
|
|
150
|
+
}
|
|
151
|
+
// Carries the CALLER's own budget rather than the helper's smaller internal default — a slow
|
|
152
|
+
// cold environment (vite re-optimizing, a stage pod still warming) can easily spend most of a
|
|
153
|
+
// short fixed timeout just getting here, leaving too little for the two extra POSTs (terms, then
|
|
154
|
+
// items) a Terms-mode step now makes.
|
|
155
|
+
if (opts.marketingConsent !== 'ignore')
|
|
156
|
+
await answerMarketingConsent({ accept: 'all', timeout });
|
|
157
|
+
};
|
|
158
|
+
return { answerMarketingConsent, loginViaDispatcher, saveScreenshot, acceptConsent, loginViaSupervisorForm };
|
|
159
|
+
};
|
|
160
|
+
//# sourceMappingURL=page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../src/page.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { AuthRole } from '@owlmeans/auth';
|
|
2
|
+
export interface PregenerateAuthTokenOptions {
|
|
3
|
+
/** Target user id / email the token represents. */
|
|
4
|
+
userId: string;
|
|
5
|
+
/**
|
|
6
|
+
* Private key to sign the bearer with, e.g. `ed25519:<base64>` from
|
|
7
|
+
* `.env.dev.secrets`. MUST be the key the target backend trusts as its own
|
|
8
|
+
* signing key (it verifies bearers against `cfg.alias`/`cfg.service`).
|
|
9
|
+
*/
|
|
10
|
+
pk: string;
|
|
11
|
+
scopes?: string[];
|
|
12
|
+
role?: AuthRole;
|
|
13
|
+
entityId?: string;
|
|
14
|
+
profileId?: string;
|
|
15
|
+
/** `source` recorded in the Auth payload (usually the backend service alias). */
|
|
16
|
+
source?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface SupervisorApiAuthOptions {
|
|
19
|
+
/** Auth-manager API base URL (the backend serving /authentication/* and /authenticate). */
|
|
20
|
+
apiBaseUrl: string;
|
|
21
|
+
/** Target user id / email to authenticate (and register on first use). */
|
|
22
|
+
userId: string;
|
|
23
|
+
/** Supervisor private key, e.g. `ed25519:<base64>` from `.env.dev.secrets`. */
|
|
24
|
+
pk: string;
|
|
25
|
+
/** Paths, overridable for non-default routing. */
|
|
26
|
+
paths?: {
|
|
27
|
+
init?: string;
|
|
28
|
+
authenticate?: string;
|
|
29
|
+
dispatch?: string;
|
|
30
|
+
};
|
|
31
|
+
fetchImpl?: typeof fetch;
|
|
32
|
+
}
|
|
33
|
+
/** Bearers for a backend, minted without a browser. */
|
|
34
|
+
export interface SupervisorAuthHelper {
|
|
35
|
+
/**
|
|
36
|
+
* Mint a ready-to-use `ED25519-BASIC-TOKEN ...` bearer offline, reusing
|
|
37
|
+
* `@owlmeans/test-auth`'s `makeBearer`. This is the "set a token directly"
|
|
38
|
+
* fast-path for e2e/integration tests: no UI, no live auth round-trip. The
|
|
39
|
+
* backend accepts it because it is signed by the project's own trusted key.
|
|
40
|
+
*
|
|
41
|
+
* For a faithful end-to-end login (real supervisor plugin + registration), drive
|
|
42
|
+
* {@link PageHelper.loginViaSupervisorForm} instead.
|
|
43
|
+
*/
|
|
44
|
+
pregenerateAuthToken: (opts: PregenerateAuthTokenOptions) => Promise<string>;
|
|
45
|
+
/**
|
|
46
|
+
* Pregenerate a real bearer by driving the live PK-based supervisor flow over the
|
|
47
|
+
* backend API (no browser): `/authentication/init` -> sign the challenge with the
|
|
48
|
+
* supervisor key -> `/authentication/authenticate` -> `/authenticate` (dispatcher
|
|
49
|
+
* exchange). This is the faithful "set a token directly via API" path
|
|
50
|
+
* (registers the user on first use), independent of any front-end routing.
|
|
51
|
+
*
|
|
52
|
+
* Returns the final `ED25519-BASIC-TOKEN ...` bearer the backend accepts.
|
|
53
|
+
*/
|
|
54
|
+
authenticateViaSupervisorApi: (opts: SupervisorApiAuthOptions) => Promise<string>;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/supervisor/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAG9C,MAAM,WAAW,2BAA2B;IAC1C,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC,2FAA2F;IAC3F,UAAU,EAAE,MAAM,CAAA;IAClB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAA;IACd,+EAA+E;IAC/E,EAAE,EAAE,MAAM,CAAA;IACV,kDAAkD;IAClD,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACnE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAED,uDAAuD;AACvD,MAAM,WAAW,oBAAoB;IACnC;;;;;;;;OAQG;IACH,oBAAoB,EAAE,CAAC,IAAI,EAAE,2BAA2B,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC5E;;;;;;;;OAQG;IACH,4BAA4B,EAAE,CAAC,IAAI,EAAE,wBAAwB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CAClF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/supervisor/types.ts"],"names":[],"mappings":""}
|
package/build/supervisor.d.ts
CHANGED
|
@@ -1,72 +1,14 @@
|
|
|
1
1
|
import type { Page } from 'playwright';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* backend accepts it because it is signed by the project's own trusted key.
|
|
8
|
-
*
|
|
9
|
-
* For a faithful end-to-end login (real supervisor plugin + registration), drive
|
|
10
|
-
* {@link loginViaSupervisorForm} instead.
|
|
11
|
-
*/
|
|
12
|
-
export declare const pregenerateAuthToken: (opts: PregenerateAuthTokenOptions) => Promise<string>;
|
|
13
|
-
/**
|
|
14
|
-
* Inject a pre-generated bearer into an app that uses the standard owlmeans
|
|
15
|
-
* dispatcher: navigate to `/dispatcher?token=...` so the web app authenticates
|
|
16
|
-
* and redirects home natively. Note: apps that override the DISPATCHER route
|
|
17
|
-
* (e.g. to force an external IdP) should use {@link loginViaSupervisorForm}.
|
|
18
|
-
*/
|
|
19
|
-
export declare const loginViaDispatcher: (page: Page, baseUrl: string, token: string, opts?: {
|
|
20
|
-
dispatcherPath?: string;
|
|
21
|
-
waitUntil?: 'commit' | 'domcontentloaded' | 'load' | 'networkidle';
|
|
22
|
-
/**
|
|
23
|
-
* Answer the marketing-consent step if it is shown right after the dispatcher navigates away.
|
|
24
|
-
* Defaults to `'save'` (select-all and save) — see {@link answerMarketingConsent}. Pass
|
|
25
|
-
* `'ignore'` to skip the call entirely, e.g. in a spec that answers the step itself.
|
|
26
|
-
*/
|
|
27
|
-
marketingConsent?: 'save' | 'ignore';
|
|
28
|
-
}) => Promise<void>;
|
|
29
|
-
/**
|
|
30
|
-
* Pregenerate a real bearer by driving the live PK-based supervisor flow over the
|
|
31
|
-
* backend API (no browser): `/authentication/init` -> sign the challenge with the
|
|
32
|
-
* supervisor key -> `/authentication/authenticate` -> `/authenticate` (dispatcher
|
|
33
|
-
* exchange). This is the faithful "set a token directly via API" path
|
|
34
|
-
* (registers the user on first use), independent of any front-end routing.
|
|
35
|
-
*
|
|
36
|
-
* Returns the final `ED25519-BASIC-TOKEN ...` bearer the backend accepts.
|
|
37
|
-
*/
|
|
2
|
+
import type { AcceptConsentOptions, SupervisorFormLoginOptions } from './page/types.js';
|
|
3
|
+
import type { SupervisorApiAuthOptions, SupervisorAuthHelper } from './supervisor/types.js';
|
|
4
|
+
export declare const createSupervisorAuthHelper: () => SupervisorAuthHelper;
|
|
5
|
+
export declare const supervisorAuthHelper: SupervisorAuthHelper;
|
|
6
|
+
/** @deprecated compat:factory-refactor — use `supervisorAuthHelper.authenticateViaSupervisorApi(…)` */
|
|
38
7
|
export declare const authenticateViaSupervisorApi: (opts: SupervisorApiAuthOptions) => Promise<string>;
|
|
39
|
-
/**
|
|
40
|
-
* Save a full-page screenshot to `<dir>/<name>.png`, creating `dir` if needed.
|
|
41
|
-
* Returns the absolute file path. Use a host-backed folder (e.g. the project's
|
|
42
|
-
* `tmp/tests/screenshots`) so the file is visible whether the test runs on the
|
|
43
|
-
* host or inside a dev container.
|
|
44
|
-
*/
|
|
8
|
+
/** @deprecated compat:factory-refactor — use `makePageHelper(page).saveScreenshot(…)` */
|
|
45
9
|
export declare const saveScreenshot: (page: Page, dir: string, name: string) => Promise<string>;
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
* An OwlMeans app asks for consent BEFORE it will start an authentication flow, and the dialog is
|
|
50
|
-
* a modal with no dismissal — by design, since a decision is what the gate is waiting for. For a
|
|
51
|
-
* test that means the login form renders, resolves, reports itself "visible, enabled and stable"
|
|
52
|
-
* and still cannot be clicked, because the overlay intercepts the pointer. Playwright retries for
|
|
53
|
-
* the full timeout and then blames the button, which is the most misleading failure in this file:
|
|
54
|
-
* nothing is wrong with the form.
|
|
55
|
-
*
|
|
56
|
-
* Accepting is the honest default for a login helper — the flow it is about to drive is exactly
|
|
57
|
-
* what the dialog is gating — but it is best-effort: an app without the widget, or one where the
|
|
58
|
-
* visitor already decided, simply has no dialog and this returns at once.
|
|
59
|
-
*
|
|
60
|
-
* @returns whether a dialog was actually answered.
|
|
61
|
-
*/
|
|
62
|
-
export declare const acceptConsent: (page: Page, opts?: {
|
|
63
|
-
timeout?: number;
|
|
64
|
-
}) => Promise<boolean>;
|
|
65
|
-
/**
|
|
66
|
-
* Drive the PK-based supervisor login FORM end-to-end (the faithful path that
|
|
67
|
-
* exercises the real supervisor plugin + registration): navigate to the
|
|
68
|
-
* supervisor login route, fill the user id + private key, submit, and wait for
|
|
69
|
-
* the app to leave the login screen.
|
|
70
|
-
*/
|
|
10
|
+
/** @deprecated compat:factory-refactor — use `makePageHelper(page).acceptConsent(…)` */
|
|
11
|
+
export declare const acceptConsent: (page: Page, opts?: AcceptConsentOptions) => Promise<boolean>;
|
|
12
|
+
/** @deprecated compat:factory-refactor — use `makePageHelper(page).loginViaSupervisorForm(…)` */
|
|
71
13
|
export declare const loginViaSupervisorForm: (page: Page, opts: SupervisorFormLoginOptions) => Promise<void>;
|
|
72
14
|
//# sourceMappingURL=supervisor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../src/supervisor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../src/supervisor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAOtC,OAAO,KAAK,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAA;AACvF,OAAO,KAAK,EAA+B,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAExH,eAAO,MAAM,0BAA0B,QAAO,oBAuE7C,CAAA;AAED,eAAO,MAAM,oBAAoB,sBAA+B,CAAA;AAEhE,uGAAuG;AACvG,eAAO,MAAM,4BAA4B,SAAgB,wBAAwB,KAAG,OAAO,CAAC,MAAM,CACnC,CAAA;AAE/D,yFAAyF;AACzF,eAAO,MAAM,cAAc,SAAgB,IAAI,OAAO,MAAM,QAAQ,MAAM,KAAG,OAAO,CAAC,MAAM,CACrC,CAAA;AAEtD,wFAAwF;AACxF,eAAO,MAAM,aAAa,SAAgB,IAAI,SAAS,oBAAoB,KAAG,OAAO,CAAC,OAAO,CAC7C,CAAA;AAEhD,iGAAiG;AACjG,eAAO,MAAM,sBAAsB,SAAgB,IAAI,QAAQ,0BAA0B,KAAG,OAAO,CAAC,IAAI,CAC/C,CAAA"}
|