@rehearsal-labs/retest 0.1.0 → 0.3.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 +12 -5
- package/dist/agent/session.d.ts +21 -2
- package/dist/agent/session.d.ts.map +1 -1
- package/dist/agent/session.js +73 -11
- package/dist/api/app-page.d.ts +39 -3
- package/dist/api/app-page.d.ts.map +1 -1
- package/dist/api/app-page.js +108 -0
- package/dist/api/dialog.d.ts +38 -0
- package/dist/api/dialog.d.ts.map +1 -0
- package/dist/api/dialog.js +78 -0
- package/dist/api/drag.d.ts +32 -0
- package/dist/api/drag.d.ts.map +1 -0
- package/dist/api/drag.js +26 -0
- package/dist/api/files.d.ts +49 -0
- package/dist/api/files.d.ts.map +1 -0
- package/dist/api/files.js +168 -0
- package/dist/api/inbox.d.ts +97 -0
- package/dist/api/inbox.d.ts.map +1 -0
- package/dist/api/inbox.js +191 -0
- package/dist/api/locator-recipes.d.ts +1 -1
- package/dist/api/locator-recipes.d.ts.map +1 -1
- package/dist/api/locator-recipes.js +4 -3
- package/dist/api/page.d.ts +214 -4
- package/dist/api/page.d.ts.map +1 -1
- package/dist/api/route.d.ts +21 -0
- package/dist/api/route.d.ts.map +1 -0
- package/dist/api/route.js +99 -0
- package/dist/api/source-location.d.ts.map +1 -1
- package/dist/api/source-location.js +3 -1
- package/dist/api/test-run.d.ts +127 -1
- package/dist/api/test-run.d.ts.map +1 -1
- package/dist/api/test-run.js +293 -0
- package/dist/assertions/expect.d.ts +91 -2
- package/dist/assertions/expect.d.ts.map +1 -1
- package/dist/assertions/expect.js +98 -0
- package/dist/assertions/look-until.d.ts +5 -0
- package/dist/assertions/look-until.d.ts.map +1 -1
- package/dist/assertions/look-until.js +1 -1
- package/dist/assertions/poll-layout.d.ts +24 -0
- package/dist/assertions/poll-layout.d.ts.map +1 -0
- package/dist/assertions/poll-layout.js +63 -0
- package/dist/assertions/screenshot.d.ts +36 -0
- package/dist/assertions/screenshot.d.ts.map +1 -0
- package/dist/assertions/screenshot.js +125 -0
- package/dist/browser/accessibility.d.ts.map +1 -1
- package/dist/browser/accessibility.js +22 -1
- package/dist/browser/actionability.d.ts +9 -6
- package/dist/browser/actionability.d.ts.map +1 -1
- package/dist/browser/actionability.js +17 -8
- package/dist/browser/browser.d.ts.map +1 -1
- package/dist/browser/browser.js +15 -4
- package/dist/browser/builds.d.ts +35 -6
- package/dist/browser/builds.d.ts.map +1 -1
- package/dist/browser/builds.js +115 -16
- package/dist/browser/cdp/connection.d.ts +6 -0
- package/dist/browser/cdp/connection.d.ts.map +1 -1
- package/dist/browser/cdp/connection.js +8 -0
- package/dist/browser/cdp/transport.d.ts.map +1 -1
- package/dist/browser/cdp/transport.js +4 -4
- package/dist/browser/checked-state.d.ts +2 -2
- package/dist/browser/checked-state.d.ts.map +1 -1
- package/dist/browser/chromium-process.d.ts +32 -2
- package/dist/browser/chromium-process.d.ts.map +1 -1
- package/dist/browser/chromium-process.js +95 -17
- package/dist/browser/contract.d.ts +119 -5
- package/dist/browser/contract.d.ts.map +1 -1
- package/dist/browser/dialogs.d.ts +157 -0
- package/dist/browser/dialogs.d.ts.map +1 -0
- package/dist/browser/dialogs.js +271 -0
- package/dist/browser/downloads.d.ts +71 -0
- package/dist/browser/downloads.d.ts.map +1 -0
- package/dist/browser/downloads.js +253 -0
- package/dist/browser/drag.d.ts +50 -0
- package/dist/browser/drag.d.ts.map +1 -0
- package/dist/browser/drag.js +584 -0
- package/dist/browser/electron-window-watch.d.ts +32 -0
- package/dist/browser/electron-window-watch.d.ts.map +1 -0
- package/dist/browser/electron-window-watch.js +93 -0
- package/dist/browser/electron.d.ts +14 -3
- package/dist/browser/electron.d.ts.map +1 -1
- package/dist/browser/electron.js +57 -9
- package/dist/browser/element-queries.d.ts +51 -15
- package/dist/browser/element-queries.d.ts.map +1 -1
- package/dist/browser/element-queries.js +92 -13
- package/dist/browser/emulation.d.ts.map +1 -1
- package/dist/browser/emulation.js +7 -5
- package/dist/browser/executables.d.ts +16 -1
- package/dist/browser/executables.d.ts.map +1 -1
- package/dist/browser/executables.js +50 -18
- package/dist/browser/file-chooser.d.ts +75 -0
- package/dist/browser/file-chooser.d.ts.map +1 -0
- package/dist/browser/file-chooser.js +449 -0
- package/dist/browser/firefox/accessible-names.d.ts +5 -4
- package/dist/browser/firefox/accessible-names.d.ts.map +1 -1
- package/dist/browser/firefox/accessible-names.js +11 -6
- package/dist/browser/firefox/bridge.js +3 -2
- package/dist/browser/firefox/executable.d.ts +14 -14
- package/dist/browser/firefox/executable.d.ts.map +1 -1
- package/dist/browser/firefox/executable.js +29 -21
- package/dist/browser/firefox/input.d.ts +5 -0
- package/dist/browser/firefox/input.d.ts.map +1 -1
- package/dist/browser/firefox/input.js +6 -3
- package/dist/browser/firefox/launch.js +1 -1
- package/dist/browser/firefox/navigation.d.ts +5 -2
- package/dist/browser/firefox/navigation.d.ts.map +1 -1
- package/dist/browser/firefox/navigation.js +48 -14
- package/dist/browser/firefox/orphans.d.ts.map +1 -1
- package/dist/browser/firefox/orphans.js +34 -2
- package/dist/browser/firefox/page.d.ts +11 -1
- package/dist/browser/firefox/page.d.ts.map +1 -1
- package/dist/browser/firefox/page.js +179 -26
- package/dist/browser/firefox/process.d.ts +20 -1
- package/dist/browser/firefox/process.d.ts.map +1 -1
- package/dist/browser/firefox/process.js +124 -22
- package/dist/browser/firefox/profile.d.ts +5 -0
- package/dist/browser/firefox/profile.d.ts.map +1 -1
- package/dist/browser/firefox/profile.js +17 -1
- package/dist/browser/firefox/storage.d.ts.map +1 -1
- package/dist/browser/firefox/storage.js +4 -2
- package/dist/browser/firefox/subscriptions.d.ts +26 -0
- package/dist/browser/firefox/subscriptions.d.ts.map +1 -0
- package/dist/browser/firefox/subscriptions.js +10 -0
- package/dist/browser/frames.d.ts +205 -0
- package/dist/browser/frames.d.ts.map +1 -0
- package/dist/browser/frames.js +657 -0
- package/dist/browser/input-guard.d.ts +18 -5
- package/dist/browser/input-guard.d.ts.map +1 -1
- package/dist/browser/input-guard.js +65 -6
- package/dist/browser/isolated-world.d.ts +8 -1
- package/dist/browser/isolated-world.d.ts.map +1 -1
- package/dist/browser/launch.d.ts +6 -0
- package/dist/browser/launch.d.ts.map +1 -1
- package/dist/browser/launch.js +14 -1
- package/dist/browser/layout.d.ts +120 -0
- package/dist/browser/layout.d.ts.map +1 -0
- package/dist/browser/layout.js +213 -0
- package/dist/browser/locate.d.ts +10 -0
- package/dist/browser/locate.d.ts.map +1 -1
- package/dist/browser/locate.js +24 -6
- package/dist/browser/origin-document.d.ts +4 -0
- package/dist/browser/origin-document.d.ts.map +1 -1
- package/dist/browser/origin-document.js +9 -1
- package/dist/browser/page-scripts.d.ts +48 -0
- package/dist/browser/page-scripts.d.ts.map +1 -1
- package/dist/browser/page-scripts.js +515 -39
- package/dist/browser/page.d.ts +60 -1
- package/dist/browser/page.d.ts.map +1 -1
- package/dist/browser/page.js +275 -32
- package/dist/browser/popups.d.ts +166 -0
- package/dist/browser/popups.d.ts.map +1 -0
- package/dist/browser/popups.js +317 -0
- package/dist/browser/routes.d.ts +97 -0
- package/dist/browser/routes.d.ts.map +1 -0
- package/dist/browser/routes.js +226 -0
- package/dist/browser/screenshot.d.ts +44 -0
- package/dist/browser/screenshot.d.ts.map +1 -0
- package/dist/browser/screenshot.js +51 -0
- package/dist/browser/shadow-candidates.d.ts +20 -0
- package/dist/browser/shadow-candidates.d.ts.map +1 -0
- package/dist/browser/shadow-candidates.js +77 -0
- package/dist/browser/webkit/page.d.ts +11 -1
- package/dist/browser/webkit/page.d.ts.map +1 -1
- package/dist/browser/webkit/page.js +53 -2
- package/dist/browser/webkit/relay.d.ts.map +1 -1
- package/dist/browser/webkit/relay.js +5 -1
- package/dist/cli/commands/doctor.js +3 -3
- package/dist/cli/commands/inspect.js +3 -2
- package/dist/cli/commands/install.d.ts.map +1 -1
- package/dist/cli/commands/install.js +26 -13
- package/dist/cli/commands/licences.d.ts +22 -0
- package/dist/cli/commands/licences.d.ts.map +1 -1
- package/dist/cli/commands/licences.js +62 -20
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +4 -2
- package/dist/cli/doctor/checks.js +4 -1
- package/dist/cli/inspect/diagnostics.js +3 -3
- package/dist/cli/inspect/test-timeline.d.ts.map +1 -1
- package/dist/cli/inspect/test-timeline.js +45 -11
- package/dist/cli/install/doctor-rows.d.ts.map +1 -1
- package/dist/cli/install/doctor-rows.js +5 -4
- package/dist/cli/install/file-changes.d.ts +44 -0
- package/dist/cli/install/file-changes.d.ts.map +1 -0
- package/dist/cli/install/file-changes.js +81 -0
- package/dist/cli/install/install-archive.d.ts +3 -1
- package/dist/cli/install/install-archive.d.ts.map +1 -1
- package/dist/cli/install/install-archive.js +80 -33
- package/dist/cli/install/lock.d.ts.map +1 -1
- package/dist/cli/install/lock.js +108 -21
- package/dist/cli/install/media-doctor.d.ts.map +1 -1
- package/dist/cli/install/media-doctor.js +2 -1
- package/dist/cli/install/media-install.d.ts.map +1 -1
- package/dist/cli/install/media-install.js +38 -19
- package/dist/cli/install/media-pins.d.ts +7 -1
- package/dist/cli/install/media-pins.d.ts.map +1 -1
- package/dist/cli/install/media-pins.js +23 -12
- package/dist/cli/install/media-record.d.ts.map +1 -1
- package/dist/cli/install/media-record.js +10 -9
- package/dist/cli/install/media-report.d.ts +3 -1
- package/dist/cli/install/media-report.d.ts.map +1 -1
- package/dist/cli/install/media-report.js +7 -5
- package/dist/cli/install/media-tools.d.ts.map +1 -1
- package/dist/cli/install/media-tools.js +6 -4
- package/dist/cli/install/process-start.d.ts +3 -2
- package/dist/cli/install/process-start.d.ts.map +1 -1
- package/dist/cli/install/process-start.js +4 -0
- package/dist/cli/install/report.d.ts.map +1 -1
- package/dist/cli/install/report.js +11 -7
- package/dist/cli/install/supervisor-install.d.ts +33 -0
- package/dist/cli/install/supervisor-install.d.ts.map +1 -0
- package/dist/cli/install/supervisor-install.js +158 -0
- package/dist/cli/install/supervisor-locate.d.ts +47 -0
- package/dist/cli/install/supervisor-locate.d.ts.map +1 -0
- package/dist/cli/install/supervisor-locate.js +113 -0
- package/dist/cli/install/supervisor-pins.d.ts +21 -0
- package/dist/cli/install/supervisor-pins.d.ts.map +1 -0
- package/dist/cli/install/supervisor-pins.js +28 -0
- package/dist/cli/install/supervisor-record.d.ts +31 -0
- package/dist/cli/install/supervisor-record.d.ts.map +1 -0
- package/dist/cli/install/supervisor-record.js +104 -0
- package/dist/cli/install/supervisor-report.d.ts +11 -0
- package/dist/cli/install/supervisor-report.d.ts.map +1 -0
- package/dist/cli/install/supervisor-report.js +33 -0
- package/dist/cli/install/supervisor-tools.d.ts +43 -0
- package/dist/cli/install/supervisor-tools.d.ts.map +1 -0
- package/dist/cli/install/supervisor-tools.js +114 -0
- package/dist/cli/install/unpack.d.ts +23 -3
- package/dist/cli/install/unpack.d.ts.map +1 -1
- package/dist/cli/install/unpack.js +124 -10
- package/dist/cli/install/zip-member.d.ts +15 -0
- package/dist/cli/install/zip-member.d.ts.map +1 -0
- package/dist/cli/install/zip-member.js +77 -0
- package/dist/cli/interrupt.d.ts +1 -1
- package/dist/cli/interrupt.d.ts.map +1 -1
- package/dist/cli/interrupt.js +15 -10
- package/dist/cli/terminal.d.ts +9 -1
- package/dist/cli/terminal.d.ts.map +1 -1
- package/dist/cli/terminal.js +14 -0
- package/dist/config/define.d.ts +2 -2
- package/dist/config/define.js +2 -2
- package/dist/config/loaded.d.ts +12 -2
- package/dist/config/loaded.d.ts.map +1 -1
- package/dist/config/read-inboxes.d.ts +10 -0
- package/dist/config/read-inboxes.d.ts.map +1 -0
- package/dist/config/read-inboxes.js +78 -0
- package/dist/config/register.d.ts +5 -1
- package/dist/config/register.d.ts.map +1 -1
- package/dist/config/types.d.ts +36 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/validate.d.ts.map +1 -1
- package/dist/config/validate.js +4 -1
- package/dist/diagnostics/artifact.d.ts.map +1 -1
- package/dist/diagnostics/artifact.js +10 -2
- package/dist/diagnostics/attempt.d.ts +5 -0
- package/dist/diagnostics/attempt.d.ts.map +1 -1
- package/dist/diagnostics/attempt.js +10 -0
- package/dist/diagnostics/chromium-collector.d.ts +9 -1
- package/dist/diagnostics/chromium-collector.d.ts.map +1 -1
- package/dist/diagnostics/chromium-collector.js +19 -4
- package/dist/diagnostics/firefox-collector.d.ts +11 -10
- package/dist/diagnostics/firefox-collector.d.ts.map +1 -1
- package/dist/diagnostics/firefox-collector.js +16 -11
- package/dist/diagnostics/observations.d.ts +8 -0
- package/dist/diagnostics/observations.d.ts.map +1 -1
- package/dist/diagnostics/session-capture.d.ts.map +1 -1
- package/dist/diagnostics/session-capture.js +8 -0
- package/dist/index.d.ts +9 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/media/client.d.ts +2 -1
- package/dist/media/client.d.ts.map +1 -1
- package/dist/media/client.js +16 -5
- package/dist/media/host.d.ts +32 -0
- package/dist/media/host.d.ts.map +1 -0
- package/dist/media/host.js +50 -0
- package/dist/media/locate.d.ts.map +1 -1
- package/dist/media/locate.js +4 -3
- package/dist/media/policy.d.ts +2 -2
- package/dist/media/policy.d.ts.map +1 -1
- package/dist/media/policy.js +1 -1
- package/dist/native/processes.d.ts.map +1 -1
- package/dist/native/processes.js +7 -3
- package/dist/playwright/not-yet.d.ts.map +1 -1
- package/dist/playwright/not-yet.js +5 -2
- package/dist/protocol/commands.d.ts +122 -13
- package/dist/protocol/commands.d.ts.map +1 -1
- package/dist/protocol/commands.js +85 -6
- package/dist/protocol/diagnostics.d.ts +10 -0
- package/dist/protocol/diagnostics.d.ts.map +1 -1
- package/dist/protocol/diagnostics.js +5 -0
- package/dist/protocol/dialogs.d.ts +104 -0
- package/dist/protocol/dialogs.d.ts.map +1 -0
- package/dist/protocol/dialogs.js +101 -0
- package/dist/protocol/drag.d.ts +45 -0
- package/dist/protocol/drag.d.ts.map +1 -0
- package/dist/protocol/drag.js +31 -0
- package/dist/protocol/events.d.ts +153 -1
- package/dist/protocol/events.d.ts.map +1 -1
- package/dist/protocol/events.js +97 -0
- package/dist/protocol/files.d.ts +83 -0
- package/dist/protocol/files.d.ts.map +1 -0
- package/dist/protocol/files.js +73 -0
- package/dist/protocol/inbox.d.ts +87 -0
- package/dist/protocol/inbox.d.ts.map +1 -0
- package/dist/protocol/inbox.js +51 -0
- package/dist/protocol/index.d.ts +4 -1
- package/dist/protocol/index.d.ts.map +1 -1
- package/dist/protocol/layout-checks.d.ts +83 -0
- package/dist/protocol/layout-checks.d.ts.map +1 -0
- package/dist/protocol/layout-checks.js +214 -0
- package/dist/protocol/layout.d.ts +135 -0
- package/dist/protocol/layout.d.ts.map +1 -0
- package/dist/protocol/layout.js +124 -0
- package/dist/protocol/locator-checks.d.ts +19 -2
- package/dist/protocol/locator-checks.d.ts.map +1 -1
- package/dist/protocol/locator-checks.js +23 -1
- package/dist/protocol/locator.d.ts +55 -7
- package/dist/protocol/locator.d.ts.map +1 -1
- package/dist/protocol/locator.js +99 -18
- package/dist/protocol/messages.d.ts +95 -0
- package/dist/protocol/messages.d.ts.map +1 -1
- package/dist/protocol/messages.js +63 -0
- package/dist/protocol/popups.d.ts +43 -0
- package/dist/protocol/popups.d.ts.map +1 -0
- package/dist/protocol/popups.js +27 -0
- package/dist/protocol/result.d.ts +5 -0
- package/dist/protocol/result.d.ts.map +1 -1
- package/dist/protocol/result.js +1 -0
- package/dist/protocol/routes.d.ts +136 -0
- package/dist/protocol/routes.d.ts.map +1 -0
- package/dist/protocol/routes.js +191 -0
- package/dist/protocol/screenshot.d.ts +219 -0
- package/dist/protocol/screenshot.d.ts.map +1 -0
- package/dist/protocol/screenshot.js +335 -0
- package/dist/reporters/actions.d.ts +6 -4
- package/dist/reporters/actions.d.ts.map +1 -1
- package/dist/reporters/actions.js +24 -6
- package/dist/reporters/agent.d.ts.map +1 -1
- package/dist/reporters/agent.js +4 -2
- package/dist/reporters/commands.d.ts +12 -3
- package/dist/reporters/commands.d.ts.map +1 -1
- package/dist/reporters/commands.js +29 -11
- package/dist/reporters/dialogs-popups.d.ts +22 -0
- package/dist/reporters/dialogs-popups.d.ts.map +1 -0
- package/dist/reporters/dialogs-popups.js +30 -0
- package/dist/reporters/failure-card.d.ts +10 -1
- package/dist/reporters/failure-card.d.ts.map +1 -1
- package/dist/reporters/failure-card.js +5 -1
- package/dist/reporters/format.d.ts +33 -0
- package/dist/reporters/format.d.ts.map +1 -1
- package/dist/reporters/format.js +42 -0
- package/dist/reporters/html/comparison-view.d.ts +12 -0
- package/dist/reporters/html/comparison-view.d.ts.map +1 -0
- package/dist/reporters/html/comparison-view.js +21 -0
- package/dist/reporters/html/diagnostics-view.js +8 -0
- package/dist/reporters/html/downloads-view.d.ts +10 -0
- package/dist/reporters/html/downloads-view.d.ts.map +1 -0
- package/dist/reporters/html/downloads-view.js +29 -0
- package/dist/reporters/html/style.d.ts.map +1 -1
- package/dist/reporters/html/style.js +3 -0
- package/dist/reporters/html/summary-view.d.ts.map +1 -1
- package/dist/reporters/html/summary-view.js +3 -2
- package/dist/reporters/html/test-view.d.ts.map +1 -1
- package/dist/reporters/html/test-view.js +6 -3
- package/dist/reporters/html/timeline-view.d.ts.map +1 -1
- package/dist/reporters/html/timeline-view.js +26 -2
- package/dist/reporters/human-card.js +11 -1
- package/dist/reporters/human.d.ts +3 -1
- package/dist/reporters/human.d.ts.map +1 -1
- package/dist/reporters/human.js +11 -9
- package/dist/reporters/routes.d.ts +9 -0
- package/dist/reporters/routes.d.ts.map +1 -0
- package/dist/reporters/routes.js +17 -0
- package/dist/reporters/style.d.ts +21 -2
- package/dist/reporters/style.d.ts.map +1 -1
- package/dist/reporters/style.js +11 -2
- package/dist/runner/app-server.d.ts +27 -7
- package/dist/runner/app-server.d.ts.map +1 -1
- package/dist/runner/app-server.js +74 -24
- package/dist/runner/child-program.js +10 -0
- package/dist/runner/child.js +6 -2
- package/dist/runner/contract.d.ts +5 -0
- package/dist/runner/contract.d.ts.map +1 -1
- package/dist/runner/dialogs.d.ts +71 -0
- package/dist/runner/dialogs.d.ts.map +1 -0
- package/dist/runner/dialogs.js +189 -0
- package/dist/runner/files.d.ts +79 -0
- package/dist/runner/files.d.ts.map +1 -0
- package/dist/runner/files.js +312 -0
- package/dist/runner/inbox-links.d.ts +19 -0
- package/dist/runner/inbox-links.d.ts.map +1 -0
- package/dist/runner/inbox-links.js +63 -0
- package/dist/runner/inbox.d.ts +87 -0
- package/dist/runner/inbox.d.ts.map +1 -0
- package/dist/runner/inbox.js +340 -0
- package/dist/runner/index.d.ts +2 -1
- package/dist/runner/index.d.ts.map +1 -1
- package/dist/runner/media-leftovers.d.ts +7 -3
- package/dist/runner/media-leftovers.d.ts.map +1 -1
- package/dist/runner/media-leftovers.js +27 -6
- package/dist/runner/native-pool.d.ts.map +1 -1
- package/dist/runner/native-pool.js +2 -0
- package/dist/runner/observations.d.ts +15 -2
- package/dist/runner/observations.d.ts.map +1 -1
- package/dist/runner/observations.js +109 -6
- package/dist/runner/popups.d.ts +82 -0
- package/dist/runner/popups.d.ts.map +1 -0
- package/dist/runner/popups.js +236 -0
- package/dist/runner/redactor.d.ts.map +1 -1
- package/dist/runner/redactor.js +10 -6
- package/dist/runner/resources.d.ts +8 -0
- package/dist/runner/resources.d.ts.map +1 -1
- package/dist/runner/resources.js +12 -1
- package/dist/runner/routes.d.ts +23 -0
- package/dist/runner/routes.d.ts.map +1 -0
- package/dist/runner/routes.js +128 -0
- package/dist/runner/run-media.d.ts +6 -0
- package/dist/runner/run-media.d.ts.map +1 -1
- package/dist/runner/run-media.js +21 -0
- package/dist/runner/run-session.d.ts.map +1 -1
- package/dist/runner/run-session.js +102 -12
- package/dist/runner/run.d.ts.map +1 -1
- package/dist/runner/run.js +2 -1
- package/dist/runner/running-test.d.ts +35 -0
- package/dist/runner/running-test.d.ts.map +1 -1
- package/dist/runner/running-test.js +333 -22
- package/dist/runner/screenshot-baselines.d.ts +159 -0
- package/dist/runner/screenshot-baselines.d.ts.map +1 -0
- package/dist/runner/screenshot-baselines.js +357 -0
- package/dist/runner/secrets.d.ts +13 -0
- package/dist/runner/secrets.d.ts.map +1 -1
- package/dist/runner/secrets.js +6 -4
- package/dist/runner/target-drivers.d.ts +5 -2
- package/dist/runner/target-drivers.d.ts.map +1 -1
- package/dist/runner/target-drivers.js +10 -1
- package/dist/runner/test-file-process.d.ts +8 -0
- package/dist/runner/test-file-process.d.ts.map +1 -1
- package/dist/runner/test-file-process.js +26 -3
- package/dist/runner/test-pages.d.ts +3 -1
- package/dist/runner/test-pages.d.ts.map +1 -1
- package/dist/runner/test-pages.js +9 -5
- package/dist/schemas/event-v1.schema.json +118873 -6311
- package/dist/schemas/result-v1.schema.json +4 -0
- package/dist/shared/environment.d.ts +17 -0
- package/dist/shared/environment.d.ts.map +1 -0
- package/dist/shared/environment.js +27 -0
- package/dist/shared/image-diff.d.ts +36 -0
- package/dist/shared/image-diff.d.ts.map +1 -0
- package/dist/shared/image-diff.js +242 -0
- package/dist/shared/metadata-process-worker.js +15 -7
- package/dist/shared/metadata-process.d.ts +9 -1
- package/dist/shared/metadata-process.d.ts.map +1 -1
- package/dist/shared/metadata-process.js +84 -12
- package/dist/shared/png.d.ts +35 -0
- package/dist/shared/png.d.ts.map +1 -0
- package/dist/shared/png.js +251 -0
- package/dist/shared/posix-path.d.ts +12 -0
- package/dist/shared/posix-path.d.ts.map +1 -1
- package/dist/shared/posix-path.js +16 -0
- package/dist/shared/private-file.d.ts +38 -0
- package/dist/shared/private-file.d.ts.map +1 -0
- package/dist/shared/private-file.js +132 -0
- package/dist/shared/process-ownership.d.ts +67 -6
- package/dist/shared/process-ownership.d.ts.map +1 -1
- package/dist/shared/process-ownership.js +227 -45
- package/dist/shared/process-supervisor.d.ts +309 -0
- package/dist/shared/process-supervisor.d.ts.map +1 -0
- package/dist/shared/process-supervisor.js +737 -0
- package/dist/shared/process-system.d.ts +113 -0
- package/dist/shared/process-system.d.ts.map +1 -0
- package/dist/shared/process-system.js +254 -0
- package/dist/shared/regular-file.d.ts +2 -2
- package/dist/shared/regular-file.d.ts.map +1 -1
- package/dist/shared/regular-file.js +19 -2
- package/dist/store/artifacts.d.ts +28 -6
- package/dist/store/artifacts.d.ts.map +1 -1
- package/dist/store/artifacts.js +58 -6
- package/dist/store/rebuild-result.d.ts.map +1 -1
- package/dist/store/rebuild-result.js +6 -0
- package/dist/store/run-store.d.ts +5 -2
- package/dist/store/run-store.d.ts.map +1 -1
- package/dist/store/run-store.js +48 -4
- package/media/Cargo.lock +16 -0
- package/media/Cargo.toml +16 -1
- package/media/src/encoder.rs +56 -12
- package/media/src/frame.rs +7 -1
- package/media/src/main.rs +20 -2
- package/media/src/place.rs +230 -11
- package/media/src/process_ownership_windows.rs +1058 -0
- package/media/src/recording.rs +15 -7
- package/media/src/replies.rs +55 -0
- package/media/src/server.rs +72 -2
- package/media/src/store.rs +71 -2
- package/package.json +9 -4
- package/src/cli/install/media-notices.txt +465 -1
- package/supervisor/Cargo.lock +25 -0
- package/supervisor/Cargo.toml +22 -0
- package/supervisor/NOTICES +464 -0
- package/supervisor/build.rs +44 -0
- package/supervisor/src/command.rs +612 -0
- package/supervisor/src/jobs.rs +1650 -0
- package/supervisor/src/main.rs +71 -0
- package/supervisor/src/reply.rs +367 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { textPatternOf } from "../protocol/locator.js";
|
|
2
|
+
import { abortReasons, describeRoutePattern, routeAnswerProblem, routePatternProblem } from "../protocol/routes.js";
|
|
3
|
+
import { isPlainObject } from "../protocol/schema.js";
|
|
4
|
+
import { listWords } from "../shared/list-words.js";
|
|
5
|
+
import { formatValue } from "./format-value.js";
|
|
6
|
+
import { misuse } from "./misuse.js";
|
|
7
|
+
const fulfilKeys = new Set(['status', 'headers', 'contentType', 'body']);
|
|
8
|
+
/**
|
|
9
|
+
* Adds a route to the app's page: from now on every request of the page whose address `pattern` matches is answered
|
|
10
|
+
* with `answer`, before any route added earlier. Resolves once the page holds it.
|
|
11
|
+
*
|
|
12
|
+
* @example await route(page, 'http://127.0.0.1:4173/api/tasks', { status: 200, contentType: 'application/json', body: '[]' })
|
|
13
|
+
*/
|
|
14
|
+
export function route({ run, app }, pattern, answer) {
|
|
15
|
+
const location = run.location();
|
|
16
|
+
const read = readPattern(pattern, 'route', run);
|
|
17
|
+
const record = readAnswer(answer, run);
|
|
18
|
+
return run.changeRoutes({ app, label: `page.route(${describeRoutePattern(read)})`, request: { kind: 'add', pattern: read, answer: record }, location });
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Removes every route of the app's page added with `pattern`, written as it was. Resolves once the page holds the change.
|
|
22
|
+
*
|
|
23
|
+
* @example await unroute(page, 'http://127.0.0.1:4173/api/tasks')
|
|
24
|
+
*/
|
|
25
|
+
export function unroute({ run, app }, pattern) {
|
|
26
|
+
const location = run.location();
|
|
27
|
+
const read = readPattern(pattern, 'unroute', run);
|
|
28
|
+
return run.changeRoutes({ app, label: `page.unroute(${describeRoutePattern(read)})`, request: { kind: 'remove', pattern: read }, location });
|
|
29
|
+
}
|
|
30
|
+
function readPattern(pattern, method, run) {
|
|
31
|
+
const read = typeof pattern === 'string' ? pattern : pattern instanceof RegExp ? textPatternOf(pattern) : undefined;
|
|
32
|
+
if (read === undefined)
|
|
33
|
+
throw misuse(`page.${method}() takes a glob of the whole address, such as '**/api/tasks', or a RegExp, received ${formatValue(pattern)}.`, run);
|
|
34
|
+
const problem = routePatternProblem(read, method);
|
|
35
|
+
if (problem !== undefined)
|
|
36
|
+
throw misuse(problem, run);
|
|
37
|
+
return read;
|
|
38
|
+
}
|
|
39
|
+
// An answer is data, since no function crosses to the process that runs the browser: each part is read as the wire
|
|
40
|
+
// carries it, and a body of bytes goes as base64.
|
|
41
|
+
function readAnswer(answer, run) {
|
|
42
|
+
if (!isPlainObject(answer))
|
|
43
|
+
throw misuse(`page.route() takes an answer such as { status: 200, body: 'ok' } or { abort: 'connectionrefused' }, received ${formatValue(answer)}.`, run);
|
|
44
|
+
const given = Object.entries(answer).filter(([, value]) => value !== undefined);
|
|
45
|
+
const unknown = given.find(([key]) => key !== 'abort' && !fulfilKeys.has(key));
|
|
46
|
+
if (unknown !== undefined)
|
|
47
|
+
throw misuse(`page.route() has no answer option ${JSON.stringify(unknown[0])}. An answer takes status, headers, contentType and body, or abort.`, run);
|
|
48
|
+
const parts = Object.fromEntries(given);
|
|
49
|
+
if ('abort' in parts) {
|
|
50
|
+
if (given.length > 1)
|
|
51
|
+
throw misuse('page.route() takes an answer that gives a response or one that aborts the request, not both.', run);
|
|
52
|
+
const reason = abortReasons.find((each) => each === parts['abort']);
|
|
53
|
+
if (reason === undefined)
|
|
54
|
+
throw misuse(`page.route() takes abort as one of ${listWords(abortReasons.map((each) => `'${each}'`), 'or')}, received ${formatValue(parts['abort'])}.`, run);
|
|
55
|
+
return { abort: reason };
|
|
56
|
+
}
|
|
57
|
+
const record = { ...status(parts['status'], run), ...headers(parts['headers'], run), ...contentType(parts['contentType'], run), ...body(parts['body'], run) };
|
|
58
|
+
const problem = routeAnswerProblem(record);
|
|
59
|
+
if (problem !== undefined)
|
|
60
|
+
throw misuse(problem, run);
|
|
61
|
+
return record;
|
|
62
|
+
}
|
|
63
|
+
function status(value, run) {
|
|
64
|
+
if (value === undefined)
|
|
65
|
+
return {};
|
|
66
|
+
if (typeof value !== 'number')
|
|
67
|
+
throw misuse(`page.route() takes status as a number, such as 404, received ${formatValue(value)}.`, run);
|
|
68
|
+
return { status: value };
|
|
69
|
+
}
|
|
70
|
+
function headers(value, run) {
|
|
71
|
+
if (value === undefined)
|
|
72
|
+
return {};
|
|
73
|
+
const refused = () => misuse(`page.route() takes headers as names with text values, such as { 'x-total': '3' }, received ${formatValue(value)}.`, run);
|
|
74
|
+
if (!isPlainObject(value))
|
|
75
|
+
throw refused();
|
|
76
|
+
const read = {};
|
|
77
|
+
for (const [name, header] of Object.entries(value)) {
|
|
78
|
+
if (typeof header !== 'string')
|
|
79
|
+
throw refused();
|
|
80
|
+
read[name] = header;
|
|
81
|
+
}
|
|
82
|
+
return { headers: read };
|
|
83
|
+
}
|
|
84
|
+
function contentType(value, run) {
|
|
85
|
+
if (value === undefined)
|
|
86
|
+
return {};
|
|
87
|
+
if (typeof value !== 'string')
|
|
88
|
+
throw misuse(`page.route() takes contentType as text, such as 'application/json', received ${formatValue(value)}.`, run);
|
|
89
|
+
return { contentType: value };
|
|
90
|
+
}
|
|
91
|
+
function body(value, run) {
|
|
92
|
+
if (value === undefined)
|
|
93
|
+
return {};
|
|
94
|
+
if (typeof value === 'string')
|
|
95
|
+
return { body: value };
|
|
96
|
+
if (value instanceof Uint8Array)
|
|
97
|
+
return { base64: Buffer.from(value.buffer, value.byteOffset, value.byteLength).toString('base64') };
|
|
98
|
+
throw misuse(`page.route() takes a body as text or bytes, received ${formatValue(value)}.`, run);
|
|
99
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-location.d.ts","sourceRoot":"","sources":["../../src/api/source-location.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;
|
|
1
|
+
{"version":3,"file":"source-location.d.ts","sourceRoot":"","sources":["../../src/api/source-location.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAc7D;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAM1E;AAED,oGAAoG;AACpG,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAOvF;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,cAAc,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG3F"}
|
|
@@ -5,7 +5,9 @@ import { formatLine } from "../protocol/location.js";
|
|
|
5
5
|
import { relativePosixPath } from "../shared/posix-path.js";
|
|
6
6
|
// The folder holding this copy of Retest: `src` when run from source, `dist` when built.
|
|
7
7
|
const ownDirectory = fileURLToPath(new URL('../', import.meta.url));
|
|
8
|
-
|
|
8
|
+
// A frame names its script by a file URL or an absolute path: a POSIX one, or on Windows a drive or UNC path, as V8
|
|
9
|
+
// writes a frame a source map placed.
|
|
10
|
+
const stackFrame = /(?:\(|at )((?:file:\/\/)?\/[^()]*?|[A-Za-z]:[\\/][^()]*?|\\\\[^()]*?):(\d+):(\d+)\)?$/;
|
|
9
11
|
const maxFrames = 64;
|
|
10
12
|
/**
|
|
11
13
|
* Where the code that called into Retest sits: the first stack frame outside Retest's own files.
|
package/dist/api/test-run.d.ts
CHANGED
|
@@ -2,9 +2,16 @@ import type { ObserveAfter, CommandResult, PageCommand } from '../protocol/comma
|
|
|
2
2
|
import type { EvaluationAnswer, EvaluationCall } from '../protocol/evaluation.ts';
|
|
3
3
|
import type { ChildEvent } from '../protocol/events.ts';
|
|
4
4
|
import type { Failure, SourceLocation } from '../protocol/failures.ts';
|
|
5
|
+
import type { DialogAnswer, DialogRecord } from '../protocol/dialogs.ts';
|
|
6
|
+
import type { FilesAnswer, FilesRequest } from '../protocol/files.ts';
|
|
7
|
+
import type { RouteReply, RouteRequest } from '../protocol/routes.ts';
|
|
8
|
+
import type { InboxAnswer, InboxRequest, ReceivedMessageRecord } from '../protocol/inbox.ts';
|
|
9
|
+
import type { LayoutRequest } from '../protocol/layout-checks.ts';
|
|
5
10
|
import type { LocatorRecipe } from '../protocol/locator.ts';
|
|
6
11
|
import type { ChildMessage } from '../protocol/messages.ts';
|
|
12
|
+
import type { ScreenshotRequest } from '../protocol/screenshot.ts';
|
|
7
13
|
import type { Timeouts } from '../protocol/timeouts.ts';
|
|
14
|
+
import type { PopupAnswer, PopupRecord } from '../protocol/popups.ts';
|
|
8
15
|
import type { RunTime } from './run-time.ts';
|
|
9
16
|
import type { RunnableTest } from './test-body.ts';
|
|
10
17
|
import { RetestError } from './failure.ts';
|
|
@@ -27,6 +34,58 @@ export type TestRunOptions = {
|
|
|
27
34
|
/** The clock the test's budgets and durations count on, and the waits assertions poll with. The host's by default. */
|
|
28
35
|
time?: RunTime;
|
|
29
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* A read of an inbox as the test asked for it: the call as the test wrote it, what it asks for, where the test sent it
|
|
39
|
+
* from, and the time it gave itself with `{ timeout }`, when it gave one.
|
|
40
|
+
*/
|
|
41
|
+
export type InboxReading = {
|
|
42
|
+
readonly label: string;
|
|
43
|
+
readonly request: InboxRequest;
|
|
44
|
+
readonly location: SourceLocation | undefined;
|
|
45
|
+
readonly timeoutMs?: number;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* A wait the parent makes about files, as the test asked for it: the call as the test wrote it, what it waits for, where
|
|
49
|
+
* the test sent it from, and its time in milliseconds, before the test's own time left cuts it.
|
|
50
|
+
*/
|
|
51
|
+
export type FilesWaiting = {
|
|
52
|
+
readonly label: string;
|
|
53
|
+
readonly request: FilesRequest;
|
|
54
|
+
readonly location: SourceLocation | undefined;
|
|
55
|
+
readonly timeoutMs: number;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* A wait for what an action opens on an app's page, as the test asked for it: the app, the call as the test wrote it,
|
|
59
|
+
* where the test sent it from, the time it gave itself with `{ timeout }`, when it gave one, and the action, which the
|
|
60
|
+
* wait runs once the page is armed.
|
|
61
|
+
*/
|
|
62
|
+
export type OpeningWait = {
|
|
63
|
+
readonly app: string;
|
|
64
|
+
readonly label: string;
|
|
65
|
+
readonly location: SourceLocation | undefined;
|
|
66
|
+
readonly timeoutMs?: number | undefined;
|
|
67
|
+
readonly action: () => Promise<unknown>;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* An answer to a dialog the test was given: the app whose page shows it, its id, whether to accept it and the text a
|
|
71
|
+
* prompt takes, the call as the test wrote it and where, and the action that opened it, which the answer waits for.
|
|
72
|
+
*/
|
|
73
|
+
export type DialogAnswering = {
|
|
74
|
+
readonly app: string;
|
|
75
|
+
readonly dialog: string;
|
|
76
|
+
readonly accept: boolean;
|
|
77
|
+
readonly promptText?: string | undefined;
|
|
78
|
+
readonly label: string;
|
|
79
|
+
readonly location: SourceLocation | undefined;
|
|
80
|
+
readonly acted: Promise<void>;
|
|
81
|
+
};
|
|
82
|
+
/** A change to an app's routes, as the test asked for it: the app, the call as the test wrote it, and where it was sent from. */
|
|
83
|
+
export type RouteChange = {
|
|
84
|
+
readonly app: string;
|
|
85
|
+
readonly label: string;
|
|
86
|
+
readonly request: RouteRequest;
|
|
87
|
+
readonly location: SourceLocation | undefined;
|
|
88
|
+
};
|
|
30
89
|
/** How a test ended, as the child reports it. */
|
|
31
90
|
export type Verdict = {
|
|
32
91
|
status: 'passed' | 'failed';
|
|
@@ -35,7 +94,7 @@ export type Verdict = {
|
|
|
35
94
|
durationMs: number;
|
|
36
95
|
};
|
|
37
96
|
type ActionCommand = Exclude<PageCommand, {
|
|
38
|
-
kind: 'observe' | 'observePage';
|
|
97
|
+
kind: 'observe' | 'observePage' | 'observeLayout' | 'observeScreenshot';
|
|
39
98
|
}>;
|
|
40
99
|
/**
|
|
41
100
|
* One test running in the child. It runs the test's hooks and function, sends each app's commands one at a
|
|
@@ -78,6 +137,62 @@ export declare class TestRun {
|
|
|
78
137
|
* earlier test never reaches a later one.
|
|
79
138
|
*/
|
|
80
139
|
requestEvaluation(call: EvaluationCall, location: SourceLocation | undefined): Promise<EvaluationAnswer>;
|
|
140
|
+
/**
|
|
141
|
+
* Asks the parent to read an inbox. The parent reads the mailbox, looks again until a message arrives or the read's
|
|
142
|
+
* time runs out, and answers with the message, its codes and links hidden; `wrap` turns that answer into what the
|
|
143
|
+
* test receives. The read touches no page, so it holds no app, and it starts at once. Its time is its own `timeoutMs`,
|
|
144
|
+
* or the assertion budget, cut to what the test has left. It changes what the next read gives, so it may not run
|
|
145
|
+
* inside the function `expect.poll` calls.
|
|
146
|
+
*/
|
|
147
|
+
readInbox<T>({ label, request, location, timeoutMs }: InboxReading, wrap: (message: ReceivedMessageRecord) => T): Operation<T>;
|
|
148
|
+
resolveInbox(id: number, answer: InboxAnswer): void;
|
|
149
|
+
/**
|
|
150
|
+
* Asks the parent to arm an app's page for the next JavaScript dialog, runs the action once the page is armed, and
|
|
151
|
+
* resolves with what `wrap` makes of the dialog as soon as it opens. The action is still waiting then, since a page
|
|
152
|
+
* holds the input that opened a dialog until the dialog is answered; `wrap` is given the action's own promise, which
|
|
153
|
+
* settles once the action does. An action that fails before any dialog opened fails the wait with its own failure,
|
|
154
|
+
* and the parent stops waiting. A wait that sees no dialog in its time fails, unless its action failed meanwhile,
|
|
155
|
+
* whose failure it gives instead. The wait acts on a page, so it may not run inside the function `expect.poll` calls.
|
|
156
|
+
*/
|
|
157
|
+
waitForDialog<T>(wait: OpeningWait, wrap: (dialog: DialogRecord, acted: Promise<void>) => T): Operation<T>;
|
|
158
|
+
/**
|
|
159
|
+
* As `waitForDialog`, for the next page the action opens: the parent hands it over as an app of its own, and the wait
|
|
160
|
+
* resolves with what `wrap` makes of it once the action is over too, so the next command to the page that opened it
|
|
161
|
+
* never meets the action still running. An action that fails fails the wait with its own failure.
|
|
162
|
+
*/
|
|
163
|
+
waitForPopup<T>(wait: OpeningWait, wrap: (popup: PopupRecord) => T): Operation<T>;
|
|
164
|
+
/**
|
|
165
|
+
* Asks the parent to answer a dialog the test was given, then waits for the action that opened it, so the answer's
|
|
166
|
+
* step ends once its action has. An answer the parent could not give fails, and an action that failed fails it too,
|
|
167
|
+
* with its own failure. It acts on a page, so it may not run inside the function `expect.poll` calls.
|
|
168
|
+
*/
|
|
169
|
+
answerDialog({ app, dialog, accept, promptText, label, location, acted }: DialogAnswering): Operation<void>;
|
|
170
|
+
resolveDialog(id: number, answer: DialogAnswer): void;
|
|
171
|
+
resolvePopup(id: number, answer: PopupAnswer): void;
|
|
172
|
+
/**
|
|
173
|
+
* Asks the parent to wait for what `request` names, runs `action` meanwhile when one is given, and resolves with what
|
|
174
|
+
* `wrap` makes of the parent's answer once the action is over and the parent has answered. The wait holds no app, so
|
|
175
|
+
* the action's own commands go as they would without it; the request goes first, so the parent is waiting before
|
|
176
|
+
* the action's first command arrives. An action that fails fails the wait with its own failure, and the parent lets go
|
|
177
|
+
* of what it armed. A wait with an action acts on a page, so it may not run inside the function `expect.poll` calls.
|
|
178
|
+
*/
|
|
179
|
+
awaitFiles<T>({ label, request, location, timeoutMs }: FilesWaiting, wrap: (answer: Extract<FilesAnswer, {
|
|
180
|
+
ok: true;
|
|
181
|
+
}>) => T | Promise<T>, action?: () => unknown): Operation<T>;
|
|
182
|
+
resolveFiles(id: number, answer: FilesAnswer): void;
|
|
183
|
+
/**
|
|
184
|
+
* Asks the parent to change an app's routes, and resolves once the page holds the change, so the test's next command
|
|
185
|
+
* to the page meets it. It needs the app to itself, as an action does: a request already on its way when the routes
|
|
186
|
+
* change could meet either. Its time is the action budget, cut to what the test has left. It changes what the page's
|
|
187
|
+
* requests get, so it may not run inside the function `expect.poll` calls.
|
|
188
|
+
*/
|
|
189
|
+
changeRoutes({ app, label, request, location }: RouteChange): Operation<void>;
|
|
190
|
+
resolveRoute(id: number, answer: RouteReply): void;
|
|
191
|
+
/**
|
|
192
|
+
* The folder a path a test wrote is read against, as an import's is: that of the file the call came from, or the
|
|
193
|
+
* test's own file when the call's place is unknown.
|
|
194
|
+
*/
|
|
195
|
+
callerFolder(location: SourceLocation | undefined): string;
|
|
81
196
|
resolveEvaluation(id: number, answer: EvaluationAnswer): void;
|
|
82
197
|
emit(event: ChildEvent): void;
|
|
83
198
|
countAssertion(): void;
|
|
@@ -104,6 +219,17 @@ export declare class TestRun {
|
|
|
104
219
|
* change. The look is marked as a check's, as `observe` marks its own.
|
|
105
220
|
*/
|
|
106
221
|
observePage(app: string, timeoutMs: number, location: SourceLocation | undefined, after?: ObserveAfter): Promise<CommandResult>;
|
|
222
|
+
/**
|
|
223
|
+
* Measures an app's page once for a layout assertion: the elements `request` names, and their words when it asks. With
|
|
224
|
+
* `after`, the page first waits for its next change. The look is marked as a check's, as `observe` marks its own.
|
|
225
|
+
*/
|
|
226
|
+
observeLayout(app: string, request: LayoutRequest, timeoutMs: number, location: SourceLocation | undefined, after?: ObserveAfter): Promise<CommandResult>;
|
|
227
|
+
/**
|
|
228
|
+
* Takes a picture of an app's page, or of one element, for a screenshot assertion, and learns its size and how it
|
|
229
|
+
* stands against its baseline; the pixels stay with the parent. `previous` names the look before it in the same check,
|
|
230
|
+
* whose picture this one must match to have settled. The look is marked as a check's, as `observe` marks its own.
|
|
231
|
+
*/
|
|
232
|
+
observeScreenshot(app: string, request: ScreenshotRequest, previous: string | undefined, timeoutMs: number, location: SourceLocation | undefined): Promise<CommandResult>;
|
|
107
233
|
/**
|
|
108
234
|
* Reads an app's page once outside any check, its address and title, as `page.url()` and `page.title()` do inside
|
|
109
235
|
* `read`. No assertion follows such a look, so it is not marked as a check's.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-run.d.ts","sourceRoot":"","sources":["../../src/api/test-run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACvF,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AACjF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;
|
|
1
|
+
{"version":3,"file":"test-run.d.ts","sourceRoot":"","sources":["../../src/api/test-run.ts"],"names":[],"mappings":"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"}
|
package/dist/api/test-run.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { dirname, join } from 'node:path';
|
|
1
2
|
import { describeCommand } from "../protocol/commands.js";
|
|
2
3
|
import { Deadline, elapsedMs, smallestBudget } from "../protocol/deadline.js";
|
|
3
4
|
import { failure, withAlso, withLocation } from "../protocol/failures.js";
|
|
@@ -30,6 +31,13 @@ export class TestRun {
|
|
|
30
31
|
#failures = [];
|
|
31
32
|
#answers = new Map();
|
|
32
33
|
#evaluations = new Map();
|
|
34
|
+
#inboxReads = new Map();
|
|
35
|
+
// Waits for dialogs and popups and answers to dialogs, by id; a wait is answered more than once, armed then opened.
|
|
36
|
+
#pageWaits = new Map();
|
|
37
|
+
// The dialogs the test was given and has not answered yet, by id, with where it asked for each.
|
|
38
|
+
#dialogsOpen = new Map();
|
|
39
|
+
#filesRequests = new Map();
|
|
40
|
+
#routeChanges = new Map();
|
|
33
41
|
#lanes = new CommandLanes();
|
|
34
42
|
#aborted = Promise.withResolvers();
|
|
35
43
|
// Work created since the last function the test ran returned; each function answers for its own.
|
|
@@ -122,6 +130,246 @@ export class TestRun {
|
|
|
122
130
|
this.#options.send({ type: 'evaluate', testId: this.testId, attemptId: this.attemptId, id, call, ...(location === undefined ? {} : { location }), ...(stepId === undefined ? {} : { stepId }) });
|
|
123
131
|
return promise;
|
|
124
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Asks the parent to read an inbox. The parent reads the mailbox, looks again until a message arrives or the read's
|
|
135
|
+
* time runs out, and answers with the message, its codes and links hidden; `wrap` turns that answer into what the
|
|
136
|
+
* test receives. The read touches no page, so it holds no app, and it starts at once. Its time is its own `timeoutMs`,
|
|
137
|
+
* or the assertion budget, cut to what the test has left. It changes what the next read gives, so it may not run
|
|
138
|
+
* inside the function `expect.poll` calls.
|
|
139
|
+
*/
|
|
140
|
+
readInbox({ label, request, location, timeoutMs }, wrap) {
|
|
141
|
+
const work = { label, location };
|
|
142
|
+
const operation = this.#track('read', work);
|
|
143
|
+
const refusal = this.#refusal() ?? this.#whileReading(work);
|
|
144
|
+
if (refusal !== undefined) {
|
|
145
|
+
operation.reject(refusal);
|
|
146
|
+
return operation;
|
|
147
|
+
}
|
|
148
|
+
const id = this.#options.nextCommandId();
|
|
149
|
+
const stepId = currentScope()?.stepId;
|
|
150
|
+
this.#inboxReads.set(id, (answer) => {
|
|
151
|
+
if (answer.ok)
|
|
152
|
+
operation.resolve(wrap(answer.message));
|
|
153
|
+
else
|
|
154
|
+
operation.reject(this.fail(withLocation(answer.failure, location)));
|
|
155
|
+
});
|
|
156
|
+
const budget = this.assertionBudget(timeoutMs ?? this.timeouts.assertion);
|
|
157
|
+
this.#options.send({ type: 'inbox', testId: this.testId, attemptId: this.attemptId, id, request, timeoutMs: budget, ...(location === undefined ? {} : { location }), ...(stepId === undefined ? {} : { stepId }) });
|
|
158
|
+
return operation;
|
|
159
|
+
}
|
|
160
|
+
resolveInbox(id, answer) {
|
|
161
|
+
const resolve = this.#inboxReads.get(id);
|
|
162
|
+
if (resolve === undefined)
|
|
163
|
+
return;
|
|
164
|
+
this.#inboxReads.delete(id);
|
|
165
|
+
resolve(answer);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Asks the parent to arm an app's page for the next JavaScript dialog, runs the action once the page is armed, and
|
|
169
|
+
* resolves with what `wrap` makes of the dialog as soon as it opens. The action is still waiting then, since a page
|
|
170
|
+
* holds the input that opened a dialog until the dialog is answered; `wrap` is given the action's own promise, which
|
|
171
|
+
* settles once the action does. An action that fails before any dialog opened fails the wait with its own failure,
|
|
172
|
+
* and the parent stops waiting. A wait that sees no dialog in its time fails, unless its action failed meanwhile,
|
|
173
|
+
* whose failure it gives instead. The wait acts on a page, so it may not run inside the function `expect.poll` calls.
|
|
174
|
+
*/
|
|
175
|
+
waitForDialog(wait, wrap) {
|
|
176
|
+
return this.#waitForOpening('dialog', wait, (answer, acted) => {
|
|
177
|
+
if (!('dialog' in answer))
|
|
178
|
+
throw new Error('Retest answered a wait for a dialog with a page');
|
|
179
|
+
this.#dialogsOpen.set(answer.dialog.id, { type: answer.dialog.type, location: wait.location });
|
|
180
|
+
return wrap(answer.dialog, acted);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* As `waitForDialog`, for the next page the action opens: the parent hands it over as an app of its own, and the wait
|
|
185
|
+
* resolves with what `wrap` makes of it once the action is over too, so the next command to the page that opened it
|
|
186
|
+
* never meets the action still running. An action that fails fails the wait with its own failure.
|
|
187
|
+
*/
|
|
188
|
+
waitForPopup(wait, wrap) {
|
|
189
|
+
return this.#waitForOpening('popup', wait, async (answer, acted) => {
|
|
190
|
+
if (!('popup' in answer))
|
|
191
|
+
throw new Error('Retest answered a wait for a page with a dialog');
|
|
192
|
+
await acted;
|
|
193
|
+
return wrap(answer.popup);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Asks the parent to answer a dialog the test was given, then waits for the action that opened it, so the answer's
|
|
198
|
+
* step ends once its action has. An answer the parent could not give fails, and an action that failed fails it too,
|
|
199
|
+
* with its own failure. It acts on a page, so it may not run inside the function `expect.poll` calls.
|
|
200
|
+
*/
|
|
201
|
+
answerDialog({ app, dialog, accept, promptText, label, location, acted }) {
|
|
202
|
+
const work = { label, location };
|
|
203
|
+
const operation = this.#track('read', work);
|
|
204
|
+
const refusal = this.#refusal() ?? this.#whileReading(work);
|
|
205
|
+
if (refusal !== undefined) {
|
|
206
|
+
operation.reject(refusal);
|
|
207
|
+
return operation;
|
|
208
|
+
}
|
|
209
|
+
this.#dialogsOpen.delete(dialog);
|
|
210
|
+
const id = this.#options.nextCommandId();
|
|
211
|
+
const stepId = currentScope()?.stepId;
|
|
212
|
+
this.#pageWaits.set(id, (answer) => {
|
|
213
|
+
this.#pageWaits.delete(id);
|
|
214
|
+
if (answer.kind === 'answered')
|
|
215
|
+
acted.then(() => operation.resolve(), (error) => operation.reject(error));
|
|
216
|
+
else if (answer.kind === 'failed')
|
|
217
|
+
operation.reject(this.fail(withLocation(answer.failure, location)));
|
|
218
|
+
});
|
|
219
|
+
const request = { kind: 'answer', dialog, accept, ...(promptText === undefined ? {} : { promptText }) };
|
|
220
|
+
const timeoutMs = this.assertionBudget(this.timeouts.action);
|
|
221
|
+
this.#options.send({ type: 'dialog', testId: this.testId, attemptId: this.attemptId, id, app, request, timeoutMs, ...(location === undefined ? {} : { location }), ...(stepId === undefined ? {} : { stepId }) });
|
|
222
|
+
return operation;
|
|
223
|
+
}
|
|
224
|
+
resolveDialog(id, answer) {
|
|
225
|
+
this.#pageWaits.get(id)?.(answer);
|
|
226
|
+
}
|
|
227
|
+
resolvePopup(id, answer) {
|
|
228
|
+
this.#pageWaits.get(id)?.(answer);
|
|
229
|
+
}
|
|
230
|
+
// The wait is armed before the action runs, so the parent hands over what the action's first command opens. The
|
|
231
|
+
// answer to the request comes on another turn, so the action runs in the scope the test called from, as its step.
|
|
232
|
+
#waitForOpening(kind, { app, label, location, timeoutMs, action }, take) {
|
|
233
|
+
const work = { label, location };
|
|
234
|
+
const operation = this.#track('read', work);
|
|
235
|
+
const refusal = this.#refusal() ?? this.#whileReading(work);
|
|
236
|
+
if (refusal !== undefined) {
|
|
237
|
+
operation.reject(refusal);
|
|
238
|
+
return operation;
|
|
239
|
+
}
|
|
240
|
+
const scope = currentScope() ?? { run: this };
|
|
241
|
+
const id = this.#options.nextCommandId();
|
|
242
|
+
const sending = { app, location, stepId: scope.stepId };
|
|
243
|
+
let acted;
|
|
244
|
+
let opened = false;
|
|
245
|
+
const fail = (problem) => operation.reject(this.fail(withLocation(problem, location)));
|
|
246
|
+
this.#pageWaits.set(id, (answer) => {
|
|
247
|
+
if (answer.kind === 'armed') {
|
|
248
|
+
const running = callInScope(scope, action).then(() => undefined);
|
|
249
|
+
acted = running;
|
|
250
|
+
running.then(undefined, (error) => {
|
|
251
|
+
if (opened)
|
|
252
|
+
return;
|
|
253
|
+
this.#pageWaits.delete(id);
|
|
254
|
+
this.#sendWait(kind, this.#options.nextCommandId(), { kind: 'stop', wait: id }, 1, sending);
|
|
255
|
+
operation.reject(error);
|
|
256
|
+
});
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
this.#pageWaits.delete(id);
|
|
260
|
+
if (answer.kind === 'opened') {
|
|
261
|
+
opened = true;
|
|
262
|
+
// The action may still be running: `take` is given its promise, so its own end is never lost.
|
|
263
|
+
const settled = acted ?? Promise.resolve();
|
|
264
|
+
Promise.resolve()
|
|
265
|
+
.then(() => take(answer, settled))
|
|
266
|
+
.then((value) => operation.resolve(value), (error) => operation.reject(error));
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
if (answer.kind !== 'failed')
|
|
270
|
+
return;
|
|
271
|
+
// The action's own failure says more than a wait that saw nothing while the action ran.
|
|
272
|
+
if (acted === undefined)
|
|
273
|
+
fail(answer.failure);
|
|
274
|
+
else
|
|
275
|
+
acted.then(() => fail(answer.failure), (error) => operation.reject(error));
|
|
276
|
+
});
|
|
277
|
+
this.#sendWait(kind, id, { kind: 'wait' }, this.assertionBudget(timeoutMs ?? this.timeouts.action), sending);
|
|
278
|
+
return operation;
|
|
279
|
+
}
|
|
280
|
+
#sendWait(kind, id, request, timeoutMs, { app, location, stepId }) {
|
|
281
|
+
const scope = { testId: this.testId, attemptId: this.attemptId, id, app, timeoutMs, ...(location === undefined ? {} : { location }), ...(stepId === undefined ? {} : { stepId }) };
|
|
282
|
+
this.#options.send(kind === 'dialog' ? { type: 'dialog', ...scope, request } : { type: 'popup', ...scope, request });
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Asks the parent to wait for what `request` names, runs `action` meanwhile when one is given, and resolves with what
|
|
286
|
+
* `wrap` makes of the parent's answer once the action is over and the parent has answered. The wait holds no app, so
|
|
287
|
+
* the action's own commands go as they would without it; the request goes first, so the parent is waiting before
|
|
288
|
+
* the action's first command arrives. An action that fails fails the wait with its own failure, and the parent lets go
|
|
289
|
+
* of what it armed. A wait with an action acts on a page, so it may not run inside the function `expect.poll` calls.
|
|
290
|
+
*/
|
|
291
|
+
awaitFiles({ label, request, location, timeoutMs }, wrap, action) {
|
|
292
|
+
const work = { label, location };
|
|
293
|
+
const operation = this.#track('read', work);
|
|
294
|
+
const refusal = this.#refusal() ?? (action === undefined ? undefined : this.#whileReading(work));
|
|
295
|
+
if (refusal !== undefined) {
|
|
296
|
+
operation.reject(refusal);
|
|
297
|
+
return operation;
|
|
298
|
+
}
|
|
299
|
+
const id = this.#sendFiles(request, smallestBudget(timeoutMs, this.#deadline.commandTimeoutMs), location);
|
|
300
|
+
const answered = new Promise((resolve) => this.#filesRequests.set(id, resolve));
|
|
301
|
+
started(action).then(async () => {
|
|
302
|
+
const answer = await answered;
|
|
303
|
+
if (!answer.ok)
|
|
304
|
+
return operation.reject(this.fail(withLocation(answer.failure, location)));
|
|
305
|
+
try {
|
|
306
|
+
operation.resolve(await wrap(answer));
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
operation.reject(error);
|
|
310
|
+
}
|
|
311
|
+
}, (error) => {
|
|
312
|
+
this.#filesRequests.delete(id);
|
|
313
|
+
this.#sendFiles({ kind: 'release', request: id }, 1, location);
|
|
314
|
+
operation.reject(error);
|
|
315
|
+
});
|
|
316
|
+
return operation;
|
|
317
|
+
}
|
|
318
|
+
resolveFiles(id, answer) {
|
|
319
|
+
const resolve = this.#filesRequests.get(id);
|
|
320
|
+
if (resolve === undefined)
|
|
321
|
+
return;
|
|
322
|
+
this.#filesRequests.delete(id);
|
|
323
|
+
resolve(answer);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Asks the parent to change an app's routes, and resolves once the page holds the change, so the test's next command
|
|
327
|
+
* to the page meets it. It needs the app to itself, as an action does: a request already on its way when the routes
|
|
328
|
+
* change could meet either. Its time is the action budget, cut to what the test has left. It changes what the page's
|
|
329
|
+
* requests get, so it may not run inside the function `expect.poll` calls.
|
|
330
|
+
*/
|
|
331
|
+
changeRoutes({ app, label, request, location }) {
|
|
332
|
+
const work = { label, location };
|
|
333
|
+
const operation = this.#track('read', work);
|
|
334
|
+
const refusal = this.#refusal() ?? this.#whileReading(work) ?? this.#clash(app, work, 'action');
|
|
335
|
+
if (refusal !== undefined) {
|
|
336
|
+
operation.reject(refusal);
|
|
337
|
+
return operation;
|
|
338
|
+
}
|
|
339
|
+
this.#lanes.startAction(app, work);
|
|
340
|
+
const id = this.#options.nextCommandId();
|
|
341
|
+
const stepId = currentScope()?.stepId;
|
|
342
|
+
this.#routeChanges.set(id, (answer) => {
|
|
343
|
+
this.#lanes.endAction(app, work);
|
|
344
|
+
if (answer.ok)
|
|
345
|
+
operation.resolve();
|
|
346
|
+
else
|
|
347
|
+
operation.reject(this.fail(withLocation(answer.failure, location)));
|
|
348
|
+
});
|
|
349
|
+
const timeoutMs = this.assertionBudget(this.timeouts.action);
|
|
350
|
+
this.#options.send({ type: 'route', testId: this.testId, attemptId: this.attemptId, id, app, request, timeoutMs, ...(location === undefined ? {} : { location }), ...(stepId === undefined ? {} : { stepId }) });
|
|
351
|
+
return operation;
|
|
352
|
+
}
|
|
353
|
+
resolveRoute(id, answer) {
|
|
354
|
+
const resolve = this.#routeChanges.get(id);
|
|
355
|
+
if (resolve === undefined)
|
|
356
|
+
return;
|
|
357
|
+
this.#routeChanges.delete(id);
|
|
358
|
+
resolve(answer);
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* The folder a path a test wrote is read against, as an import's is: that of the file the call came from, or the
|
|
362
|
+
* test's own file when the call's place is unknown.
|
|
363
|
+
*/
|
|
364
|
+
callerFolder(location) {
|
|
365
|
+
return dirname(join(this.#options.rootDir, location?.file ?? this.#options.file));
|
|
366
|
+
}
|
|
367
|
+
#sendFiles(request, timeoutMs, location) {
|
|
368
|
+
const id = this.#options.nextCommandId();
|
|
369
|
+
const stepId = currentScope()?.stepId;
|
|
370
|
+
this.#options.send({ type: 'files', testId: this.testId, attemptId: this.attemptId, id, request, timeoutMs, ...(location === undefined ? {} : { location }), ...(stepId === undefined ? {} : { stepId }) });
|
|
371
|
+
return id;
|
|
372
|
+
}
|
|
125
373
|
resolveEvaluation(id, answer) {
|
|
126
374
|
const resolve = this.#evaluations.get(id);
|
|
127
375
|
if (resolve === undefined)
|
|
@@ -201,6 +449,27 @@ export class TestRun {
|
|
|
201
449
|
return Promise.resolve({ ok: false, failure: refusal.failure });
|
|
202
450
|
return this.#send(app, { kind: 'observePage', ...(after === undefined ? {} : { after }), check: true }, { timeoutMs, location });
|
|
203
451
|
}
|
|
452
|
+
/**
|
|
453
|
+
* Measures an app's page once for a layout assertion: the elements `request` names, and their words when it asks. With
|
|
454
|
+
* `after`, the page first waits for its next change. The look is marked as a check's, as `observe` marks its own.
|
|
455
|
+
*/
|
|
456
|
+
observeLayout(app, request, timeoutMs, location, after) {
|
|
457
|
+
const refusal = this.#refusal();
|
|
458
|
+
if (refusal !== undefined)
|
|
459
|
+
return Promise.resolve({ ok: false, failure: refusal.failure });
|
|
460
|
+
return this.#send(app, { kind: 'observeLayout', ...request, ...(after === undefined ? {} : { after }), check: true }, { timeoutMs, location });
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Takes a picture of an app's page, or of one element, for a screenshot assertion, and learns its size and how it
|
|
464
|
+
* stands against its baseline; the pixels stay with the parent. `previous` names the look before it in the same check,
|
|
465
|
+
* whose picture this one must match to have settled. The look is marked as a check's, as `observe` marks its own.
|
|
466
|
+
*/
|
|
467
|
+
observeScreenshot(app, request, previous, timeoutMs, location) {
|
|
468
|
+
const refusal = this.#refusal();
|
|
469
|
+
if (refusal !== undefined)
|
|
470
|
+
return Promise.resolve({ ok: false, failure: refusal.failure });
|
|
471
|
+
return this.#send(app, { kind: 'observeScreenshot', ...request, ...(previous === undefined ? {} : { previous }), check: true }, { timeoutMs, location });
|
|
472
|
+
}
|
|
204
473
|
/**
|
|
205
474
|
* Reads an app's page once outside any check, its address and title, as `page.url()` and `page.title()` do inside
|
|
206
475
|
* `read`. No assertion follows such a look, so it is not marked as a check's.
|
|
@@ -291,6 +560,8 @@ export class TestRun {
|
|
|
291
560
|
await yieldToEventLoop();
|
|
292
561
|
if (ending.kind === 'threw')
|
|
293
562
|
this.recordThrown(ending.error);
|
|
563
|
+
for (const problem of this.#dialogsLeftOpen(what))
|
|
564
|
+
this.record(problem);
|
|
294
565
|
for (const problem of this.#unfinishedWork(what))
|
|
295
566
|
this.record(problem);
|
|
296
567
|
return ending;
|
|
@@ -400,6 +671,15 @@ export class TestRun {
|
|
|
400
671
|
#isRecorded(error) {
|
|
401
672
|
return error instanceof RetestError && this.#failures.includes(error.failure);
|
|
402
673
|
}
|
|
674
|
+
// A dialog the test was given and never answered holds its page, and the action that opened it cannot finish.
|
|
675
|
+
#dialogsLeftOpen(what) {
|
|
676
|
+
const open = [...this.#dialogsOpen.values()];
|
|
677
|
+
this.#dialogsOpen.clear();
|
|
678
|
+
return open.map(({ type, location }) => {
|
|
679
|
+
const message = `The ${type} dialog page.dialog() gave on ${this.describeLine(location)} was still open when ${what} returned. Answer it with dialog.accept() or dialog.dismiss().`;
|
|
680
|
+
return failure('not_awaited', message, location);
|
|
681
|
+
});
|
|
682
|
+
}
|
|
403
683
|
// Judges the work created since the last function returned, then forgets it.
|
|
404
684
|
#unfinishedWork(what) {
|
|
405
685
|
const tracked = this.#tracked;
|
|
@@ -431,10 +711,23 @@ function calledMethod(command) {
|
|
|
431
711
|
return `keyboard.${command.operation}`;
|
|
432
712
|
case 'nativeAlert':
|
|
433
713
|
return `alert.${command.operation}`;
|
|
714
|
+
case 'setChooserFiles':
|
|
715
|
+
return 'setFiles';
|
|
434
716
|
default:
|
|
435
717
|
return command.kind;
|
|
436
718
|
}
|
|
437
719
|
}
|
|
720
|
+
// A function the test passed, started at once; what it throws as it starts is its failure, as what it rejects with is.
|
|
721
|
+
function started(action) {
|
|
722
|
+
if (action === undefined)
|
|
723
|
+
return Promise.resolve();
|
|
724
|
+
try {
|
|
725
|
+
return Promise.resolve(action());
|
|
726
|
+
}
|
|
727
|
+
catch (error) {
|
|
728
|
+
return Promise.reject(error);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
438
731
|
function lineOrNull(location) {
|
|
439
732
|
return location === undefined ? null : formatLine(location);
|
|
440
733
|
}
|