@plan2net/typo3-playwright-toolkit 0.15.0 → 0.17.0
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 +74 -5
- package/dist/builders/content-builder.d.ts +2 -2
- package/dist/builders/content-builder.d.ts.map +1 -1
- package/dist/builders/content-builder.js +4 -4
- package/dist/builders/content-builder.js.map +1 -1
- package/dist/builders/core-content.d.ts +4 -4
- package/dist/builders/core-content.d.ts.map +1 -1
- package/dist/builders/core-content.js +8 -8
- package/dist/builders/core-content.js.map +1 -1
- package/dist/builders/page-builder.d.ts +1 -1
- package/dist/builders/page-builder.d.ts.map +1 -1
- package/dist/builders/page-builder.js +2 -2
- package/dist/builders/page-builder.js.map +1 -1
- package/dist/builders/relations.d.ts +3 -3
- package/dist/builders/relations.d.ts.map +1 -1
- package/dist/builders/relations.js +7 -6
- package/dist/builders/relations.js.map +1 -1
- package/dist/checks/screenshot.d.ts +7 -0
- package/dist/checks/screenshot.d.ts.map +1 -1
- package/dist/checks/screenshot.js +113 -8
- package/dist/checks/screenshot.js.map +1 -1
- package/dist/clean/cli.d.ts +3 -0
- package/dist/clean/cli.d.ts.map +1 -0
- package/dist/clean/cli.js +32 -0
- package/dist/clean/cli.js.map +1 -0
- package/dist/doctor/cli.d.ts +3 -0
- package/dist/doctor/cli.d.ts.map +1 -0
- package/dist/doctor/cli.js +41 -0
- package/dist/doctor/cli.js.map +1 -0
- package/dist/doctor/reporter.d.ts +22 -0
- package/dist/doctor/reporter.d.ts.map +1 -0
- package/dist/doctor/reporter.js +224 -0
- package/dist/doctor/reporter.js.map +1 -0
- package/dist/global-setup.d.ts +18 -0
- package/dist/global-setup.d.ts.map +1 -1
- package/dist/global-setup.js +6 -3
- package/dist/global-setup.js.map +1 -1
- package/dist/http/api-secret.js +1 -1
- package/dist/http/record-edit.d.ts.map +1 -1
- package/dist/http/record-edit.js +7 -6
- package/dist/http/record-edit.js.map +1 -1
- package/dist/inspect/cli.js +2 -2
- package/dist/inspect/links.d.ts +2 -0
- package/dist/inspect/links.d.ts.map +1 -1
- package/dist/inspect/links.js +8 -0
- package/dist/inspect/links.js.map +1 -1
- package/dist/media/media-manifest.d.ts +6 -0
- package/dist/media/media-manifest.d.ts.map +1 -0
- package/dist/media/media-manifest.js +31 -0
- package/dist/media/media-manifest.js.map +1 -0
- package/dist/playwright/base-config.d.ts.map +1 -1
- package/dist/playwright/base-config.js +3 -0
- package/dist/playwright/base-config.js.map +1 -1
- package/dist/state/run-namespace.d.ts +2 -0
- package/dist/state/run-namespace.d.ts.map +1 -1
- package/dist/state/run-namespace.js +1 -1
- package/dist/state/run-namespace.js.map +1 -1
- package/package.json +3 -1
|
@@ -42,12 +42,93 @@ export async function loadLazyElements(page) {
|
|
|
42
42
|
.querySelectorAll('[loading="lazy"]')
|
|
43
43
|
.forEach((element) => (element.loading = 'eager')));
|
|
44
44
|
}
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
// A capture reaching past the viewport collapses it to 1x1 first, and a width-based
|
|
46
|
+
// `media` on a `<source>` flips while it is collapsed, dropping the decoded image.
|
|
47
|
+
export async function freezeResponsiveImages(page) {
|
|
48
|
+
await page.evaluate(() => {
|
|
49
|
+
document.querySelectorAll('img').forEach((image) => {
|
|
50
|
+
const resolved = image.currentSrc;
|
|
51
|
+
if (!resolved) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
image.dataset.toolkitFrozen = JSON.stringify({
|
|
55
|
+
src: image.getAttribute('src'),
|
|
56
|
+
srcset: image.getAttribute('srcset'),
|
|
57
|
+
sizes: image.getAttribute('sizes'),
|
|
58
|
+
width: image.getAttribute('width'),
|
|
59
|
+
height: image.getAttribute('height'),
|
|
60
|
+
});
|
|
61
|
+
const sources = Array.from(image.closest('picture')?.querySelectorAll('source') ?? []);
|
|
62
|
+
// width and height on the chosen source lay the img out, and disabling it
|
|
63
|
+
// would drop them.
|
|
64
|
+
const chosen = sources.find((source) => !source.media || matchMedia(source.media).matches);
|
|
65
|
+
for (const dimension of ['width', 'height']) {
|
|
66
|
+
const value = chosen?.getAttribute(dimension);
|
|
67
|
+
if (null != value) {
|
|
68
|
+
image.setAttribute(dimension, value);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
sources.forEach((source) => {
|
|
72
|
+
source.dataset.toolkitFrozen = JSON.stringify({ media: source.getAttribute('media') });
|
|
73
|
+
// Never matches, so selection falls through to the img below.
|
|
74
|
+
source.media = 'not all';
|
|
75
|
+
});
|
|
76
|
+
image.removeAttribute('srcset');
|
|
77
|
+
image.removeAttribute('sizes');
|
|
78
|
+
if (image.src !== resolved) {
|
|
79
|
+
image.src = resolved;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
// Settle first, or a loading image has no currentSrc to pin it to; settle again,
|
|
85
|
+
// because pinning a <picture> starts a load of its own.
|
|
86
|
+
export async function prepareImagesForCapture(page) {
|
|
87
|
+
const stalled = await waitForImagesDecoded(page);
|
|
88
|
+
await freezeResponsiveImages(page);
|
|
89
|
+
await waitForImagesDecoded(page);
|
|
90
|
+
return stalled;
|
|
91
|
+
}
|
|
92
|
+
export async function restoreResponsiveImages(page) {
|
|
93
|
+
await page.evaluate(() => {
|
|
94
|
+
const put = (element, name, value) => null === value ? element.removeAttribute(name) : element.setAttribute(name, value);
|
|
95
|
+
document.querySelectorAll('img[data-toolkit-frozen]').forEach((image) => {
|
|
96
|
+
image
|
|
97
|
+
.closest('picture')
|
|
98
|
+
?.querySelectorAll('source[data-toolkit-frozen]')
|
|
99
|
+
.forEach((source) => {
|
|
100
|
+
const { media } = JSON.parse(source.dataset.toolkitFrozen ?? '{}');
|
|
101
|
+
put(source, 'media', media);
|
|
102
|
+
delete source.dataset.toolkitFrozen;
|
|
103
|
+
});
|
|
104
|
+
const frozen = JSON.parse(image.dataset.toolkitFrozen ?? '{}');
|
|
105
|
+
Object.entries(frozen).forEach(([name, value]) => put(image, name, value));
|
|
106
|
+
delete image.dataset.toolkitFrozen;
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const DECODE_TIMEOUT = 15000;
|
|
111
|
+
/** @returns the sources of the images that never decoded, empty when all did */
|
|
112
|
+
export async function waitForImagesDecoded(page, timeout = DECODE_TIMEOUT) {
|
|
113
|
+
const deadline = Date.now() + timeout;
|
|
114
|
+
const stalled = await settleImages(page, timeout);
|
|
115
|
+
const left = deadline - Date.now();
|
|
116
|
+
// Out of budget, so a second round would settle nothing and report every image.
|
|
117
|
+
if (left <= 0) {
|
|
118
|
+
return stalled;
|
|
119
|
+
}
|
|
120
|
+
// A load that starts during a round is not waited for by it, which is how
|
|
121
|
+
// applyDeferredStylesheets re-selects a source after the image read as complete.
|
|
122
|
+
return settleImages(page, left);
|
|
123
|
+
}
|
|
124
|
+
function settleImages(page, timeout) {
|
|
125
|
+
return page.evaluate(async (timeout) => {
|
|
47
126
|
const images = Array.from(document.querySelectorAll('img'));
|
|
127
|
+
const stalled = new Set(images);
|
|
48
128
|
const settle = (image) => new Promise((resolve) => {
|
|
49
129
|
const finish = async () => {
|
|
50
130
|
await image.decode().catch(() => { });
|
|
131
|
+
stalled.delete(image);
|
|
51
132
|
resolve();
|
|
52
133
|
};
|
|
53
134
|
if (image.complete) {
|
|
@@ -55,13 +136,29 @@ async function waitForImagesDecoded(page, timeout = 15000) {
|
|
|
55
136
|
return;
|
|
56
137
|
}
|
|
57
138
|
image.addEventListener('load', () => void finish(), { once: true });
|
|
58
|
-
image.addEventListener('error', () =>
|
|
139
|
+
image.addEventListener('error', () => {
|
|
140
|
+
stalled.delete(image);
|
|
141
|
+
resolve();
|
|
142
|
+
}, { once: true });
|
|
59
143
|
});
|
|
60
144
|
const timeoutPromise = new Promise((resolve) => setTimeout(resolve, timeout));
|
|
61
145
|
await Promise.race([Promise.all(images.map(settle)), timeoutPromise]);
|
|
62
146
|
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));
|
|
147
|
+
// The snapshot above predates anything that started loading since.
|
|
148
|
+
document.querySelectorAll('img').forEach((image) => {
|
|
149
|
+
if (!image.complete) {
|
|
150
|
+
stalled.add(image);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
return Array.from(stalled, (image) => image.currentSrc || image.src);
|
|
63
154
|
}, timeout);
|
|
64
155
|
}
|
|
156
|
+
/** An undecoded image is blank, and a first run writes that blank as the baseline. */
|
|
157
|
+
export function warnAboutUndecodedImages(stalled, timeout) {
|
|
158
|
+
console.warn(`[typo3-playwright-toolkit] ${stalled.length} ${1 === stalled.length ? 'image' : 'images'} ` +
|
|
159
|
+
`did not decode within ${timeout}ms and will be blank in the screenshot:\n ` +
|
|
160
|
+
stalled.join('\n '));
|
|
161
|
+
}
|
|
65
162
|
/**
|
|
66
163
|
* Finishes the `media="print"` async-CSS trick by hand. A stylesheet loaded as
|
|
67
164
|
* print and swapped to `all` on load is not applied while it is still print, so
|
|
@@ -113,11 +210,19 @@ export async function expectScreenshot(target, name, options = {}) {
|
|
|
113
210
|
await page.evaluate(() => document.fonts.ready);
|
|
114
211
|
await waitForAnimations(page, undefined, 3000);
|
|
115
212
|
await loadLazyElements(page);
|
|
116
|
-
await
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
213
|
+
const stalled = await prepareImagesForCapture(page);
|
|
214
|
+
if (stalled.length > 0) {
|
|
215
|
+
warnAboutUndecodedImages(stalled, DECODE_TIMEOUT);
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
// Playwright creates a missing reference itself and has --update-snapshots
|
|
219
|
+
// for the rest; hand-building the snapshot path got the platform suffix
|
|
220
|
+
// wrong off Linux.
|
|
221
|
+
await expect(shot).toHaveScreenshot(`${name}.png`, comparisonOptions(wholePage, screenshotOptions));
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
await restoreResponsiveImages(page);
|
|
225
|
+
}
|
|
121
226
|
}
|
|
122
227
|
export function comparisonOptions(wholePage, perCall) {
|
|
123
228
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/checks/screenshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAoB/C,MAAM,aAAa,GAAG;;;;;;EAMpB,CAAA;AAEF,MAAM,UAAU,eAAe,CAAC,SAAmB;IAC/C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,CAAA;IACb,CAAC;IAED,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,qCAAqC,CAAA;AACvE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAU,EAAE,QAAiB,EAAE,OAAO,GAAG,IAAI;IACjF,MAAM,IAAI,CAAC,QAAQ,CACf,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE;QAC5B,MAAM,cAAc,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAA;QACnF,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAA;QAExE,MAAM,UAAU,GAAG,KAAK,IAAI,EAAE;YAC1B,MAAM,UAAU,GAAG,IAAI,EAAE,aAAa,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,CAAA;YAC/D,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,OAAO,CAAC,IAAI,CAAC;oBACf,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC;oBAC9E,cAAc;iBACjB,CAAC,CAAA;YACN,CAAC;QACL,CAAC,CAAA;QAED,6EAA6E;QAC7E,MAAM,UAAU,EAAE,CAAA;QAClB,MAAM,UAAU,EAAE,CAAA;IACtB,CAAC,EACD,EAAE,QAAQ,EAAE,OAAO,EAAE,CACxB,CAAA;AACL,CAAC;AAED,4EAA4E;AAC5E,sDAAsD;AACtD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAU;IAC7C,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CACrB,QAAQ;SACH,gBAAgB,CAAuC,kBAAkB,CAAC;SAC1E,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC,CACzD,CAAA;AACL,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,IAAU,EAAE,OAAO,GAAG,KAAK;
|
|
1
|
+
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/checks/screenshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/clean/cli.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { sweepOrphans } from '../global-teardown.js';
|
|
4
|
+
import { httpCleanup } from '../http/cleanup-client.js';
|
|
5
|
+
import { findStateDir, recordedTestingUrl } from '../inspect/links.js';
|
|
6
|
+
import { OWNER_ACTIVE_MS } from '../state/run-namespace.js';
|
|
7
|
+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
8
|
+
console.log('Usage: typo3-playwright-clean');
|
|
9
|
+
console.log('Drops the test databases and run state a stopped run left behind.');
|
|
10
|
+
process.exit(0);
|
|
11
|
+
}
|
|
12
|
+
const stateDir = findStateDir(process.cwd());
|
|
13
|
+
if (undefined === stateDir) {
|
|
14
|
+
console.log('Nothing to clean: no .test-state directory here.');
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
const testingURL = recordedTestingUrl(stateDir);
|
|
18
|
+
if (undefined === testingURL) {
|
|
19
|
+
console.log('Nothing to clean: no run recorded a testing URL.');
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
const consumerRoot = path.dirname(stateDir);
|
|
23
|
+
const config = {
|
|
24
|
+
testingURL,
|
|
25
|
+
paths: { consumerRoot, stateDir, sessionDir: path.join(consumerRoot, 'var/session') },
|
|
26
|
+
// The window prepareRun uses to decide another process owns a run, so a run
|
|
27
|
+
// younger than it keeps its databases and state.
|
|
28
|
+
cleanup: { orphanAgeMs: OWNER_ACTIVE_MS },
|
|
29
|
+
};
|
|
30
|
+
const reclaimed = await sweepOrphans(config, httpCleanup(config));
|
|
31
|
+
console.log(`Dropped ${reclaimed} test database${1 === reclaimed ? '' : 's'}.`);
|
|
32
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/clean/cli.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAE5B,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAE3D,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACjE,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;IAC5C,OAAO,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAA;IAChF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACnB,CAAC;AAED,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;AAC5C,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;IACzB,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAA;IAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACnB,CAAC;AAED,MAAM,UAAU,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAA;AAC/C,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAA;IAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACnB,CAAC;AAED,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;AAC3C,MAAM,MAAM,GAAkB;IAC1B,UAAU;IACV,KAAK,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,EAAE;IACrF,4EAA4E;IAC5E,iDAAiD;IACjD,OAAO,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE;CAC5C,CAAA;AAED,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAA;AAEjE,OAAO,CAAC,GAAG,CAAC,WAAW,SAAS,iBAAiB,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/doctor/cli.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
7
|
+
import { parseArgs } from 'node:util';
|
|
8
|
+
try {
|
|
9
|
+
const { values } = parseArgs({ options: {
|
|
10
|
+
help: { type: 'boolean', short: 'h' },
|
|
11
|
+
config: { type: 'string', short: 'c' },
|
|
12
|
+
project: { type: 'string', multiple: true },
|
|
13
|
+
} });
|
|
14
|
+
if (values.help) {
|
|
15
|
+
console.log('Usage: typo3-playwright-doctor [--project name] [--config file]');
|
|
16
|
+
console.log('Checks browsers and TYPO3 without running tests, builds, or repairs.');
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
const require = createRequire(import.meta.url);
|
|
20
|
+
// Playwright 1.44 writes .last-run.json even in list mode, into an output
|
|
21
|
+
// directory it creates first, so the project's own test-results survives
|
|
22
|
+
// only if that directory is a throwaway.
|
|
23
|
+
const outputDir = mkdtempSync(join(tmpdir(), 'typo3-playwright-doctor-'));
|
|
24
|
+
process.on('exit', () => rmSync(outputDir, { recursive: true, force: true }));
|
|
25
|
+
const args = ['test', '--list', '--pass-with-no-tests', '--output', outputDir,
|
|
26
|
+
'--reporter', fileURLToPath(new URL('./reporter.js', import.meta.url))];
|
|
27
|
+
if (values.config)
|
|
28
|
+
args.push('--config', values.config);
|
|
29
|
+
for (const project of values.project ?? [])
|
|
30
|
+
args.push('--project', project);
|
|
31
|
+
const playwrightCli = require.resolve('@playwright/test/cli');
|
|
32
|
+
process.env.PW_DOCTOR_PROJECTS = JSON.stringify(values.project ?? []);
|
|
33
|
+
process.argv = [process.execPath, playwrightCli, ...args];
|
|
34
|
+
await import(pathToFileURL(playwrightCli).href);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error(`✗ ${error.message}`);
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/doctor/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,IAAI,CAAC;IACD,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,OAAO,EAAE;YACpC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;YACrC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE;YACtC,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;SAC9C,EAAE,CAAC,CAAA;IACJ,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAA;QAC9E,OAAO,CAAC,GAAG,CAAC,sEAAsE,CAAC,CAAA;IACvF,CAAC;SAAM,CAAC;QACJ,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAE9C,0EAA0E;QAC1E,yEAAyE;QACzE,yCAAyC;QACzC,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,0BAA0B,CAAC,CAAC,CAAA;QACzE,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;QAE7E,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,sBAAsB,EAAE,UAAU,EAAE,SAAS;YACzE,YAAY,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QAC3E,IAAI,MAAM,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;QACvD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE;YAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QAC3E,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAA;QAC7D,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAA;QACrE,OAAO,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,CAAA;QACzD,MAAM,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAA;IACnD,CAAC;AACL,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACb,OAAO,CAAC,KAAK,CAAC,KAAM,KAAe,CAAC,OAAO,EAAE,CAAC,CAAA;IAC9C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;AACxB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { FullConfig, FullResult, Reporter, TestError } from '@playwright/test/reporter';
|
|
2
|
+
export default class DoctorReporter implements Reporter {
|
|
3
|
+
private config?;
|
|
4
|
+
private failed;
|
|
5
|
+
printsToStdio(): boolean;
|
|
6
|
+
onBegin(config: FullConfig): void;
|
|
7
|
+
onError(error: TestError): void;
|
|
8
|
+
onEnd(result: FullResult): Promise<{
|
|
9
|
+
status: FullResult['status'];
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* A reporter's config lists every project whatever --project selected, and the
|
|
13
|
+
* run's suites hold only projects that already have a test file. So the
|
|
14
|
+
* selection is applied here, with Playwright's wildcard and case rules.
|
|
15
|
+
*/
|
|
16
|
+
private selectedProjects;
|
|
17
|
+
private checkBrowser;
|
|
18
|
+
private checkApi;
|
|
19
|
+
private fail;
|
|
20
|
+
private skip;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/doctor/reporter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAe,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAWzG,MAAM,CAAC,OAAO,OAAO,cAAe,YAAW,QAAQ;IACnD,OAAO,CAAC,MAAM,CAAC,CAAY;IAC3B,OAAO,CAAC,MAAM,CAAI;IAElB,aAAa,IAAI,OAAO;IAIxB,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAIjC,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAIzB,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;KAAE,CAAC;IAyB1E;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;YAWV,YAAY;YA8BZ,QAAQ;IA+FtB,OAAO,CAAC,IAAI;IAKZ,OAAO,CAAC,IAAI;CAGf"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { chromium, firefox, webkit } from '@playwright/test';
|
|
2
|
+
import { getToolkitConfig } from '../config.js';
|
|
3
|
+
import { generateTestId, TEST_ID_HEADER } from '../contract.js';
|
|
4
|
+
import { resolveApiSecret, SECRET_HEADER } from '../http/api-secret.js';
|
|
5
|
+
import { httpCleanup } from '../http/cleanup-client.js';
|
|
6
|
+
import { isTestingContext, MINIMUM_API_VERSION, readHealth } from '../global-setup.js';
|
|
7
|
+
const BROWSERS = { chromium, firefox, webkit };
|
|
8
|
+
const BROWSER_TIMEOUT_MS = 10000;
|
|
9
|
+
export default class DoctorReporter {
|
|
10
|
+
config;
|
|
11
|
+
failed = 0;
|
|
12
|
+
printsToStdio() {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
onBegin(config) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
}
|
|
18
|
+
onError(error) {
|
|
19
|
+
console.error(`✗ Playwright config: ${error.message ?? error.value}`);
|
|
20
|
+
}
|
|
21
|
+
async onEnd(result) {
|
|
22
|
+
if (!this.config || result.status !== 'passed') {
|
|
23
|
+
return { status: 'failed' };
|
|
24
|
+
}
|
|
25
|
+
console.log(`✓ Playwright config loaded: ${this.config.configFile}`);
|
|
26
|
+
let toolkit;
|
|
27
|
+
try {
|
|
28
|
+
toolkit = getToolkitConfig();
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
this.fail('Toolkit configuration', error.message);
|
|
32
|
+
return { status: 'failed' };
|
|
33
|
+
}
|
|
34
|
+
for (const project of this.selectedProjects(this.config)) {
|
|
35
|
+
await this.checkBrowser(project, toolkit);
|
|
36
|
+
}
|
|
37
|
+
await this.checkApi(toolkit);
|
|
38
|
+
console.log(this.failed ? `Not ready: ${this.failed} check(s) failed.` : 'Ready to run tests.');
|
|
39
|
+
return { status: this.failed ? 'failed' : 'passed' };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A reporter's config lists every project whatever --project selected, and the
|
|
43
|
+
* run's suites hold only projects that already have a test file. So the
|
|
44
|
+
* selection is applied here, with Playwright's wildcard and case rules.
|
|
45
|
+
*/
|
|
46
|
+
selectedProjects(config) {
|
|
47
|
+
const names = JSON.parse(process.env.PW_DOCTOR_PROJECTS ?? '[]');
|
|
48
|
+
if (!names.length) {
|
|
49
|
+
return config.projects;
|
|
50
|
+
}
|
|
51
|
+
const patterns = names.map((name) => new RegExp(`^${name.split('*')
|
|
52
|
+
.map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('.*')}$`, 'i'));
|
|
53
|
+
return config.projects.filter((project) => patterns.some((pattern) => pattern.test(project.name)));
|
|
54
|
+
}
|
|
55
|
+
async checkBrowser(project, toolkit) {
|
|
56
|
+
const browserName = project.use.browserName ?? 'chromium';
|
|
57
|
+
const label = project.name || browserName;
|
|
58
|
+
const connect = connectOptions(project);
|
|
59
|
+
let browser;
|
|
60
|
+
try {
|
|
61
|
+
const launch = { ...project.use.launchOptions };
|
|
62
|
+
if (project.use.headless !== undefined)
|
|
63
|
+
launch.headless = project.use.headless;
|
|
64
|
+
if (project.use.channel !== undefined)
|
|
65
|
+
launch.channel = project.use.channel;
|
|
66
|
+
browser = connect
|
|
67
|
+
? await BROWSERS[browserName].connect(connect.wsEndpoint, { timeout: BROWSER_TIMEOUT_MS, ...connect })
|
|
68
|
+
: await BROWSERS[browserName].launch({ timeout: BROWSER_TIMEOUT_MS, ...launch });
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
this.fail(`Browser [${label}]`, error.message);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
console.log(`✓ Browser [${label}] ${connect ? 'connected' : 'launched'}`);
|
|
75
|
+
try {
|
|
76
|
+
const page = await browser.newPage(pageOptions(project));
|
|
77
|
+
await page.goto(toolkit.testingURL, { timeout: BROWSER_TIMEOUT_MS, waitUntil: 'domcontentloaded' });
|
|
78
|
+
console.log(`✓ Browser access [${label}]: testing URL reachable`);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
this.fail(`Browser access [${label}]`, error.message);
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
await browser.close();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async checkApi(config) {
|
|
88
|
+
let secret;
|
|
89
|
+
try {
|
|
90
|
+
secret = resolveApiSecret(config);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
this.fail('API secret', error.message);
|
|
94
|
+
this.skip('API authentication', 'API compatibility', 'Database and session checks');
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const url = `${config.testingURL}/typo3/test-api/health`;
|
|
98
|
+
const headers = { [SECRET_HEADER]: secret };
|
|
99
|
+
let preflight;
|
|
100
|
+
try {
|
|
101
|
+
preflight = await readHealth(url, headers, fetch, (reason) => `Unreachable: ${reason}. Check the testing hostname and web server.`);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
this.fail('Testing URL', error.message);
|
|
105
|
+
this.skip('API authentication', 'API compatibility', 'Database and session checks');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
console.log(`✓ Testing URL reachable: ${config.testingURL}`);
|
|
109
|
+
if (preflight.status === 401 || preflight.status === 403) {
|
|
110
|
+
this.fail('API secret', 'Request refused. Check PLAYWRIGHT_TOOLKIT_SECRET or run ddev playwright prepare.');
|
|
111
|
+
this.skip('API compatibility', 'Database and session checks');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (!answered(preflight.status)) {
|
|
115
|
+
this.fail('Test API', `HTTP ${preflight.status}. Check the Testing site's PHP and web-server logs.`);
|
|
116
|
+
this.skip('API compatibility', 'Database and session checks');
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
console.log('✓ API secret accepted');
|
|
120
|
+
if (typeof preflight.body?.api !== 'number' || !Number.isInteger(preflight.body.api) || preflight.body.api < MINIMUM_API_VERSION) {
|
|
121
|
+
this.fail('Toolkit API version', 'Run composer update plan2net/playwright-toolkit.');
|
|
122
|
+
this.skip('Database and session checks');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
console.log('✓ Toolkit API versions compatible');
|
|
126
|
+
if (!confirmsTestingContext(preflight.body.checks?.context)) {
|
|
127
|
+
this.fail('Testing context', 'Point testingURL at the hostname configured with TYPO3_CONTEXT=Testing.');
|
|
128
|
+
this.skip('Database and session checks');
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const testId = generateTestId();
|
|
132
|
+
try {
|
|
133
|
+
const health = await readHealth(url, { ...headers, [TEST_ID_HEADER]: testId }, fetch, (reason) => `Diagnostic request failed: ${reason}`);
|
|
134
|
+
if (!answered(health.status)) {
|
|
135
|
+
this.fail('Test API', `HTTP ${health.status}. Check the Testing site's PHP and web-server logs.`);
|
|
136
|
+
this.skip('Database and session checks');
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (!confirmsTestingContext(health.body?.checks?.context)) {
|
|
140
|
+
this.fail('Testing context', 'The diagnostic response did not confirm a Testing context.');
|
|
141
|
+
this.skip('Database and session checks');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const failuresBefore = this.failed;
|
|
145
|
+
for (const [name, label, remedy] of [
|
|
146
|
+
['database', 'Test database created from template', 'Run ddev playwright prepare --force.'],
|
|
147
|
+
['session', 'Backend session usable', 'Run ddev playwright prepare --force.'],
|
|
148
|
+
['media', 'Media fixtures seeded', 'Check mediaPath and mediaStorage, then run ddev playwright prepare.'],
|
|
149
|
+
]) {
|
|
150
|
+
const check = health.body.checks?.[name];
|
|
151
|
+
if (check?.ok === true) {
|
|
152
|
+
console.log(`✓ ${label}`);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
this.fail(label, `${check?.detail ?? 'No check result returned'}. ${remedy}`);
|
|
156
|
+
if (name === 'database')
|
|
157
|
+
this.skip('Backend session check');
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (this.failed === failuresBefore && (!health.ok || health.body.ok !== true)) {
|
|
162
|
+
this.fail('Test API', 'The health response reports failure without a failed check. Check the PHP logs.');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
this.fail('Test database', error.message);
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
const [cleanup] = await httpCleanup(config).drop([testId]);
|
|
170
|
+
if (cleanup?.outcome === 'dropped' || cleanup?.outcome === 'absent') {
|
|
171
|
+
console.log('✓ Diagnostic database removed');
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
this.fail('Diagnostic database cleanup', `db${testId}: ${cleanup?.outcome ?? 'no result'}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
fail(check, detail) {
|
|
179
|
+
console.error(`✗ ${check}: ${detail}`);
|
|
180
|
+
this.failed++;
|
|
181
|
+
}
|
|
182
|
+
skip(...checks) {
|
|
183
|
+
for (const check of checks)
|
|
184
|
+
console.log(`– ${check} skipped`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/** Playwright's own environment override wins, the way it does for a test run. */
|
|
188
|
+
function connectOptions(project) {
|
|
189
|
+
if (!process.env.PW_TEST_CONNECT_WS_ENDPOINT) {
|
|
190
|
+
return project.use.connectOptions;
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
wsEndpoint: process.env.PW_TEST_CONNECT_WS_ENDPOINT,
|
|
194
|
+
headers: process.env.PW_TEST_CONNECT_HEADERS
|
|
195
|
+
? JSON.parse(process.env.PW_TEST_CONNECT_HEADERS)
|
|
196
|
+
: undefined,
|
|
197
|
+
exposeNetwork: process.env.PW_TEST_CONNECT_EXPOSE_NETWORK,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/** A toolkit header a consumer configured context-wide must not ride along on a browser request. */
|
|
201
|
+
function pageOptions(project) {
|
|
202
|
+
const options = { ...project.use.contextOptions };
|
|
203
|
+
options.extraHTTPHeaders = { ...(project.use.extraHTTPHeaders ?? options.extraHTTPHeaders) };
|
|
204
|
+
for (const header of Object.keys(options.extraHTTPHeaders)) {
|
|
205
|
+
if ([SECRET_HEADER.toLowerCase(), TEST_ID_HEADER.toLowerCase()].includes(header.toLowerCase())) {
|
|
206
|
+
delete options.extraHTTPHeaders[header];
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (project.use.ignoreHTTPSErrors !== undefined)
|
|
210
|
+
options.ignoreHTTPSErrors = project.use.ignoreHTTPSErrors;
|
|
211
|
+
if (project.use.httpCredentials !== undefined)
|
|
212
|
+
options.httpCredentials = project.use.httpCredentials;
|
|
213
|
+
if (project.use.proxy !== undefined)
|
|
214
|
+
options.proxy = project.use.proxy;
|
|
215
|
+
return options;
|
|
216
|
+
}
|
|
217
|
+
/** 200 is healthy and 503 is a reported check failure; anything else is the site breaking. */
|
|
218
|
+
function answered(status) {
|
|
219
|
+
return status === 200 || status === 503;
|
|
220
|
+
}
|
|
221
|
+
function confirmsTestingContext(check) {
|
|
222
|
+
return check?.ok === true && isTestingContext(check.detail);
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../src/doctor/reporter.ts"],"names":[],"mappings":"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"}
|
package/dist/global-setup.d.ts
CHANGED
|
@@ -2,6 +2,23 @@ import { type ToolkitConfig } from './config.js';
|
|
|
2
2
|
export declare function preflightTestId(config: ToolkitConfig): string;
|
|
3
3
|
/** The oldest extension this toolkit can talk to. */
|
|
4
4
|
export declare const MINIMUM_API_VERSION = 1;
|
|
5
|
+
interface HealthResponse {
|
|
6
|
+
status: number;
|
|
7
|
+
ok: boolean;
|
|
8
|
+
body: {
|
|
9
|
+
ok?: boolean;
|
|
10
|
+
api?: unknown;
|
|
11
|
+
checks?: Record<string, {
|
|
12
|
+
ok: boolean;
|
|
13
|
+
detail: string;
|
|
14
|
+
}>;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The body is read whatever the status: an unhealthy site still reports its
|
|
19
|
+
* version, and "too old" is a different problem from "unhealthy".
|
|
20
|
+
*/
|
|
21
|
+
export declare function readHealth(healthUrl: string, headers: Record<string, string>, doFetch: typeof fetch, unreachable: (reason: string) => string): Promise<HealthResponse>;
|
|
5
22
|
/**
|
|
6
23
|
* Sends no test ID, and runs before any test ID exists. A request with one makes
|
|
7
24
|
* the extension create a database, and an extension this old has no endpoint to
|
|
@@ -10,6 +27,7 @@ export declare const MINIMUM_API_VERSION = 1;
|
|
|
10
27
|
export declare function verifyApiVersion(config: ToolkitConfig, options?: {
|
|
11
28
|
fetchImpl?: typeof fetch;
|
|
12
29
|
}): Promise<number>;
|
|
30
|
+
export declare function isTestingContext(reported: string): boolean;
|
|
13
31
|
export declare function runHealthCheck(testingURL: string, options?: {
|
|
14
32
|
testId?: string;
|
|
15
33
|
secret?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"global-setup.d.ts","sourceRoot":"","sources":["../src/global-setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAOlE,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAK7D;AAED,qDAAqD;AACrD,eAAO,MAAM,mBAAmB,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"global-setup.d.ts","sourceRoot":"","sources":["../src/global-setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAOlE,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAK7D;AAED,qDAAqD;AACrD,eAAO,MAAM,mBAAmB,IAAI,CAAA;AAEpC,UAAU,cAAc;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,EAAE,EAAE,OAAO,CAAA;IACX,IAAI,EAAE;QAAE,EAAE,CAAC,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,EAAE,EAAE,OAAO,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAA;CAClG;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC5B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,OAAO,EAAE,OAAO,KAAK,EACrB,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GACxC,OAAO,CAAC,cAAc,CAAC,CA2BzB;AAgBD;;;;GAIG;AACH,wBAAsB,gBAAgB,CAClC,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CAAO,GAC3C,OAAO,CAAC,MAAM,CAAC,CA0CjB;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAiBD,wBAAsB,cAAc,CAChC,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CAAO,GAC7E,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED,iBAAe,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAqB1C;AAED,eAAe,WAAW,CAAA"}
|
package/dist/global-setup.js
CHANGED
|
@@ -15,7 +15,7 @@ export const MINIMUM_API_VERSION = 1;
|
|
|
15
15
|
* The body is read whatever the status: an unhealthy site still reports its
|
|
16
16
|
* version, and "too old" is a different problem from "unhealthy".
|
|
17
17
|
*/
|
|
18
|
-
async function readHealth(healthUrl, headers, doFetch, unreachable) {
|
|
18
|
+
export async function readHealth(healthUrl, headers, doFetch, unreachable) {
|
|
19
19
|
let response;
|
|
20
20
|
try {
|
|
21
21
|
response = await doFetch(healthUrl, {
|
|
@@ -69,7 +69,7 @@ export async function verifyApiVersion(config, options = {}) {
|
|
|
69
69
|
'The toolkit secret does not match the one the extension expects.',
|
|
70
70
|
'',
|
|
71
71
|
'Under DDEV both sides read var/playwright/api-secret, which',
|
|
72
|
-
'`ddev playwright
|
|
72
|
+
'`ddev playwright prepare` writes. Run it, or set PLAYWRIGHT_TOOLKIT_SECRET',
|
|
73
73
|
'to the same value on both sides when PHP and Node run in separate containers.',
|
|
74
74
|
].join('\n'));
|
|
75
75
|
}
|
|
@@ -87,9 +87,12 @@ export async function verifyApiVersion(config, options = {}) {
|
|
|
87
87
|
}
|
|
88
88
|
return reported;
|
|
89
89
|
}
|
|
90
|
+
export function isTestingContext(reported) {
|
|
91
|
+
return /^Testing(\/|$)/.test(reported);
|
|
92
|
+
}
|
|
90
93
|
/** Cannot fail while the endpoint itself is gated: here so a moved gate stops the run. */
|
|
91
94
|
function assertTestingContext(healthUrl, reported) {
|
|
92
|
-
if (undefined === reported ||
|
|
95
|
+
if (undefined === reported || isTestingContext(reported)) {
|
|
93
96
|
return;
|
|
94
97
|
}
|
|
95
98
|
throw new Error([
|