Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions COMPATIBILITY.md

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions docs-site/public/api/E2E.Engine.EngineDisposeContext.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="canonical" href="https://www.hardkoded.com/e2e-dotnet/api/E2E.Engine/EngineDisposeContext/">
<meta http-equiv="refresh" content="0; url=/e2e-dotnet/api/E2E.Engine/EngineDisposeContext/">
<title>Redirecting…</title>
<script>location.replace("/e2e-dotnet/api/E2E.Engine/EngineDisposeContext/" + (location.hash || ""));</script>
</head>
<body>
<p><a href="/e2e-dotnet/api/E2E.Engine/EngineDisposeContext/">Continue</a></p>
</body>
</html>
13 changes: 13 additions & 0 deletions docs-site/public/api/E2E.Engine.IDisposableEngine.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="canonical" href="https://www.hardkoded.com/e2e-dotnet/api/E2E.Engine/IDisposableEngine/">
<meta http-equiv="refresh" content="0; url=/e2e-dotnet/api/E2E.Engine/IDisposableEngine/">
<title>Redirecting…</title>
<script>location.replace("/e2e-dotnet/api/E2E.Engine/IDisposableEngine/" + (location.hash || ""));</script>
</head>
<body>
<p><a href="/e2e-dotnet/api/E2E.Engine/IDisposableEngine/">Continue</a></p>
</body>
</html>
63 changes: 63 additions & 0 deletions docs-site/src/content/docs/api/E2E.Engine/EngineDisposeContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
title: "EngineDisposeContext"
description: "What DisposeAsync is given: the cleanup budget of one engine's dispose, and whether it may keep what it holds for a replacement worker. Upstream's EngineDisp..."
editUrl: false
prev: false
next: false
sidebar:
label: "EngineDisposeContext"
hidden: true
---

<a id="E2E_Engine_EngineDisposeContext"></a>

Namespace: [E2E.Engine](/api/E2E.Engine/)


```csharp
public sealed record EngineDisposeContext : IEquatable<EngineDisposeContext>
```


What `DisposeAsync` is given: the cleanup budget of one engine's
dispose, and whether it may keep what it holds for a replacement worker. Upstream's `EngineDisposeContext` (`engine/index.ts`).

**Inheritance:** [object](https://learn.microsoft.com/dotnet/api/system.object)

**Implements:** [IEquatable&lt;EngineDisposeContext&gt;](https://learn.microsoft.com/dotnet/api/system.iequatable-1)

[View source](https://github.com/hardkoded/e2e-dotnet/blob/main/src/E2E/Engine/IPreparableEngine.cs)

## Properties

<a id="E2E_Engine_EngineDisposeContext_CleanupTimeout_"></a>
<a id="E2E_Engine_EngineDisposeContext_CleanupTimeout"></a>

### CleanupTimeout


```csharp
public required TimeSpan CleanupTimeout { get; init; }
```


The cleanup budget the dispose shares.

**Value:** [TimeSpan](https://learn.microsoft.com/dotnet/api/system.timespan)

<a id="E2E_Engine_EngineDisposeContext_ReuseSignal_"></a>
<a id="E2E_Engine_EngineDisposeContext_ReuseSignal"></a>

### ReuseSignal


```csharp
public CancellationToken? ReuseSignal { get; init; }
```


Upstream's `reuseSignal`: a token that is live (not canceled) permits the engine to keep the run-owned resources its workers hold
for a replacement, until the token is canceled or the dispose settles. Null or a canceled token requires the final cleanup, which is
what a run that retires its workers asks for.

**Value:** [CancellationToken?](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)
50 changes: 50 additions & 0 deletions docs-site/src/content/docs/api/E2E.Engine/IDisposableEngine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: "IDisposableEngine"
description: "An engine with upstream's optional dispose hook (declared in engine/index.ts): worker shutdown within the cleanup budget, where the engine releases what its..."
editUrl: false
prev: false
next: false
sidebar:
label: "IDisposableEngine"
hidden: true
---

<a id="E2E_Engine_IDisposableEngine"></a>

Namespace: [E2E.Engine](/api/E2E.Engine/)


```csharp
public interface IDisposableEngine : IEngine
```


An engine with upstream's optional `dispose` hook (declared in `engine/index.ts`): worker shutdown within the cleanup budget,
where the engine releases what its workers hold, or keeps the run-owned part of it when [ReuseSignal](/api/E2E.Engine/EngineDisposeContext/#E2E_Engine_EngineDisposeContext_ReuseSignal) is live.
.NET-only name: upstream's engine has the member in the same contract as `prepare` and `finish`.

[View source](https://github.com/hardkoded/e2e-dotnet/blob/main/src/E2E/Engine/IPreparableEngine.cs)

## Methods

<a id="E2E_Engine_IDisposableEngine_DisposeAsync_"></a>
<a id="E2E_Engine_IDisposableEngine_DisposeAsync_E2E_Engine_EngineDisposeContext_System_Threading_CancellationToken_"></a>

### DisposeAsync(EngineDisposeContext, CancellationToken)


```csharp
Task DisposeAsync(EngineDisposeContext context, CancellationToken cancellationToken)
```


Shuts down the engine's workers, within [CleanupTimeout](/api/E2E.Engine/EngineDisposeContext/#E2E_Engine_EngineDisposeContext_CleanupTimeout). A failure is a cleanup error.

**Parameters**

| Name | Type | Description |
| --- | --- | --- |
| `context` | [EngineDisposeContext](/api/E2E.Engine/EngineDisposeContext/) | |
| `cancellationToken` | [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken) | |

**Returns:** [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ public interface IPreparableEngine : IEngine

An engine with upstream's optional `prepare` and `finish` hooks (declared in `engine/index.ts`): what a run provisions
once per target before any worker starts, such as a hosted device, and gives back after the last worker ended, so the provisioning
happens once per run instead of per worker. The port has no test runner that calls them: a host that starts the engine on its own, as
happens once per run instead of per worker. The run's own path calls them: `Runner.RunAsync` and the run fixtures of `E2E.NUnit`
and `E2E.XUnit.V3` prepare each engine once and finish it when the run ends, and a host that starts the engine on its own, as
`e2e explore` and `e2e mcp` do, calls them around the one attempt (upstream's `openStandaloneAttempt`), prepare when
the session opens and finish when it closes, on every path; the mobile adapters' `MobileAppTest` runs them once per test process.
the session opens and finish when it closes, on every path.
.NET-only name: upstream tests the engine handle for the members. [WebEngine](/api/E2E.Engine/WebEngine/) does not implement it, because it leases
for the attempt it starts.

Expand Down
4 changes: 3 additions & 1 deletion docs-site/src/content/docs/api/E2E.Engine/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Public types in the `E2E.Engine` namespace.
| [EngineAppInfo](/api/E2E.Engine/EngineAppInfo/) | The app the harness resolved from the target's declaration, as an engine's doctor hook reads it: the site policy and what a device launches. The URL itself stays with the harness. Upstream's EngineAppInfo, with the members the port's config declares. |
| [EngineArtifactsSpec](/api/E2E.Engine/EngineArtifactsSpec/) | Upstream's artifacts hooks of an engine: the screenshot, and video started and stopped together. |
| [EngineCleanupContext](/api/E2E.Engine/EngineCleanupContext/) | Upstream's EngineCleanupContext: the signal and the cleanup budget the harness hands an engine's cleanup hooks. |
| [EngineDisposeContext](/api/E2E.Engine/EngineDisposeContext/) | What DisposeAsync is given: the cleanup budget of one engine's dispose, and whether it may keep what it holds for a replacement worker. Upstream's EngineDisposeContext (engine/index.ts). |
| [EngineDoctorCheck](/api/E2E.Engine/EngineDoctorCheck/) | One finding of DoctorAsync. Upstream's EngineDoctorCheck. |
| [EngineDoctorInfo](/api/E2E.Engine/EngineDoctorInfo/) | The facts handed to an engine's doctor (DoctorAsync), once per target in the process e2e doctor runs in. Upstream's EngineDoctorInfo; its signal is the CancellationToken of the call. |
| [EngineFinishInfo](/api/E2E.Engine/EngineFinishInfo/) | The facts handed to an engine's finish (FinishAsync), once per run and target after the last worker is gone, with the cleanup budget of one hook. Upstream's EngineFinishInfo. |
Expand Down Expand Up @@ -140,11 +141,12 @@ Public types in the `E2E.Engine` namespace.
| [IBrowserProvider](/api/E2E.Engine/IBrowserProvider/) | A source of hosted browsers: the seam a hosted browser service plugs into (upstream BrowserProvider). In Worker scope AcquireAsync is called once per worker slot, for every slot at once, in the runner; a worker whose browser drops calls it again, from its own process, for a replacement. In Attempt scope every attempt start calls it from the worker. ReleaseAsync is called exactly once per lease, by the process that acquired it, also after an acquire of another slot failed; a worker that dies first never calls it, and SweepAsync releases what it left. A provider must not rely on runner-process state to serve a request from a worker. Nothing here knows any vendor. |
| [IBrowserRoute](/api/E2E.Engine/IBrowserRoute/) | One intercepted request, as an engine hands it to a route handler. The harness has already validated each decision and takes at most one. |
| [IBrowserSession](/api/E2E.Engine/IBrowserSession/) | The browser-shaped surface an engine session can add on top of IEngineSession. The Browser fixture uses it, and fails with UNSUPPORTED_CAPABILITY when the session does not implement it. The harness has already validated every argument. |
| [IDisposableEngine](/api/E2E.Engine/IDisposableEngine/) | An engine with upstream's optional dispose hook (declared in engine/index.ts): worker shutdown within the cleanup budget, where the engine releases what its workers hold, or keeps the run-owned part of it when ReuseSignal is live. .NET-only name: upstream's engine has the member in the same contract as prepare and finish. |
| [IDoctorEngine](/api/E2E.Engine/IDoctorEngine/) | An engine with upstream's optional doctor hook (declared in engine/index.ts): what e2e doctor asks once per target, instead of starting a run. Without it the target gets one engine check with status skip. .NET-only name: upstream's Engine declares the member, and the port keeps its optional hooks in their own interfaces (IPreparableEngine), so an engine without the hook compiles unchanged. |
| [IEngine](/api/E2E.Engine/IEngine/) | The body of one target. Core knows this contract and never an engine's internals. Version is the engine version. It is not part of the replay cache key: a recording re-finds its nodes at replay. |
| [IEngineFixtureHost](/api/E2E.Engine/IEngineFixtureHost/) | An engine session that contributes a fixture, which the harness tells about the attempt when it starts. .NET-only: upstream's engine declares fixtures, factories the harness calls with an EngineFixtureContext; the port's session builds its own fixture (Device), so this hands it the context. |
| [IEngineSession](/api/E2E.Engine/IEngineSession/) | One attempt's session with the app. Disposed at the end of the attempt, after afterEach. |
| [IPreparableEngine](/api/E2E.Engine/IPreparableEngine/) | An engine with upstream's optional prepare and finish hooks (declared in engine/index.ts): what a run provisions once per target before any worker starts, such as a hosted device, and gives back after the last worker ended, so the provisioning happens once per run instead of per worker. The port has no test runner that calls them: a host that starts the engine on its own, as e2e explore and e2e mcp do, calls them around the one attempt (upstream's openStandaloneAttempt), prepare when the session opens and finish when it closes, on every path; the mobile adapters' MobileAppTest runs them once per test process. .NET-only name: upstream tests the engine handle for the members. WebEngine does not implement it, because it leases for the attempt it starts. |
| [IPreparableEngine](/api/E2E.Engine/IPreparableEngine/) | An engine with upstream's optional prepare and finish hooks (declared in engine/index.ts): what a run provisions once per target before any worker starts, such as a hosted device, and gives back after the last worker ended, so the provisioning happens once per run instead of per worker. The run's own path calls them: Runner.RunAsync and the run fixtures of E2E.NUnit and E2E.XUnit.V3 prepare each engine once and finish it when the run ends, and a host that starts the engine on its own, as e2e explore and e2e mcp do, calls them around the one attempt (upstream's openStandaloneAttempt), prepare when the session opens and finish when it closes, on every path. .NET-only name: upstream tests the engine handle for the members. WebEngine does not implement it, because it leases for the attempt it starts. |
| [ISessionApp](/api/E2E.Engine/ISessionApp/) | Upstream's SessionApp: the app's session hooks, each failing with UNSUPPORTED_CAPABILITY when the engine lacks it. |
| [ISessionArtifacts](/api/E2E.Engine/ISessionArtifacts/) | Upstream's SessionArtifacts: the screenshot, and video started and stopped together when the engine declares them. |
| [ISessionKeyboard](/api/E2E.Engine/ISessionKeyboard/) | Upstream's SessionKeyboard: typing, pressing, and dismissing for whatever holds focus. |
Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/content/docs/api/E2E.NUnit/E2ERunFixture.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public Task StopAppCommandsAsync()
```


Ends the run's events and runs the reporters that [Config](#E2E_NUnit_E2ERunFixture_Config) lists in `reporters` once `report.json` is final, then stops
Finishes the engines the run prepared, ends the run's events and runs the reporters that [Config](#E2E_NUnit_E2ERunFixture_Config) lists in `reporters` once `report.json` is final, then stops
the app commands that the tests of this process started, and deletes the sessions that setup tests saved (see `E2ESetupAttribute`).

**Returns:** [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public ValueTask DisposeAsync()
```


Ends the run's events and runs the reporters that [Config](#E2E_XUnit_V3_E2ERunFixture_Config) lists in `reporters` once `report.json` is final, then
Finishes the engines the run prepared, ends the run's events and runs the reporters that [Config](#E2E_XUnit_V3_E2ERunFixture_Config) lists in `reporters` once `report.json` is final, then
stops the app commands that the tests of this process started, and deletes the sessions that setup tests saved (see `E2ESetupAttribute`).

**Returns:** [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask)
Expand Down
15 changes: 15 additions & 0 deletions docs-site/src/content/docs/api/E2E/E2EFixture.md
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,21 @@ the port's counterpart of `--agent`. Unset, it is `default`. Override to set it

**Value:** [string](https://learn.microsoft.com/dotnet/api/system.string)

<a id="E2E_E2EFixture_RunEnvironment_"></a>
<a id="E2E_E2EFixture_RunEnvironment"></a>

### RunEnvironment


```csharp
protected virtual IReadOnlyDictionary<string, string?> RunEnvironment { get; }
```


The environment the workers of this run start with, under what prepare leaves them. Defaults to the process's.

**Value:** [IReadOnlyDictionary&lt;string, string&gt;](https://learn.microsoft.com/dotnet/api/system.collections.generic.ireadonlydictionary-2)

<a id="E2E_E2EFixture_Screen_"></a>
<a id="E2E_E2EFixture_Screen"></a>

Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/content/docs/docs/writing-an-engine.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ Run a test class against your engine. Check the lifecycle order, observations, a
| `defineEngine`, `EngineHandle`, `engine.capabilities` | Ported as `EngineManifest.DefineEngine`, `EngineHandle`, and the computed `Capabilities` set. `IEngine.Capabilities` remains a flags enum you declare, and the test runner does not run a `DefineEngine` handle. |
| The `e2e/engine` import path and the `e2e` peer dependency | `E2E.Engine` types in the `E2E` package. |
| `prepare`/`init`/`startAttempt` as three hooks, `endAttempt`/`dispose` as two | `StartAsync` and `DisposeAsync` do the work of each pair. |
| `workers`, `reuseSignal`, per-hook `signal` and `timeoutMs` | Not in the port: there is no worker pool. The harness bounds a start by the launch timeout and a dispose by the cleanup timeout. |
| `workers`, per-hook `signal` and `timeoutMs`, a scheduler's grant of `reuseSignal` | Not in the port: there is no worker pool, so no scheduler grants a reuse signal. The port's name for the signal is `EngineDisposeContext.ReuseSignal`, and the mobile engine honors it through `IDisposableEngine`. The harness bounds a start by the launch timeout and a dispose by the cleanup timeout. |
| `context.resolveSecret` | `EngineStartOptions.ResolveSecret` is `internal`. It resolves only a secret the engine lists in `Secrets` and fails any other with `SECRET_UNAVAILABLE`. [#1246](https://github.com/hardkoded/e2e-dotnet/issues/1246) tracks making it public. |
| `fixtures`, `context.fixture`, `expectable`, `requires: ['<name>']` | Not public. [#1197](https://github.com/hardkoded/e2e-dotnet/issues/1197) tracks contributed fixtures and [#1185](https://github.com/hardkoded/e2e-dotnet/issues/1185) the `requires` its. |
| `observe(context, options)` `signal` on every call | Every call takes a `CancellationToken`. |
Expand Down
Loading
Loading