Skip to content

Commit c09f0a8

Browse files
constantantclaude
andcommitted
docs: update READMEs for v1.8.0/v0.5.0/v0.7.0 features
- Root README: bump ext version to 0.7.0, add includeMswHandlers option, expand mocks section with /testing entry and injectMockResource, expand extension section with Scenarios, History inspector, local mocks - openapi-resource-gen README: add includeMswHandlers option and output structure entries, add MSW handlers section, update implementation notes - openapi-resource-mocks README: add /testing sub-entry section covering mockResource(), MockResourceHandle, and sequence mocking - openapi-resource-devtools README: expand History tab with request inspector details, add Scenarios to toolbar table, add Local mocks section Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ac9ef67 commit c09f0a8

4 files changed

Lines changed: 179 additions & 4 deletions

File tree

README.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ Re-run the generator command whenever your spec changes — it overwrites genera
9393
| `namingConvention` | no | `kebab` | `kebab` or `camel` — controls file names |
9494
| `providedIn` | no | `none` | `none` (use `provideX()` helpers) or `root` (self-registering) |
9595
| `includeMocks` | no | `false` | Co-generate `.mock.ts` providers, `index.mock.ts` barrels, and `mocks.manifest.json` — requires `@constantant/openapi-resource-mocks` |
96+
| `includeMswHandlers` | no | `false` | Co-generate `.msw.ts` MSW 2.x handler files and `index.msw.ts` barrels — requires [`msw`](https://mswjs.io) >= 2.0.0 |
9697
| `specId` | no | derived | Identifier embedded in `MockResourceMeta` and `mocks.manifest.json`. Defaults to `baseUrlToken` with `_BASE_URL` stripped (e.g. `PETSTORE_BASE_URL``petstore`). Must match when importing into the DevTools panel. |
9798
| `verbose` | no | `false` | Print a `+`/`~`/`-` summary of created, updated, and deleted files after generation. |
9899

@@ -257,17 +258,27 @@ A companion package that provides zero-HTTP, pure-DI mocks for generated tokens.
257258
- `provideMockResourceBus()` — registers the bus; exposes `window.__openApiMocks__` and `openApiMock(key)` for Playwright
258259
- `provideMockResource(token, key, initialBehavior?, meta?)` — replaces a token's factory with a mock; the optional `meta` (`MockResourceMeta`) is embedded automatically in generated `.mock.ts` files and used by the DevTools panel to resolve response schemas
259260
- DOM event bridge (`openapi-mock-event` / `openapi-mock-control`) — lets the Chrome Extension DevTools panel observe and control mocks in real time
261+
- `injectMockResource<T>(key)` — retrieves the `MockResourceRef<T>` for a registered key inside an injection context (e.g. `TestBed.runInInjectionContext`)
260262
- `MockResourceRef<T>``resolve()`, `setLoading()`, `fail()`, `reset()`, `simulateProgress()`, `getHistory()`
263+
- **`/testing` sub-entry**`mockResource(token, behavior?)` returns a `MockResourceHandle<T>` extending `FactoryProvider`; drop directly into `TestBed` providers without a full bus setup; supports `{ sequence: [...] }` for multi-step per-call responses
261264

262265
See [`tools/openapi-resource-mocks/README.md`](tools/openapi-resource-mocks/README.md) for full documentation.
263266

264267
---
265268

266269
## Chrome DevTools Extension — OpenAPI Resource Mocks DevTools
267270

268-
Current version: **0.6.0** | Status: pending Chrome Web Store review
271+
Current version: **0.7.0** | Status: pending Chrome Web Store review
269272

270-
A Chrome DevTools panel that connects to any Angular app running `@constantant/openapi-resource-mocks`. It lists every registered mock token, shows live state, and lets you resolve, fail, catch, or reset mocks without touching code. The **Specs** tab lets you import a `mocks.manifest.json` or full OpenAPI spec to enable schema-aware features in the Respond tab: auto-generated example payloads (⚡ Example) and JSON schema validation (✓ Validate).
273+
A Chrome DevTools panel that connects to any Angular app running `@constantant/openapi-resource-mocks`. It lists every registered mock token, shows live state, and lets you resolve, fail, catch, or reset mocks without touching code.
274+
275+
Key panel features:
276+
- **Mock table** — live status, catch mode toggle, resolve/fail/reset actions per token
277+
- **Respond tab** — JSON editor with schema-aware ⚡ Example generation and ✓ Validate; delay control; catch mode release
278+
- **History tab** — reverse-chronological event log; for `request`/`caught` events shows the filled URL (`GET /pet/42`), path-param rows labeled by name, and Query / Body sections for remaining args; binary payloads (`[FormData]`, `[Blob]`, etc.) shown as inline badges
279+
- **Specs tab** — import `mocks.manifest.json` or a full OpenAPI spec (JSON or YAML, file or URL) to enable schema-aware features
280+
- **Scenarios** toolbar button — save named snapshots of the full mock table state, load / delete them, or export / import as JSON for cross-machine sharing
281+
- **+ New mock** button — create a panel-managed (local) mock before `provideMockResource()` exists in the app, pre-configure catch mode and a response value, and have it promoted in-place when the key is registered
271282

272283
### Install
273284

tools/openapi-resource-devtools/README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,17 @@ Manually resolve, fail, or control the selected mock:
8787

8888
### History tab
8989

90-
Reverse-chronological event log for the selected mock (up to 200 entries). Each row shows the timestamp, event type badge, and a truncated JSON preview of the value or error. A **Clear** button wipes the log.
90+
Reverse-chronological event log for the selected mock (up to 200 entries). A **Clear** button wipes the log.
91+
92+
Each row shows the timestamp, event type badge, and a one-line preview. For `request` and `caught` events the preview shows the **filled URL** — e.g. `GET /pet/42` — derived from the operation's path template and the actual args the component passed.
93+
94+
Clicking a row expands a structured detail view:
95+
96+
- **Filled URL** — the path with `{param}` placeholders substituted by positional args (e.g. `GET /pet/{petId}``GET /pet/42`)
97+
- **Path param rows** — one row per `{param}`, labeled by name from the spec, showing the actual value passed
98+
- **Query / Body section** — remaining args after path params are labeled **Query** (GET/HEAD/DELETE) or **Body** (POST/PUT/PATCH)
99+
- **Binary badges**`[FormData]`, `[Blob]`, `[ArrayBuffer]`, and `[File: name]` are displayed as inline badges instead of quoted strings
100+
- **Response / Error sections** — shown for `resolve` and `error` events
91101

92102
---
93103

@@ -145,10 +155,28 @@ After each release, if catch mode is still on, the resource is immediately re-in
145155
| ⏸ Catch All | Toggles catch mode on every registered mock |
146156
| Clear | Removes all mocks from the panel (does not affect the page) |
147157
| Reset All | Calls `reset()` on every mock, returning them to `idle` |
158+
| Scenarios | Opens the Scenarios dialog — save named snapshots of the full mock table state, load / delete them, or export / import as JSON for cross-machine sharing |
148159
| Filter… | Filters the mock table by key name |
149160

150161
---
151162

163+
## Local (unregistered) mocks
164+
165+
The **+ New mock** button in the mock table toolbar lets you create a panel-managed mock before `provideMockResource()` exists in the Angular app. Use this to pre-configure a mock response while you're still writing the component code:
166+
167+
1. Click **+ New mock** — the **Create mock** dialog opens.
168+
2. Pick a spec from the **Specs** tab (the spec must already be imported), then select an operation.
169+
3. The key is auto-generated from the operationId (e.g. `findPetsByStatus``FIND_PETS_BY_STATUS`). Edit it if needed.
170+
4. Click **Create** — the new entry appears in the mock table with status `local`.
171+
172+
Local mock entries support all panel controls: catch mode, the Respond tab (including ⚡ Example and ✓ Validate when a spec is imported), and the History tab. Control messages to the page are silently ignored until the matching key is registered by the app.
173+
174+
When the app registers `provideMockResource(..., 'FIND_PETS_BY_STATUS', ...)`, the local entry is **promoted in-place** — its status transitions to `idle`, catch mode is preserved, and any pending catch-mode control is re-sent to the now-live bus.
175+
176+
Local mock entries are persisted across DevTools sessions in `chrome.storage.local`.
177+
178+
---
179+
152180
## Local development
153181

154182
```bash

tools/openapi-resource-gen/README.md

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ Re-run the same command whenever your spec changes — the generator overwrites
8787
| `namingConvention` | no | `kebab` | `kebab``find-pets-by-status.token.ts`; `camel``findPetsByStatus.token.ts` |
8888
| `providedIn` | no | `none` | `none` or `root` — see table above |
8989
| `includeMocks` | no | `false` | Emit a `.mock.ts` per endpoint plus `index.mock.ts` barrels and a `mocks.manifest.json` — requires [`@constantant/openapi-resource-mocks`](https://www.npmjs.com/package/@constantant/openapi-resource-mocks) |
90+
| `includeMswHandlers` | no | `false` | Emit a `.msw.ts` per endpoint plus `index.msw.ts` barrels — requires [`msw`](https://mswjs.io) >= 2.0.0 |
9091
| `specId` | no | derived from `baseUrlToken` | Identifier embedded in every generated `MockResourceMeta` and in `mocks.manifest.json`. Defaults to `baseUrlToken` with `_BASE_URL` stripped and lowercased (e.g. `PETSTORE_BASE_URL``petstore`). Must match the value used when importing the spec into the DevTools panel. |
9192
| `verbose` | no | `false` | Print a `+`/`~`/`-` summary of created, updated, and deleted files after generation. |
9293

@@ -101,12 +102,15 @@ Re-run the same command whenever your spec changes — the generator overwrites
101102
{scheme}.security-token.ts # one per security scheme (if any)
102103
index.ts # re-exports all tag barrels + base-url + security tokens
103104
index.mock.ts # (--includeMocks) re-exports all tag mock barrels
105+
index.msw.ts # (--includeMswHandlers) re-exports all tag MSW handler arrays
104106
mocks.manifest.json # (--includeMocks) machine-readable endpoint list + specId for the DevTools panel
105107
{tag}/
106108
index.ts # re-exports all token files in this tag folder
107109
index.mock.ts # (--includeMocks) re-exports all mock files in this tag
110+
index.msw.ts # (--includeMswHandlers) re-exports all MSW handlers in this tag
108111
{operation-id}.token.ts # one file per endpoint
109112
{operation-id}.mock.ts # (--includeMocks) typed mock provider per endpoint
113+
{operation-id}.msw.ts # (--includeMswHandlers) MSW 2.x handler factory + pre-called array
110114
```
111115

112116
Tags map to subfolders; untagged operations go into `default/`.
@@ -235,6 +239,70 @@ Stale tag folders (left empty after their barrels are removed) are also deleted.
235239

236240
---
237241

242+
## MSW handlers (`--includeMswHandlers`)
243+
244+
Pass `--includeMswHandlers` to co-generate [MSW 2.x](https://mswjs.io) handler files
245+
alongside every `.token.ts`. Requires `msw >= 2.0.0`:
246+
247+
```bash
248+
npm install -D msw
249+
250+
npx nx g @constantant/openapi-resource-gen:api-resource \
251+
--specPath=specs/petstore.yaml \
252+
--outputDir=libs/petstore-data-access/src \
253+
--baseUrlToken=PETSTORE_BASE_URL \
254+
--includeMswHandlers
255+
```
256+
257+
### Generated MSW file
258+
259+
Each `.msw.ts` file exports a handler factory and a pre-called array:
260+
261+
```typescript
262+
// pet/find-pets-by-status.msw.ts (generated)
263+
import { http, HttpResponse } from 'msw';
264+
import type { FindPetsByStatusResponse } from './find-pets-by-status.token';
265+
266+
export function findPetsByStatusHandler(body?: FindPetsByStatusResponse | null) {
267+
return http.get('/pet/findByStatus', () =>
268+
body !== undefined
269+
? HttpResponse.json(body)
270+
: new HttpResponse(null, { status: 204 }),
271+
);
272+
}
273+
274+
export const findPetsByStatusHandlers = [findPetsByStatusHandler()];
275+
```
276+
277+
Path params (`{id}`) are converted to MSW `:id` syntax. DELETE and other no-response endpoints
278+
emit `new HttpResponse(null, { status: 204 })` by default.
279+
280+
### Barrel imports
281+
282+
The generator registers a `/msw` path alias in `tsconfig.base.json` automatically:
283+
284+
```json
285+
"@myapp/petstore-data-access/msw": ["libs/petstore-data-access/src/index.msw.ts"]
286+
```
287+
288+
Use the pre-built arrays for a quick setup, or import the factory to override the response:
289+
290+
```typescript
291+
import { findPetsByStatusHandlers } from '@myapp/petstore-data-access/msw';
292+
import { findPetsByStatusHandler } from '@myapp/petstore-data-access/msw';
293+
294+
// In your MSW setup file:
295+
server.use(...findPetsByStatusHandlers);
296+
297+
// Override with a specific response in a test:
298+
server.use(findPetsByStatusHandler([{ id: 1, name: 'Rex', status: 'available' }]));
299+
```
300+
301+
MSW handler files are intentionally kept out of the main `index.ts` barrel so they
302+
are never bundled into a production build.
303+
304+
---
305+
238306
## Generated token anatomy
239307

240308
### GET with query params
@@ -736,7 +804,7 @@ navigation in and destroyed on navigation out, with no cross-route state leakage
736804
| Type generation | `openapi-typescript` programmatic API | Emit `schema.d.ts` — the single source of truth for all request/response types |
737805
| Spec dereferencing | `@apidevtools/swagger-parser` | Resolve all `$ref` chains for endpoint extraction |
738806
| Security parsing | `parseSecuritySchemes(api)` | Extract scheme definitions; resolve per-operation overrides |
739-
| Code generation | `renderTokenFile()` / `renderSecurityTokenFile()` / `renderMockFile()` | Direct string assembly for token and mock files |
807+
| Code generation | `renderTokenFile()` / `renderSecurityTokenFile()` / `renderMockFile()` / `renderMswFile()` | Direct string assembly for token, mock, and MSW handler files |
740808
| Formatting | `@nx/devkit` `formatFiles()` | Runs Prettier over all written files |
741809

742810
Hyphenated path parameter names (e.g. `{enterprise-team}` in the GitHub spec)

tools/openapi-resource-mocks/README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,74 @@ Types come from the generated lib — no hand-written interfaces needed.
111111

112112
---
113113

114+
## Unit test helpers (`/testing`)
115+
116+
`@constantant/openapi-resource-mocks/testing` is a lightweight sub-entry for unit tests and
117+
Storybook. It does not import `MockResourceBus`, register DOM events, or touch `window`
118+
it simply wraps a token with a `MockResourceRef` and drops it into `TestBed` as a
119+
`FactoryProvider`.
120+
121+
```typescript
122+
import { mockResource } from '@constantant/openapi-resource-mocks/testing';
123+
import { FIND_PETS_BY_STATUS } from '@myapp/petstore-data-access';
124+
125+
const petsMock = mockResource(FIND_PETS_BY_STATUS, { value: [] });
126+
127+
TestBed.configureTestingModule({
128+
imports: [PetsComponent],
129+
providers: [petsMock], // MockResourceHandle extends FactoryProvider — drop it in directly
130+
});
131+
132+
fixture.detectChanges();
133+
134+
petsMock.ref.resolve([{ id: 1, name: 'Rex', status: 'available', photoUrls: [] }]);
135+
fixture.detectChanges();
136+
137+
petsMock.expectCalled();
138+
petsMock.expectCalledWith({ status: 'available' });
139+
console.log(petsMock.calls); // readonly unknown[][] — all factory invocations and their args
140+
```
141+
142+
### `mockResource<T>(token, behaviorOrOptions?)`
143+
144+
Returns `MockResourceHandle<T>`, which extends `FactoryProvider`.
145+
146+
The second argument sets the initial mock state (same shapes as `provideMockResource`):
147+
148+
| Shape | Effect |
149+
|-------|--------|
150+
| `{ value: T }` | Resolves immediately |
151+
| `{ value: T, delay: ms }` | Loading for `ms` ms, then resolves |
152+
| `{ loading: true }` | Stays loading indefinitely |
153+
| `{ error: unknown }` | Fails immediately |
154+
| `{ error: unknown, delay: ms }` | Loading for `ms` ms, then fails |
155+
156+
### Response sequences
157+
158+
Pass `{ sequence: [...] }` to advance through multiple states — each factory call (and
159+
each `reload()` in resolved state) consumes the next entry; the last entry repeats when exhausted:
160+
161+
```typescript
162+
const mock = mockResource(FIND_PETS_BY_STATUS, {
163+
sequence: [
164+
{ loading: true },
165+
{ error: new Error('timeout') },
166+
{ value: [{ id: 1, name: 'Rex', status: 'available', photoUrls: [] }] },
167+
],
168+
});
169+
```
170+
171+
### `MockResourceHandle<T>`
172+
173+
| Member | Description |
174+
|--------|-------------|
175+
| `.ref` | `MockResourceRef<T>` — the underlying ref; call `.resolve()`, `.fail()`, etc. to change state mid-test |
176+
| `.calls` | `readonly unknown[][]` — all args the factory was invoked with |
177+
| `.expectCalled()` | Throws if the factory was never called |
178+
| `.expectCalledWith(...args)` | Throws if no call matches (deep equality via recursive comparison) |
179+
180+
---
181+
114182
## File upload / download progress
115183

116184
### In-process (unit tests / Storybook)

0 commit comments

Comments
 (0)