@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.
Files changed (58) hide show
  1. package/README.md +74 -5
  2. package/dist/builders/content-builder.d.ts +2 -2
  3. package/dist/builders/content-builder.d.ts.map +1 -1
  4. package/dist/builders/content-builder.js +4 -4
  5. package/dist/builders/content-builder.js.map +1 -1
  6. package/dist/builders/core-content.d.ts +4 -4
  7. package/dist/builders/core-content.d.ts.map +1 -1
  8. package/dist/builders/core-content.js +8 -8
  9. package/dist/builders/core-content.js.map +1 -1
  10. package/dist/builders/page-builder.d.ts +1 -1
  11. package/dist/builders/page-builder.d.ts.map +1 -1
  12. package/dist/builders/page-builder.js +2 -2
  13. package/dist/builders/page-builder.js.map +1 -1
  14. package/dist/builders/relations.d.ts +3 -3
  15. package/dist/builders/relations.d.ts.map +1 -1
  16. package/dist/builders/relations.js +7 -6
  17. package/dist/builders/relations.js.map +1 -1
  18. package/dist/checks/screenshot.d.ts +7 -0
  19. package/dist/checks/screenshot.d.ts.map +1 -1
  20. package/dist/checks/screenshot.js +113 -8
  21. package/dist/checks/screenshot.js.map +1 -1
  22. package/dist/clean/cli.d.ts +3 -0
  23. package/dist/clean/cli.d.ts.map +1 -0
  24. package/dist/clean/cli.js +32 -0
  25. package/dist/clean/cli.js.map +1 -0
  26. package/dist/doctor/cli.d.ts +3 -0
  27. package/dist/doctor/cli.d.ts.map +1 -0
  28. package/dist/doctor/cli.js +41 -0
  29. package/dist/doctor/cli.js.map +1 -0
  30. package/dist/doctor/reporter.d.ts +22 -0
  31. package/dist/doctor/reporter.d.ts.map +1 -0
  32. package/dist/doctor/reporter.js +224 -0
  33. package/dist/doctor/reporter.js.map +1 -0
  34. package/dist/global-setup.d.ts +18 -0
  35. package/dist/global-setup.d.ts.map +1 -1
  36. package/dist/global-setup.js +6 -3
  37. package/dist/global-setup.js.map +1 -1
  38. package/dist/http/api-secret.js +1 -1
  39. package/dist/http/record-edit.d.ts.map +1 -1
  40. package/dist/http/record-edit.js +7 -6
  41. package/dist/http/record-edit.js.map +1 -1
  42. package/dist/inspect/cli.js +2 -2
  43. package/dist/inspect/links.d.ts +2 -0
  44. package/dist/inspect/links.d.ts.map +1 -1
  45. package/dist/inspect/links.js +8 -0
  46. package/dist/inspect/links.js.map +1 -1
  47. package/dist/media/media-manifest.d.ts +6 -0
  48. package/dist/media/media-manifest.d.ts.map +1 -0
  49. package/dist/media/media-manifest.js +31 -0
  50. package/dist/media/media-manifest.js.map +1 -0
  51. package/dist/playwright/base-config.d.ts.map +1 -1
  52. package/dist/playwright/base-config.js +3 -0
  53. package/dist/playwright/base-config.js.map +1 -1
  54. package/dist/state/run-namespace.d.ts +2 -0
  55. package/dist/state/run-namespace.d.ts.map +1 -1
  56. package/dist/state/run-namespace.js +1 -1
  57. package/dist/state/run-namespace.js.map +1 -1
  58. 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
- async function waitForImagesDecoded(page, timeout = 15000) {
46
- await page.evaluate(async (timeout) => {
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', () => resolve(), { once: true });
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 waitForImagesDecoded(page);
117
- // Playwright creates a missing reference itself and has --update-snapshots
118
- // for the rest; hand-building the snapshot path got the platform suffix
119
- // wrong off Linux.
120
- await expect(shot).toHaveScreenshot(`${name}.png`, comparisonOptions(wholePage, screenshotOptions));
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":"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"}
1
+ {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/checks/screenshot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -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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"}
@@ -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;AA4DpC;;;;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;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"}
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"}
@@ -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-prepare` writes. Run it, or set PLAYWRIGHT_TOOLKIT_SECRET',
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 || /^Testing(\/|$)/.test(reported)) {
95
+ if (undefined === reported || isTestingContext(reported)) {
93
96
  return;
94
97
  }
95
98
  throw new Error([