@e2edev/e2e 0.5.0 → 0.6.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 +64 -25
- package/dist/agent/act.d.ts +2 -2
- package/dist/agent/act.js +14 -37
- package/dist/agent/act.js.map +1 -1
- package/dist/agent/actions.d.ts +2 -2
- package/dist/agent/actions.d.ts.map +1 -1
- package/dist/agent/actions.js +1 -1
- package/dist/agent/ai-sdk.d.ts +1 -2
- package/dist/agent/ai-sdk.d.ts.map +1 -1
- package/dist/agent/ai-sdk.js +1 -2
- package/dist/agent/ai-sdk.js.map +1 -1
- package/dist/agent/default-agent.d.ts +10 -32
- package/dist/agent/default-agent.d.ts.map +1 -1
- package/dist/agent/default-agent.js +6 -13
- package/dist/agent/default-agent.js.map +1 -1
- package/dist/agent/derived.d.ts +1 -1
- package/dist/agent/derived.js +1 -1
- package/dist/agent/error.d.ts +2 -4
- package/dist/agent/error.d.ts.map +1 -1
- package/dist/agent/error.js +3 -5
- package/dist/agent/error.js.map +1 -1
- package/dist/agent/executor.d.ts +23 -52
- package/dist/agent/executor.d.ts.map +1 -1
- package/dist/agent/executor.js +1 -2
- package/dist/agent/executor.js.map +1 -1
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +10 -7
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/invocation.d.ts +8 -6
- package/dist/agent/invocation.d.ts.map +1 -1
- package/dist/agent/invocation.js +9 -4
- package/dist/agent/invocation.js.map +1 -1
- package/dist/agent/ledger.d.ts +17 -12
- package/dist/agent/ledger.d.ts.map +1 -1
- package/dist/agent/ledger.js +6 -9
- package/dist/agent/ledger.js.map +1 -1
- package/dist/agent/model/adapter.d.ts +7 -4
- package/dist/agent/model/adapter.d.ts.map +1 -1
- package/dist/agent/model/adapter.js +2 -2
- package/dist/agent/model/adapter.js.map +1 -1
- package/dist/agent/model/router.d.ts +1 -1
- package/dist/agent/model/router.d.ts.map +1 -1
- package/dist/agent/model/router.js +1 -1
- package/dist/agent/model/router.js.map +1 -1
- package/dist/agent/model/sdk.d.ts +11 -1
- package/dist/agent/model/sdk.d.ts.map +1 -1
- package/dist/agent/model/sdk.js +54 -10
- package/dist/agent/model/sdk.js.map +1 -1
- package/dist/agent/observation.d.ts +7 -7
- package/dist/agent/observation.d.ts.map +1 -1
- package/dist/agent/observation.js +7 -7
- package/dist/agent/observation.js.map +1 -1
- package/dist/agent/phases.d.ts +3 -3
- package/dist/agent/phases.d.ts.map +1 -1
- package/dist/agent/phases.js +4 -4
- package/dist/agent/phases.js.map +1 -1
- package/dist/agent/primitives.d.ts +4 -25
- package/dist/agent/primitives.d.ts.map +1 -1
- package/dist/agent/primitives.js +3 -36
- package/dist/agent/primitives.js.map +1 -1
- package/dist/agent/prompts.d.ts +1 -1
- package/dist/agent/prompts.js +1 -1
- package/dist/agent/protocol.d.ts +2 -3
- package/dist/agent/protocol.d.ts.map +1 -1
- package/dist/agent/protocol.js +2 -3
- package/dist/agent/protocol.js.map +1 -1
- package/dist/agent/public.d.ts +8 -10
- package/dist/agent/public.d.ts.map +1 -1
- package/dist/agent/public.js +7 -8
- package/dist/agent/public.js.map +1 -1
- package/dist/agent/replay.d.ts +2 -2
- package/dist/agent/replay.d.ts.map +1 -1
- package/dist/agent/replay.js +1 -1
- package/dist/agent/secrets.d.ts +3 -3
- package/dist/agent/secrets.d.ts.map +1 -1
- package/dist/agent/secrets.js +4 -4
- package/dist/agent/secrets.js.map +1 -1
- package/dist/agent/step-cache.d.ts +1 -1
- package/dist/agent/step-cache.d.ts.map +1 -1
- package/dist/agent/step-cache.js +7 -1
- package/dist/agent/step-cache.js.map +1 -1
- package/dist/agent/tool-loop.d.ts +9 -33
- package/dist/agent/tool-loop.d.ts.map +1 -1
- package/dist/agent/tool-loop.js +15 -38
- package/dist/agent/tool-loop.js.map +1 -1
- package/dist/agent/tool.d.ts +4 -5
- package/dist/agent/tool.d.ts.map +1 -1
- package/dist/agent/tool.js +2 -7
- package/dist/agent/tool.js.map +1 -1
- package/dist/cache/anchors.d.ts +2 -2
- package/dist/cache/anchors.d.ts.map +1 -1
- package/dist/cache/anchors.js +1 -1
- package/dist/cache/context.d.ts +6 -1
- package/dist/cache/context.d.ts.map +1 -1
- package/dist/cache/context.js +2 -1
- package/dist/cache/context.js.map +1 -1
- package/dist/cache/decide.d.ts +1 -1
- package/dist/cache/decide.js +1 -1
- package/dist/cache/identity.d.ts +9 -9
- package/dist/cache/identity.d.ts.map +1 -1
- package/dist/cache/identity.js +6 -6
- package/dist/cache/identity.js.map +1 -1
- package/dist/cache/recorder.d.ts +4 -2
- package/dist/cache/recorder.d.ts.map +1 -1
- package/dist/cache/recorder.js +10 -1
- package/dist/cache/recorder.js.map +1 -1
- package/dist/cache/relocate.d.ts +2 -2
- package/dist/cache/relocate.d.ts.map +1 -1
- package/dist/cache/relocate.js +1 -1
- package/dist/cache/store.d.ts +1 -1
- package/dist/cache/store.js +1 -1
- package/dist/cache/trace.d.ts +16 -1
- package/dist/cache/trace.d.ts.map +1 -1
- package/dist/cache/trace.js +22 -1
- package/dist/cache/trace.js.map +1 -1
- package/dist/cli/bin.js +9 -1
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/cache.d.ts +25 -0
- package/dist/cli/cache.d.ts.map +1 -0
- package/dist/cli/cache.js +249 -0
- package/dist/cli/cache.js.map +1 -0
- package/dist/cli/docs-url.d.ts +3 -0
- package/dist/cli/docs-url.d.ts.map +1 -0
- package/dist/cli/docs-url.js +3 -0
- package/dist/cli/docs-url.js.map +1 -0
- package/dist/cli/guide.d.ts +4 -0
- package/dist/cli/guide.d.ts.map +1 -0
- package/dist/cli/guide.js +16 -0
- package/dist/cli/guide.js.map +1 -0
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +211 -42
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init/agent-skill.d.ts +34 -0
- package/dist/cli/init/agent-skill.d.ts.map +1 -0
- package/dist/cli/init/agent-skill.js +44 -0
- package/dist/cli/init/agent-skill.js.map +1 -0
- package/dist/cli/init/{backends.d.ts → engines.d.ts} +39 -32
- package/dist/cli/init/engines.d.ts.map +1 -0
- package/dist/cli/init/{backends.js → engines.js} +43 -34
- package/dist/cli/init/engines.js.map +1 -0
- package/dist/cli/init/package.d.ts +19 -3
- package/dist/cli/init/package.d.ts.map +1 -1
- package/dist/cli/init/package.js +20 -20
- package/dist/cli/init/package.js.map +1 -1
- package/dist/cli/init/scaffold.d.ts +3 -3
- package/dist/cli/init/scaffold.d.ts.map +1 -1
- package/dist/cli/init/scaffold.js +13 -12
- package/dist/cli/init/scaffold.js.map +1 -1
- package/dist/cli/init.d.ts +14 -2
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +104 -25
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/signals.d.ts +5 -2
- package/dist/cli/signals.d.ts.map +1 -1
- package/dist/cli/signals.js +9 -3
- package/dist/cli/signals.js.map +1 -1
- package/dist/cli/skill.d.ts +16 -0
- package/dist/cli/skill.d.ts.map +1 -0
- package/dist/cli/skill.js +57 -0
- package/dist/cli/skill.js.map +1 -0
- package/dist/collect/collect.d.ts +40 -3
- package/dist/collect/collect.d.ts.map +1 -1
- package/dist/collect/collect.js +142 -19
- package/dist/collect/collect.js.map +1 -1
- package/dist/collect/registry.d.ts +1 -1
- package/dist/collect/registry.d.ts.map +1 -1
- package/dist/collect/registry.js +2 -2
- package/dist/collect/registry.js.map +1 -1
- package/dist/collect/select.d.ts +1 -1
- package/dist/collect/select.d.ts.map +1 -1
- package/dist/collect/select.js +81 -8
- package/dist/collect/select.js.map +1 -1
- package/dist/config/agent.d.ts +14 -2
- package/dist/config/agent.d.ts.map +1 -1
- package/dist/config/agent.js +36 -11
- package/dist/config/agent.js.map +1 -1
- package/dist/config/app.d.ts +76 -19
- package/dist/config/app.d.ts.map +1 -1
- package/dist/config/app.js +159 -104
- package/dist/config/app.js.map +1 -1
- package/dist/config/diagnose.d.ts +15 -0
- package/dist/config/diagnose.d.ts.map +1 -0
- package/dist/config/diagnose.js +122 -0
- package/dist/config/diagnose.js.map +1 -0
- package/dist/config/load.d.ts +9 -1
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +35 -3
- package/dist/config/load.js.map +1 -1
- package/dist/config/resolve.d.ts +8 -7
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +73 -40
- package/dist/config/resolve.js.map +1 -1
- package/dist/config/validate.d.ts +6 -2
- package/dist/config/validate.d.ts.map +1 -1
- package/dist/config/validate.js +20 -3
- package/dist/config/validate.js.map +1 -1
- package/dist/credentials.d.ts +1 -1
- package/dist/credentials.d.ts.map +1 -1
- package/dist/credentials.js +1 -1
- package/dist/credentials.js.map +1 -1
- package/dist/{backend → engine}/contract.d.ts +27 -19
- package/dist/engine/contract.d.ts.map +1 -0
- package/dist/{backend → engine}/contract.js +18 -18
- package/dist/engine/contract.js.map +1 -0
- package/dist/{backend → engine}/index.d.ts +141 -79
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/{backend → engine}/index.js +62 -37
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/session.d.ts +23 -0
- package/dist/engine/session.d.ts.map +1 -0
- package/dist/{backend → engine}/session.js +58 -51
- package/dist/engine/session.js.map +1 -0
- package/dist/{backend → engine}/surface.d.ts +11 -11
- package/dist/engine/surface.d.ts.map +1 -0
- package/dist/{backend → engine}/surface.js +2 -2
- package/dist/engine/surface.js.map +1 -0
- package/dist/engine/timing.d.ts.map +1 -0
- package/dist/engine/timing.js +8 -0
- package/dist/engine/timing.js.map +1 -0
- package/dist/expect/async.d.ts +1 -1
- package/dist/expect/async.d.ts.map +1 -1
- package/dist/expect/async.js +37 -1
- package/dist/expect/async.js.map +1 -1
- package/dist/expect/index.js +1 -1
- package/dist/expect/values.d.ts +1 -1
- package/dist/expect/values.d.ts.map +1 -1
- package/dist/expect/values.js +1 -1
- package/dist/expect/values.js.map +1 -1
- package/dist/index.d.ts +3 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -5
- package/dist/index.js.map +1 -1
- package/dist/internal/brands.d.ts +1 -1
- package/dist/internal/brands.d.ts.map +1 -1
- package/dist/internal/brands.js +1 -1
- package/dist/internal/brands.js.map +1 -1
- package/dist/internal/errors.d.ts +37 -19
- package/dist/internal/errors.d.ts.map +1 -1
- package/dist/internal/errors.js +94 -44
- package/dist/internal/errors.js.map +1 -1
- package/dist/internal/globs.d.ts +2 -2
- package/dist/internal/globs.d.ts.map +1 -1
- package/dist/internal/globs.js +2 -2
- package/dist/internal/globs.js.map +1 -1
- package/dist/internal/ids.d.ts +3 -3
- package/dist/internal/ids.d.ts.map +1 -1
- package/dist/internal/ids.js +3 -3
- package/dist/internal/ids.js.map +1 -1
- package/dist/internal/node-version.d.ts +10 -0
- package/dist/internal/node-version.d.ts.map +1 -0
- package/dist/internal/node-version.js +28 -0
- package/dist/internal/node-version.js.map +1 -0
- package/dist/internal/objects.d.ts +21 -0
- package/dist/internal/objects.d.ts.map +1 -0
- package/dist/internal/objects.js +14 -0
- package/dist/internal/objects.js.map +1 -0
- package/dist/internal/package-manager.d.ts +10 -0
- package/dist/internal/package-manager.d.ts.map +1 -0
- package/dist/internal/package-manager.js +43 -0
- package/dist/internal/package-manager.js.map +1 -0
- package/dist/internal/redact.d.ts +1 -1
- package/dist/internal/redact.d.ts.map +1 -1
- package/dist/internal/redact.js +1 -1
- package/dist/internal/redact.js.map +1 -1
- package/dist/internal/suggest.d.ts +16 -0
- package/dist/internal/suggest.d.ts.map +1 -0
- package/dist/internal/suggest.js +61 -0
- package/dist/internal/suggest.js.map +1 -0
- package/dist/internal/text.d.ts +1 -1
- package/dist/internal/text.d.ts.map +1 -1
- package/dist/internal/text.js +1 -1
- package/dist/internal/text.js.map +1 -1
- package/dist/internal/urls.d.ts +3 -3
- package/dist/internal/urls.d.ts.map +1 -1
- package/dist/internal/urls.js +8 -3
- package/dist/internal/urls.js.map +1 -1
- package/dist/locator/engine.d.ts +7 -7
- package/dist/locator/engine.d.ts.map +1 -1
- package/dist/locator/engine.js +14 -14
- package/dist/locator/engine.js.map +1 -1
- package/dist/locator/expression.d.ts +5 -3
- package/dist/locator/expression.d.ts.map +1 -1
- package/dist/locator/expression.js +25 -5
- package/dist/locator/expression.js.map +1 -1
- package/dist/locator/screen.d.ts +1 -1
- package/dist/locator/screen.d.ts.map +1 -1
- package/dist/locator/screen.js +3 -3
- package/dist/locator/screen.js.map +1 -1
- package/dist/report/build.d.ts +10 -9
- package/dist/report/build.d.ts.map +1 -1
- package/dist/report/build.js +25 -22
- package/dist/report/build.js.map +1 -1
- package/dist/report/code-frame.d.ts +8 -4
- package/dist/report/code-frame.d.ts.map +1 -1
- package/dist/report/code-frame.js +23 -18
- package/dist/report/code-frame.js.map +1 -1
- package/dist/report/debug-steps.js +1 -1
- package/dist/report/debug-steps.js.map +1 -1
- package/dist/report/format.d.ts +73 -0
- package/dist/report/format.d.ts.map +1 -0
- package/dist/report/format.js +147 -0
- package/dist/report/format.js.map +1 -0
- package/dist/report/junit.d.ts +1 -1
- package/dist/report/junit.d.ts.map +1 -1
- package/dist/report/junit.js +1 -1
- package/dist/report/junit.js.map +1 -1
- package/dist/report/list.d.ts +96 -47
- package/dist/report/list.d.ts.map +1 -1
- package/dist/report/list.js +489 -244
- package/dist/report/list.js.map +1 -1
- package/dist/report/live-window.d.ts +28 -0
- package/dist/report/live-window.d.ts.map +1 -0
- package/dist/report/live-window.js +102 -0
- package/dist/report/live-window.js.map +1 -0
- package/dist/report/write.d.ts +1 -1
- package/dist/report/write.d.ts.map +1 -1
- package/dist/report/write.js +1 -1
- package/dist/report/write.js.map +1 -1
- package/dist/run/budget.d.ts +2 -2
- package/dist/run/budget.js +2 -2
- package/dist/run/declared-processes.d.ts +30 -0
- package/dist/run/declared-processes.d.ts.map +1 -0
- package/dist/run/declared-processes.js +61 -0
- package/dist/run/declared-processes.js.map +1 -0
- package/dist/run/events.d.ts +30 -2
- package/dist/run/events.d.ts.map +1 -1
- package/dist/run/events.js.map +1 -1
- package/dist/run/execute.d.ts +19 -16
- package/dist/run/execute.d.ts.map +1 -1
- package/dist/run/execute.js +65 -67
- package/dist/run/execute.js.map +1 -1
- package/dist/run/fixture-recording.d.ts +10 -4
- package/dist/run/fixture-recording.d.ts.map +1 -1
- package/dist/run/fixture-recording.js +19 -6
- package/dist/run/fixture-recording.js.map +1 -1
- package/dist/run/fixtures.d.ts +2 -2
- package/dist/run/fixtures.d.ts.map +1 -1
- package/dist/run/fixtures.js +72 -44
- package/dist/run/fixtures.js.map +1 -1
- package/dist/run/in-process.d.ts +1 -1
- package/dist/run/in-process.js +1 -1
- package/dist/run/managed-process.d.ts +46 -9
- package/dist/run/managed-process.d.ts.map +1 -1
- package/dist/run/managed-process.js +136 -50
- package/dist/run/managed-process.js.map +1 -1
- package/dist/run/realm.d.ts +2 -2
- package/dist/run/realm.js +2 -2
- package/dist/run/runner.d.ts +23 -1
- package/dist/run/runner.d.ts.map +1 -1
- package/dist/run/runner.js +111 -40
- package/dist/run/runner.js.map +1 -1
- package/dist/run/scheduler.d.ts +5 -5
- package/dist/run/scheduler.d.ts.map +1 -1
- package/dist/run/scheduler.js +7 -7
- package/dist/run/scheduler.js.map +1 -1
- package/dist/run/serial.d.ts +10 -2
- package/dist/run/serial.d.ts.map +1 -1
- package/dist/run/serial.js +5 -3
- package/dist/run/serial.js.map +1 -1
- package/dist/run/sessions.d.ts +10 -10
- package/dist/run/sessions.d.ts.map +1 -1
- package/dist/run/sessions.js +11 -11
- package/dist/run/sessions.js.map +1 -1
- package/dist/run/steps.d.ts +3 -3
- package/dist/run/steps.d.ts.map +1 -1
- package/dist/run/steps.js +1 -1
- package/dist/run/steps.js.map +1 -1
- package/dist/run/units.d.ts +1 -1
- package/dist/run/units.js +1 -1
- package/dist/run/worker/entry.d.ts +1 -1
- package/dist/run/worker/entry.js +2 -2
- package/dist/run/worker/entry.js.map +1 -1
- package/dist/run/worker/protocol.d.ts +18 -6
- package/dist/run/worker/protocol.d.ts.map +1 -1
- package/dist/run/worker/protocol.js +1 -1
- package/dist/run/worker/protocol.js.map +1 -1
- package/dist/run/worker/session.d.ts +2 -2
- package/dist/run/worker/session.d.ts.map +1 -1
- package/dist/run/worker/session.js +5 -3
- package/dist/run/worker/session.js.map +1 -1
- package/dist/types.d.ts +58 -41
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -2
- package/package.json +13 -12
- package/skills/e2e/SKILL.md +110 -0
- package/skills/e2e/references/agent.md +210 -0
- package/skills/e2e/references/debugging.md +81 -0
- package/skills/e2e/references/running.md +153 -0
- package/skills/e2e/references/setup.md +238 -0
- package/skills/e2e/references/writing-tests.md +289 -0
- package/dist/backend/contract.d.ts.map +0 -1
- package/dist/backend/contract.js.map +0 -1
- package/dist/backend/index.d.ts.map +0 -1
- package/dist/backend/index.js.map +0 -1
- package/dist/backend/session.d.ts +0 -23
- package/dist/backend/session.d.ts.map +0 -1
- package/dist/backend/session.js.map +0 -1
- package/dist/backend/surface.d.ts.map +0 -1
- package/dist/backend/surface.js.map +0 -1
- package/dist/backend/timing.d.ts.map +0 -1
- package/dist/backend/timing.js +0 -8
- package/dist/backend/timing.js.map +0 -1
- package/dist/cli/init/backends.d.ts.map +0 -1
- package/dist/cli/init/backends.js.map +0 -1
- package/dist/report/live-status.d.ts +0 -51
- package/dist/report/live-status.d.ts.map +0 -1
- package/dist/report/live-status.js +0 -163
- package/dist/report/live-status.js.map +0 -1
- package/dist/run/fixture-legacy.d.ts +0 -36
- package/dist/run/fixture-legacy.d.ts.map +0 -1
- package/dist/run/fixture-legacy.js +0 -143
- package/dist/run/fixture-legacy.js.map +0 -1
- /package/dist/{backend → engine}/timing.d.ts +0 -0
package/dist/config/app.js
CHANGED
|
@@ -1,142 +1,195 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Per-target app resolution: what an engine declares
|
|
3
|
+
* about the app it drives, validated where an error can name the target.
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
2
7
|
import { ConfigurationError } from '../internal/errors.js';
|
|
8
|
+
import { obj } from '../internal/objects.js';
|
|
3
9
|
import { isImplicitTestHost, normalizeBaseUrl } from '../internal/urls.js';
|
|
4
10
|
import { httpUrl, positiveInt } from './validate.js';
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
const services = resolveServices(raw.app?.services);
|
|
25
|
-
const rawUrl = raw.app?.url ?? env['APP_URL'];
|
|
26
|
-
if (rawUrl === undefined || rawUrl === '') {
|
|
27
|
-
// Not every surface has an app URL to point at (a device, a desktop
|
|
28
|
-
// shell): a synthetic loopback base keeps navigation resolution and
|
|
29
|
-
// identity digests defined, and `app.open()` fails loud with
|
|
30
|
-
// APP_URL_REQUIRED the moment a test actually needs one. A configured
|
|
31
|
-
// app command without a URL is still a mistake worth failing early on.
|
|
32
|
-
const orphaned = Object.keys(raw.app ?? {}).filter((key) => !URL_FREE_APP_KEYS.has(key));
|
|
33
|
-
if (orphaned.length > 0) {
|
|
34
|
-
throw new ConfigurationError('INVALID_CONFIG', `app.${orphaned[0]} requires app.url: set app.url in e2e.config.ts or the APP_URL environment variable`);
|
|
35
|
-
}
|
|
36
|
-
if (raw.app?.command === undefined) {
|
|
37
|
-
return {
|
|
38
|
-
configured: false,
|
|
39
|
-
base: normalizeBaseUrl('http://127.0.0.1:1'),
|
|
40
|
-
readyUrl: 'http://127.0.0.1:1/',
|
|
41
|
-
allowedOrigins: [],
|
|
42
|
-
environment: 'test',
|
|
43
|
-
command: undefined,
|
|
44
|
-
services,
|
|
45
|
-
identity: undefined,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
throw new ConfigurationError('APP_URL_REQUIRED', 'an app URL is required alongside app.command: set app.url in e2e.config.ts or the APP_URL environment variable');
|
|
11
|
+
const ENVIRONMENTS = new Set(['test', 'staging', 'production']);
|
|
12
|
+
/**
|
|
13
|
+
* Resolves one target's app from its engine's `app` declaration. Every fact
|
|
14
|
+
* is optional: a URL normalizes like any base URL, origins must be serialized
|
|
15
|
+
* origins, a command needs something to poll, services need one readiness
|
|
16
|
+
* contract each, and the identity defaults to where the app is served when
|
|
17
|
+
* the engine gives none. `projectRoot` anchors every command's `log` path.
|
|
18
|
+
*/
|
|
19
|
+
export function resolveTargetApp(targetName, engine, projectRoot) {
|
|
20
|
+
const declared = engine?.app ?? {};
|
|
21
|
+
const where = `target "${targetName}" engine ${engine?.name ?? 'none'}`;
|
|
22
|
+
const base = declared.url === undefined ? undefined : normalizeBaseUrl(declared.url);
|
|
23
|
+
const environment = declared.environment ??
|
|
24
|
+
(base !== undefined && !isImplicitTestHost(new URL(base.href).hostname) ? 'production' : 'test');
|
|
25
|
+
if (!ENVIRONMENTS.has(environment)) {
|
|
26
|
+
throw new ConfigurationError('INVALID_CONFIG', `${where} declares invalid app.environment "${String(environment)}"`);
|
|
49
27
|
}
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// digest, not a gate: a loopback, `.localhost`, or `.test` host is `test`,
|
|
54
|
-
// any other host is `production` unless the config says otherwise.
|
|
55
|
-
const environment = raw.app?.environment ?? (isImplicitTestHost(baseHost) ? 'test' : 'production');
|
|
56
|
-
if (!['test', 'staging', 'production'].includes(environment)) {
|
|
57
|
-
throw new ConfigurationError('INVALID_CONFIG', `invalid app.environment "${environment}"`);
|
|
28
|
+
const allowedOrigins = declared.allowedOrigins ?? (base === undefined ? [] : [base.origin]);
|
|
29
|
+
if (!Array.isArray(allowedOrigins)) {
|
|
30
|
+
throw new ConfigurationError('INVALID_CONFIG', `${where} app.allowedOrigins must be an array`);
|
|
58
31
|
}
|
|
59
|
-
const allowedOrigins = raw.app?.allowedOrigins ?? [base.origin];
|
|
60
32
|
for (const origin of allowedOrigins) {
|
|
61
33
|
let parsed;
|
|
62
34
|
try {
|
|
63
35
|
parsed = new URL(origin);
|
|
64
36
|
}
|
|
65
37
|
catch {
|
|
66
|
-
throw new ConfigurationError('INVALID_CONFIG',
|
|
38
|
+
throw new ConfigurationError('INVALID_CONFIG', `${where} declares an invalid allowed origin: ${origin}`);
|
|
67
39
|
}
|
|
68
40
|
if (parsed.origin !== origin) {
|
|
69
|
-
throw new ConfigurationError('INVALID_CONFIG',
|
|
41
|
+
throw new ConfigurationError('INVALID_CONFIG', `${where} allowed origin must be a serialized origin, got ${origin} (expected ${parsed.origin})`);
|
|
70
42
|
}
|
|
71
43
|
}
|
|
72
|
-
const
|
|
73
|
-
if (command !== undefined)
|
|
74
|
-
validateCommand(command, 'app.command');
|
|
75
|
-
const identity = raw.app?.identity;
|
|
44
|
+
const identity = declared.identity;
|
|
76
45
|
if (identity !== undefined && (typeof identity !== 'string' || identity.trim() === '')) {
|
|
77
|
-
throw new ConfigurationError('INVALID_CONFIG',
|
|
46
|
+
throw new ConfigurationError('INVALID_CONFIG', `${where} app.identity must be a non-empty string`);
|
|
47
|
+
}
|
|
48
|
+
const command = declared.command;
|
|
49
|
+
if (command !== undefined)
|
|
50
|
+
validateCommand(command, `${where} app.command`, projectRoot);
|
|
51
|
+
const readyUrl = httpUrl(declared.readyUrl, `${where} app.readyUrl`) ?? base?.href;
|
|
52
|
+
if (command !== undefined && readyUrl === undefined) {
|
|
53
|
+
throw new ConfigurationError('APP_URL_REQUIRED', `${where} declares app.command without a URL to poll: declare url or readyUrl beside it`);
|
|
78
54
|
}
|
|
79
55
|
return {
|
|
80
|
-
configured: true,
|
|
81
56
|
base,
|
|
82
|
-
readyUrl: httpUrl(raw.app?.readyUrl, 'app.readyUrl') ?? base.href,
|
|
83
57
|
allowedOrigins,
|
|
84
58
|
environment,
|
|
59
|
+
identity: identity ?? (base === undefined ? undefined : `${base.origin}${base.basePath}`),
|
|
85
60
|
command,
|
|
86
|
-
|
|
87
|
-
|
|
61
|
+
readyUrl: command === undefined ? undefined : readyUrl,
|
|
62
|
+
services: resolveServices(declared.services, projectRoot, `${where} app.services`),
|
|
88
63
|
};
|
|
89
64
|
}
|
|
90
65
|
/**
|
|
91
|
-
* The shape every spawned command shares: a non-empty executable
|
|
92
|
-
*
|
|
93
|
-
* make the readiness loop spin
|
|
66
|
+
* The shape every spawned command shares: a non-empty executable, when set
|
|
67
|
+
* positive integer timeouts, and when set a `log` path inside the project
|
|
68
|
+
* root. A NaN or infinite budget would otherwise make the readiness loop spin
|
|
69
|
+
* without a deadline; a log outside the root would let config write anywhere.
|
|
94
70
|
*/
|
|
95
|
-
function validateCommand(command, label) {
|
|
71
|
+
function validateCommand(command, label, projectRoot) {
|
|
96
72
|
if (typeof command !== 'object' || command === null) {
|
|
97
73
|
throw new ConfigurationError('INVALID_CONFIG', `${label} must be an object`);
|
|
98
74
|
}
|
|
99
75
|
if (typeof command.executable !== 'string' || command.executable.length === 0) {
|
|
100
76
|
throw new ConfigurationError('INVALID_CONFIG', `${label}.executable is required`);
|
|
101
77
|
}
|
|
102
|
-
positiveInt(command.startupTimeout, `${label}.startupTimeout
|
|
103
|
-
positiveInt(command.shutdownTimeout, `${label}.shutdownTimeout
|
|
78
|
+
positiveInt(command.startupTimeout, `${label}.startupTimeout`, 'milliseconds');
|
|
79
|
+
positiveInt(command.shutdownTimeout, `${label}.shutdownTimeout`, 'milliseconds');
|
|
80
|
+
if (command.log !== undefined) {
|
|
81
|
+
if (typeof command.log !== 'string' || command.log.trim() === '') {
|
|
82
|
+
throw new ConfigurationError('INVALID_CONFIG', `${label}.log must be a non-empty path`);
|
|
83
|
+
}
|
|
84
|
+
if (!insideProjectRoot(projectRoot, path.resolve(projectRoot, command.log))) {
|
|
85
|
+
throw new ConfigurationError('INVALID_CONFIG', `${label}.log must be a file inside the project root, got ${JSON.stringify(command.log)}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (command.reuseExisting !== undefined && typeof command.reuseExisting !== 'boolean') {
|
|
89
|
+
throw new ConfigurationError('INVALID_CONFIG', `${label}.reuseExisting must be a boolean`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** Only a command with a URL to probe can find something already answering there. */
|
|
93
|
+
function rejectReuse(command, label, reason) {
|
|
94
|
+
if (command.reuseExisting !== undefined) {
|
|
95
|
+
throw new ConfigurationError('INVALID_CONFIG', `${label}.reuseExisting needs readyUrl: ${reason}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* `target` with the symlinks of its deepest existing ancestor resolved and the
|
|
100
|
+
* missing tail appended as written. A log file usually does not exist yet,
|
|
101
|
+
* but the directory a symlink points at does, so this is what the runner
|
|
102
|
+
* would actually open.
|
|
103
|
+
*/
|
|
104
|
+
function realpathOfExisting(target) {
|
|
105
|
+
const tail = [];
|
|
106
|
+
let current = target;
|
|
107
|
+
for (;;) {
|
|
108
|
+
try {
|
|
109
|
+
return path.join(fs.realpathSync(current), ...tail);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
const parent = path.dirname(current);
|
|
113
|
+
if (parent === current)
|
|
114
|
+
return target;
|
|
115
|
+
tail.unshift(path.basename(current));
|
|
116
|
+
current = parent;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
104
119
|
}
|
|
105
|
-
/**
|
|
106
|
-
|
|
107
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Whether `target` is a path strictly below the project root once both are
|
|
122
|
+
* resolved through the filesystem: an in-project symlink pointing outside is
|
|
123
|
+
* rejected, a symlinked project root still counts as the root, and a name
|
|
124
|
+
* that merely starts with `..` (`..logs/out.log`) is an ordinary entry.
|
|
125
|
+
*/
|
|
126
|
+
function insideProjectRoot(projectRoot, target) {
|
|
127
|
+
const relative = path.relative(realpathOfExisting(projectRoot), realpathOfExisting(target));
|
|
128
|
+
return (relative !== '' &&
|
|
129
|
+
relative !== '..' &&
|
|
130
|
+
!relative.startsWith(`..${path.sep}`) &&
|
|
131
|
+
!path.isAbsolute(relative));
|
|
132
|
+
}
|
|
133
|
+
/** The longest `name` a service may carry; a label, not a description. */
|
|
134
|
+
const SERVICE_NAME_MAX_LENGTH = 64;
|
|
135
|
+
/**
|
|
136
|
+
* The name a service goes by in errors, reporter output, and the report: the
|
|
137
|
+
* explicit `name`, trimmed, or the executable's base name (`docker`, `pnpm`,
|
|
138
|
+
* and for a shell wrapper just `sh`, which is when an explicit name earns its
|
|
139
|
+
* keep). Explicit names must be unique so two failures never read alike.
|
|
140
|
+
*/
|
|
141
|
+
function serviceName(service, position, taken) {
|
|
142
|
+
if (service.name === undefined)
|
|
143
|
+
return path.basename(service.executable);
|
|
144
|
+
const name = typeof service.name === 'string' ? service.name.trim() : '';
|
|
145
|
+
if (name.length === 0 || name.length > SERVICE_NAME_MAX_LENGTH) {
|
|
146
|
+
throw new ConfigurationError('INVALID_CONFIG', `${position}.name must be a non-empty string of at most ${SERVICE_NAME_MAX_LENGTH} characters`);
|
|
147
|
+
}
|
|
148
|
+
if (taken.has(name)) {
|
|
149
|
+
throw new ConfigurationError('INVALID_CONFIG', `${position}.name "${name}" is already used by another service; service names must be unique`);
|
|
150
|
+
}
|
|
151
|
+
taken.add(name);
|
|
152
|
+
return name;
|
|
108
153
|
}
|
|
109
154
|
/**
|
|
110
|
-
* Resolves `
|
|
111
|
-
* readiness contract (`readyUrl` or `waitForExit`), and a `teardown` is a
|
|
155
|
+
* Resolves a declaration's `services`: every service is a command with exactly
|
|
156
|
+
* one readiness contract (`readyUrl` or `waitForExit`), and a `teardown` is a
|
|
112
157
|
* command of its own. The service fields that only steer the runner
|
|
113
|
-
* (`readyUrl`, `waitForExit`, `teardown`) are lifted out of the
|
|
158
|
+
* (`name`, `readyUrl`, `waitForExit`, `teardown`) are lifted out of the
|
|
159
|
+
* command; `reuseExisting` stays on it, and only a `readyUrl` service may set it.
|
|
160
|
+
* `projectRoot` anchors each `log` path; `prefix` names the declaring target
|
|
161
|
+
* in errors, so a failing service is traceable to the engine that declared it.
|
|
114
162
|
*/
|
|
115
|
-
export function resolveServices(raw) {
|
|
163
|
+
export function resolveServices(raw, projectRoot, prefix = 'app.services') {
|
|
116
164
|
if (raw === undefined)
|
|
117
165
|
return [];
|
|
118
166
|
if (!Array.isArray(raw)) {
|
|
119
|
-
throw new ConfigurationError('INVALID_CONFIG',
|
|
167
|
+
throw new ConfigurationError('INVALID_CONFIG', `${prefix} must be an array`);
|
|
120
168
|
}
|
|
169
|
+
const names = new Set();
|
|
121
170
|
return raw.map((service, index) => {
|
|
122
|
-
const position =
|
|
123
|
-
validateCommand(service, position);
|
|
124
|
-
const { readyUrl: rawReadyUrl, waitForExit, teardown, ...command } = service;
|
|
171
|
+
const position = `${prefix}[${index}]`;
|
|
172
|
+
validateCommand(service, position, projectRoot);
|
|
173
|
+
const { name: _name, readyUrl: rawReadyUrl, waitForExit, teardown, ...command } = service;
|
|
125
174
|
const readyUrl = httpUrl(rawReadyUrl, `${position}.readyUrl`);
|
|
126
175
|
if ((readyUrl !== undefined) === (waitForExit === true)) {
|
|
127
176
|
throw new ConfigurationError('INVALID_CONFIG', `${position} needs exactly one readiness contract: set readyUrl or waitForExit: true`);
|
|
128
177
|
}
|
|
129
178
|
const readiness = readyUrl === undefined ? { waitForExit: true } : { readyUrl };
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
179
|
+
if (readyUrl === undefined)
|
|
180
|
+
rejectReuse(command, position, 'a waitForExit service has nothing to reuse');
|
|
181
|
+
const name = serviceName(service, position, names);
|
|
182
|
+
const label = `service "${name}"`;
|
|
183
|
+
if (teardown !== undefined) {
|
|
184
|
+
validateCommand(teardown, `${position}.teardown`, projectRoot);
|
|
185
|
+
rejectReuse(teardown, `${position}.teardown`, 'a teardown command has nothing to reuse');
|
|
186
|
+
}
|
|
133
187
|
return {
|
|
134
188
|
label,
|
|
189
|
+
name: service.name === undefined ? undefined : name,
|
|
135
190
|
command,
|
|
136
191
|
readiness,
|
|
137
|
-
teardown: teardown === undefined
|
|
138
|
-
? undefined
|
|
139
|
-
: { label: `${label} teardown (${commandLine(teardown)})`, command: teardown },
|
|
192
|
+
teardown: teardown === undefined ? undefined : { label: `${label} teardown`, command: teardown },
|
|
140
193
|
};
|
|
141
194
|
});
|
|
142
195
|
}
|
|
@@ -147,22 +200,24 @@ function digestCommand(command) {
|
|
|
147
200
|
return { ...rest, env: Object.fromEntries(Object.keys(env).map((key) => [key, { envName: key }])) };
|
|
148
201
|
}
|
|
149
202
|
/**
|
|
150
|
-
* The
|
|
151
|
-
*
|
|
152
|
-
*
|
|
203
|
+
* The declarative part of an engine's `app` manifest as it enters the config
|
|
204
|
+
* digest: hooks stripped, and every `command.env`, service env, and service
|
|
205
|
+
* teardown env value replaced by `{ envName: key }`, so no environment value
|
|
206
|
+
* contributes to the digest.
|
|
153
207
|
*/
|
|
154
|
-
export function
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
208
|
+
export function digestAppDeclaration(app) {
|
|
209
|
+
const { url, allowedOrigins, environment, identity, command, readyUrl, services } = app;
|
|
210
|
+
return obj({
|
|
211
|
+
url,
|
|
212
|
+
allowedOrigins,
|
|
213
|
+
environment,
|
|
214
|
+
identity,
|
|
215
|
+
readyUrl,
|
|
216
|
+
command: command === undefined ? undefined : digestCommand(command),
|
|
217
|
+
services: services?.map(({ teardown, ...service }) => obj({
|
|
218
|
+
...digestCommand(service),
|
|
219
|
+
teardown: teardown === undefined ? undefined : digestCommand(teardown),
|
|
220
|
+
})),
|
|
221
|
+
});
|
|
167
222
|
}
|
|
168
223
|
//# sourceMappingURL=app.js.map
|
package/dist/config/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/config/app.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/config/app.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turns a module loading failure into a sentence that names the fix. The
|
|
3
|
+
* loader's own messages are accurate but stop at the symptom: a missing
|
|
4
|
+
* package reads the same whether it was never added or just not installed,
|
|
5
|
+
* and a removed export looks like a typo.
|
|
6
|
+
*/
|
|
7
|
+
/** The runtime exports of `@e2edev/e2e`; a unit test keeps this list equal to the real module. */
|
|
8
|
+
export declare const RUNTIME_EXPORTS: readonly string[];
|
|
9
|
+
/**
|
|
10
|
+
* The message of a failed import of `importer`, extended with what to do
|
|
11
|
+
* about it when the cause is one the runner recognizes. Any other cause keeps
|
|
12
|
+
* its own message.
|
|
13
|
+
*/
|
|
14
|
+
export declare function explainModuleError(cause: unknown, importer: string): string;
|
|
15
|
+
//# sourceMappingURL=diagnose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.d.ts","sourceRoot":"","sources":["../../src/config/diagnose.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,kGAAkG;AAClG,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAS5C,CAAC;AASF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG3E"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turns a module loading failure into a sentence that names the fix. The
|
|
3
|
+
* loader's own messages are accurate but stop at the symptom: a missing
|
|
4
|
+
* package reads the same whether it was never added or just not installed,
|
|
5
|
+
* and a removed export looks like a typo.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { withHint } from '../internal/errors.js';
|
|
10
|
+
import { addDevDependencyCommand, detectPackageManager } from '../internal/package-manager.js';
|
|
11
|
+
import { didYouMean, suggest } from '../internal/suggest.js';
|
|
12
|
+
/** The runtime exports of `@e2edev/e2e`; a unit test keeps this list equal to the real module. */
|
|
13
|
+
export const RUNTIME_EXPORTS = [
|
|
14
|
+
'test',
|
|
15
|
+
'expect',
|
|
16
|
+
'credentials',
|
|
17
|
+
'AgentError',
|
|
18
|
+
'BLOCKABLE_CODES',
|
|
19
|
+
'RUNTIME_CODES',
|
|
20
|
+
'buildTraceEntry',
|
|
21
|
+
'readTraceEntry',
|
|
22
|
+
];
|
|
23
|
+
/**
|
|
24
|
+
* The message of a failed import of `importer`, extended with what to do
|
|
25
|
+
* about it when the cause is one the runner recognizes. Any other cause keeps
|
|
26
|
+
* its own message.
|
|
27
|
+
*/
|
|
28
|
+
export function explainModuleError(cause, importer) {
|
|
29
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
30
|
+
return withHint(message, moduleErrorHint(message, cause?.code, importer));
|
|
31
|
+
}
|
|
32
|
+
function moduleErrorHint(message, code, importer) {
|
|
33
|
+
if (code === 'ERR_MODULE_NOT_FOUND') {
|
|
34
|
+
const missing = /Cannot find (?:package|module) '([^']+)'/.exec(message)?.[1];
|
|
35
|
+
if (missing !== undefined && !missing.startsWith('.') && !path.isAbsolute(missing)) {
|
|
36
|
+
return missingPackageHint(packageNameOf(missing), importer);
|
|
37
|
+
}
|
|
38
|
+
return '';
|
|
39
|
+
}
|
|
40
|
+
if (code === 'ERR_PACKAGE_PATH_NOT_EXPORTED') {
|
|
41
|
+
const match = /Package subpath '([^']+)' is not defined by "exports" in (.+?package\.json)/.exec(message);
|
|
42
|
+
return match === null ? '' : subpathHint(match[1], match[2]);
|
|
43
|
+
}
|
|
44
|
+
const missingExport = /The requested module '([^']+)' does not provide an export named '([^']+)'/.exec(message);
|
|
45
|
+
return missingExport === null ? '' : missingExportHint(missingExport[1], missingExport[2]);
|
|
46
|
+
}
|
|
47
|
+
/** `@scope/name/subpath` and `name/subpath` reduce to the package that would be installed. */
|
|
48
|
+
function packageNameOf(specifier) {
|
|
49
|
+
const parts = specifier.split('/');
|
|
50
|
+
return specifier.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
|
|
51
|
+
}
|
|
52
|
+
function missingPackageHint(name, importer) {
|
|
53
|
+
const manifest = nearestManifest(path.dirname(importer));
|
|
54
|
+
const manager = detectPackageManager(manifest?.dir ?? path.dirname(importer), manifest?.packageManager);
|
|
55
|
+
if (manifest?.dependencies.has(name) === true) {
|
|
56
|
+
return `${name} is declared in ${manifest.path} but is not installed: run ${manager} install`;
|
|
57
|
+
}
|
|
58
|
+
return `add it to the project: ${addDevDependencyCommand(manager, name)}`;
|
|
59
|
+
}
|
|
60
|
+
function subpathHint(subpath, manifestPath) {
|
|
61
|
+
let parsed;
|
|
62
|
+
try {
|
|
63
|
+
parsed = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return '';
|
|
67
|
+
}
|
|
68
|
+
const name = typeof parsed.name === 'string' ? parsed.name : path.basename(path.dirname(manifestPath));
|
|
69
|
+
const entries = typeof parsed.exports === 'object' && parsed.exports !== null && !Array.isArray(parsed.exports)
|
|
70
|
+
? Object.keys(parsed.exports).filter((key) => key.startsWith('.'))
|
|
71
|
+
: ['.'];
|
|
72
|
+
const specifiers = entries.map((entry) => (entry === '.' ? name : `${name}/${entry.slice(2)}`));
|
|
73
|
+
const attempted = `${name}/${subpath.replace(/^\.\//, '')}`;
|
|
74
|
+
return `${name} exports ${specifiers.join(', ')}${didYouMean(attempted, specifiers)}`;
|
|
75
|
+
}
|
|
76
|
+
function missingExportHint(specifier, exportName) {
|
|
77
|
+
if (specifier !== '@e2edev/e2e')
|
|
78
|
+
return '';
|
|
79
|
+
if (exportName === 'defineConfig') {
|
|
80
|
+
return 'defineConfig was removed in @e2edev/e2e 0.5: default-export the object and end it with satisfies E2EConfig';
|
|
81
|
+
}
|
|
82
|
+
const suggestion = suggest(exportName, RUNTIME_EXPORTS);
|
|
83
|
+
if (suggestion !== undefined)
|
|
84
|
+
return `did you mean "${suggestion}"?`;
|
|
85
|
+
return /^[A-Z]/.test(exportName)
|
|
86
|
+
? `if ${exportName} is a type, import it with import type { ${exportName} } from '@e2edev/e2e'`
|
|
87
|
+
: `@e2edev/e2e exports ${RUNTIME_EXPORTS.join(', ')}`;
|
|
88
|
+
}
|
|
89
|
+
/** The closest package.json above `dir`, read for its declared dependencies. */
|
|
90
|
+
function nearestManifest(dir) {
|
|
91
|
+
let current = dir;
|
|
92
|
+
for (;;) {
|
|
93
|
+
const manifestPath = path.join(current, 'package.json');
|
|
94
|
+
if (existsSync(manifestPath)) {
|
|
95
|
+
try {
|
|
96
|
+
const parsed = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
97
|
+
const dependencies = new Set();
|
|
98
|
+
for (const block of ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']) {
|
|
99
|
+
const section = parsed[block];
|
|
100
|
+
if (typeof section === 'object' && section !== null) {
|
|
101
|
+
for (const name of Object.keys(section))
|
|
102
|
+
dependencies.add(name);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
path: manifestPath,
|
|
107
|
+
dir: current,
|
|
108
|
+
packageManager: typeof parsed['packageManager'] === 'string' ? parsed['packageManager'] : undefined,
|
|
109
|
+
dependencies,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const parent = path.dirname(current);
|
|
117
|
+
if (parent === current)
|
|
118
|
+
return undefined;
|
|
119
|
+
current = parent;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=diagnose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.js","sourceRoot":"","sources":["../../src/config/diagnose.ts"],"names":[],"mappings":"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"}
|
package/dist/config/load.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
/** Config discovery and ESM/TypeScript loading
|
|
1
|
+
/** Config discovery and ESM/TypeScript loading. */
|
|
2
|
+
import { ConfigurationError } from '../internal/errors.ts';
|
|
2
3
|
import type { E2EConfig } from '../types.ts';
|
|
3
4
|
export interface DiscoveredConfig {
|
|
4
5
|
readonly configPath: string | undefined;
|
|
@@ -10,6 +11,13 @@ export interface DiscoveredConfig {
|
|
|
10
11
|
* repository root. The selected file's directory is the project root.
|
|
11
12
|
*/
|
|
12
13
|
export declare function discoverConfig(cwd: string, explicitPath?: string): DiscoveredConfig;
|
|
14
|
+
/**
|
|
15
|
+
* The failure for a run that found no config file: where the search looked,
|
|
16
|
+
* a lookalike in the working directory when one exists, and otherwise the
|
|
17
|
+
* command that creates a config. Thrown by the CLI path only; an embedding
|
|
18
|
+
* host passes its config as a value.
|
|
19
|
+
*/
|
|
20
|
+
export declare function missingConfigError(cwd: string): ConfigurationError;
|
|
13
21
|
/**
|
|
14
22
|
* Imports a TypeScript/ESM module with erasable-syntax support. Every call
|
|
15
23
|
* evaluates the module afresh: the query carries the caller's key (what the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"AAAA,mDAAmD;AAMnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAoB7C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,gBAAgB,CA2BnF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,CASlE;AAWD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,SAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAO9F;AAED,mEAAmE;AACnE,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAuB7E"}
|
package/dist/config/load.js
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
|
-
/** Config discovery and ESM/TypeScript loading
|
|
1
|
+
/** Config discovery and ESM/TypeScript loading. */
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { pathToFileURL } from 'node:url';
|
|
5
5
|
import { register } from 'tsx/esm/api';
|
|
6
6
|
import { ConfigurationError } from '../internal/errors.js';
|
|
7
|
+
import { explainModuleError } from './diagnose.js';
|
|
7
8
|
import { esmPackageHint } from './esm.js';
|
|
8
9
|
const CONFIG_NAMES = ['e2e.config.ts', 'e2e.config.mts'];
|
|
10
|
+
/** Spellings a config author might reach for that the loader does not read. */
|
|
11
|
+
const CONFIG_LOOKALIKES = [
|
|
12
|
+
'e2e.config.js',
|
|
13
|
+
'e2e.config.mjs',
|
|
14
|
+
'e2e.config.cjs',
|
|
15
|
+
'e2e.config.cts',
|
|
16
|
+
'e2e.config.json',
|
|
17
|
+
'e2e.config.mts.ts',
|
|
18
|
+
'e2e.ts',
|
|
19
|
+
'e2e.json',
|
|
20
|
+
'e2e-config.ts',
|
|
21
|
+
'e2e.conf.ts',
|
|
22
|
+
];
|
|
9
23
|
/**
|
|
10
24
|
* Discovers the config file. With `--config` the explicit path wins. Otherwise
|
|
11
25
|
* the search starts at cwd and inspects each parent, stopping after the
|
|
@@ -37,6 +51,21 @@ export function discoverConfig(cwd, explicitPath) {
|
|
|
37
51
|
}
|
|
38
52
|
return { configPath: undefined, projectRoot: path.resolve(cwd) };
|
|
39
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* The failure for a run that found no config file: where the search looked,
|
|
56
|
+
* a lookalike in the working directory when one exists, and otherwise the
|
|
57
|
+
* command that creates a config. Thrown by the CLI path only; an embedding
|
|
58
|
+
* host passes its config as a value.
|
|
59
|
+
*/
|
|
60
|
+
export function missingConfigError(cwd) {
|
|
61
|
+
const root = path.resolve(cwd);
|
|
62
|
+
const lookalike = CONFIG_LOOKALIKES.find((name) => existsSync(path.join(root, name)));
|
|
63
|
+
const searched = `no ${CONFIG_NAMES.join(' or ')} found in ${root} or its parent directories`;
|
|
64
|
+
const remedy = lookalike === undefined
|
|
65
|
+
? 'run e2e init to create one, or pass --config <path>'
|
|
66
|
+
: `found ${lookalike}, but only ${CONFIG_NAMES.join(' and ')} are loaded: rename it and keep it an ES module`;
|
|
67
|
+
return new ConfigurationError('CONFIG_NOT_FOUND', `${searched}; ${remedy}`);
|
|
68
|
+
}
|
|
40
69
|
/**
|
|
41
70
|
* The process-wide TypeScript loader, registered on first use. `tsImport`
|
|
42
71
|
* would register a fresh, never-removed loader hook per call - once per
|
|
@@ -68,11 +97,14 @@ export async function loadConfigModule(configPath) {
|
|
|
68
97
|
moduleValue = await importModule(configPath);
|
|
69
98
|
}
|
|
70
99
|
catch (cause) {
|
|
71
|
-
throw new ConfigurationError('CONFIG_LOAD_FAILED', `failed to load config ${configPath}: ${cause
|
|
100
|
+
throw new ConfigurationError('CONFIG_LOAD_FAILED', `failed to load config ${configPath}: ${explainModuleError(cause, configPath)}`, { cause });
|
|
72
101
|
}
|
|
73
102
|
const defaultExport = moduleValue.default;
|
|
74
103
|
if (typeof defaultExport !== 'object' || defaultExport === null) {
|
|
75
|
-
|
|
104
|
+
const found = defaultExport === undefined
|
|
105
|
+
? 'has no default export'
|
|
106
|
+
: `default-exports ${typeof defaultExport === 'function' ? 'a function' : `a ${typeof defaultExport}`}`;
|
|
107
|
+
throw new ConfigurationError('INVALID_CONFIG', `config ${configPath} ${found}; write export default { targets: [...] } satisfies E2EConfig`);
|
|
76
108
|
}
|
|
77
109
|
return defaultExport;
|
|
78
110
|
}
|