@owlmeans/test-ui 0.1.18-rc.34 → 0.1.18-rc.35
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 +1 -1
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/testing-ui/SKILL.md +3 -31
- package/build/index.d.ts +0 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +0 -1
- package/build/index.js.map +1 -1
- package/build/supervisor.d.ts +0 -12
- package/build/supervisor.d.ts.map +1 -1
- package/build/supervisor.js +0 -5
- package/build/supervisor.js.map +1 -1
- package/package.json +7 -7
- package/src/index.ts +0 -1
- package/src/supervisor.ts +1 -20
- package/build/marketing-consent.d.ts +0 -31
- package/build/marketing-consent.d.ts.map +0 -1
- package/build/marketing-consent.js +0 -53
- package/build/marketing-consent.js.map +0 -1
- package/src/marketing-consent.ts +0 -72
package/README.md
CHANGED
|
@@ -58,7 +58,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
58
58
|
your project's skill store (`.agents/skills/`):
|
|
59
59
|
|
|
60
60
|
```sh
|
|
61
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
61
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.34
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/test-ui",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-09-
|
|
4
|
+
"version": "0.1.18-rc.35",
|
|
5
|
+
"generatedAt": "2026-09-22T20:45:24.040Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -6,7 +6,7 @@ description: Category-D component-level acceptance tests for OwlMeans Common UI
|
|
|
6
6
|
|
|
7
7
|
# UI Acceptance Tests — Category D (bun test + Playwright as a library)
|
|
8
8
|
|
|
9
|
-
**Install:** `"@owlmeans/test-ui": "^0.1.18-rc.
|
|
9
|
+
**Install:** `"@owlmeans/test-ui": "^0.1.18-rc.35"` in `devDependencies`
|
|
10
10
|
|
|
11
11
|
`@owlmeans/test-ui` depends on `playwright`, so the browser library arrives with it; add
|
|
12
12
|
`playwright` to `devDependencies` as well when a spec imports a launcher itself. The Vite harness
|
|
@@ -70,9 +70,8 @@ sits behind auth without hand-rolling a token:
|
|
|
70
70
|
|---|---|
|
|
71
71
|
| `pregenerateAuthToken(opts)` | Mint an `ED25519-BASIC-TOKEN …` bearer offline from a trusted private key — no browser, no round trip. Options: `{ userId, pk, scopes?, role?, entityId?, profileId?, source? }`. |
|
|
72
72
|
| `authenticateViaSupervisorApi(opts)` | Drive the live PK supervisor flow over the backend API (init → sign → authenticate → dispatch), registering the user on first use. Options: `{ apiBaseUrl, userId, pk, paths?, fetchImpl? }`. |
|
|
73
|
-
| `loginViaDispatcher(page, baseUrl, token, opts?)` | Inject a bearer through the standard `/dispatcher?token=…` route
|
|
74
|
-
| `loginViaSupervisorForm(page, opts)` | Drive the real login form end-to-end — navigate, answer consent, fill user id + key, submit, wait for the landing
|
|
75
|
-
| `answerMarketingConsent(page, opts?)` | Answer the `@owlmeans/web-marketing-consent` full-page step if it is shown right after login. Options: `{ accept?: 'all' \| 'none', timeout? }`, default `accept: 'all'`. Returns whether the step was actually shown and answered — `false` means it never appeared. |
|
|
73
|
+
| `loginViaDispatcher(page, baseUrl, token, opts?)` | Inject a bearer through the standard `/dispatcher?token=…` route and wait for the app to navigate away. |
|
|
74
|
+
| `loginViaSupervisorForm(page, opts)` | Drive the real login form end-to-end — navigate, answer consent, fill user id + key, submit, wait for the landing. Options: `{ baseUrl, userId, pk, path?, expectPath?, timeout?, waitUntil?, consent?, screenshotDir? }`. |
|
|
76
75
|
|
|
77
76
|
These need a project whose backend trusts the private key they sign with, so they belong to specs
|
|
78
77
|
that run against a real app rather than a mounted component. See `[[supervisor-auth]]` for the
|
|
@@ -310,30 +309,3 @@ app that ships no consent widget the login helper therefore sits for a full minu
|
|
|
310
309
|
the first field, with nothing on screen to explain it. Drive such an app with `consent: 'ignore'`,
|
|
311
310
|
which skips the call entirely; that is also the switch a spec flips when it wants to answer the
|
|
312
311
|
dialog itself.
|
|
313
|
-
|
|
314
|
-
## `answerMarketingConsent` — cheap absence detection, unlike the cookie dialog
|
|
315
|
-
|
|
316
|
-
`loginViaSupervisorForm` and `loginViaDispatcher` both call `answerMarketingConsent(page, { accept:
|
|
317
|
-
'all' })` right after they confirm the app has navigated away from login/dispatch, and both default
|
|
318
|
-
`marketingConsent` (their own option, not `answerMarketingConsent`'s) to `'save'` — pass
|
|
319
|
-
`'ignore'` to skip the call in a spec that drives the step itself. `@owlmeans/web-marketing-consent`
|
|
320
|
-
renders a full-page step, when shown, with `[data-marketing-consent]` (root),
|
|
321
|
-
`[data-marketing-consent-all]` (select-all), `[data-marketing-consent-item="<key>"]` (per-consent),
|
|
322
|
-
`[data-marketing-consent-save]`, `[data-marketing-consent-skip]` (shown only after a save error) and
|
|
323
|
-
`[data-marketing-consent-error]`.
|
|
324
|
-
|
|
325
|
-
Unlike `acceptConsent`, whose `false` return deliberately costs the full wait (see above),
|
|
326
|
-
`answerMarketingConsent` does NOT pay the full `timeout` (default `6_000`) when the step is absent.
|
|
327
|
-
The screen is opt-in per app and most applications and environments don't have it wired in yet, and this helper
|
|
328
|
-
is called unconditionally by both login helpers — a full-timeout tax on every login, on every app,
|
|
329
|
-
whether or not the screen exists, would be an unacceptable regression to every existing suite. It
|
|
330
|
-
instead races `[data-marketing-consent]` against the generic "the app has already landed" /
|
|
331
|
-
"still on the login screen" markers the login helpers themselves already rely on (`#app-prompt`,
|
|
332
|
-
`[data-login-method]`) via the same `locator('a, b, c').first().waitFor({ state: 'visible' })` idiom
|
|
333
|
-
`loginViaSupervisorForm` uses for its own dialog-vs-form race. By the time a login helper calls this,
|
|
334
|
-
one of those markers has typically already rendered, so on an app without the screen the race
|
|
335
|
-
resolves as soon as it does — no fixed sleep, and no meaningful added latency over what the login
|
|
336
|
-
helper already paid to get there. Returns `false` when the step never appeared; `true` when it did,
|
|
337
|
-
whether the save succeeded or fell back to clicking `[data-marketing-consent-skip]` after a save
|
|
338
|
-
error (logged as a console warning, never thrown) — the step is "answered" either way, so a spec is
|
|
339
|
-
never permanently blocked behind a flaky save.
|
package/build/index.d.ts
CHANGED
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA"}
|
package/build/index.js
CHANGED
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA"}
|
package/build/supervisor.d.ts
CHANGED
|
@@ -35,12 +35,6 @@ export declare const pregenerateAuthToken: (opts: PregenerateAuthTokenOptions) =
|
|
|
35
35
|
export declare const loginViaDispatcher: (page: Page, baseUrl: string, token: string, opts?: {
|
|
36
36
|
dispatcherPath?: string;
|
|
37
37
|
waitUntil?: 'commit' | 'domcontentloaded' | 'load' | 'networkidle';
|
|
38
|
-
/**
|
|
39
|
-
* Answer the marketing-consent step if it is shown right after the dispatcher navigates away.
|
|
40
|
-
* Defaults to `'save'` (select-all and save) — see {@link answerMarketingConsent}. Pass
|
|
41
|
-
* `'ignore'` to skip the call entirely, e.g. in a spec that answers the step itself.
|
|
42
|
-
*/
|
|
43
|
-
marketingConsent?: 'save' | 'ignore';
|
|
44
38
|
}) => Promise<void>;
|
|
45
39
|
export interface SupervisorApiAuthOptions {
|
|
46
40
|
/** Auth-manager API base URL (the backend serving /authentication/* and /authenticate). */
|
|
@@ -102,12 +96,6 @@ export interface SupervisorFormLoginOptions {
|
|
|
102
96
|
consent?: 'accept' | 'ignore';
|
|
103
97
|
/** When set, capture the filled login form (`supervisor-login-form.png`) before submit. */
|
|
104
98
|
screenshotDir?: string;
|
|
105
|
-
/**
|
|
106
|
-
* Answer the marketing-consent step if it is shown right after landing. Defaults to `'save'`
|
|
107
|
-
* (select-all and save) — see {@link answerMarketingConsent}. Pass `'ignore'` to skip the call
|
|
108
|
-
* entirely, e.g. in a spec that answers the step itself.
|
|
109
|
-
*/
|
|
110
|
-
marketingConsent?: 'save' | 'ignore';
|
|
111
99
|
}
|
|
112
100
|
/**
|
|
113
101
|
* Answer the cookie-consent dialog if one is up, so the page underneath can be driven.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../src/supervisor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,KAAK,EAAyB,QAAQ,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../src/supervisor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,KAAK,EAAyB,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AASrE,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;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,SAAgB,2BAA2B,KAAG,OAAO,CAAC,MAAM,CAe5F,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,SACvB,IAAI,WAAW,MAAM,SAAS,MAAM,SACnC;IAAE,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,QAAQ,GAAG,kBAAkB,GAAG,MAAM,GAAG,aAAa,CAAA;CAAE,KACrG,OAAO,CAAC,IAAI,CAQd,CAAA;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;AAgBD;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,SACjC,wBAAwB,KAC7B,OAAO,CAAC,MAAM,CAkChB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,SAAgB,IAAI,OAAO,MAAM,QAAQ,MAAM,KAAG,OAAO,CAAC,MAAM,CAM1F,CAAA;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;CACvB;AAID;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,aAAa,SAClB,IAAI,SAAS;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,KACtC,OAAO,CAAC,OAAO,CAajB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,SAC3B,IAAI,QAAQ,0BAA0B,KAC3C,OAAO,CAAC,IAAI,CAiCd,CAAA"}
|
package/build/supervisor.js
CHANGED
|
@@ -5,7 +5,6 @@ import { makeKeyPairModel } from '@owlmeans/basic-keys';
|
|
|
5
5
|
import { createIdOfLength } from '@owlmeans/basic-ids';
|
|
6
6
|
import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope';
|
|
7
7
|
import { makeBearer } from '@owlmeans/test-auth';
|
|
8
|
-
import { answerMarketingConsent } from './marketing-consent.js';
|
|
9
8
|
/**
|
|
10
9
|
* Mint a ready-to-use `ED25519-BASIC-TOKEN ...` bearer offline, reusing
|
|
11
10
|
* `@owlmeans/test-auth`'s `makeBearer`. This is the "set a token directly"
|
|
@@ -44,8 +43,6 @@ export const loginViaDispatcher = async (page, baseUrl, token, opts) => {
|
|
|
44
43
|
await page.goto(url.toString(), { waitUntil: opts?.waitUntil ?? 'domcontentloaded' });
|
|
45
44
|
// Wait until the dispatcher has navigated away (token consumed).
|
|
46
45
|
await page.waitForURL(u => !u.pathname.startsWith(path), { timeout: 30_000 });
|
|
47
|
-
if (opts?.marketingConsent !== 'ignore')
|
|
48
|
-
await answerMarketingConsent(page, { accept: 'all' });
|
|
49
46
|
};
|
|
50
47
|
const postJson = async (fetchImpl, url, body) => {
|
|
51
48
|
const res = await fetchImpl(url, {
|
|
@@ -175,7 +172,5 @@ export const loginViaSupervisorForm = async (page, opts) => {
|
|
|
175
172
|
else {
|
|
176
173
|
await page.waitForURL(url => !url.pathname.startsWith(path), { timeout });
|
|
177
174
|
}
|
|
178
|
-
if (opts.marketingConsent !== 'ignore')
|
|
179
|
-
await answerMarketingConsent(page, { accept: 'all' });
|
|
180
175
|
};
|
|
181
176
|
//# sourceMappingURL=supervisor.js.map
|
package/build/supervisor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../src/supervisor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGzC,OAAO,EACL,iBAAiB,EAAE,QAAQ,IAAI,IAAI,EAAE,kBAAkB,EAAE,sBAAsB,EAChF,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../src/supervisor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGzC,OAAO,EACL,iBAAiB,EAAE,QAAQ,IAAI,IAAI,EAAE,kBAAkB,EAAE,sBAAsB,EAChF,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAmBhD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,EAAE,IAAiC,EAAmB,EAAE;IAC/F,MAAM,IAAI,GAAS;QACjB,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC;QAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM;QACxC,UAAU,EAAE,IAAI,CAAC,QAAQ;QACzB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC;QAC5B,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI;QAC5B,IAAI,EAAE,iBAAiB,CAAC,iBAAiB;QACzC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE;QACzB,MAAM,EAAE,IAAI;QACZ,SAAS,EAAE,IAAI,IAAI,EAAE;KACtB,CAAA;IAED,OAAO,UAAU,CAAC,IAAI,EAAE,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;AACpD,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EACrC,IAAU,EAAE,OAAe,EAAE,KAAa,EAC1C,IAAsG,EACvF,EAAE;IACjB,MAAM,IAAI,GAAG,IAAI,EAAE,cAAc,IAAI,aAAa,CAAA;IAClD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IAClC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IACpC,kGAAkG;IAClG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,kBAAkB,EAAE,CAAC,CAAA;IACrF,iEAAiE;IACjE,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAA;AAC/E,CAAC,CAAA;AAcD,MAAM,QAAQ,GAAG,KAAK,EACpB,SAAuB,EAAE,GAAW,EAAE,IAAa,EACrC,EAAE;IAChB,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;QAC/B,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAA;IACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,kBAAkB,GAAG,OAAO,GAAG,CAAC,MAAM,IAAI,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;IAC/F,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAA;AACnB,CAAC,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAK,EAC/C,IAA8B,EACb,EAAE;IACnB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAA;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,IAAI,sBAAsB,CAAA;IAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,YAAY,IAAI,8BAA8B,CAAA;IAC3E,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,EAAE,QAAQ,IAAI,eAAe,CAAA;IAE5D,kEAAkE;IAClE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE,IAAI,GAAG,QAAQ,EAAE;QAC/D,IAAI,EAAE,kBAAkB,CAAC,UAAU;KACpC,CAA0B,CAAA;IAE3B,2EAA2E;IAC3E,MAAM,YAAY,GAAG,iBAAiB,CAAS,SAAS,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAA;IACtF,MAAM,IAAI,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAA;IACjC,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;SAC9C,IAAI,CAAC,sBAAsB,CAAC,YAAY,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;IAEhE,MAAM,WAAW,GAAoB;QACnC,IAAI,EAAE,kBAAkB,CAAC,UAAU;QACnC,SAAS;QACT,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC/C,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM,EAAE,CAAC,GAAG,CAAC;KACd,CAAA;IAED,uDAAuD;IACvD,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE,IAAI,GAAG,QAAQ,EAAE,WAAW,CAAsB,CAAA;IAEjG,mEAAmE;IACnE,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE,IAAI,GAAG,YAAY,EAAE,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,EAAE,CAAsB,CAAA;IAEhH,OAAO,KAAK,CAAC,KAAK,CAAA;AACpB,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAAE,IAAU,EAAE,GAAW,EAAE,IAAY,EAAmB,EAAE;IAC7F,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;IAC3B,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAA;IACxC,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAgCD,MAAM,uBAAuB,GAAG,qCAAqC,CAAA;AAErE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAChC,IAAU,EAAE,IAA2B,EACrB,EAAE;IACpB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAA;IACpD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,KAAK,EAAE,CAAC,CAAA;IAC7E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;IACD,+FAA+F;IAC/F,uFAAuF;IACvF,MAAM,IAAI,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,KAAK,EAAE,CAAA;IACvD,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,KAAK,EAAE,CAAC,CAAA;IAE5E,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,EACzC,IAAU,EAAE,IAAgC,EAC7B,EAAE;IACjB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,uBAAuB,CAAA;IACjD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,MAAM,CAAA;IACtC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;QACtD,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,kBAAkB,EAAE,OAAO;KACzD,CAAC,CAAA;IAEF,oGAAoG;IACpG,gGAAgG;IAChG,gGAAgG;IAChG,8FAA8F;IAC9F,8FAA8F;IAC9F,MAAM,IAAI,CAAC,OAAO,CAAC,2DAA2D,CAAC;SAC5E,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAA;IAEjD,IAAI,IAAI,CAAC,OAAO,KAAK,QAAQ;QAAE,MAAM,aAAa,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;IAErE,iGAAiG;IACjG,2FAA2F;IAC3F,MAAM,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;IAC3E,MAAM,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;IAElE,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,EAAE,CAAC;QAC/B,MAAM,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,uBAAuB,CAAC,CAAA;IACzE,CAAC;IAED,MAAM,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,CAAA;IAE9D,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;QAC5B,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAW,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;IACtF,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;IAC3E,CAAC;AACH,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/test-ui",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.35",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -22,12 +22,12 @@
|
|
|
22
22
|
"./harness": "./harness/index.html"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@owlmeans/auth": "^0.1.18-rc.
|
|
26
|
-
"@owlmeans/basic-envelope": "^0.1.18-rc.
|
|
27
|
-
"@owlmeans/basic-ids": "^0.1.18-rc.
|
|
28
|
-
"@owlmeans/basic-keys": "^0.1.18-rc.
|
|
29
|
-
"@owlmeans/test": "^0.1.18-rc.
|
|
30
|
-
"@owlmeans/test-auth": "^0.1.18-rc.
|
|
25
|
+
"@owlmeans/auth": "^0.1.18-rc.32",
|
|
26
|
+
"@owlmeans/basic-envelope": "^0.1.18-rc.33",
|
|
27
|
+
"@owlmeans/basic-ids": "^0.1.18-rc.31",
|
|
28
|
+
"@owlmeans/basic-keys": "^0.1.18-rc.35",
|
|
29
|
+
"@owlmeans/test": "^0.1.18-rc.30",
|
|
30
|
+
"@owlmeans/test-auth": "^0.1.18-rc.33",
|
|
31
31
|
"playwright": "^1.61.1"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
package/src/index.ts
CHANGED
package/src/supervisor.ts
CHANGED
|
@@ -9,7 +9,6 @@ import { makeKeyPairModel } from '@owlmeans/basic-keys'
|
|
|
9
9
|
import { createIdOfLength } from '@owlmeans/basic-ids'
|
|
10
10
|
import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope'
|
|
11
11
|
import { makeBearer } from '@owlmeans/test-auth'
|
|
12
|
-
import { answerMarketingConsent } from './marketing-consent.js'
|
|
13
12
|
|
|
14
13
|
export interface PregenerateAuthTokenOptions {
|
|
15
14
|
/** Target user id / email the token represents. */
|
|
@@ -62,15 +61,7 @@ export const pregenerateAuthToken = async (opts: PregenerateAuthTokenOptions): P
|
|
|
62
61
|
*/
|
|
63
62
|
export const loginViaDispatcher = async (
|
|
64
63
|
page: Page, baseUrl: string, token: string,
|
|
65
|
-
opts?: {
|
|
66
|
-
dispatcherPath?: string, waitUntil?: 'commit' | 'domcontentloaded' | 'load' | 'networkidle'
|
|
67
|
-
/**
|
|
68
|
-
* Answer the marketing-consent step if it is shown right after the dispatcher navigates away.
|
|
69
|
-
* Defaults to `'save'` (select-all and save) — see {@link answerMarketingConsent}. Pass
|
|
70
|
-
* `'ignore'` to skip the call entirely, e.g. in a spec that answers the step itself.
|
|
71
|
-
*/
|
|
72
|
-
marketingConsent?: 'save' | 'ignore'
|
|
73
|
-
}
|
|
64
|
+
opts?: { dispatcherPath?: string, waitUntil?: 'commit' | 'domcontentloaded' | 'load' | 'networkidle' }
|
|
74
65
|
): Promise<void> => {
|
|
75
66
|
const path = opts?.dispatcherPath ?? '/dispatcher'
|
|
76
67
|
const url = new URL(path, baseUrl)
|
|
@@ -79,8 +70,6 @@ export const loginViaDispatcher = async (
|
|
|
79
70
|
await page.goto(url.toString(), { waitUntil: opts?.waitUntil ?? 'domcontentloaded' })
|
|
80
71
|
// Wait until the dispatcher has navigated away (token consumed).
|
|
81
72
|
await page.waitForURL(u => !u.pathname.startsWith(path), { timeout: 30_000 })
|
|
82
|
-
|
|
83
|
-
if (opts?.marketingConsent !== 'ignore') await answerMarketingConsent(page, { accept: 'all' })
|
|
84
73
|
}
|
|
85
74
|
|
|
86
75
|
export interface SupervisorApiAuthOptions {
|
|
@@ -198,12 +187,6 @@ export interface SupervisorFormLoginOptions {
|
|
|
198
187
|
consent?: 'accept' | 'ignore'
|
|
199
188
|
/** When set, capture the filled login form (`supervisor-login-form.png`) before submit. */
|
|
200
189
|
screenshotDir?: string
|
|
201
|
-
/**
|
|
202
|
-
* Answer the marketing-consent step if it is shown right after landing. Defaults to `'save'`
|
|
203
|
-
* (select-all and save) — see {@link answerMarketingConsent}. Pass `'ignore'` to skip the call
|
|
204
|
-
* entirely, e.g. in a spec that answers the step itself.
|
|
205
|
-
*/
|
|
206
|
-
marketingConsent?: 'save' | 'ignore'
|
|
207
190
|
}
|
|
208
191
|
|
|
209
192
|
const DEFAULT_SUPERVISOR_PATH = '/authentication/login/pk-supervisor'
|
|
@@ -282,6 +265,4 @@ export const loginViaSupervisorForm = async (
|
|
|
282
265
|
} else {
|
|
283
266
|
await page.waitForURL(url => !url.pathname.startsWith(path), { timeout })
|
|
284
267
|
}
|
|
285
|
-
|
|
286
|
-
if (opts.marketingConsent !== 'ignore') await answerMarketingConsent(page, { accept: 'all' })
|
|
287
268
|
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { Page } from 'playwright';
|
|
2
|
-
export interface AnswerMarketingConsentOptions {
|
|
3
|
-
/**
|
|
4
|
-
* Which choice to save when the step is shown. `'all'` (the default) ticks the "select all"
|
|
5
|
-
* checkbox before saving; `'none'` saves with every item left unchecked, which is a valid,
|
|
6
|
-
* fully-compliant state on its own.
|
|
7
|
-
*/
|
|
8
|
-
accept?: 'none' | 'all';
|
|
9
|
-
timeout?: number;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Answer the marketing-consent full-page step (`@owlmeans/web-marketing-consent`) if it is shown
|
|
13
|
-
* right after login, so a spec driving {@link loginViaSupervisorForm} or {@link loginViaDispatcher}
|
|
14
|
-
* is never blocked behind it.
|
|
15
|
-
*
|
|
16
|
-
* The screen is opt-in per app, and most apps/environments will not have it wired in — that makes
|
|
17
|
-
* detecting its ABSENCE cheaply the whole point. A plain `waitFor` on `[data-marketing-consent]`
|
|
18
|
-
* alone would cost the full `timeout` on every login of every app that never renders it (the same
|
|
19
|
-
* caveat `acceptConsent` documents for the cookie dialog). Instead this races the step's own root
|
|
20
|
-
* against the generic OwlMeans "the app has already landed" / "still on the login screen" markers
|
|
21
|
-
* this file's own login helpers already wait on (`#app-prompt`, `[data-login-method]`) — by the
|
|
22
|
-
* time a login helper calls this, one of those has typically already rendered, so the race resolves
|
|
23
|
-
* as soon as it does: no fixed sleep, and in the common "step absent" case, no material added
|
|
24
|
-
* latency over what the login helper already paid to get here.
|
|
25
|
-
*
|
|
26
|
-
* @returns whether the step was actually shown and answered (including the error/skip fallback
|
|
27
|
-
* below); `false` when it never appeared within `timeout`, which is the expected result everywhere
|
|
28
|
-
* the screen is not yet configured or the visitor already has saved consents.
|
|
29
|
-
*/
|
|
30
|
-
export declare const answerMarketingConsent: (page: Page, opts?: AnswerMarketingConsentOptions) => Promise<boolean>;
|
|
31
|
-
//# sourceMappingURL=marketing-consent.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"marketing-consent.d.ts","sourceRoot":"","sources":["../src/marketing-consent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEtC,MAAM,WAAW,6BAA6B;IAC5C;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,sBAAsB,SAC3B,IAAI,SAAS,6BAA6B,KAC/C,OAAO,CAAC,OAAO,CAoCjB,CAAA"}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
const DEFAULT_MARKETING_CONSENT_TIMEOUT = 6_000;
|
|
2
|
-
/**
|
|
3
|
-
* Answer the marketing-consent full-page step (`@owlmeans/web-marketing-consent`) if it is shown
|
|
4
|
-
* right after login, so a spec driving {@link loginViaSupervisorForm} or {@link loginViaDispatcher}
|
|
5
|
-
* is never blocked behind it.
|
|
6
|
-
*
|
|
7
|
-
* The screen is opt-in per app, and most apps/environments will not have it wired in — that makes
|
|
8
|
-
* detecting its ABSENCE cheaply the whole point. A plain `waitFor` on `[data-marketing-consent]`
|
|
9
|
-
* alone would cost the full `timeout` on every login of every app that never renders it (the same
|
|
10
|
-
* caveat `acceptConsent` documents for the cookie dialog). Instead this races the step's own root
|
|
11
|
-
* against the generic OwlMeans "the app has already landed" / "still on the login screen" markers
|
|
12
|
-
* this file's own login helpers already wait on (`#app-prompt`, `[data-login-method]`) — by the
|
|
13
|
-
* time a login helper calls this, one of those has typically already rendered, so the race resolves
|
|
14
|
-
* as soon as it does: no fixed sleep, and in the common "step absent" case, no material added
|
|
15
|
-
* latency over what the login helper already paid to get here.
|
|
16
|
-
*
|
|
17
|
-
* @returns whether the step was actually shown and answered (including the error/skip fallback
|
|
18
|
-
* below); `false` when it never appeared within `timeout`, which is the expected result everywhere
|
|
19
|
-
* the screen is not yet configured or the visitor already has saved consents.
|
|
20
|
-
*/
|
|
21
|
-
export const answerMarketingConsent = async (page, opts) => {
|
|
22
|
-
const timeout = opts?.timeout ?? DEFAULT_MARKETING_CONSENT_TIMEOUT;
|
|
23
|
-
const step = page.locator('[data-marketing-consent]');
|
|
24
|
-
try {
|
|
25
|
-
await page.locator('[data-marketing-consent], #app-prompt, [data-login-method]')
|
|
26
|
-
.first().waitFor({ state: 'visible', timeout });
|
|
27
|
-
}
|
|
28
|
-
catch {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
if (await step.count() === 0)
|
|
32
|
-
return false;
|
|
33
|
-
if ((opts?.accept ?? 'all') === 'all') {
|
|
34
|
-
await page.locator('[data-marketing-consent-all]').click();
|
|
35
|
-
}
|
|
36
|
-
// 'none' leaves every item unchecked and clicks nothing else before saving.
|
|
37
|
-
await page.locator('[data-marketing-consent-save]').click();
|
|
38
|
-
const outcome = await Promise.race([
|
|
39
|
-
step.waitFor({ state: 'detached', timeout }).then(() => 'saved'),
|
|
40
|
-
page.locator('[data-marketing-consent-error]').waitFor({ state: 'visible', timeout })
|
|
41
|
-
.then(() => 'error')
|
|
42
|
-
]).catch(() => 'error');
|
|
43
|
-
if (outcome !== 'saved') {
|
|
44
|
-
const skip = page.locator('[data-marketing-consent-skip]');
|
|
45
|
-
if (await skip.count() > 0) {
|
|
46
|
-
console.warn('[@owlmeans/test-ui] marketing consent save did not complete; using the skip link instead');
|
|
47
|
-
await skip.click();
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
// Answered either way: saved, or skipped past a flaky save. Never leaves the caller blocked.
|
|
51
|
-
return true;
|
|
52
|
-
};
|
|
53
|
-
//# sourceMappingURL=marketing-consent.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"marketing-consent.js","sourceRoot":"","sources":["../src/marketing-consent.ts"],"names":[],"mappings":"AAYA,MAAM,iCAAiC,GAAG,KAAK,CAAA;AAE/C;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,EACzC,IAAU,EAAE,IAAoC,EAC9B,EAAE;IACpB,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,IAAI,iCAAiC,CAAA;IAClE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAA;IAErD,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,OAAO,CAAC,4DAA4D,CAAC;aAC7E,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAA;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,MAAM,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAE1C,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC;QACtC,MAAM,IAAI,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAC,KAAK,EAAE,CAAA;IAC5D,CAAC;IACD,4EAA4E;IAE5E,MAAM,IAAI,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC,KAAK,EAAE,CAAA;IAE3D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;QACjC,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAgB,CAAC;QACzE,IAAI,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;aAClF,IAAI,CAAC,GAAG,EAAE,CAAC,OAAgB,CAAC;KAChC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAgB,CAAC,CAAA;IAEhC,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAA;QAC1D,IAAI,MAAM,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,0FAA0F,CAAC,CAAA;YACxG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;QACpB,CAAC;IACH,CAAC;IAED,6FAA6F;IAC7F,OAAO,IAAI,CAAA;AACb,CAAC,CAAA"}
|
package/src/marketing-consent.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import type { Page } from 'playwright'
|
|
2
|
-
|
|
3
|
-
export interface AnswerMarketingConsentOptions {
|
|
4
|
-
/**
|
|
5
|
-
* Which choice to save when the step is shown. `'all'` (the default) ticks the "select all"
|
|
6
|
-
* checkbox before saving; `'none'` saves with every item left unchecked, which is a valid,
|
|
7
|
-
* fully-compliant state on its own.
|
|
8
|
-
*/
|
|
9
|
-
accept?: 'none' | 'all'
|
|
10
|
-
timeout?: number
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const DEFAULT_MARKETING_CONSENT_TIMEOUT = 6_000
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Answer the marketing-consent full-page step (`@owlmeans/web-marketing-consent`) if it is shown
|
|
17
|
-
* right after login, so a spec driving {@link loginViaSupervisorForm} or {@link loginViaDispatcher}
|
|
18
|
-
* is never blocked behind it.
|
|
19
|
-
*
|
|
20
|
-
* The screen is opt-in per app, and most apps/environments will not have it wired in — that makes
|
|
21
|
-
* detecting its ABSENCE cheaply the whole point. A plain `waitFor` on `[data-marketing-consent]`
|
|
22
|
-
* alone would cost the full `timeout` on every login of every app that never renders it (the same
|
|
23
|
-
* caveat `acceptConsent` documents for the cookie dialog). Instead this races the step's own root
|
|
24
|
-
* against the generic OwlMeans "the app has already landed" / "still on the login screen" markers
|
|
25
|
-
* this file's own login helpers already wait on (`#app-prompt`, `[data-login-method]`) — by the
|
|
26
|
-
* time a login helper calls this, one of those has typically already rendered, so the race resolves
|
|
27
|
-
* as soon as it does: no fixed sleep, and in the common "step absent" case, no material added
|
|
28
|
-
* latency over what the login helper already paid to get here.
|
|
29
|
-
*
|
|
30
|
-
* @returns whether the step was actually shown and answered (including the error/skip fallback
|
|
31
|
-
* below); `false` when it never appeared within `timeout`, which is the expected result everywhere
|
|
32
|
-
* the screen is not yet configured or the visitor already has saved consents.
|
|
33
|
-
*/
|
|
34
|
-
export const answerMarketingConsent = async (
|
|
35
|
-
page: Page, opts?: AnswerMarketingConsentOptions
|
|
36
|
-
): Promise<boolean> => {
|
|
37
|
-
const timeout = opts?.timeout ?? DEFAULT_MARKETING_CONSENT_TIMEOUT
|
|
38
|
-
const step = page.locator('[data-marketing-consent]')
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
await page.locator('[data-marketing-consent], #app-prompt, [data-login-method]')
|
|
42
|
-
.first().waitFor({ state: 'visible', timeout })
|
|
43
|
-
} catch {
|
|
44
|
-
return false
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (await step.count() === 0) return false
|
|
48
|
-
|
|
49
|
-
if ((opts?.accept ?? 'all') === 'all') {
|
|
50
|
-
await page.locator('[data-marketing-consent-all]').click()
|
|
51
|
-
}
|
|
52
|
-
// 'none' leaves every item unchecked and clicks nothing else before saving.
|
|
53
|
-
|
|
54
|
-
await page.locator('[data-marketing-consent-save]').click()
|
|
55
|
-
|
|
56
|
-
const outcome = await Promise.race([
|
|
57
|
-
step.waitFor({ state: 'detached', timeout }).then(() => 'saved' as const),
|
|
58
|
-
page.locator('[data-marketing-consent-error]').waitFor({ state: 'visible', timeout })
|
|
59
|
-
.then(() => 'error' as const)
|
|
60
|
-
]).catch(() => 'error' as const)
|
|
61
|
-
|
|
62
|
-
if (outcome !== 'saved') {
|
|
63
|
-
const skip = page.locator('[data-marketing-consent-skip]')
|
|
64
|
-
if (await skip.count() > 0) {
|
|
65
|
-
console.warn('[@owlmeans/test-ui] marketing consent save did not complete; using the skip link instead')
|
|
66
|
-
await skip.click()
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Answered either way: saved, or skipped past a flaky save. Never leaves the caller blocked.
|
|
71
|
-
return true
|
|
72
|
-
}
|