@fluojs/testing 2.0.0 → 3.0.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.ko.md +94 -12
- package/README.md +96 -12
- package/dist/babel-decorators-plugin.d.ts +1 -0
- package/dist/babel-decorators-plugin.d.ts.map +1 -1
- package/dist/babel-decorators-plugin.js +1 -0
- package/dist/byte-range-portability-consumer.test-fixture.d.ts +2 -0
- package/dist/byte-range-portability-consumer.test-fixture.d.ts.map +1 -0
- package/dist/byte-range-portability-consumer.test-fixture.js +11 -0
- package/dist/conformance/fetch-style-websocket-conformance.d.ts +1 -0
- package/dist/conformance/fetch-style-websocket-conformance.d.ts.map +1 -1
- package/dist/conformance/fetch-style-websocket-conformance.js +1 -1
- package/dist/conformance/platform-shell-lifecycle-conformance.d.ts +30 -0
- package/dist/conformance/platform-shell-lifecycle-conformance.d.ts.map +1 -0
- package/dist/conformance/platform-shell-lifecycle-conformance.js +259 -0
- package/dist/http.d.ts +2 -1
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +8 -3
- package/dist/mock.js +1 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +45 -73
- package/dist/portability/error-representation-abort-portability.d.ts +36 -0
- package/dist/portability/error-representation-abort-portability.d.ts.map +1 -0
- package/dist/portability/error-representation-abort-portability.js +190 -0
- package/dist/portability/error-representation-portability-fixture.d.ts +58 -0
- package/dist/portability/error-representation-portability-fixture.d.ts.map +1 -0
- package/dist/portability/error-representation-portability-fixture.js +202 -0
- package/dist/portability/error-representation-portability.d.ts +50 -0
- package/dist/portability/error-representation-portability.d.ts.map +1 -0
- package/dist/portability/error-representation-portability.js +153 -0
- package/dist/portability/http-adapter-portability.d.ts +24 -1
- package/dist/portability/http-adapter-portability.d.ts.map +1 -1
- package/dist/portability/http-adapter-portability.js +441 -68
- package/dist/portability/response-cookie-portability.d.ts +16 -0
- package/dist/portability/response-cookie-portability.d.ts.map +1 -0
- package/dist/portability/response-cookie-portability.js +81 -0
- package/dist/portability/web-runtime-adapter-portability.d.ts +23 -1
- package/dist/portability/web-runtime-adapter-portability.d.ts.map +1 -1
- package/dist/portability/web-runtime-adapter-portability.js +356 -31
- package/dist/types.d.ts +5 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +19 -15
package/README.ko.md
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
<p><a href="./README.md"><kbd>English</kbd></a> <strong><kbd>한국어</kbd></strong></p>
|
|
4
4
|
|
|
5
|
-
Node.js
|
|
5
|
+
Node.js `>=24.0.0 <27` fluo 애플리케이션을 위한 기본 request-level 테스트 헬퍼, 모듈 구성, 프로바이더 오버라이드 유틸리티입니다.
|
|
6
6
|
|
|
7
7
|
`@fluojs/testing`은 fluo 애플리케이션 테스트를 위한 공식적인 기준(Baseline)을 제공합니다. 격리된 테스트 환경을 구축하고, 의존성을 가짜(Fake)나 목(Mock)으로 교체하며, 모듈 그래프에서 직접 컴포넌트를 resolve하거나 `createTestApp(...).request(...).send()`로 가상 HTTP 요청을 실행하여 e2e 스타일 테스트를 수행할 수 있게 합니다.
|
|
8
8
|
|
|
9
|
+
Coordinated Node 24 릴리스를 준비한다면 패키지 업그레이드 전에 [소비자 마이그레이션 가이드](../../docs/getting-started/migrate-node24.ko.md)를 따르세요.
|
|
10
|
+
|
|
9
11
|
## 목차
|
|
10
12
|
|
|
11
13
|
- [설치](#설치)
|
|
@@ -13,6 +15,7 @@ Node.js 20+ fluo 애플리케이션을 위한 기본 request-level 테스트 헬
|
|
|
13
15
|
- [빠른 시작](#빠른-시작)
|
|
14
16
|
- [주요 패턴](#주요-패턴)
|
|
15
17
|
- [canonical TDD ladder](#canonical-tdd-ladder)
|
|
18
|
+
- [React Consumer Testing Recipe](#react-consumer-testing-recipe)
|
|
16
19
|
- [공개 API](#공개-api)
|
|
17
20
|
- [관련 패키지](#관련-패키지)
|
|
18
21
|
- [예제 소스](#예제-소스)
|
|
@@ -23,9 +26,9 @@ Node.js 20+ fluo 애플리케이션을 위한 기본 request-level 테스트 헬
|
|
|
23
26
|
pnpm add -D @fluojs/testing vitest
|
|
24
27
|
```
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
Vitest `^4.1.11`은 mock 헬퍼와 `@fluojs/testing/vitest` 엔트리포인트가 요구하는 peer dependency입니다. `@babel/core`는 Vitest decorators plugin이 사용하는 워크스페이스의 Babel을 로드하기 때문에 peer로 선언되어 있습니다. 따라서 non-Vitest harness subpath만 사용하더라도 패키지 매니저가 해당 peer 경고를 표시할 수 있습니다.
|
|
27
30
|
|
|
28
|
-
`@fluojs/testing/vitest`를 사용할 때는 `fluoBabelDecoratorsPlugin()`이 런타임에 Babel을 호출하므로, 사용하는 워크스페이스에 `@babel/core`도 함께 설치해야 합니다. Vitest 플러그인은 Vite query/hash suffix를 제거한 뒤 `.ts`, `.tsx`, `.mts`, `.cts` 소스 id를 변환하고, `node_modules`는 건너뛰며, 가장 가까운 root Babel config인 `babel.config.cjs`, `babel.config.mjs`, `babel.config.js`, `babel.config.json`을 해석합니다.
|
|
31
|
+
`@fluojs/testing/vitest`를 사용할 때는 `fluoBabelDecoratorsPlugin()`이 런타임에 Babel을 호출하므로, 사용하는 워크스페이스에 `@babel/core`도 함께 설치해야 합니다. Vitest 플러그인은 `enforce: 'pre'`로 실행되어 decorator가 있는 TypeScript가 Vite 8 normal-stage Rolldown/Oxc transform보다 먼저 Babel에 도달하게 합니다. Vite query/hash suffix를 제거한 뒤 `.ts`, `.tsx`, `.mts`, `.cts` 소스 id를 변환하고, `node_modules`는 건너뛰며, 가장 가까운 root Babel config인 `babel.config.cjs`, `babel.config.mjs`, `babel.config.js`, `babel.config.json`을 해석합니다.
|
|
29
32
|
|
|
30
33
|
```bash
|
|
31
34
|
pnpm add -D @babel/core
|
|
@@ -76,12 +79,44 @@ const module = await createTestingModule({ rootModule: AppModule })
|
|
|
76
79
|
})
|
|
77
80
|
.compile();
|
|
78
81
|
|
|
79
|
-
|
|
82
|
+
let testError: unknown;
|
|
83
|
+
let testFailed = false;
|
|
84
|
+
let disposeError: unknown;
|
|
85
|
+
let disposeFailed = false;
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const service = await module.resolve(UserService);
|
|
89
|
+
} catch (error: unknown) {
|
|
90
|
+
testError = error;
|
|
91
|
+
testFailed = true;
|
|
92
|
+
} finally {
|
|
93
|
+
try {
|
|
94
|
+
await module.container.dispose();
|
|
95
|
+
} catch (error: unknown) {
|
|
96
|
+
disposeFailed = true;
|
|
97
|
+
disposeError = error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (testFailed) {
|
|
102
|
+
if (disposeFailed) {
|
|
103
|
+
throw new AggregateError(
|
|
104
|
+
[testError, disposeError],
|
|
105
|
+
'Test and testing module disposal both failed.',
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
throw testError;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (disposeFailed) {
|
|
113
|
+
throw disposeError;
|
|
114
|
+
}
|
|
80
115
|
```
|
|
81
116
|
|
|
82
|
-
Testing builder는 route-pipeline 테스트에서 cross-cutting behavior를 교체할 수 있도록 `overrideProviders([[token, value], ...])`, `overrideGuard(...)`, `overrideInterceptor(...)`, `overrideFilter(...)`도 지원합니다. Guard와 interceptor override는 route가 같은 token을 `@UseGuards(...)` 또는 `@UseInterceptors(...)`로 참조할 때 request path에서도 안전하게 검증할 수 있습니다. Filter override는 컴파일된 module graph의 token을 교체하므로, 해당 filter가 runtime app 표면에 등록되는 경우 request-level coverage와 함께 사용하세요.
|
|
117
|
+
Testing builder는 route-pipeline 테스트에서 cross-cutting behavior를 교체할 수 있도록 `overrideProviders([[token, value], ...])`, `overrideGuard(...)`, `overrideInterceptor(...)`, `overrideFilter(...)`도 지원합니다. Guard와 interceptor override는 route가 같은 token을 `@UseGuards(...)` 또는 `@UseInterceptors(...)`로 참조할 때 request path에서도 안전하게 검증할 수 있습니다. Filter override는 컴파일된 module graph의 token을 교체하므로, 해당 filter가 runtime app 표면에 등록되는 경우 request-level coverage와 함께 사용하세요. 성공적으로 컴파일된 모든 `TestingModuleRef`를 보관하고 caller-owned `container`는 `finally`(suite setup은 `afterEach`)에서 dispose하여 통과, 실패, 조기 반환 테스트 모두 lifecycle resource를 해제하세요. 완료된 `container.dispose()` 호출은 idempotent합니다. Teardown 실패는 surface되며, in-flight assertion도 실패할 수 있다면 어느 하나를 suppress하거나 assertion failure를 대체하지 말고(예: `AggregateError`) 두 오류를 함께 보고하세요.
|
|
83
118
|
|
|
84
|
-
`compile()`은 lifecycle hook이 있는 singleton provider에 대해 production module bootstrap과 같은 의미를 따릅니다. effective provider graph를 해석하고, testing module을 반환하기 전에 provider 순서대로 각 instance의 `onModuleInit()`을 실행한 뒤 `onApplicationBootstrap()`을 실행합니다. `get()`은 synchronous singleton 및 multi-provider 경로에서도 DI ownership 의미를 보존하므로, 반복 sync read는 같은 singleton contribution을 재사용하고
|
|
119
|
+
`compile()`은 module에 선언했거나 override한 factory provider를 포함해 lifecycle hook이 있는 singleton provider에 대해 production module bootstrap과 같은 의미를 따릅니다. effective provider graph를 해석하고, testing module을 반환하기 전에 provider 순서대로 각 instance의 `onModuleInit()`을 실행한 뒤 `onApplicationBootstrap()`을 실행합니다. Builder는 반환 시점까지 내부에서 생성한 container를 소유합니다. Override 적용, lifecycle hook 실행, resolved singleton 동기화가 실패하면 reject하기 전에 container를 dispose합니다. Cleanup이 성공하면 원래 compile 실패를 그대로 보존하고, cleanup도 실패하면 원래 실패와 cleanup 실패를 `AggregateError`로 함께 보고합니다. 성공한 `TestingModuleRef`의 동작은 바뀌지 않으며 호출자는 unconditional `finally` 또는 `afterEach` cleanup을 통해 `module.container.dispose()`의 소유권을 계속 가집니다. `get()`은 synchronous singleton 및 multi-provider 경로에서도 DI ownership 의미를 보존하므로, 반복 sync read는 같은 singleton contribution을 재사용하고 container가 해당 instance를 계속 정리할 수 있습니다.
|
|
85
120
|
|
|
86
121
|
### `overrideModule()` 사용 시 모듈 identity 보존
|
|
87
122
|
|
|
@@ -120,7 +155,18 @@ try {
|
|
|
120
155
|
|
|
121
156
|
`app.request(...).send()`는 수동 `FrameworkRequest`/`FrameworkResponse` stub 없이 HTTP 의미에 가까운 테스트를 작성하게 해 주고 runtime dispatch와 같은 isolated request-scoped DI boundary를 생성하므로 애플리케이션 개발자의 기본 경로입니다. Assertion 실패가 runtime resource 누수로 이어지지 않도록 반환된 app은 `finally` 블록에서 닫으세요. `app.dispatch(...)`, `makeRequest(...)`, raw `FluoFactory.create(...)` 테스트는 adapter/runtime contract, framework internal, 또는 low-level dispatch boundary 자체를 증명해야 하는 compatibility case에 남겨 둡니다.
|
|
122
157
|
|
|
123
|
-
|
|
158
|
+
Cookie-bound route에는 adapter가 정규화한 cookie 값을 담는 object request overload를 사용하세요.
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
const response = await app.request({
|
|
162
|
+
path: '/session',
|
|
163
|
+
cookies: { session: 'test-session' },
|
|
164
|
+
}).send();
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`cookies`는 `FrameworkRequest.cookies`에 직접 할당됩니다. `Cookie` header를 parse하거나 adapter별 cookie 의미를 도입하지 않습니다. `TestingModuleRef.dispatch(...)`도 같은 정규화된 cookie record를 받습니다.
|
|
168
|
+
|
|
169
|
+
`createTestApp(...)`은 runtime HTTP bootstrap과 같은 application bootstrap option을 받습니다. 여기에는 `providers`, `filters`, `converters`, `interceptors`, `middleware`, `observers`, `versioning`, `conditionalRequest`, `errorRepresentation`, diagnostics option이 포함됩니다. 따라서 application test는 같은 virtual request pipeline으로 canonical JSON, negotiated HTML, conditional `304`/`412`, `HEAD`, 406, provider fallback을 검증할 수 있습니다. 테스트 헬퍼는 request-context middleware를 앞에 추가하되, 호출자가 넘긴 middleware를 같은 app middleware chain 안에 보존합니다.
|
|
124
170
|
|
|
125
171
|
### 명시적 서브패스의 mock 헬퍼
|
|
126
172
|
|
|
@@ -132,20 +178,34 @@ const repo = createMock<UserRepository>({ findById: vi.fn() });
|
|
|
132
178
|
const mailer = createDeepMock(MailService);
|
|
133
179
|
```
|
|
134
180
|
|
|
135
|
-
`asMock(
|
|
181
|
+
`asMock(fn)`은 함수만 받아 Vitest `Mock<T>`로 좁히며, 임의의 값을 변환하는 cast가 아닙니다. `mockToken(token, value)`는 token 기반 override를 위해 `{ provide: token, useValue: value }` 형태의 `ValueProvider` descriptor를 만듭니다. `createMock(..., { strict: true })`는 지정하지 않은 member 접근을 거부합니다. `DeepMocked<T>`는 root `@fluojs/testing` 패키지, `@fluojs/testing/types`, `@fluojs/testing/mock`에서 모두 노출됩니다. 세 경로는 Vitest peer declaration을 non-mock runtime helper로 끌어들이지 않으면서 같은 Vitest-compatible mock type boundary를 공유합니다. Vitest를 사용하지 않는 소비자는 `@fluojs/testing/app`, `@fluojs/testing/module`, 또는 harness subpath에서 non-mock helper만 import하세요.
|
|
136
182
|
|
|
137
183
|
배포된 런타임 import가 안정적으로 해석되도록, mock 헬퍼를 사용할 워크스페이스에는 `vitest`를 함께 설치해야 합니다.
|
|
138
184
|
|
|
139
185
|
### 적합성 및 이식성 하니스
|
|
140
186
|
|
|
141
|
-
프레임워크 지향 플랫폼 패키지를 작성할 때는 `@fluojs/testing/platform-conformance`, `@fluojs/testing/http-adapter-portability`, `@fluojs/testing/web-runtime-adapter-portability` 같은 서브패스를 사용해 적합성 및 이식성 검증을 수행합니다.
|
|
187
|
+
프레임워크 지향 플랫폼 패키지를 작성할 때는 `@fluojs/testing/platform-conformance`, `@fluojs/testing/platform-shell-lifecycle-conformance`, `@fluojs/testing/http-adapter-portability`, `@fluojs/testing/web-runtime-adapter-portability` 같은 서브패스를 사용해 적합성 및 이식성 검증을 수행합니다.
|
|
188
|
+
|
|
189
|
+
`createPlatformShellLifecycleConformanceHarness({ createShell })`는 active `start()` / `stop()` overlap 전체가 `PlatformLifecycleConflictError`로 reject되는지, callback reentry가 synchronous 시점과 임의의 await 이후에도 conflict-safe한지, 실패한 transition이 settle된 뒤 호출자가 retry할 수 있는지 검증합니다. 컴포넌트 수준 검사는 `createPlatformConformanceHarness(...).assertAll()`에 유지하세요. PlatformShell lifecycle 계약은 의도적으로 별도 harness입니다.
|
|
142
190
|
|
|
143
191
|
이식성 하니스의 cleanup도 계약에 포함됩니다. 앱이 bootstrap된 뒤 setup, `listen()`, partial app을 노출한 run callback, assertion이 실패하면 하니스는 해당 partial app을 닫습니다. `app.close()`가 실패하면 하니스는 cleanup 실패를 보고하며, setup 또는 assertion이 이미 실패한 경우에는 원래 실패와 cleanup 실패를 모두 보존하는 aggregate error를 발생시킵니다.
|
|
144
192
|
|
|
145
|
-
`HttpAdapterPortabilityHarness`와 web-runtime portability harness 메서드는 공개 어댑터 계약 체크입니다. 직접 같은 검증을 다시 만들기보다 `assertPreservesMalformedCookieValues()`, `assertSupportsSseStreaming()`, `assertPreservesRawBodyForJsonAndText()`, `assertPreservesExactRawBodyBytesForByteSensitivePayloads()`, `assertExcludesRawBodyForMultipart()`, `assertDefaultsMultipartTotalLimitToMaxBodySize()`, `assertSettlesStreamDrainWaitOnClose()`, `assertReportsConfiguredHostInStartupLogs()`, `assertReportsHttpsStartupUrl(...)`, `assertRemovesShutdownSignalListenersAfterClose()`처럼 초점이 분명한 assertion을 사용하세요.
|
|
193
|
+
`HttpAdapterPortabilityHarness`와 web-runtime portability harness 메서드는 공개 어댑터 계약 체크입니다. 직접 같은 검증을 다시 만들기보다 `assertSupportsCustomHttpRouteMethods()`, `assertPreservesMalformedCookieValues()`, `assertSupportsSseStreaming()`, `assertPreservesRawBodyForJsonAndText()`, `assertPreservesExactRawBodyBytesForByteSensitivePayloads()`, `assertExcludesRawBodyForMultipart()`, `assertDefaultsMultipartTotalLimitToMaxBodySize()`, `assertSettlesStreamDrainWaitOnClose()`, `assertReportsConfiguredHostInStartupLogs()`, `assertReportsHttpsStartupUrl(...)`, `assertRemovesShutdownSignalListenersAfterClose()`처럼 초점이 분명한 assertion을 사용하세요.
|
|
194
|
+
|
|
195
|
+
Adapter가 body-bearing `QUERY`와 대표 `PURGE` route를 real listener 또는 fetch dispatch seam으로 실행하는지 증명하려면 `assertSupportsCustomHttpRouteMethods()`를 사용하세요. 이 assertion은 `CONNECT`를 일반 routing conformance 범위 밖에 두며 custom method에 native route handoff를 요구하지 않습니다.
|
|
146
196
|
|
|
147
197
|
HTTP 어댑터가 런타임 전반에서 `rawBody`의 byte-sensitive payload byte를 그대로 보존하는지 증명해야 할 때는 `assertPreservesExactRawBodyBytesForByteSensitivePayloads()`를 사용하세요.
|
|
148
198
|
|
|
199
|
+
JSON, HTML, `HEAD`, unsupported `Accept` 406, already-committed response 동작을 증명하려면
|
|
200
|
+
`assertSupportsHttpErrorRepresentations()`를 사용하세요. Network harness는 shared
|
|
201
|
+
`NetworkHttpErrorRepresentationBootstrapOptions`를 adapt하고 fetch-style harness는
|
|
202
|
+
`WebHttpErrorRepresentationBootstrapOptions`를 adapt합니다. Adapter bootstrap type에 추가 required field가
|
|
203
|
+
있다면 `createErrorRepresentationBootstrapOptions`를 제공하세요. Typed builder는 common fixture field만 받아 cast
|
|
204
|
+
없이 해당 adapter의 complete bootstrap option을 반환합니다.
|
|
205
|
+
`assertDoesNotCommitAbortedHttpErrorRepresentations()`는 HTML provider를 시작한 뒤 adapter의 native request
|
|
206
|
+
surface를 통해 abort하고, cancellation 이후 provider result와 canonical JSON fallback 어느 쪽도 write되지 않음을
|
|
207
|
+
증명합니다.
|
|
208
|
+
|
|
149
209
|
## canonical TDD ladder
|
|
150
210
|
|
|
151
211
|
애플리케이션 기능 테스트는 가장 작은 명시적 dependency boundary에서 시작해 바깥쪽으로 확장합니다.
|
|
@@ -167,14 +227,35 @@ test/
|
|
|
167
227
|
|
|
168
228
|
fluo는 테스트가 명시적인 `rootModule`을 이름으로 지정해야 한다는 점에서 NestJS와 다릅니다. 테스트 유틸리티는 legacy TypeScript design metadata나 reflection flag에서 dependency를 추론하지 않고, 작성자가 만든 module graph를 컴파일합니다.
|
|
169
229
|
|
|
230
|
+
## React Consumer Testing Recipe
|
|
231
|
+
|
|
232
|
+
React 애플리케이션은 같은 testing ladder를 유지하고 React-specific testing helper 대신 기존 boundary에
|
|
233
|
+
build/browser evidence를 추가합니다.
|
|
234
|
+
|
|
235
|
+
1. Render-policy 및 metadata composition을 pure value로 unit test합니다.
|
|
236
|
+
2. Direct page return, missing-renderer diagnostic, DTO validation, request-scope identity, response ownership,
|
|
237
|
+
guard, interceptor, native mutation route는 `createTestApp({ rootModule })`로 검증하고 `finally`에서 app을
|
|
238
|
+
닫습니다.
|
|
239
|
+
3. CI에서 `fluo typegen ... --check`를 실행하고 generated-route fixture를 TypeScript로 compile합니다.
|
|
240
|
+
Positive route-id/params case와 negative unknown-id, missing-param, extra-param, stale-output case를 유지합니다.
|
|
241
|
+
4. React DOM으로 server markup을 hydrate합니다. Aligned tree는 diagnostic 없이 interactive해야 하고,
|
|
242
|
+
의도적으로 mismatch한 tree 하나는 `onRecoverableError`를 capture해야 합니다.
|
|
243
|
+
5. Production asset을 대상으로 Playwright를 실행한 뒤 별도 `javaScriptEnabled: false` context에서 native
|
|
244
|
+
form scenario를 반복해 일반 `POST` → `303` → `GET` fallback을 executable 상태로 유지합니다.
|
|
245
|
+
|
|
246
|
+
Runnable map은 [`@fluojs/react`](../react/README.ko.md#consumer-testing-loop)와
|
|
247
|
+
[`examples/react-vite-ssr`](../../examples/react-vite-ssr/README.ko.md#canonical-consumer-test-map)에
|
|
248
|
+
문서화되어 있습니다. 이 layer들은 이미 real HTTP dispatcher와 application page renderer를 compose하므로
|
|
249
|
+
synthetic React test runtime은 필요한 setup을 줄이기보다 coverage를 약화시킵니다.
|
|
250
|
+
|
|
170
251
|
## 공개 API
|
|
171
252
|
|
|
172
253
|
- **루트 패키지**: `createTestingModule(...)`, `Test.createTestingModule(...)`, `createTestApp(...)`, 모듈 introspection 헬퍼, `DeepMocked<T>`를 포함한 공용 app/module 테스트 타입
|
|
173
254
|
- **서브패스**: `@fluojs/testing/app`, `@fluojs/testing/module`, `@fluojs/testing/http`, `@fluojs/testing/mock` (`DeepMocked<T>` 포함), `@fluojs/testing/types` (`DeepMocked<T>` 포함), `@fluojs/testing/vitest`, `@fluojs/testing/vitest/tooling`
|
|
174
|
-
- **하니스 서브패스**: `platform-conformance`, `http-adapter-portability`, `web-runtime-adapter-portability`, `fetch-style-websocket-conformance`
|
|
255
|
+
- **하니스 서브패스**: `platform-conformance`, `platform-shell-lifecycle-conformance`, `http-adapter-portability`, `web-runtime-adapter-portability`, `fetch-style-websocket-conformance`. HTTP portability harness는 adapter-owned bootstrap typing을 위해 `assertSupportsConditionalRequests()`, `assertSupportsCustomHttpRouteMethods()`, `assertSupportsSingleByteRanges()`, `assertSupportsHttpErrorRepresentations()`, `assertDoesNotCommitAbortedHttpErrorRepresentations()`, `assertSupportsPortableResponseCookies()`, `createConditionalRequestBootstrapOptions`, `createErrorRepresentationBootstrapOptions`, `NetworkHttpErrorRepresentationBootstrapOptions`, `WebHttpErrorRepresentationBootstrapOptions`를 노출합니다.
|
|
175
256
|
- **도구 지원**: `@fluojs/testing/vitest`의 `fluoBabelDecoratorsPlugin()` 및 `@fluojs/testing/vitest/tooling`의 Vitest workspace config helper (`vitest`와 `@babel/core`를 함께 요구)
|
|
176
257
|
|
|
177
|
-
Package manifest는 `engines.node >=
|
|
258
|
+
Package manifest는 public body-bearing RFC `QUERY` portability assertion이 사용하는 검증된 Node listener window와 일치하도록 `engines.node >=24.0.0 <27`을 선언합니다. Node 24 미만과 Node 27 이상은 제외됩니다. 문서화된 경우 non-Node runtime 애플리케이션 테스트에서 runtime-native 도구를 사용할 수 있지만, 배포된 `@fluojs/testing` 패키지 자체는 이 정확한 Node.js engine 범위를 따릅니다.
|
|
178
259
|
|
|
179
260
|
`@fluojs/testing/vitest/tooling`은 각 package의 공개 `exports`에 선언된 entrypoint만 workspace alias로 매핑합니다. Private source file, internal helper, export되지 않은 source entrypoint는 의도적으로 제외하므로 테스트가 published package 소비자에게 제공되는 import boundary와 같은 경계를 검증합니다.
|
|
180
261
|
|
|
@@ -187,5 +268,6 @@ Package manifest는 `engines.node >=20.0.0`을 선언합니다. 문서화된 경
|
|
|
187
268
|
## 예제 소스
|
|
188
269
|
|
|
189
270
|
- `packages/testing/src/module.test.ts`
|
|
271
|
+
- `packages/testing/src/portability/error-representation-portability.ts`
|
|
190
272
|
- `examples/minimal/src/app.test.ts`
|
|
191
273
|
- `examples/auth-jwt-passport/src/app.test.ts`
|
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
<p><strong><kbd>English</kbd></strong> <a href="./README.ko.md"><kbd>한국어</kbd></a></p>
|
|
4
4
|
|
|
5
|
-
Node.js
|
|
5
|
+
Node.js `>=24.0.0 <27` request-level testing helpers, testing module construction, and provider overrides for fluo applications.
|
|
6
|
+
|
|
7
|
+
Preparing for the coordinated Node 24 release? Follow the [consumer migration guide](../../docs/getting-started/migrate-node24.md) before upgrading packages.
|
|
6
8
|
|
|
7
9
|
## Table of Contents
|
|
8
10
|
|
|
@@ -11,6 +13,7 @@ Node.js 20+ request-level testing helpers, testing module construction, and prov
|
|
|
11
13
|
- [Quick Start](#quick-start)
|
|
12
14
|
- [Common Patterns](#common-patterns)
|
|
13
15
|
- [Canonical TDD Ladder](#canonical-tdd-ladder)
|
|
16
|
+
- [React Consumer Testing Recipe](#react-consumer-testing-recipe)
|
|
14
17
|
- [Public API](#public-api)
|
|
15
18
|
- [Related Packages](#related-packages)
|
|
16
19
|
- [Example Sources](#example-sources)
|
|
@@ -21,9 +24,9 @@ Node.js 20+ request-level testing helpers, testing module construction, and prov
|
|
|
21
24
|
pnpm add -D @fluojs/testing vitest
|
|
22
25
|
```
|
|
23
26
|
|
|
24
|
-
`
|
|
27
|
+
Vitest `^4.1.11` is a required peer dependency for the mock helpers and the `@fluojs/testing/vitest` entrypoint. `@babel/core` is declared as a peer because the Vitest decorators plugin loads Babel from the consuming workspace; package managers may surface that peer even when you only use the non-Vitest harness subpaths.
|
|
25
28
|
|
|
26
|
-
If you use `@fluojs/testing/vitest`, install `@babel/core` in the consuming workspace as well because `fluoBabelDecoratorsPlugin()` invokes Babel at runtime. The Vitest plugin transforms `.ts`, `.tsx`, `.mts`, and `.cts` source ids after removing Vite query/hash suffixes, skips `node_modules`, and resolves the nearest root Babel config named `babel.config.cjs`, `babel.config.mjs`, `babel.config.js`, or `babel.config.json`:
|
|
29
|
+
If you use `@fluojs/testing/vitest`, install `@babel/core` in the consuming workspace as well because `fluoBabelDecoratorsPlugin()` invokes Babel at runtime. The Vitest plugin runs with `enforce: 'pre'` so decorator-bearing TypeScript reaches Babel before Vite 8 normal-stage Rolldown/Oxc transforms. It transforms `.ts`, `.tsx`, `.mts`, and `.cts` source ids after removing Vite query/hash suffixes, skips `node_modules`, and resolves the nearest root Babel config named `babel.config.cjs`, `babel.config.mjs`, `babel.config.js`, or `babel.config.json`:
|
|
27
30
|
|
|
28
31
|
```bash
|
|
29
32
|
pnpm add -D @babel/core
|
|
@@ -74,12 +77,44 @@ const module = await createTestingModule({ rootModule: AppModule })
|
|
|
74
77
|
})
|
|
75
78
|
.compile();
|
|
76
79
|
|
|
77
|
-
|
|
80
|
+
let testError: unknown;
|
|
81
|
+
let testFailed = false;
|
|
82
|
+
let disposeError: unknown;
|
|
83
|
+
let disposeFailed = false;
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const service = await module.resolve(UserService);
|
|
87
|
+
} catch (error: unknown) {
|
|
88
|
+
testError = error;
|
|
89
|
+
testFailed = true;
|
|
90
|
+
} finally {
|
|
91
|
+
try {
|
|
92
|
+
await module.container.dispose();
|
|
93
|
+
} catch (error: unknown) {
|
|
94
|
+
disposeFailed = true;
|
|
95
|
+
disposeError = error;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (testFailed) {
|
|
100
|
+
if (disposeFailed) {
|
|
101
|
+
throw new AggregateError(
|
|
102
|
+
[testError, disposeError],
|
|
103
|
+
'Test and testing module disposal both failed.',
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
throw testError;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (disposeFailed) {
|
|
111
|
+
throw disposeError;
|
|
112
|
+
}
|
|
78
113
|
```
|
|
79
114
|
|
|
80
|
-
The testing builder also supports `overrideProviders([[token, value], ...])`, `overrideGuard(...)`, `overrideInterceptor(...)`, and `overrideFilter(...)` for route-pipeline tests that need to replace cross-cutting behavior. Guard and interceptor overrides are request-path safe when the route references the same token via `@UseGuards(...)` or `@UseInterceptors(...)`; filter overrides replace the token in the compiled module graph and should be paired with request-level coverage where that filter is registered in the runtime app surface.
|
|
115
|
+
The testing builder also supports `overrideProviders([[token, value], ...])`, `overrideGuard(...)`, `overrideInterceptor(...)`, and `overrideFilter(...)` for route-pipeline tests that need to replace cross-cutting behavior. Guard and interceptor overrides are request-path safe when the route references the same token via `@UseGuards(...)` or `@UseInterceptors(...)`; filter overrides replace the token in the compiled module graph and should be paired with request-level coverage where that filter is registered in the runtime app surface. Retain every successfully compiled `TestingModuleRef` and dispose its caller-owned `container` from `finally` (or `afterEach` for suite setup) so passing, failing, and early-returning tests all release lifecycle resources. A completed `container.dispose()` is idempotent. Teardown failures surface; when an in-flight assertion can also fail, report both errors (for example with `AggregateError`) rather than suppressing or replacing the assertion failure.
|
|
81
116
|
|
|
82
|
-
`compile()` follows production module-bootstrap semantics for lifecycle-bearing singleton providers: it resolves the effective provider graph, runs `onModuleInit()` for each resolved instance, then runs `onApplicationBootstrap()` in the same provider order before the testing module is returned. `get()` keeps DI ownership semantics for synchronous singleton and multi-provider paths, so repeated sync reads reuse the same singleton contributions and
|
|
117
|
+
`compile()` follows production module-bootstrap semantics for lifecycle-bearing singleton providers, including module-declared and overridden factory providers: it resolves the effective provider graph, runs `onModuleInit()` for each resolved instance, then runs `onApplicationBootstrap()` in the same provider order before the testing module is returned. The builder owns its internally created container until that return: if applying overrides, running lifecycle hooks, or synchronizing resolved singletons fails, it disposes the container before rejecting. Successful cleanup preserves the original compile failure; a cleanup failure is reported with the original failure in an `AggregateError`. Successful `TestingModuleRef` behavior is unchanged, and callers retain ownership of `module.container.dispose()` through an unconditional `finally` or `afterEach` cleanup. `get()` keeps DI ownership semantics for synchronous singleton and multi-provider paths, so repeated sync reads reuse the same singleton contributions and the container can still clean them up.
|
|
83
118
|
|
|
84
119
|
### Preserve module identity with `overrideModule()`
|
|
85
120
|
|
|
@@ -118,7 +153,18 @@ try {
|
|
|
118
153
|
|
|
119
154
|
`app.request(...).send()` is the preferred app-developer path because it keeps tests close to HTTP semantics without manual `FrameworkRequest`/`FrameworkResponse` stubs and creates the same isolated request-scoped DI boundary as runtime dispatch. Close the returned app from a `finally` block so assertion failures do not leak runtime resources. Keep `app.dispatch(...)`, `makeRequest(...)`, and raw `FluoFactory.create(...)` tests for adapter/runtime contracts, framework internals, or compatibility cases where the low-level dispatch boundary itself is what the test must prove.
|
|
120
155
|
|
|
121
|
-
|
|
156
|
+
For cookie-bound routes, use the object request overload with adapter-normalized cookie values:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
const response = await app.request({
|
|
160
|
+
path: '/session',
|
|
161
|
+
cookies: { session: 'test-session' },
|
|
162
|
+
}).send();
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`cookies` is assigned directly to `FrameworkRequest.cookies`; it does not parse a `Cookie` header or introduce adapter-specific cookie semantics. `TestingModuleRef.dispatch(...)` accepts the same normalized cookie record.
|
|
166
|
+
|
|
167
|
+
`createTestApp(...)` accepts the same application bootstrap options as the runtime HTTP bootstrap, including `providers`, `filters`, `converters`, `interceptors`, `middleware`, `observers`, `versioning`, `conditionalRequest`, `errorRepresentation`, and diagnostics options. This lets application tests assert canonical JSON, negotiated HTML, conditional `304`/`412`, `HEAD`, 406, and provider fallback behavior through the same virtual request pipeline. The testing helper prepends its request-context middleware while preserving caller-provided middleware in the same app middleware chain.
|
|
122
168
|
|
|
123
169
|
### Mock helpers from explicit subpaths
|
|
124
170
|
|
|
@@ -130,20 +176,34 @@ const repo = createMock<UserRepository>({ findById: vi.fn() });
|
|
|
130
176
|
const mailer = createDeepMock(MailService);
|
|
131
177
|
```
|
|
132
178
|
|
|
133
|
-
`asMock(
|
|
179
|
+
`asMock(fn)` accepts only a function and narrows it to Vitest `Mock<T>`; it is not an arbitrary-value cast. `mockToken(token, value)` creates a `ValueProvider` descriptor shaped as `{ provide: token, useValue: value }` for token-based overrides. `createMock(..., { strict: true })` rejects access to unspecified members. `DeepMocked<T>` is exposed from the root `@fluojs/testing` package, `@fluojs/testing/types`, and `@fluojs/testing/mock`; all three paths intentionally share the same Vitest-compatible mock type boundary without importing Vitest peer declarations through non-mock runtime helpers. Consumers that do not use Vitest should import only non-mock helpers from `@fluojs/testing/app`, `@fluojs/testing/module`, or the harness subpaths.
|
|
134
180
|
|
|
135
181
|
Install `vitest` in the consuming workspace before using the mock helpers so the published runtime import resolves consistently.
|
|
136
182
|
|
|
137
183
|
### Conformance and portability harnesses
|
|
138
184
|
|
|
139
|
-
Use subpaths like `@fluojs/testing/platform-conformance`, `@fluojs/testing/http-adapter-portability`, and `@fluojs/testing/web-runtime-adapter-portability` when authoring framework-facing platform packages.
|
|
185
|
+
Use subpaths like `@fluojs/testing/platform-conformance`, `@fluojs/testing/platform-shell-lifecycle-conformance`, `@fluojs/testing/http-adapter-portability`, and `@fluojs/testing/web-runtime-adapter-portability` when authoring framework-facing platform packages.
|
|
186
|
+
|
|
187
|
+
Use `createPlatformShellLifecycleConformanceHarness({ createShell })` to verify every active `start()` / `stop()` overlap rejects with `PlatformLifecycleConflictError`, callback reentry remains conflict-safe before and after arbitrary awaits, and callers can retry after a failed transition settles. Keep component-level checks in `createPlatformConformanceHarness(...).assertAll()`; the PlatformShell lifecycle contract is intentionally a separate harness.
|
|
140
188
|
|
|
141
189
|
Portability harness cleanup is part of the contract: if setup, `listen()`, a run callback that surfaces a partial app, or an assertion fails after an app has been bootstrapped, the harness closes that partial app. If `app.close()` fails, the harness reports that cleanup failure, and when setup or an assertion already failed it raises an aggregate error that preserves both the original failure and the cleanup failure.
|
|
142
190
|
|
|
143
|
-
`HttpAdapterPortabilityHarness` and web-runtime portability harness methods are the public adapter contract checks. Prefer focused assertions such as `assertPreservesMalformedCookieValues()`, `assertSupportsSseStreaming()`, `assertPreservesRawBodyForJsonAndText()`, `assertPreservesExactRawBodyBytesForByteSensitivePayloads()`, `assertExcludesRawBodyForMultipart()`, `assertDefaultsMultipartTotalLimitToMaxBodySize()`, `assertSettlesStreamDrainWaitOnClose()`, `assertReportsConfiguredHostInStartupLogs()`, `assertReportsHttpsStartupUrl(...)`, and `assertRemovesShutdownSignalListenersAfterClose()` instead of hand-rolled equivalents.
|
|
191
|
+
`HttpAdapterPortabilityHarness` and web-runtime portability harness methods are the public adapter contract checks. Prefer focused assertions such as `assertSupportsCustomHttpRouteMethods()`, `assertPreservesMalformedCookieValues()`, `assertSupportsSseStreaming()`, `assertPreservesRawBodyForJsonAndText()`, `assertPreservesExactRawBodyBytesForByteSensitivePayloads()`, `assertExcludesRawBodyForMultipart()`, `assertDefaultsMultipartTotalLimitToMaxBodySize()`, `assertSettlesStreamDrainWaitOnClose()`, `assertReportsConfiguredHostInStartupLogs()`, `assertReportsHttpsStartupUrl(...)`, and `assertRemovesShutdownSignalListenersAfterClose()` instead of hand-rolled equivalents.
|
|
192
|
+
|
|
193
|
+
Use `assertSupportsCustomHttpRouteMethods()` to prove that the adapter executes body-bearing `QUERY` and representative `PURGE` routes through its real listener or fetch dispatch seam. The assertion keeps `CONNECT` outside ordinary routing conformance and does not require custom methods to use a native route handoff.
|
|
144
194
|
|
|
145
195
|
Use `assertPreservesExactRawBodyBytesForByteSensitivePayloads()` when an HTTP adapter must prove `rawBody` keeps byte-sensitive payload bytes intact across runtimes.
|
|
146
196
|
|
|
197
|
+
Use `assertSupportsHttpErrorRepresentations()` to prove JSON, HTML, `HEAD`, unsupported `Accept`
|
|
198
|
+
406, and already-committed response behavior. Network harnesses adapt the shared
|
|
199
|
+
`NetworkHttpErrorRepresentationBootstrapOptions`; fetch-style harnesses adapt
|
|
200
|
+
`WebHttpErrorRepresentationBootstrapOptions`. Supply `createErrorRepresentationBootstrapOptions`
|
|
201
|
+
when an adapter's bootstrap type contains additional required fields—the typed builder receives only
|
|
202
|
+
the common fixture fields and returns that adapter's complete bootstrap options without casts.
|
|
203
|
+
Use `assertDoesNotCommitAbortedHttpErrorRepresentations()` to start an HTML provider, abort through
|
|
204
|
+
the adapter's native request surface, and prove that neither the provider result nor canonical JSON
|
|
205
|
+
fallback is written after cancellation.
|
|
206
|
+
|
|
147
207
|
## Canonical TDD Ladder
|
|
148
208
|
|
|
149
209
|
For application features, build tests from the smallest explicit dependency boundary outward:
|
|
@@ -165,14 +225,37 @@ test/
|
|
|
165
225
|
|
|
166
226
|
fluo differs from NestJS by requiring tests to name an explicit `rootModule`. The testing utilities compile the module graph you authored instead of inferring dependencies from legacy TypeScript design metadata or reflection flags.
|
|
167
227
|
|
|
228
|
+
## React Consumer Testing Recipe
|
|
229
|
+
|
|
230
|
+
React applications keep the same testing ladder and add build/browser evidence at the existing
|
|
231
|
+
boundaries instead of introducing a React-specific testing helper:
|
|
232
|
+
|
|
233
|
+
1. Unit-test render-policy and metadata composition as pure values.
|
|
234
|
+
2. Use `createTestApp({ rootModule })` for direct page returns, missing-renderer diagnostics, DTO
|
|
235
|
+
validation, request-scope identity, response ownership, guards, interceptors, and native mutation
|
|
236
|
+
routes. Close the app in `finally`.
|
|
237
|
+
3. Run `fluo typegen ... --check` in CI and compile generated-route fixtures with TypeScript. Keep
|
|
238
|
+
positive route-id/params cases and negative unknown-id, missing-param, extra-param, and stale-output
|
|
239
|
+
cases.
|
|
240
|
+
4. Hydrate server markup with React DOM. Assert an aligned tree is interactive without diagnostics,
|
|
241
|
+
and capture `onRecoverableError` for one deliberately mismatched tree.
|
|
242
|
+
5. Run Playwright against production assets, then repeat the native form scenario in a separate
|
|
243
|
+
`javaScriptEnabled: false` context so the ordinary `POST` → `303` → `GET` fallback stays executable.
|
|
244
|
+
|
|
245
|
+
The runnable map is documented in
|
|
246
|
+
[`@fluojs/react`](../react/README.md#consumer-testing-loop) and
|
|
247
|
+
[`examples/react-vite-ssr`](../../examples/react-vite-ssr/README.md#canonical-consumer-test-map).
|
|
248
|
+
These layers already compose the real HTTP dispatcher and application page renderer, so a synthetic
|
|
249
|
+
React test runtime would reduce coverage rather than remove necessary setup.
|
|
250
|
+
|
|
168
251
|
## Public API
|
|
169
252
|
|
|
170
253
|
- **Root package**: `createTestingModule(...)`, `Test.createTestingModule(...)`, `createTestApp(...)`, module introspection helpers, and shared app/module testing types including `DeepMocked<T>`
|
|
171
254
|
- **Subpaths**: `@fluojs/testing/app`, `@fluojs/testing/module`, `@fluojs/testing/http`, `@fluojs/testing/mock` (including `DeepMocked<T>`), `@fluojs/testing/types` (including `DeepMocked<T>`), `@fluojs/testing/vitest`, `@fluojs/testing/vitest/tooling`
|
|
172
|
-
- **Harness subpaths**: `platform-conformance`, `http-adapter-portability`, `web-runtime-adapter-portability`, `fetch-style-websocket-conformance`
|
|
255
|
+
- **Harness subpaths**: `platform-conformance`, `platform-shell-lifecycle-conformance`, `http-adapter-portability`, `web-runtime-adapter-portability`, `fetch-style-websocket-conformance`. The HTTP portability harnesses expose `assertSupportsConditionalRequests()`, `assertSupportsCustomHttpRouteMethods()`, `assertSupportsSingleByteRanges()`, `assertSupportsHttpErrorRepresentations()`, `assertDoesNotCommitAbortedHttpErrorRepresentations()`, `assertSupportsPortableResponseCookies()`, `createConditionalRequestBootstrapOptions`, `createErrorRepresentationBootstrapOptions`, `NetworkHttpErrorRepresentationBootstrapOptions`, and `WebHttpErrorRepresentationBootstrapOptions` for adapter-owned bootstrap typing.
|
|
173
256
|
- **Tooling**: `@fluojs/testing/vitest` with `fluoBabelDecoratorsPlugin()` and `@fluojs/testing/vitest/tooling` with Vitest workspace config helpers (requires `vitest` and `@babel/core` in the consuming workspace)
|
|
174
257
|
|
|
175
|
-
The package manifest declares `engines.node >=
|
|
258
|
+
The package manifest declares `engines.node >=24.0.0 <27`, matching the verified Node listener windows used by its public body-bearing RFC `QUERY` portability assertion. Node versions below 24 and Node 27+ are excluded. Non-Node runtime application tests can still use runtime-native tools where documented, but the published `@fluojs/testing` package itself is governed by that exact Node.js engine range.
|
|
176
259
|
|
|
177
260
|
`@fluojs/testing/vitest/tooling` maps workspace aliases only for each package's declared public `exports`. Private source files, internal helpers, and unexported source entrypoints are intentionally excluded so tests exercise the same import boundaries that consumers receive from published packages.
|
|
178
261
|
|
|
@@ -185,5 +268,6 @@ The package manifest declares `engines.node >=20.0.0`. Non-Node runtime applicat
|
|
|
185
268
|
## Example Sources
|
|
186
269
|
|
|
187
270
|
- `packages/testing/src/module.test.ts`
|
|
271
|
+
- `packages/testing/src/portability/error-representation-portability.ts`
|
|
188
272
|
- `examples/minimal/src/app.test.ts`
|
|
189
273
|
- `examples/auth-jwt-passport/src/app.test.ts`
|
|
@@ -16,6 +16,7 @@ export declare function resolveNearestBabelConfigFile(filePath: string): string;
|
|
|
16
16
|
*/
|
|
17
17
|
export declare function createFluoBabelDecoratorsPlugin(resolveConfigFile: (filePath: string) => string): {
|
|
18
18
|
name: string;
|
|
19
|
+
enforce: "pre";
|
|
19
20
|
transform(code: string, id: string): Promise<{
|
|
20
21
|
code: string;
|
|
21
22
|
map: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-decorators-plugin.d.ts","sourceRoot":"","sources":["../src/babel-decorators-plugin.ts"],"names":[],"mappings":"AAsBA;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA2BtE;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAC7C,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM
|
|
1
|
+
{"version":3,"file":"babel-decorators-plugin.d.ts","sourceRoot":"","sources":["../src/babel-decorators-plugin.ts"],"names":[],"mappings":"AAsBA;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA2BtE;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAC7C,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM;;;oBAKvB,MAAM,MAAM,MAAM;;;;;;;;;;;;EAwB3C;AAED;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,UAAU,CAAC,OAAO,+BAA+B,CAAC,CAAC"}
|
|
@@ -54,6 +54,7 @@ export function resolveNearestBabelConfigFile(filePath) {
|
|
|
54
54
|
export function createFluoBabelDecoratorsPlugin(resolveConfigFile) {
|
|
55
55
|
return {
|
|
56
56
|
name: 'fluo-babel-decorators',
|
|
57
|
+
enforce: 'pre',
|
|
57
58
|
async transform(code, id) {
|
|
58
59
|
const filePath = normalizeTransformId(id);
|
|
59
60
|
if (!isTypeScriptSource(filePath) || isNodeModulesPath(filePath)) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-range-portability-consumer.test-fixture.d.ts","sourceRoot":"","sources":["../src/byte-range-portability-consumer.test-fixture.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createByteRangeResponse } from '@fluojs/http';
|
|
2
|
+
import { createHttpAdapterPortabilityHarness } from '@fluojs/testing/http-adapter-portability';
|
|
3
|
+
import { createWebRuntimeHttpAdapterPortabilityHarness } from '@fluojs/testing/web-runtime-adapter-portability';
|
|
4
|
+
const bytes = Uint8Array.from([0, 1, 2]);
|
|
5
|
+
const options = {
|
|
6
|
+
contentType: 'application/octet-stream'
|
|
7
|
+
};
|
|
8
|
+
const source = bytes;
|
|
9
|
+
void createByteRangeResponse(source, options);
|
|
10
|
+
void createHttpAdapterPortabilityHarness;
|
|
11
|
+
void createWebRuntimeHttpAdapterPortabilityHarness;
|
|
@@ -6,6 +6,7 @@ export interface FetchStyleWebSocketConformanceHarnessOptions<TAdapter extends H
|
|
|
6
6
|
createAdapter: () => TAdapter;
|
|
7
7
|
expectedReason: string;
|
|
8
8
|
expectedSupport?: FetchStyleHttpAdapterRealtimeCapability['support'];
|
|
9
|
+
expectedVersion?: FetchStyleHttpAdapterRealtimeCapability['version'];
|
|
9
10
|
name: string;
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-style-websocket-conformance.d.ts","sourceRoot":"","sources":["../../src/conformance/fetch-style-websocket-conformance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uCAAuC,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAEpG;;GAEG;AACH,MAAM,WAAW,4CAA4C,CAC3D,QAAQ,SAAS,sBAAsB,GAAG,sBAAsB;IAEhE,aAAa,EAAE,MAAM,QAAQ,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,uCAAuC,CAAC,SAAS,CAAC,CAAC;IACrE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,qBAAa,qCAAqC,CAChD,QAAQ,SAAS,sBAAsB,GAAG,sBAAsB;IAEpD,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,4CAA4C,CAAC,QAAQ,CAAC;IAE5F,0CAA0C,IAAI,IAAI;CAoCnD;AAED;;;;;GAKG;AACH,wBAAgB,2CAA2C,CACzD,QAAQ,SAAS,sBAAsB,GAAG,sBAAsB,EAEhE,OAAO,EAAE,4CAA4C,CAAC,QAAQ,CAAC,GAC9D,qCAAqC,CAAC,QAAQ,CAAC,CAEjD"}
|
|
1
|
+
{"version":3,"file":"fetch-style-websocket-conformance.d.ts","sourceRoot":"","sources":["../../src/conformance/fetch-style-websocket-conformance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uCAAuC,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAEpG;;GAEG;AACH,MAAM,WAAW,4CAA4C,CAC3D,QAAQ,SAAS,sBAAsB,GAAG,sBAAsB;IAEhE,aAAa,EAAE,MAAM,QAAQ,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,uCAAuC,CAAC,SAAS,CAAC,CAAC;IACrE,eAAe,CAAC,EAAE,uCAAuC,CAAC,SAAS,CAAC,CAAC;IACrE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,qBAAa,qCAAqC,CAChD,QAAQ,SAAS,sBAAsB,GAAG,sBAAsB;IAEpD,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,4CAA4C,CAAC,QAAQ,CAAC;IAE5F,0CAA0C,IAAI,IAAI;CAoCnD;AAED;;;;;GAKG;AACH,wBAAgB,2CAA2C,CACzD,QAAQ,SAAS,sBAAsB,GAAG,sBAAsB,EAEhE,OAAO,EAAE,4CAA4C,CAAC,QAAQ,CAAC,GAC9D,qCAAqC,CAAC,QAAQ,CAAC,CAEjD"}
|
|
@@ -25,7 +25,7 @@ export class FetchStyleWebSocketConformanceHarness {
|
|
|
25
25
|
if (capability.mode !== 'request-upgrade') {
|
|
26
26
|
throw new Error(`${this.options.name} adapter changed the fetch-style raw websocket upgrade mode.`);
|
|
27
27
|
}
|
|
28
|
-
if (capability.version !== 1) {
|
|
28
|
+
if (capability.version !== (this.options.expectedVersion ?? 1)) {
|
|
29
29
|
throw new Error(`${this.options.name} adapter changed the fetch-style raw websocket contract version.`);
|
|
30
30
|
}
|
|
31
31
|
if (capability.support !== expectedSupport) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PlatformComponent, PlatformShell } from '@fluojs/runtime';
|
|
2
|
+
/**
|
|
3
|
+
* Describes the PlatformShell lifecycle conformance harness options contract.
|
|
4
|
+
*/
|
|
5
|
+
export interface PlatformShellLifecycleConformanceHarnessOptions {
|
|
6
|
+
createShell: (component: PlatformComponent) => PlatformShell;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Represents lifecycle exclusivity checks for a PlatformShell implementation.
|
|
10
|
+
*/
|
|
11
|
+
export declare class PlatformShellLifecycleConformanceHarness {
|
|
12
|
+
private readonly options;
|
|
13
|
+
constructor(options: PlatformShellLifecycleConformanceHarnessOptions);
|
|
14
|
+
assertAll(): Promise<void>;
|
|
15
|
+
assertOverlappingTransitionsRejectImmediately(): Promise<void>;
|
|
16
|
+
assertCallbackReentryRejects(): Promise<void>;
|
|
17
|
+
assertSettledTransitionsPermitRetries(): Promise<void>;
|
|
18
|
+
assertSequentialTransitionsRemainIdempotent(): Promise<void>;
|
|
19
|
+
private assertSynchronousStartCallbackReentryRejects;
|
|
20
|
+
private assertAwaitedStopCallbackReentryRejects;
|
|
21
|
+
private assertFailedTransitionPermitsRetry;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create PlatformShell lifecycle conformance harness.
|
|
25
|
+
*
|
|
26
|
+
* @param options The options.
|
|
27
|
+
* @returns The create PlatformShell lifecycle conformance harness result.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createPlatformShellLifecycleConformanceHarness(options: PlatformShellLifecycleConformanceHarnessOptions): PlatformShellLifecycleConformanceHarness;
|
|
30
|
+
//# sourceMappingURL=platform-shell-lifecycle-conformance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-shell-lifecycle-conformance.d.ts","sourceRoot":"","sources":["../../src/conformance/platform-shell-lifecycle-conformance.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EAIjB,aAAa,EAId,MAAM,iBAAiB,CAAC;AA4GzB;;GAEG;AACH,MAAM,WAAW,+CAA+C;IAC9D,WAAW,EAAE,CAAC,SAAS,EAAE,iBAAiB,KAAK,aAAa,CAAC;CAC9D;AAED;;GAEG;AACH,qBAAa,wCAAwC;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,+CAA+C;IAE/E,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAO1B,6CAA6C,IAAI,OAAO,CAAC,IAAI,CAAC;IAoC9D,4BAA4B,IAAI,OAAO,CAAC,IAAI,CAAC;IAK7C,qCAAqC,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtD,2CAA2C,IAAI,OAAO,CAAC,IAAI,CAAC;YAgBpD,4CAA4C;YAkB5C,uCAAuC;YAqBvC,kCAAkC;CAsBjD;AAkDD;;;;;GAKG;AACH,wBAAgB,8CAA8C,CAC5D,OAAO,EAAE,+CAA+C,GACvD,wCAAwC,CAE1C"}
|