@khanacademy/wonder-blocks-testing 10.1.1 → 11.0.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/es/index.js +15 -390
  3. package/dist/gql/types.d.ts +1 -2
  4. package/dist/harness/adapters/data.d.ts +1 -1
  5. package/dist/harness/adapters/index.d.ts +41 -0
  6. package/dist/harness/adapters/ssr.d.ts +1 -1
  7. package/dist/index.d.ts +8 -13
  8. package/dist/index.js +54 -399
  9. package/package.json +9 -7
  10. package/src/gql/__tests__/mock-gql-fetch.test.tsx +1 -1
  11. package/src/gql/__tests__/types.typestest.ts +1 -1
  12. package/src/gql/__tests__/wb-data-integration.test.tsx +1 -1
  13. package/src/gql/mock-gql-fetch.ts +1 -1
  14. package/src/gql/types.ts +4 -2
  15. package/src/harness/adapters/__tests__/ssr.test.tsx +1 -1
  16. package/src/harness/adapters/data.tsx +1 -1
  17. package/src/harness/adapters/{adapters.ts → index.ts} +10 -11
  18. package/src/harness/adapters/ssr.tsx +1 -1
  19. package/src/index.ts +32 -13
  20. package/tsconfig-build.json +1 -0
  21. package/tsconfig-build.tsbuildinfo +1 -1
  22. package/dist/fetch/fetch-request-matches-mock.d.ts +0 -5
  23. package/dist/fetch/mock-fetch.d.ts +0 -5
  24. package/dist/fetch/types.d.ts +0 -9
  25. package/dist/fixtures/fixtures.basic.stories.d.ts +0 -13
  26. package/dist/fixtures/fixtures.d.ts +0 -13
  27. package/dist/fixtures/fixtures.defaultwrapper.stories.d.ts +0 -9
  28. package/dist/fixtures/types.d.ts +0 -36
  29. package/dist/harness/adapt.d.ts +0 -17
  30. package/dist/harness/adapters/adapters.d.ts +0 -36
  31. package/dist/harness/adapters/css.d.ts +0 -12
  32. package/dist/harness/adapters/portal.d.ts +0 -12
  33. package/dist/harness/adapters/router.d.ts +0 -94
  34. package/dist/harness/get-named-adapter-component.d.ts +0 -16
  35. package/dist/harness/hook-harness.d.ts +0 -13
  36. package/dist/harness/make-hook-harness.d.ts +0 -17
  37. package/dist/harness/make-test-harness.d.ts +0 -15
  38. package/dist/harness/test-harness.d.ts +0 -33
  39. package/dist/harness/types.d.ts +0 -36
  40. package/dist/mock-requester.d.ts +0 -5
  41. package/dist/respond-with.d.ts +0 -75
  42. package/dist/response-impl.d.ts +0 -1
  43. package/dist/settle-controller.d.ts +0 -19
  44. package/dist/settle-signal.d.ts +0 -18
  45. package/dist/types.d.ts +0 -25
  46. package/src/__tests__/mock-requester.test.ts +0 -212
  47. package/src/__tests__/respond-with.test.ts +0 -524
  48. package/src/__tests__/response-impl.test.js +0 -47
  49. package/src/__tests__/settle-controller.test.ts +0 -28
  50. package/src/__tests__/settle-signal.test.ts +0 -104
  51. package/src/fetch/__tests__/__snapshots__/mock-fetch.test.ts.snap +0 -29
  52. package/src/fetch/__tests__/fetch-request-matches-mock.test.ts +0 -98
  53. package/src/fetch/__tests__/mock-fetch.test.ts +0 -83
  54. package/src/fetch/fetch-request-matches-mock.ts +0 -42
  55. package/src/fetch/mock-fetch.ts +0 -20
  56. package/src/fetch/types.ts +0 -14
  57. package/src/fixtures/__tests__/fixtures.test.tsx +0 -147
  58. package/src/fixtures/fixtures.basic.stories.tsx +0 -62
  59. package/src/fixtures/fixtures.defaultwrapper.stories.tsx +0 -49
  60. package/src/fixtures/fixtures.tsx +0 -72
  61. package/src/fixtures/types.ts +0 -42
  62. package/src/harness/__tests__/adapt.test.tsx +0 -248
  63. package/src/harness/__tests__/hook-harness.test.ts +0 -73
  64. package/src/harness/__tests__/make-hook-harness.test.tsx +0 -93
  65. package/src/harness/__tests__/make-test-harness.test.tsx +0 -195
  66. package/src/harness/__tests__/test-harness.test.ts +0 -75
  67. package/src/harness/__tests__/types.typestest.tsx +0 -103
  68. package/src/harness/adapt.tsx +0 -41
  69. package/src/harness/adapters/__tests__/__snapshots__/router.test.tsx.snap +0 -5
  70. package/src/harness/adapters/__tests__/css.test.tsx +0 -95
  71. package/src/harness/adapters/__tests__/portal.test.tsx +0 -30
  72. package/src/harness/adapters/__tests__/router.test.tsx +0 -252
  73. package/src/harness/adapters/css.tsx +0 -66
  74. package/src/harness/adapters/portal.tsx +0 -25
  75. package/src/harness/adapters/router.tsx +0 -205
  76. package/src/harness/get-named-adapter-component.tsx +0 -36
  77. package/src/harness/hook-harness.ts +0 -22
  78. package/src/harness/make-hook-harness.tsx +0 -40
  79. package/src/harness/make-test-harness.tsx +0 -60
  80. package/src/harness/test-harness.ts +0 -13
  81. package/src/harness/types.ts +0 -47
  82. package/src/mock-requester.ts +0 -68
  83. package/src/respond-with.ts +0 -263
  84. package/src/response-impl.ts +0 -8
  85. package/src/settle-controller.ts +0 -34
  86. package/src/settle-signal.ts +0 -42
  87. package/src/types.ts +0 -40
@@ -1,36 +0,0 @@
1
- /// <reference path="../../../types/aphrodite.d.ts" />
2
- import type { TestHarnessConfigs } from "../types";
3
- /**
4
- * NOTE: We do not type `DefaultAdapters` with `Adapters` here because we want
5
- * the individual config types of each adapter to remain intact rather than
6
- * getting changed to `any`.
7
- */
8
- /**
9
- * The default adapters provided by Wonder Blocks.
10
- */
11
- export declare const DefaultAdapters: {
12
- readonly css: import("../types").TestHarnessAdapter<string | string[] | import("aphrodite").CSSProperties | {
13
- classes: string[];
14
- style: import("aphrodite").CSSProperties;
15
- }>;
16
- readonly data: import("../types").TestHarnessAdapter<((requestId: string) => Promise<import("@khanacademy/wonder-blocks-data").ValidCacheData> | null | undefined) | ((requestId: string) => Promise<import("@khanacademy/wonder-blocks-data").ValidCacheData> | null | undefined)[]>;
17
- readonly portal: import("../types").TestHarnessAdapter<string>;
18
- readonly router: import("../types").TestHarnessAdapter<string | Readonly<{
19
- initialEntries: import("history").LocationDescriptor<unknown>[] | undefined;
20
- initialIndex?: number | undefined;
21
- getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void) | undefined;
22
- path?: string | undefined;
23
- } | {
24
- location: import("history").LocationDescriptor<unknown>;
25
- forceStatic: true;
26
- path?: string | undefined;
27
- } | {
28
- location: import("history").LocationDescriptor<unknown>;
29
- path?: string | undefined;
30
- }>>;
31
- readonly ssr: import("../types").TestHarnessAdapter<true>;
32
- };
33
- /**
34
- * The default configurations to use with the `DefaultAdapters`.
35
- */
36
- export declare const DefaultConfigs: TestHarnessConfigs<typeof DefaultAdapters>;
@@ -1,12 +0,0 @@
1
- import type { CSSProperties } from "aphrodite";
2
- import type { TestHarnessAdapter } from "../types";
3
- type Config = string | Array<string> | CSSProperties | {
4
- classes: Array<string>;
5
- style: CSSProperties;
6
- };
7
- export declare const defaultConfig: Config | null | undefined;
8
- /**
9
- * Test harness adapter for adding CSS to the harnessed component wrapper.
10
- */
11
- export declare const adapter: TestHarnessAdapter<Config>;
12
- export {};
@@ -1,12 +0,0 @@
1
- import type { TestHarnessAdapter } from "../types";
2
- type Config = string;
3
- export declare const defaultConfig: Config | null | undefined;
4
- /**
5
- * Test harness adapter for supporting portals.
6
- *
7
- * Some components rely on rendering with a React Portal. This adapter ensures
8
- * that the DOM contains a mounting point for the portal with the expected
9
- * identifier.
10
- */
11
- export declare const adapter: TestHarnessAdapter<Config>;
12
- export {};
@@ -1,94 +0,0 @@
1
- import * as React from "react";
2
- import { MemoryRouter } from "react-router-dom";
3
- import type { LocationDescriptor } from "history";
4
- import type { TestHarnessAdapter } from "../types";
5
- type MemoryRouterProps = JSX.LibraryManagedAttributes<typeof MemoryRouter, React.ComponentProps<typeof MemoryRouter>>;
6
- /**
7
- * Configuration for the withLocation test harness adapter.
8
- */
9
- type Config = Readonly<{
10
- /**
11
- * See MemoryRouter prop for initialEntries.
12
- */
13
- initialEntries: MemoryRouterProps["initialEntries"];
14
- /**
15
- * See MemoryRouter prop for initialIndex.
16
- */
17
- initialIndex?: MemoryRouterProps["initialIndex"];
18
- /**
19
- * See MemoryRouter prop for getUserConfirmation.
20
- */
21
- getUserConfirmation?: MemoryRouterProps["getUserConfirmation"];
22
- /**
23
- * A path match to use.
24
- *
25
- * When this is specified, the harnessed component will be
26
- * rendered inside a `Route` handler with this path.
27
- *
28
- * If the path matches the location, then the route will
29
- * render the component.
30
- *
31
- * If the path does not match the location, then the route
32
- * will not render the component.
33
- */
34
- path?: string;
35
- } | {
36
- /**
37
- * The location to use.
38
- */
39
- location: LocationDescriptor;
40
- /**
41
- * Force the use of a StaticRouter, instead of MemoryRouter.
42
- */
43
- forceStatic: true;
44
- /**
45
- * A path match to use.
46
- *
47
- * When this is specified, the harnessed component will be
48
- * rendered inside a `Route` handler with this path.
49
- *
50
- * If the path matches the location, then the route will
51
- * render the component.
52
- *
53
- * If the path does not match the location, then the route
54
- * will not render the component.
55
- */
56
- path?: string;
57
- } | {
58
- /**
59
- * The initial location to use.
60
- */
61
- location: LocationDescriptor;
62
- /**
63
- * A path match to use.
64
- *
65
- * When this is specified, the harnessed component will be
66
- * rendered inside a `Route` handler with this path.
67
- *
68
- * If the path matches the location, then the route will
69
- * render the component.
70
- *
71
- * If the path does not match the location, then the route
72
- * will not render the component.
73
- */
74
- path?: string;
75
- }> | string;
76
- /**
77
- * The default configuration for this adapter.
78
- */
79
- export declare const defaultConfig: {
80
- readonly location: "/";
81
- };
82
- /**
83
- * Adapter that sets up a router and AppShell location-specific contexts.
84
- *
85
- * This allows you to ensure that components are being tested in the
86
- * AppShell world.
87
- *
88
- * NOTE(somewhatabstract): The AppShell component itself already does
89
- * the work of setting up routing and the AppShellContext and so using this
90
- * adapter with the App component will have zero-effect since AppShell will
91
- * override it.
92
- */
93
- export declare const adapter: TestHarnessAdapter<Config>;
94
- export {};
@@ -1,16 +0,0 @@
1
- import * as React from "react";
2
- import type { TestHarnessAdapter } from "./types";
3
- type Props<TConfig = any> = {
4
- children: React.ReactNode;
5
- config: TConfig;
6
- adapter: TestHarnessAdapter<TConfig>;
7
- };
8
- /**
9
- * Get a component tagged with the given name for rendering an adapter.
10
- *
11
- * We can share these across invocations because only the name is used.
12
- * The rest is configured at render time. This way we don't recreate new
13
- * components on the fly and cause remounting to occur.
14
- */
15
- export declare const getNamedAdapterComponent: (name: string) => React.FunctionComponent<Props<any>>;
16
- export {};
@@ -1,13 +0,0 @@
1
- import * as React from "react";
2
- import { DefaultAdapters } from "./adapters/adapters";
3
- import type { TestHarnessConfigs } from "./types";
4
- /**
5
- * Create test wrapper for hook testing with Wonder Blocks default adapters.
6
- *
7
- * This is primarily useful for tests within Wonder Blocks.
8
- *
9
- * If you want to expand the range of adapters or change the default
10
- * configurations, use `makeHookHarness` to create a new `hookHarness`
11
- * function.
12
- */
13
- export declare const hookHarness: (configs?: Partial<TestHarnessConfigs<typeof DefaultAdapters>>) => React.ForwardRefExoticComponent<any>;
@@ -1,17 +0,0 @@
1
- import * as React from "react";
2
- import type { TestHarnessAdapters, TestHarnessConfigs } from "./types";
3
- /**
4
- * Create a test harness method for use with React hooks.
5
- *
6
- * This returns a test harness method that applies the default configurations
7
- * to the given adapters, wrapping a given component.
8
- *
9
- * @param {TAdapters} adapters All the adapters to be supported by the returned
10
- * test harness.
11
- * @param {TestHarnessConfigs<TAdapters>} defaultConfigs Default configuration values for
12
- * the adapters.
13
- * @returns {(
14
- * configs?: $Shape<TestHarnessConfigs<TAdapters>>,
15
- * ) => React.AbstractComponent<any, any>} A test harness.
16
- */
17
- export declare const makeHookHarness: <TAdapters extends TestHarnessAdapters>(adapters: TAdapters, defaultConfigs: TestHarnessConfigs<TAdapters>) => (configs?: Partial<TestHarnessConfigs<TAdapters>> | undefined) => React.ForwardRefExoticComponent<any>;
@@ -1,15 +0,0 @@
1
- import * as React from "react";
2
- import type { TestHarnessAdapters, TestHarnessConfigs } from "./types";
3
- /**
4
- * Create a test harness method for use with React components.
5
- *
6
- * This returns a test harness method that applies the default configurations
7
- * to the given adapters, wrapping a given component.
8
- *
9
- * @param {TAdapters} adapters All the adapters to be supported by the returned
10
- * test harness.
11
- * @param {Configs<TAdapters>} defaultConfigs Default configuration values for
12
- * the adapters.
13
- * @returns A test harness.
14
- */
15
- export declare const makeTestHarness: <TAdapters extends TestHarnessAdapters>(adapters: TAdapters, defaultConfigs: TestHarnessConfigs<TAdapters>) => <TProps extends object>(Component: React.ComponentType<TProps>, configs?: Partial<TestHarnessConfigs<TAdapters>> | undefined) => React.ForwardRefExoticComponent<React.PropsWithoutRef<TProps> & React.RefAttributes<unknown>>;
@@ -1,33 +0,0 @@
1
- /// <reference path="../../types/aphrodite.d.ts" />
2
- /// <reference types="react" />
3
- /**
4
- * Wrap a component with a test harness using Wonder Blocks default adapters.
5
- *
6
- * This is primarily useful for tests within Wonder Blocks.
7
- *
8
- * If you want to expand the range of adapters or change the default
9
- * configurations, use `makeTestHarness` to create a new `testHarness`
10
- * function.
11
- */
12
- export declare const testHarness: <TProps extends object>(Component: import("react").ComponentType<TProps>, configs?: Partial<import("./types").TestHarnessConfigs<{
13
- readonly css: import("./types").TestHarnessAdapter<string | string[] | import("aphrodite").CSSProperties | {
14
- classes: string[];
15
- style: import("aphrodite").CSSProperties;
16
- }>;
17
- readonly data: import("./types").TestHarnessAdapter<((requestId: string) => Promise<import("@khanacademy/wonder-blocks-data").ValidCacheData> | null | undefined) | ((requestId: string) => Promise<import("@khanacademy/wonder-blocks-data").ValidCacheData> | null | undefined)[]>;
18
- readonly portal: import("./types").TestHarnessAdapter<string>;
19
- readonly router: import("./types").TestHarnessAdapter<string | Readonly<{
20
- initialEntries: import("history").LocationDescriptor<unknown>[] | undefined;
21
- initialIndex?: number | undefined;
22
- getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void) | undefined;
23
- path?: string | undefined;
24
- } | {
25
- location: import("history").LocationDescriptor<unknown>;
26
- forceStatic: true;
27
- path?: string | undefined;
28
- } | {
29
- location: import("history").LocationDescriptor<unknown>;
30
- path?: string | undefined;
31
- }>>;
32
- readonly ssr: import("./types").TestHarnessAdapter<true>;
33
- }>> | undefined) => import("react").ForwardRefExoticComponent<import("react").PropsWithoutRef<TProps> & import("react").RefAttributes<unknown>>;
@@ -1,36 +0,0 @@
1
- import * as React from "react";
2
- /**
3
- * A adapter to be composed with our test harness infrastructure.
4
- */
5
- export type TestHarnessAdapter<TConfig> = (children: React.ReactNode, config: TConfig) => React.ReactElement;
6
- /**
7
- * A general map of adapters by their identifiers.
8
- *
9
- * It's OK that this has `any` for the config type as this is the very base
10
- * version of a adapter set. In reality, a more specific type will be used
11
- * with the harness functions that use more specific definitions of known
12
- * adapters. This is just to support the base reality of not knowing.
13
- *
14
- * Use this on input positions only. Output positions for adapters
15
- * should infer their type in most cases to ensure the strongest typing of
16
- * the adapters.
17
- */
18
- export type TestHarnessAdapters = {
19
- readonly [adapterID: string]: TestHarnessAdapter<any>;
20
- };
21
- /**
22
- * Type for easily defining an adapter's config type.
23
- */
24
- export type TestHarnessConfig<TAdapter> = TAdapter extends TestHarnessAdapter<infer TConfig> ? TConfig : never;
25
- /**
26
- * The `TestHarnessConfigs` type as defined by parsing a given set of adapters.
27
- *
28
- * NOTE: This only works if the properties of the passed `TAdapters` type
29
- * are explicitly typed as `TestHarnessAdapter<TConfig>` so if passing in a
30
- * non-Adapters type (which we should be, to get strong `TConfig` types instead
31
- * of `any`), then that object should make sure that each adapter is strongly
32
- * marked as `TestHarnessAdapter<TConfig>`
33
- */
34
- export type TestHarnessConfigs<TAdapters extends TestHarnessAdapters> = {
35
- [K in keyof TAdapters]: TestHarnessConfig<TAdapters[K]> | null | undefined;
36
- };
@@ -1,5 +0,0 @@
1
- import type { OperationMatcher, MockFn } from "./types";
2
- /**
3
- * A generic mock request function for using when mocking fetch or gqlFetch.
4
- */
5
- export declare const mockRequester: <TOperationType>(operationMatcher: OperationMatcher<any>, operationToString: (...args: Array<any>) => string) => MockFn<TOperationType>;
@@ -1,75 +0,0 @@
1
- import { SettleSignal } from "./settle-signal";
2
- import type { GraphQLJson } from "./types";
3
- /**
4
- * This symbol is used so we can create an opaque type, using a custom field
5
- * that cannot be directly referenced since folks won't have access to the
6
- * symbol.
7
- *
8
- * See https://stackoverflow.com/a/56749647/23234
9
- */
10
- declare const opaque: unique symbol;
11
- /**
12
- * Describes a mock response to a fetch request.
13
- */
14
- export type MockResponse<TData> = {
15
- /**
16
- * This is used to enforce the use of the TData type parameter. We won't
17
- * actually attach anything to this field. Doing this makes sure that
18
- * TData is relevant to the response. Without it, it will get ignored
19
- * and a value of type MockResponse<string> will be considered the same
20
- * type as a value of type MockResponse<number> (or any other type
21
- * constraint).
22
- */
23
- [opaque]: TData;
24
- /**
25
- * Create a promise from the mocked response.
26
- *
27
- * If a signal was provided when the mock response was created, the promise
28
- * will only settle to resolution or rejection if the signal is raised.
29
- */
30
- readonly toPromise: () => Promise<Response>;
31
- };
32
- /**
33
- * Helpers to define mock responses for mocked requests.
34
- */
35
- export declare const RespondWith: Readonly<{
36
- /**
37
- * Response with text body and status code.
38
- * Status code defaults to 200.
39
- */
40
- text: <TData = string>(text: string, statusCode?: number, signal?: SettleSignal | null) => MockResponse<TData>;
41
- /**
42
- * Response with JSON body and status code 200.
43
- */
44
- json: <TJson extends Record<any, any>>(json: TJson, signal?: SettleSignal | null) => MockResponse<TJson>;
45
- /**
46
- * Response with GraphQL data JSON body and status code 200.
47
- */
48
- graphQLData: <TData_1 extends Record<any, any>>(data: TData_1, signal?: SettleSignal | null) => MockResponse<GraphQLJson<TData_1>>;
49
- /**
50
- * Response with body that will not parse as JSON and status code 200.
51
- */
52
- unparseableBody: (signal?: SettleSignal | null) => MockResponse<any>;
53
- /**
54
- * Rejects with an AbortError to simulate an aborted request.
55
- */
56
- abortedRequest: (signal?: SettleSignal | null) => MockResponse<any>;
57
- /**
58
- * Rejects with the given error.
59
- */
60
- reject: (error: Error, signal?: SettleSignal | null) => MockResponse<any>;
61
- /**
62
- * A non-200 status code with empty text body.
63
- * Equivalent to calling `ResponseWith.text("", statusCode)`.
64
- */
65
- errorStatusCode: (statusCode: number, signal?: SettleSignal | null) => MockResponse<any>;
66
- /**
67
- * Response body that is valid JSON but not a valid GraphQL response.
68
- */
69
- nonGraphQLBody: (signal?: SettleSignal | null) => MockResponse<any>;
70
- /**
71
- * Response that is a GraphQL errors response with status code 200.
72
- */
73
- graphQLErrors: (errorMessages: ReadonlyArray<string>, signal?: SettleSignal | null) => MockResponse<GraphQLJson<any>>;
74
- }>;
75
- export {};
@@ -1 +0,0 @@
1
- export declare const ResponseImpl: typeof Response;
@@ -1,19 +0,0 @@
1
- import { SettleSignal } from "./settle-signal";
2
- /**
3
- * A controller for the `RespondWith` API to control response settlement.
4
- */
5
- export declare class SettleController {
6
- private _settleFn;
7
- private _signal;
8
- constructor();
9
- /**
10
- * The signal to pass to the `RespondWith` API.
11
- */
12
- get signal(): SettleSignal;
13
- /**
14
- * Settle the signal and therefore any associated responses.
15
- *
16
- * @throws {Error} if the signal has already been settled.
17
- */
18
- settle(): void;
19
- }
@@ -1,18 +0,0 @@
1
- /**
2
- * A signal for controlling the `RespondWith` API responses.
3
- *
4
- * This provide finely-grained control over the promise lifecycle to support
5
- * complex test scenarios.
6
- */
7
- export declare class SettleSignal extends EventTarget {
8
- private _settled;
9
- constructor(setSettleFn?: ((settleFn: () => void) => unknown) | null);
10
- /**
11
- * An already settled signal.
12
- */
13
- static settle(): SettleSignal;
14
- /**
15
- * Has this signal been settled yet?
16
- */
17
- get settled(): boolean;
18
- }
package/dist/types.d.ts DELETED
@@ -1,25 +0,0 @@
1
- import type { MockResponse } from "./respond-with";
2
- /**
3
- * A valid GraphQL response as supported by our mocking framework.
4
- * Note that we don't currently support both data and errors being set.
5
- */
6
- export type GraphQLJson<TData extends Record<any, any>> = {
7
- data: TData;
8
- } | {
9
- errors: Array<{
10
- message: string;
11
- }>;
12
- };
13
- export type MockFn<TOperationType> = {
14
- (...args: Array<any>): Promise<Response>;
15
- mockOperation: MockOperationFn<TOperationType>;
16
- mockOperationOnce: MockOperationFn<TOperationType>;
17
- };
18
- export type OperationMock<TOperation> = {
19
- operation: TOperation;
20
- onceOnly: boolean;
21
- used: boolean;
22
- response: () => Promise<Response>;
23
- };
24
- export type OperationMatcher<TOperation> = (operation: TOperation, ...args: Array<any>) => boolean;
25
- export type MockOperationFn<TOperationType> = <TOperation extends TOperationType>(operation: TOperation, response: MockResponse<any>) => MockFn<TOperationType>;
@@ -1,212 +0,0 @@
1
- import {RespondWith} from "../respond-with";
2
- import {mockRequester} from "../mock-requester";
3
-
4
- describe("#mockRequester", () => {
5
- it("should return a function", () => {
6
- // Arrange
7
-
8
- // Act
9
- const result = mockRequester(jest.fn(), jest.fn());
10
-
11
- // Assert
12
- expect(result).toBeInstanceOf(Function);
13
- });
14
-
15
- it("should provide mockOperation API", () => {
16
- // Arrange
17
-
18
- // Act
19
- const result = mockRequester(jest.fn(), jest.fn());
20
-
21
- // Assert
22
- expect(result).toHaveProperty("mockOperation", expect.any(Function));
23
- });
24
-
25
- it("should provide mockOperationOnce API", () => {
26
- // Arrange
27
-
28
- // Act
29
- const result = mockRequester(jest.fn(), jest.fn());
30
-
31
- // Assert
32
- expect(result).toHaveProperty(
33
- "mockOperationOnce",
34
- expect.any(Function),
35
- );
36
- });
37
-
38
- it("should throw with helpful details formatted by operationToString if no matching mock is found", async () => {
39
- // Arrange
40
- const mockFn = mockRequester(
41
- jest.fn(),
42
- (...args: any) => `TEST FORMATTING: ${JSON.stringify(args)}`,
43
- );
44
-
45
- // Act
46
- const underTest = mockFn("any", "arguments", {we: {want: 42}});
47
-
48
- // Assert
49
- await expect(underTest).rejects.toThrowErrorMatchingInlineSnapshot(`
50
- "No matching mock response found for request:
51
- TEST FORMATTING: ["any","arguments",{"we":{"want":42}}]"
52
- `);
53
- });
54
-
55
- describe("mockOperation", () => {
56
- it("should invoke matcher with mock for a request", async () => {
57
- // Arrange
58
- const matcher = jest.fn().mockReturnValue(true);
59
- const operationToString = jest.fn();
60
- const mockFn = mockRequester(matcher, operationToString);
61
-
62
- // Act
63
- mockFn.mockOperation(
64
- "THE MOCK DESCRIPTION",
65
- RespondWith.text("TADA!"),
66
- );
67
- await mockFn("any", "arguments", {we: {want: 42}});
68
-
69
- // Assert
70
- expect(matcher).toHaveBeenCalledWith(
71
- "THE MOCK DESCRIPTION",
72
- "any",
73
- "arguments",
74
- {
75
- we: {want: 42},
76
- },
77
- );
78
- });
79
-
80
- it("should return mocked operation response if matcher returns true", async () => {
81
- // Arrange
82
- const matcher = jest.fn().mockReturnValue(true);
83
- const operationToString = jest.fn();
84
- const mockFn = mockRequester(matcher, operationToString);
85
-
86
- // Act
87
- mockFn.mockOperation(
88
- "THE MOCK DESCRIPTION",
89
- RespondWith.text("TADA!"),
90
- );
91
- const response = await mockFn("DO SOMETHING");
92
- const result = response.text();
93
-
94
- // Assert
95
- await expect(result).resolves.toBe("TADA!");
96
- });
97
-
98
- it("should skip mock if matcher returns false and try more mocks", async () => {
99
- // Arrange
100
- const matcher = jest
101
- .fn()
102
- .mockReturnValueOnce(false)
103
- .mockReturnValueOnce(true);
104
- const operationToString = jest.fn();
105
- const mockFn = mockRequester(matcher, operationToString);
106
-
107
- // Act
108
- mockFn.mockOperation(
109
- "THE MOCK DESCRIPTION 1",
110
- RespondWith.text("ONE"),
111
- );
112
- mockFn.mockOperation(
113
- "THE MOCK DESCRIPTION 2",
114
- RespondWith.text("TWO"),
115
- );
116
- const response = await mockFn("DO SOMETHING");
117
- const result = response.text();
118
-
119
- // Assert
120
- await expect(result).resolves.toBe("TWO");
121
- });
122
- });
123
-
124
- describe("mockOperationOnce", () => {
125
- it("should invoke matcher with mock for a request", async () => {
126
- // Arrange
127
- const matcher = jest.fn().mockReturnValue(true);
128
- const operationToString = jest.fn();
129
- const mockFn = mockRequester(matcher, operationToString);
130
-
131
- // Act
132
- mockFn.mockOperationOnce(
133
- "THE MOCK DESCRIPTION",
134
- RespondWith.text("TADA!"),
135
- );
136
- await mockFn("any", "arguments", {we: {want: 42}});
137
-
138
- // Assert
139
- expect(matcher).toHaveBeenCalledWith(
140
- "THE MOCK DESCRIPTION",
141
- "any",
142
- "arguments",
143
- {
144
- we: {want: 42},
145
- },
146
- );
147
- });
148
-
149
- it("should match once", async () => {
150
- // Arrange
151
- const matcher = jest.fn().mockReturnValue(true);
152
- const operationToString = jest.fn();
153
- const mockFn = mockRequester(matcher, operationToString);
154
-
155
- // Act
156
- mockFn.mockOperationOnce(
157
- "THE MOCK DESCRIPTION",
158
- RespondWith.text("TADA!"),
159
- );
160
- const response = await mockFn("DO SOMETHING");
161
- const result = response.text();
162
-
163
- // Assert
164
- await expect(result).resolves.toBe("TADA!");
165
- });
166
-
167
- it("should only match once", async () => {
168
- // Arrange
169
- const matcher = jest.fn().mockReturnValue(true);
170
- const operationToString = jest.fn();
171
- const mockFn = mockRequester(matcher, operationToString);
172
-
173
- // Act
174
- mockFn.mockOperationOnce(
175
- "THE MOCK DESCRIPTION",
176
- RespondWith.text("TADA!"),
177
- );
178
- const result = Promise.all([
179
- mockFn("DO SOMETHING"),
180
- mockFn("DO SOMETHING"),
181
- ]);
182
-
183
- // Assert
184
- await expect(result).rejects.toThrowError();
185
- });
186
-
187
- it("should skip mock if matcher returns false and try more mocks", async () => {
188
- // Arrange
189
- const matcher = jest
190
- .fn()
191
- .mockReturnValueOnce(false)
192
- .mockReturnValueOnce(true);
193
- const operationToString = jest.fn();
194
- const mockFn = mockRequester(matcher, operationToString);
195
-
196
- // Act
197
- mockFn.mockOperationOnce(
198
- "THE MOCK DESCRIPTION 1",
199
- RespondWith.text("ONE"),
200
- );
201
- mockFn.mockOperationOnce(
202
- "THE MOCK DESCRIPTION 2",
203
- RespondWith.text("TWO"),
204
- );
205
- const response = await mockFn("DO SOMETHING");
206
- const result = response.text();
207
-
208
- // Assert
209
- await expect(result).resolves.toBe("TWO");
210
- });
211
- });
212
- });