Skip to content

Commit 3924281

Browse files
committed
simple way to activate same scenario across multipl mocks
1 parent 5f64128 commit 3924281

File tree

4 files changed

+68
-4
lines changed

4 files changed

+68
-4
lines changed

docs/mocks.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,3 +240,39 @@ describe("getServers", () => {
240240
await expect(getServers()).rejects.toBeDefined();
241241
});
242242
});
243+
```
244+
245+
### Global Scenario Activation
246+
247+
Use `activateMockScenario` to activate a scenario across all registered mocks at once. This is useful for setting up a consistent state across multiple endpoints, with the option to further customize individual mocks afterwards.
248+
249+
```typescript
250+
import { activateMockScenario } from "@mocks";
251+
import { mockedGetRegistryV01Servers } from "@mocks/fixtures/registry_v0_1_servers/get";
252+
253+
describe("error handling", () => {
254+
it("shows error page when all APIs fail", async () => {
255+
// Activate "server-error" on all mocks that define it
256+
// Mocks without this scenario will use their default response
257+
activateMockScenario("server-error");
258+
259+
// Test that the app handles the error state correctly
260+
render(<App />);
261+
expect(screen.getByText("Something went wrong")).toBeVisible();
262+
});
263+
264+
it("handles partial failures gracefully", async () => {
265+
// Start with all APIs returning errors
266+
activateMockScenario("server-error");
267+
268+
// Then customize specific endpoints to succeed
269+
mockedGetRegistryV01Servers.override((data) => data);
270+
271+
// Now only other endpoints return errors, servers endpoint works
272+
render(<Dashboard />);
273+
expect(screen.getByText("Servers loaded")).toBeVisible();
274+
});
275+
});
276+
```
277+
278+
Scenario names are defined in `src/mocks/scenarioNames.ts` and provide autocomplete and documentation across all mocks. Global scenarios are automatically reset before each test via `resetAllAutoAPIMocks()` in the test setup.

src/app/catalog/[repoName]/[serverName]/[version]/actions.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { beforeEach, describe, expect, it, vi } from "vitest";
2+
import { activateMockScenario } from "@/mocks";
23
import { getServerDetails } from "./actions";
34

45
// Mock the auth to bypass authentication
@@ -47,6 +48,7 @@ describe("getServerDetails", () => {
4748

4849
describe("error handling", () => {
4950
it("returns 404 for non-existent server", async () => {
51+
activateMockScenario("empty-servers");
5052
const result = await getServerDetails("non-existent/server", "1.0.0");
5153

5254
expect(result.response.status).toBe(404);

src/mocks/autoAPIMock.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ type ScenarioFn<T> = (
1010
instance: AutoAPIMockInstance<T>,
1111
) => AutoAPIMockInstance<T>;
1212

13+
export interface UseScenarioOptions {
14+
/** If true, silently falls back to default when scenario doesn't exist. Default: false (throws) */
15+
fallbackToDefault?: boolean;
16+
}
17+
1318
export interface AutoAPIMockInstance<T> {
1419
generatedHandler: HttpResponseResolver;
1520
override: (fn: OverrideFn<T>) => AutoAPIMockInstance<T>;
@@ -18,7 +23,10 @@ export interface AutoAPIMockInstance<T> {
1823
name: MockScenarioName,
1924
fn: ScenarioFn<T>,
2025
) => AutoAPIMockInstance<T>;
21-
useScenario: (name: MockScenarioName) => AutoAPIMockInstance<T>;
26+
useScenario: (
27+
name: MockScenarioName,
28+
options?: UseScenarioOptions,
29+
) => AutoAPIMockInstance<T>;
2230
reset: () => AutoAPIMockInstance<T>;
2331
defaultValue: T;
2432
}
@@ -56,9 +64,12 @@ export function AutoAPIMock<T>(defaultValue: T): AutoAPIMockInstance<T> {
5664
return instance;
5765
},
5866

59-
useScenario(name: MockScenarioName) {
67+
useScenario(name: MockScenarioName, options?: UseScenarioOptions) {
6068
const scenarioFn = scenarios.get(name);
6169
if (!scenarioFn) {
70+
if (options?.fallbackToDefault) {
71+
return instance;
72+
}
6273
throw new Error(
6374
`Scenario "${name}" not found. Available scenarios: ${[...scenarios.keys()].join(", ") || "(none)"}`,
6475
);
@@ -82,3 +93,14 @@ export function resetAllAutoAPIMocks(): void {
8293
instance.reset();
8394
}
8495
}
96+
97+
/**
98+
* Activate a scenario globally across all registered mocks.
99+
* Mocks that don't have the scenario defined will silently use their default.
100+
*/
101+
export function activateMockScenario(name: MockScenarioName): void {
102+
for (const instance of registry) {
103+
// biome-ignore lint/correctness/useHookAtTopLevel: useScenario is not a React hook
104+
instance.useScenario(name, { fallbackToDefault: true });
105+
}
106+
}

src/mocks/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1-
export type { AutoAPIMockInstance } from "./autoAPIMock";
2-
export { AutoAPIMock, resetAllAutoAPIMocks } from "./autoAPIMock";
1+
export type { AutoAPIMockInstance, UseScenarioOptions } from "./autoAPIMock";
2+
export {
3+
AutoAPIMock,
4+
activateMockScenario,
5+
resetAllAutoAPIMocks,
6+
} from "./autoAPIMock";
37
export type { MockScenarioName } from "./scenarioNames";

0 commit comments

Comments
 (0)