@mosaicast/plugin-sdk 0.8.0 → 0.9.1

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/dist/testing.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @packageDocumentation
8
8
  */
9
- import type { BlobClient, BlobInfo, ConsentApi, LogLevel, PluginApiClient, PluginContext, PluginRoute, SchemaClient, SchemaQuery, ThemeTokens } from './index.js';
9
+ import type { BlobClient, BlobInfo, ConsentApi, DisplaySnapshot, DocClient, FeedsClient, LogLevel, PluginApiClient, PluginContext, PluginRoute, ProblemDetail, SchemaClient, SchemaQuery, TagsClient, ThemeTokens } from './index.js';
10
10
  /** One recorded {@link PluginContext.log} call. */
11
11
  export interface LogRecord {
12
12
  /** The severity it was logged at. */
@@ -45,6 +45,33 @@ export interface RecordedCall {
45
45
  /** The request body, if any. */
46
46
  body?: unknown;
47
47
  }
48
+ /**
49
+ * A canned failure: what the host would have answered instead of a body.
50
+ *
51
+ * Put one in {@link MockApiClient.responses} and the call rejects with a {@link PluginApiError} carrying
52
+ * that status — which is how a component's 404 branch and its 500 branch become separately testable.
53
+ *
54
+ * ```ts
55
+ * const ctx = makeMockCtx({ apiResponses: { 'get data/site/main/stats': apiError(403, {
56
+ * detail: 'this key is written by the plugin backend',
57
+ * }) } });
58
+ * ```
59
+ *
60
+ * @param status the HTTP status to fail with
61
+ * @param problem the RFC 7807 body, if the test cares about it
62
+ * @returns a marker the mock client turns into a rejection
63
+ * @since 0.9.0
64
+ */
65
+ export declare function apiError(status: number, problem?: ProblemDetail): CannedApiError;
66
+ /** The marker {@link apiError} produces. Recognised by {@link MockApiClient}; not a real error. */
67
+ export interface CannedApiError {
68
+ /** Discriminator, so an ordinary response object is never mistaken for a failure. */
69
+ __mosaicastApiError: true;
70
+ /** The status to reject with. */
71
+ status: number;
72
+ /** The problem body to attach. */
73
+ problem?: ProblemDetail;
74
+ }
48
75
  /** A {@link PluginApiClient} that records calls and returns canned responses. */
49
76
  export interface MockApiClient extends PluginApiClient {
50
77
  /** Every call made through this client, in order. */
@@ -52,9 +79,43 @@ export interface MockApiClient extends PluginApiClient {
52
79
  /**
53
80
  * Canned responses keyed by `"<method> <path>"` (e.g. `"get /board"`) or bare `path`; the more
54
81
  * specific key wins. Missing keys resolve to `undefined`.
82
+ *
83
+ * A value built by {@link apiError} **rejects** with a {@link PluginApiError} instead of resolving.
55
84
  */
56
85
  responses: Record<string, unknown>;
86
+ /**
87
+ * Resolves once every call made so far has settled.
88
+ *
89
+ * A component typically does `ctx.api.get(...).then(setState)`, sometimes with another `.then` behind
90
+ * it, so the mock's already-resolved promise still needs one microtask hop per `.then` before the DOM
91
+ * reflects it. A single `await Promise.resolve()` covers one hop and not two — which is why the
92
+ * symptom is **an assertion that fails only sometimes**, depending on how many hops the component
93
+ * happens to have. This waits for the calls themselves rather than for a guessed number of hops.
94
+ *
95
+ * Prefer {@link flushMockApi}, which also drains the hops the component adds after the call settles.
96
+ *
97
+ * @since 0.9.0
98
+ */
99
+ settled(): Promise<void>;
57
100
  }
101
+ /**
102
+ * Waits until every call recorded by a mock client has settled *and* the `.then` chains behind them have
103
+ * run.
104
+ *
105
+ * The two-part wait is the point: `await client.settled()` knows when the *requests* finished, and the
106
+ * microtask drain after it lets the component's own `.then(setState)` hops reach the DOM. Use it instead
107
+ * of counting `await Promise.resolve()` calls by hand.
108
+ *
109
+ * ```ts
110
+ * mount(ctx);
111
+ * await flushMockApi(ctx.api);
112
+ * expect(root.querySelector('.title')).toHaveTextContent('The Kraken');
113
+ * ```
114
+ *
115
+ * @param client the mock client — `ctx.api` from {@link makeMockCtx}
116
+ * @since 0.9.0
117
+ */
118
+ export declare function flushMockApi(client: MockApiClient): Promise<void>;
58
119
  /** A {@link ConsentApi} whose grants a test can drive. */
59
120
  export interface MockConsent extends ConsentApi {
60
121
  /** Grants a category and notifies subscribers. Granting an already-granted category does nothing. */
@@ -139,6 +200,100 @@ export interface MockSchemaClient extends SchemaClient {
139
200
  * ```
140
201
  */
141
202
  export declare function makeMockSchema(rows?: Record<string, Record<string, unknown>[]>): MockSchemaClient;
203
+ /** A {@link FeedsClient} answering from registered snapshots. @since 0.9.0 */
204
+ export interface MockFeedsClient extends FeedsClient {
205
+ /**
206
+ * Registers the snapshot `display`/`displayMany` return for a slug.
207
+ *
208
+ * Mirrors the Java kit's `FakeFeedAccess.withDisplay(...)`, so both halves of a plugin describe the
209
+ * host's answer the same way.
210
+ *
211
+ * @param slug the episode's public slug
212
+ * @param snapshot what the host would hand over
213
+ * @returns this client, for chaining
214
+ */
215
+ withDisplay(slug: string, snapshot: DisplaySnapshot): MockFeedsClient;
216
+ /** Every slug asked for, in order — batched calls contribute each slug separately. */
217
+ readonly requested: string[];
218
+ }
219
+ /**
220
+ * A {@link FeedsClient} double: snapshots you register, and **nothing for the ones you don't**.
221
+ *
222
+ * An unregistered slug resolves `null` (or is absent from a batch) rather than throwing, because that is
223
+ * what the host does for an episode this visitor may not see — a `WITHDRAWN` or tier-gated one is absent,
224
+ * not redacted. So the empty case a component must handle is the double's default, and a component that
225
+ * assumes every slug comes back fails here rather than in front of a visitor.
226
+ *
227
+ * ```ts
228
+ * const feeds = makeMockFeeds().withDisplay('kraken', { title: 'The Kraken', description: '' });
229
+ * const ctx = makeMockCtx({ feeds, episodes: ['kraken', 'gated'] });
230
+ *
231
+ * await mount(ctx);
232
+ * expect(root.textContent).toContain('The Kraken'); // and renders nothing for `gated`
233
+ * ```
234
+ *
235
+ * @param snapshots snapshots to start with, keyed by slug
236
+ * @returns a feeds double with `withDisplay` and a recorded `requested` list
237
+ * @since 0.9.0
238
+ */
239
+ export declare function makeMockFeeds(snapshots?: Record<string, DisplaySnapshot>): MockFeedsClient;
240
+ /** A {@link TagsClient} backed by an in-memory vocabulary. @since 0.9.0 */
241
+ export interface MockTagsClient extends TagsClient {
242
+ /** Seeds a tag the **feed** put on an episode — a row the plugin may read but must not remove. */
243
+ withFeedTag(episodeSlug: string, tag: string): MockTagsClient;
244
+ /** The canonical keys currently on each episode, for asserting without going through the client. */
245
+ readonly episodeTags: Record<string, string[]>;
246
+ /** The canonical keys currently on each of this plugin's subjects. */
247
+ readonly subjectTags: Record<string, string[]>;
248
+ }
249
+ /**
250
+ * A {@link TagsClient} double that **refuses what the host refuses**.
251
+ *
252
+ * Two refusals matter, and both are invisible to a component tested against a permissive double:
253
+ *
254
+ * - **Episode writes throw** unless you pass `writesEpisodes: true`, standing in for the manifest
255
+ * declaration. Off by default, so the branch where the host says no gets exercised.
256
+ * - **`untagEpisode` removes only this plugin's own assignment.** Seed the feed's side with
257
+ * {@link MockTagsClient.withFeedTag} and the tag survives your removal, exactly as the host's `source`
258
+ * column makes it survive.
259
+ *
260
+ * Canonicalisation is applied as the host applies it, so a test that writes `'Maritime '` and reads
261
+ * `'maritime'` passes here for the same reason it passes against core.
262
+ *
263
+ * @param opts `writesEpisodes` grants the episode-write capability; `subjects` and `episodes` seed
264
+ * assignments this plugin owns
265
+ * @returns a tags double
266
+ * @since 0.9.0
267
+ */
268
+ export declare function makeMockTags(opts?: {
269
+ writesEpisodes?: boolean;
270
+ subjects?: Record<string, string[]>;
271
+ episodes?: Record<string, string[]>;
272
+ }): MockTagsClient;
273
+ /** A {@link DocClient} storing in memory, keyed by resolved partition path. @since 0.9.0 */
274
+ export interface MockDocClient extends DocClient {
275
+ /** What is currently stored, keyed `"<partition>/<key>"` — e.g. `"data/user/me/marks"`. */
276
+ readonly stored: Record<string, unknown>;
277
+ }
278
+ /**
279
+ * A {@link DocClient} double: an in-memory store that **validates keys the way the client does**.
280
+ *
281
+ * A key with a `/` in it, or one over 200 characters, throws here rather than silently working — which
282
+ * matters, because against a permissive double the failure would first appear as a 400 in production.
283
+ *
284
+ * ```ts
285
+ * const docs = makeMockDocs({ 'data/user/me/marks': { b3: true } });
286
+ * const ctx = makeMockCtx({ docs });
287
+ *
288
+ * await mount(ctx);
289
+ * expect(docs.stored['data/user/me/marks']).toEqual({ b3: true, b4: true });
290
+ * ```
291
+ *
292
+ * @param initial documents to start with, keyed `"<partition>/<key>"`
293
+ * @returns a doc client double with an inspectable `stored` map
294
+ * @since 0.9.0
295
+ */
296
+ export declare function makeMockDocs(initial?: Record<string, unknown>): MockDocClient;
142
297
  /** Default theme tokens (neutral light values) used when a test does not override them. */
143
298
  export declare const DEFAULT_THEME: ThemeTokens;
144
299
  /** One recorded {@link BlobClient.upload} call. @since 0.8.0 */
@@ -234,15 +389,18 @@ export interface MockCtxOverrides extends Partial<Omit<PluginContext, 'api' | 'r
234
389
  *
235
390
  * Defaults: `site` scope, no episodes, anonymous user, **all consent denied** (a {@link makeMockConsent}
236
391
  * double — pass your own to drive grants), empty filter, a player
237
- * parked at 0s, empty route, `en` locale, unknown progress, and {@link DEFAULT_THEME}. Pass overrides to
238
- * change any field; the returned `api` is a {@link MockApiClient} recording every call, and `logs`
239
- * collects every `ctx.log(...)`.
240
- *
241
- * `episodeLabels` is deliberately **absent** by default, and `schema` and `blobs` are **`null`**. All three
242
- * are optional on the real context — the host supplies labels partially, and gives a plugin no schema and
243
- * no blob store unless its manifest declares them — so a component that needs any of them has to survive
244
- * its absence. The mock makes you face that unless you pass one in ({@link makeMockSchema},
245
- * {@link makeMockBlobs}).
392
+ * parked at 0s, empty route with an empty query and hash, `en` locale, unknown progress, and
393
+ * {@link DEFAULT_THEME}. Pass overrides to change any field; the returned `api` is a
394
+ * {@link MockApiClient} recording every call, and `logs` collects every `ctx.log(...)`.
395
+ *
396
+ * `docs` and `feeds` are real doubles ({@link makeMockDocs}, {@link makeMockFeeds}), because every plugin
397
+ * has both — the empty ones give a component nothing to render, which is the case worth defaulting to.
398
+ *
399
+ * `episodeLabels` is deliberately **absent** by default, and `schema`, `blobs` and `tags` are **`null`**.
400
+ * All four are optional on the real context — the host supplies labels partially, and gives a plugin no
401
+ * schema, no blob store and no tag surface unless its manifest declares them — so a component that needs
402
+ * any of them has to survive its absence. The mock makes you face that unless you pass one in
403
+ * ({@link makeMockSchema}, {@link makeMockBlobs}, {@link makeMockTags}).
246
404
  *
247
405
  * **`route` is the one override that merges** rather than replacing: `route: { path: 'kraken' }` pins the
248
406
  * subpath and keeps the recording `navigate`. Everything else is all-or-nothing, because everything else
@@ -1 +1 @@
1
- {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}