11# Azure Functions host E2E tests (gated)
22
3- This suite launches a ** real Azure Functions host** (` func start ` ) for the sample
3+ This suite launches a ** real Azure Functions host** (` func start ` ) for the ported
44app under [ ` test-app/ ` ] ( ./test-app ) , backed by ** Azurite** (the local Azure
5- Storage emulator) using the Durable Task ** AzureStorage** provider, and drives
6- the app entirely over HTTP. The Node.js worker, the Functions host, and the
7- Durable extension all cooperate exactly as they would in production.
5+ Storage emulator) using the Durable Task ** AzureStorage** provider, and drives the
6+ app entirely over HTTP. The Node.js worker, the Functions host, and the Durable
7+ extension all cooperate exactly as they would in production.
88
9- It mirrors the Python suite added in
10- [ durabletask-python #155 ] ( https://github.com/microsoft/durabletask-python/pull/155 ) .
9+ It is a faithful port of the Azure Functions host E2E suite from the
10+ [ ` azure-functions-durable-extension ` ] ( https://github.com/Azure/azure-functions-durable-extension )
11+ repo — the ` BasicNode ` app plus its xUnit test classes — adapted to Jest. Expected
12+ strings and Node-specific bug annotations come from that repo's
13+ ` NodeTestLanguageLocalizer ` .
1114
12- ## ⚠️ Gated until PR # 282 merges
15+ ## Published ` durable-functions ` dependency
1316
14- The sample app depends on the in-repo ` durable-functions ` package
15- (` packages/azure-functions-durable ` ) added by
16- [ durabletask-js #282 ] ( https://github.com/microsoft/durabletask-js/pull/282 ) , which
17- is ** not on ` main ` yet** . This suite is deliberately split out from #282 so it
18- can land independently without touching that package.
17+ The [ ` test-app ` ] ( ./test-app ) is wired to the ** published** npm packages
18+ ` durable-functions ` (` ^3.1.0 ` ) and ` @azure/functions ` (` ^4.11.2 ` ), so it installs
19+ and builds without any in-repo package build. This is what makes the suite
20+ genuinely runnable.
1921
20- Because the package does not exist on ` main ` , everything here is ** gated /
21- skipped** so existing CI (` npm test ` , lint, build) stays green:
22+ To run the app against an ** in-repo** build of the Azure Functions durable package
23+ instead, change the ` durable-functions ` dependency in
24+ [ ` test-app/package.json ` ] ( ./test-app/package.json ) to a ` file: ` reference (e.g.
25+ ` file:../../../packages/azure-functions-durable ` ) once that package exists on your
26+ branch, then re-run ` npm install ` . A note to this effect lives in that
27+ ` package.json ` (` comment_durable-functions ` ).
2228
23- - ** Prerequisite detection** — the suite skips cleanly unless all of these hold
24- (see ` harness.ts ` + ` global-setup.ts ` ):
29+ ## Gating / skip model
30+
31+ The suite ** skips cleanly** (it never fails) unless everything it needs is present,
32+ so it is safe to leave wired into CI and to run locally without setup:
33+
34+ - ** Prerequisite detection** — ` global-setup.ts ` only starts the shared ` func `
35+ host when all of these hold (otherwise every spec skips):
2536 1 . Azure Functions Core Tools (` func ` ) v4 is on ` PATH ` ,
2637 2 . Azurite is reachable on ` 127.0.0.1:10000 ` , and
2738 3 . the test-app is installed and built (` test-app/node_modules ` + ` test-app/dist ` ).
28-
29- On ` main ` , step 3 cannot be satisfied (the local ` durable-functions ` package is
30- absent), so the suite is a clean no-op.
31-
39+ - ** One shared host** — ` global-setup.ts ` starts a single ` func start ` host for the
40+ whole run (mirroring the C# ` FunctionAppFixture ` ) and writes its base URL to a
41+ preflight file; the specs drive it over HTTP and ` global-teardown.ts ` stops it.
3242- ** Isolation** — these specs are only run by the dedicated
33- ` jest.functions-e2e.config.js ` via ` npm run test:e2e:functions:internal ` . They
34- are ** not** part of the default ` npm test ` / workspaces test run, nor of
43+ ` jest.functions-e2e.config.js ` via ` npm run test:e2e:functions:internal ` . They are
44+ ** not** part of the default ` npm test ` / workspaces test run, nor of
3545 ` test:e2e:internal ` (which is scoped to ` tests/e2e ` ).
36- - ** CI** — ` .github/workflows/functions-e2e-tests.yaml ` gates every job behind the
37- ` RUN_FUNCTIONS_E2E ` repository variable. It is a no-op until that variable is
38- set to ` true ` (do so only after #282 has merged).
46+ - ** CI** — ` .github/workflows/functions-e2e-tests.yaml ` installs ` func ` + Azurite,
47+ installs/builds the test-app, and runs the suite on PRs that touch
48+ ` test/e2e-functions/** ` . The self-skip is the safety net if a prerequisite fails
49+ to come up.
3950
4051## What it covers
4152
42- Faithful to the (identical) ` azure-functions-durable-js ` sample app:
43-
44- - ** ` hello.spec.ts ` ** — starts the ` helloOrchestrator ` (which chains three
45- ` hello ` activities) and asserts the output is
46- ` ["Hello, Tokyo", "Hello, Seattle", "Hello, Cairo"] ` .
47- - ** ` counter1.spec.ts ` ** — signals the ` counter1 ` durable entity (` add ` , 1) via
48- HTTP and asserts the persisted state increments (1, then 2). ` reset ` is not
49- wired to an HTTP route in the sample app, so it is not tested.
50-
51- The only additions to the sample app are a plain ` /api/ping ` readiness function
52- (for host-readiness probing) and the dependency wiring (` durable-functions `
53- points at the workspace package). The Durable function code is kept byte-for-byte
54- identical to ` azure-functions-durable-js ` .
53+ One spec per area, mirroring the extension repo's test classes. Because this is the
54+ ** Storage** backend, ` [Trait("Node-DTS","Skip")] ` and ` [Trait("DTS","Skip")] ` tests
55+ are ** included** (those skips apply only to the DTS backend); ` [Trait("Node","Skip")] `
56+ tests are ` it.skip ` with a comment citing the same reason.
57+
58+ | Spec | Ported from | Notes |
59+ | ----------------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------------------- |
60+ | ` hello-cities.spec.ts ` | ` HelloCitiesTest ` | activity chaining → ` Hello Tokyo! ` etc. |
61+ | ` activity-input-type.spec.ts ` | ` ActivityInputTypeTests ` | ` byte[] ` /` int[] ` /string/custom-class serialization |
62+ | ` error-handling.spec.ts ` | ` ErrorHandlingTests ` | rethrow/catch/retry activity & entity; skips dotnet-only FailureDetails + custom-exception-properties tests |
63+ | ` external-event.spec.ts ` | ` ExternalEventTests ` | raise to running/completed/missing (raise-to-completed error skipped per #645 ) |
64+ | ` suspend-resume.spec.ts ` | ` SuspendResumeTests ` | suspend/resume running, suspended, completed |
65+ | ` terminate.spec.ts ` | ` TerminateOrchestratorTests ` | terminate running/terminated/completed/nonexistent |
66+ | ` timeout.spec.ts ` | ` TimeoutTests ` | ` Task.any ` activity-vs-timer race |
67+ | ` rewind.spec.ts ` | ` RewindOrchestratorTests ` | fail → rewind → complete; invocation counts; rewind-only-failed |
68+ | ` is-replaying.spec.ts ` | ` IsReplayingTests ` | ` isReplaying ` flags (ConditionalLog #564 and FanOutFanIn #679 skipped) |
69+ | ` large-output.spec.ts ` | ` LargeOutputOrchestratorTests ` | 65 KB via status URI + 4.5 MB via query trigger |
70+ | ` orchestration-query.spec.ts ` | ` OrchestrationQueryTests ` | ` GetAllInstances ` / ` GetRunningInstances ` |
71+ | ` purge.spec.ts ` | ` PurgeInstancesTests ` | purge by time / by entity id (purge-without-start-time #644 skipped) |
72+ | ` class-based-entity.spec.ts ` | ` ClassBasedEntityTests ` | class-based entity state |
73+
74+ ### Node bug annotations honored
75+
76+ - [ #642 ] ( https://github.com/Azure/azure-functions-durable-js/issues/642 ) — entity
77+ error text: inner "This entity failed"/"More information" assertions omitted.
78+ - [ #645 ] ( https://github.com/Azure/azure-functions-durable-js/issues/645 ) —
79+ raise-external-event to a completed instance: error assertions omitted.
80+ - [ #564 ] ( https://github.com/Azure/azure-functions-durable-js/issues/564 ) —
81+ ` isReplaying ` undefined before the first ` yield ` : ` IsReplayingConditionalLog `
82+ skipped.
83+ - [ #679 ] ( https://github.com/Azure/azure-functions-durable-js/issues/679 ) —
84+ ` IsReplayingFanOutFanIn ` skipped.
85+ - [ #644 ] ( https://github.com/Azure/azure-functions-durable-js/issues/644 ) — purge
86+ without a start time: those purge tests skipped.
87+ - Node swallows suspend/resume/terminate of a ** terminal** instance and returns
88+ success (` 200 ` ); the specs assert that behavior.
89+
90+ The test-app additions over ` BasicNode ` are a plain ` /api/ping ` readiness function
91+ (for host-readiness probing) and the published-dependency wiring. The Durable
92+ function code is otherwise kept close to the source app.
5593
5694## Running locally
5795
@@ -66,11 +104,10 @@ azurite --silent --location /tmp/azurite --blobPort 10000 --queuePort 10001 --ta
66104# 2. Install the Core Tools (if needed)
67105npm install -g azure-functions-core-tools@4
68106
69- # 3. Build the workspace (must include packages/azure-functions-durable from #282 )
107+ # 3. Install root dev deps (jest + ts-jest )
70108npm ci
71- npm run build
72109
73- # 4. Install + build the test-app
110+ # 4. Install + build the test-app (against the published durable-functions)
74111cd test/e2e-functions/test-app
75112npm install
76113npm run build
@@ -81,11 +118,24 @@ npm run test:e2e:functions:internal
81118```
82119
83120Or use the convenience wrapper, which starts Azurite (if the CLI is installed),
84- builds the workspace + test-app, and runs the suite:
121+ installs + builds the test-app, and runs the suite:
85122
86123``` bash
87124npm run test:e2e:functions
88125```
89126
90127If any prerequisite is missing, the suite skips with a ` [functions-e2e] ` note
91128instead of failing.
129+
130+ ## Follow-ups (deferred)
131+
132+ The following extension-repo test areas are ** not** ported yet. Most need extra
133+ infrastructure (an OTLP collector, multi-version host config, scheduled starts) or
134+ an orchestration that is not part of ` BasicNode ` :
135+
136+ - ** DistributedTracing / DistributedTracingEntities** — need an OTLP collector.
137+ - ** Versioning / EntityVersioning** — need a multi-version host configuration.
138+ - ** DedupeStatuses** , ** GetOrchestrationHistory** , ** HTTPFeature** , ** Restart** ,
139+ ** Scheduled** — not yet ported.
140+ - ** ` PurgeOnlyPurgesTerminalOrchestrations ` ** — needs a ` HelloActivityDIFailure `
141+ orchestration that is not present in ` BasicNode ` .
0 commit comments