@khanacademy/wonder-blocks-testing 8.0.21 → 9.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.
Files changed (32) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/es/index.js +417 -24
  3. package/dist/harness/adapters/adapters.d.ts +1 -0
  4. package/dist/harness/adapters/ssr.d.ts +12 -0
  5. package/dist/harness/test-harness.d.ts +1 -0
  6. package/dist/harness/types.d.ts +1 -1
  7. package/dist/index.js +416 -24
  8. package/dist/mock-requester.d.ts +2 -2
  9. package/package.json +2 -2
  10. package/src/fetch/fetch-request-matches-mock.ts +2 -4
  11. package/src/fetch/mock-fetch.ts +1 -1
  12. package/src/fixtures/__tests__/fixtures.test.tsx +9 -14
  13. package/src/fixtures/fixtures.basic.stories.tsx +9 -3
  14. package/src/fixtures/fixtures.tsx +1 -2
  15. package/src/gql/mock-gql-fetch.ts +1 -1
  16. package/src/harness/__tests__/hook-harness.test.ts +4 -2
  17. package/src/harness/__tests__/render-adapters.test.tsx +22 -12
  18. package/src/harness/__tests__/test-harness.test.ts +4 -2
  19. package/src/harness/__tests__/types.typestest.tsx +6 -13
  20. package/src/harness/adapters/__tests__/data.test.tsx +12 -4
  21. package/src/harness/adapters/__tests__/ssr.test.tsx +41 -0
  22. package/src/harness/adapters/adapters.ts +3 -0
  23. package/src/harness/adapters/css.tsx +1 -3
  24. package/src/harness/adapters/router.tsx +5 -17
  25. package/src/harness/adapters/ssr.tsx +33 -0
  26. package/src/harness/{make-hook-harness.ts → make-hook-harness.tsx} +3 -2
  27. package/src/harness/{render-adapters.ts → render-adapters.tsx} +1 -2
  28. package/src/harness/types.ts +1 -1
  29. package/src/mock-requester.ts +4 -11
  30. package/src/respond-with.ts +2 -1
  31. package/src/settle-controller.ts +2 -3
  32. package/tsconfig-build.tsbuildinfo +1 -1
@@ -4,7 +4,7 @@ import {renderAdapters} from "../render-adapters";
4
4
  import type {TestHarnessAdapter, TestHarnessConfigs} from "../types";
5
5
 
6
6
  describe("#renderAdapters", () => {
7
- it("should return children if no adapters", () => {
7
+ it("should render children if no adapters", () => {
8
8
  // Arrange
9
9
  const children = <div>Adapt me!</div>;
10
10
 
@@ -12,7 +12,13 @@ describe("#renderAdapters", () => {
12
12
  const result = renderAdapters({}, {}, children);
13
13
 
14
14
  // Assert
15
- expect(result).toBe(children);
15
+ expect(result).toMatchInlineSnapshot(`
16
+ <React.Fragment>
17
+ <div>
18
+ Adapt me!
19
+ </div>
20
+ </React.Fragment>
21
+ `);
16
22
  });
17
23
 
18
24
  it("should invoke the adapter with its corresponding config", () => {
@@ -38,10 +44,8 @@ describe("#renderAdapters", () => {
38
44
  it("should render each adapter and the children", () => {
39
45
  // Arrange
40
46
  const children = "Adapt me!";
41
- // @ts-expect-error: `string` is not a valid `ReactElement`.
42
- const adapter: TestHarnessAdapter<string> = (c: any, conf: any) => {
43
- return `${conf}:${c}`;
44
- };
47
+ const adapter: TestHarnessAdapter<string> = (c: any, conf: any) =>
48
+ `${conf}:${c}` as any;
45
49
  const adapters = {
46
50
  adapterA: adapter,
47
51
  adapterB: adapter,
@@ -57,16 +61,18 @@ describe("#renderAdapters", () => {
57
61
  const result = renderAdapters(adapters, configs, children);
58
62
 
59
63
  // Assert
60
- expect(result).toMatchInlineSnapshot(`"C:B:A:Adapt me!"`);
64
+ expect(result).toMatchInlineSnapshot(`
65
+ <React.Fragment>
66
+ C:B:A:Adapt me!
67
+ </React.Fragment>
68
+ `);
61
69
  });
62
70
 
63
71
  it("should skip adapters where the corresponding config is null", () => {
64
72
  // Arrange
65
73
  const children = "Adapt me!";
66
- // @ts-expect-error: `string` is not a valid `ReactElement`.
67
- const adapter: TestHarnessAdapter<string> = (c: any, conf: any) => {
68
- return `${conf}:${c}`;
69
- };
74
+ const adapter: TestHarnessAdapter<string> = (c: any, conf: any) =>
75
+ `${conf}:${c}` as any;
70
76
  const adapters = {
71
77
  adapterA: adapter,
72
78
  adapterB: adapter,
@@ -82,6 +88,10 @@ describe("#renderAdapters", () => {
82
88
  const result = renderAdapters(adapters, configs, children);
83
89
 
84
90
  // Assert
85
- expect(result).toMatchInlineSnapshot(`"C:A:Adapt me!"`);
91
+ expect(result).toMatchInlineSnapshot(`
92
+ <React.Fragment>
93
+ C:A:Adapt me!
94
+ </React.Fragment>
95
+ `);
86
96
  });
87
97
  });
@@ -35,7 +35,8 @@ describe("#testHarness", () => {
35
35
  const config = {
36
36
  router: "/boo",
37
37
  } as const;
38
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'harnessFake' does not exist on type 'typeof import("/Users/kevinbarabash/khan/wonder-blocks/packages/wonder-blocks-testing/src/harness/make-test-harness")'.
38
+ // @ts-expect-error We know harnessFake isn't real, we add it in the
39
+ // mocks at the top of this file.
39
40
  const [{harnessFake}, {testHarness}] = await ws.isolateModules(() =>
40
41
  Promise.all([
41
42
  import("../make-test-harness"),
@@ -56,7 +57,8 @@ describe("#testHarness", () => {
56
57
  const config = {
57
58
  router: "/boo",
58
59
  } as const;
59
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'returnValueFake' does not exist on type 'typeof import("/Users/kevinbarabash/khan/wonder-blocks/packages/wonder-blocks-testing/src/harness/make-test-harness")'.
60
+ // @ts-expect-error We know harnessFake isn't real, we add it in the
61
+ // mocks at the top of this file.
60
62
  const [{returnValueFake}, {testHarness}] = await ws.isolateModules(() =>
61
63
  Promise.all([
62
64
  import("../make-test-harness"),
@@ -12,13 +12,10 @@ import type {
12
12
  */
13
13
 
14
14
  //> should assert type of config.
15
- // @ts-expect-error [FEI-5019] - TS2352 - Conversion of type '(children: React.ReactNode, config: number) => React.ReactElement<any>' to type 'TestHarnessAdapter<string>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
16
- ((
17
- children: React.ReactNode,
18
- // TConfig is string, but we typed this arg as a number
19
- // $FlowExpectedError[incompatible-cast]
20
- config: number,
21
- ): React.ReactElement<any> => <div />) as TestHarnessAdapter<string>;
15
+ // @ts-expect-error TConfig is string, but we typed config as a number
16
+ ((children: React.ReactNode, config: number): React.ReactElement<any> => (
17
+ <div />
18
+ )) as TestHarnessAdapter<string>;
22
19
  //<
23
20
 
24
21
  //> should work for correct definition
@@ -36,10 +33,8 @@ import type {
36
33
  //<
37
34
 
38
35
  //> should assert if adapter is not Adapter<TConfig>
39
- // @ts-expect-error [FEI-5019] - TS2352 - Conversion of type '{ adapterString: string; }' to type 'TestHarnessAdapters' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
36
+ // @ts-expect-error String is not a adapter function
40
37
  ({
41
- // String is not a adapter function
42
- // $FlowExpectedError[incompatible-cast]
43
38
  adapterString: "string",
44
39
  } as TestHarnessAdapters);
45
40
  //<
@@ -100,11 +95,9 @@ const adapters = {
100
95
  //<
101
96
 
102
97
  //> should assert if config does not match adapter config
103
- // @ts-expect-error: Conversion of type '{ adapterA: string; adapterB: string; }' to type 'TestHarnessConfigs<{ readonly adapterA: TestHarnessAdapter<string>; readonly adapterB: TestHarnessAdapter<number>; }>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Types of property 'adapterB' are incompatible. Type 'string' is not comparable to type 'number'.
98
+ // @ts-expect-error: the config type here is a number, not a string
104
99
  ({
105
100
  adapterA: "a string, this is correct",
106
- // the config type here is a number, not a string
107
- // $FlowExpectedError[incompatible-cast]
108
101
  adapterB: "a string, but it should be a number",
109
102
  } as TestHarnessConfigs<typeof adapters>);
110
103
  //<
@@ -21,8 +21,12 @@ describe("WonderBlocksData.adapter", () => {
21
21
  const TestFixture = () => {
22
22
  const [result] = useCachedEffect("ID", jest.fn());
23
23
 
24
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'data' does not exist on type 'Result<ValidCacheData>'.
25
- return <div>CONTENT: {result?.data}</div>;
24
+ return (
25
+ <div>
26
+ CONTENT:{" "}
27
+ {result.status === "success" ? result.data : undefined}
28
+ </div>
29
+ );
26
30
  };
27
31
 
28
32
  // Act
@@ -43,8 +47,12 @@ describe("WonderBlocksData.adapter", () => {
43
47
  const TestFixture = () => {
44
48
  const [result] = useCachedEffect("ID", jest.fn());
45
49
 
46
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'data' does not exist on type 'Result<ValidCacheData>'.
47
- return <div>CONTENT:{result?.data}</div>;
50
+ return (
51
+ <div>
52
+ CONTENT:
53
+ {result.status === "success" ? result.data : undefined}
54
+ </div>
55
+ );
48
56
  };
49
57
 
50
58
  // Act
@@ -0,0 +1,41 @@
1
+ import * as React from "react";
2
+ import {render, screen} from "@testing-library/react";
3
+
4
+ import * as WBCore from "@khanacademy/wonder-blocks-core";
5
+
6
+ import * as SSR from "../ssr";
7
+
8
+ jest.mock("@khanacademy/wonder-stuff-core", () => ({
9
+ ...jest.requireActual("@khanacademy/wonder-stuff-core"),
10
+ RenderStateRoot: (props: any) => <div {...props} />,
11
+ }));
12
+
13
+ describe("SSR.adapter", () => {
14
+ it("should render the RenderStateRoot", () => {
15
+ // Arrange
16
+ const children = <div>CHILDREN!</div>;
17
+ const renderStateRootSpy = jest.spyOn(WBCore, "RenderStateRoot");
18
+
19
+ // Act
20
+ render(SSR.adapter(children, true));
21
+
22
+ // Assert
23
+ expect(renderStateRootSpy).toHaveBeenCalledWith(
24
+ {
25
+ children,
26
+ },
27
+ {},
28
+ );
29
+ });
30
+
31
+ it("should render the children correctly", () => {
32
+ // Arrange
33
+ const children = <div>CHILDREN!</div>;
34
+
35
+ // Act
36
+ render(SSR.adapter(children, true));
37
+
38
+ // Assert
39
+ expect(screen.getByText("CHILDREN!")).toBeInTheDocument();
40
+ });
41
+ });
@@ -2,6 +2,7 @@ import * as css from "./css";
2
2
  import * as data from "./data";
3
3
  import * as portal from "./portal";
4
4
  import * as router from "./router";
5
+ import * as ssr from "./ssr";
5
6
 
6
7
  import type {TestHarnessConfigs} from "../types";
7
8
 
@@ -19,6 +20,7 @@ export const DefaultAdapters = {
19
20
  data: data.adapter,
20
21
  portal: portal.adapter,
21
22
  router: router.adapter,
23
+ ssr: ssr.adapter,
22
24
  } as const;
23
25
 
24
26
  /**
@@ -29,4 +31,5 @@ export const DefaultConfigs: TestHarnessConfigs<typeof DefaultAdapters> = {
29
31
  data: data.defaultConfig,
30
32
  portal: portal.defaultConfig,
31
33
  router: router.defaultConfig,
34
+ ssr: ssr.defaultConfig,
32
35
  } as const;
@@ -40,9 +40,7 @@ const normalizeConfig = (
40
40
  return config;
41
41
  }
42
42
 
43
- // @ts-expect-error: at this point, `CSSProperties` is the only thing
44
- // that `config` can be.
45
- return {classes: [], style: config};
43
+ return {classes: [], style: config as CSSProperties};
46
44
  }
47
45
 
48
46
  throw new Error(`Invalid config: ${config}`);
@@ -98,8 +98,7 @@ const maybeWithRoute = (
98
98
  path?: string | null,
99
99
  ): React.ReactElement => {
100
100
  if (path == null) {
101
- // @ts-expect-error [FEI-5019] - TS2322 - Type 'ReactNode' is not assignable to type 'ReactElement<any, string | JSXElementConstructor<any>>'.
102
- return children;
101
+ return <>{children}</>;
103
102
  }
104
103
 
105
104
  return (
@@ -142,14 +141,12 @@ export const adapter: TestHarnessAdapter<Config> = (
142
141
 
143
142
  // Wrap children with the various contexts and routes, as per the config.
144
143
  const wrappedWithRoute = maybeWithRoute(children, config.path);
145
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'forceStatic' does not exist on type 'Readonly<{ initialEntries: LocationDescriptor<unknown>[] | undefined; initialIndex?: number | undefined; getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void) | undefined; path?: string | undefined; } | { ...; } | { ...; }>'.
146
- if (config.forceStatic) {
144
+ if ("forceStatic" in config && config.forceStatic) {
147
145
  /**
148
146
  * There may be times (SSR testing comes to mind) where we will be
149
147
  * really strict about not permitting client-side navigation events.
150
148
  */
151
149
  return (
152
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'location' does not exist on type 'Readonly<{ initialEntries: LocationDescriptor<unknown>[] | undefined; initialIndex?: number | undefined; getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void) | undefined; path?: string | undefined; } | { ...; } | { ...; }>'.
153
150
  <StaticRouter location={config.location} context={{}}>
154
151
  {wrappedWithRoute}
155
152
  </StaticRouter>
@@ -164,10 +161,8 @@ export const adapter: TestHarnessAdapter<Config> = (
164
161
  *
165
162
  * First, the easy one.
166
163
  */
167
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'location' does not exist on type 'Readonly<{ initialEntries: LocationDescriptor<unknown>[] | undefined; initialIndex?: number | undefined; getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void) | undefined; path?: string | undefined; } | { ...; } | { ...; }>'.
168
- if (typeof config.location !== "undefined") {
164
+ if ("location" in config && config.location !== undefined) {
169
165
  return (
170
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'location' does not exist on type 'Readonly<{ initialEntries: LocationDescriptor<unknown>[] | undefined; initialIndex?: number | undefined; getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void) | undefined; path?: string | undefined; } | { ...; } | { ...; }>'.
171
166
  <MemoryRouter initialEntries={[config.location]}>
172
167
  {wrappedWithRoute}
173
168
  </MemoryRouter>
@@ -178,8 +173,7 @@ export const adapter: TestHarnessAdapter<Config> = (
178
173
  * If it's not the easy one, it should be the complex one.
179
174
  * Let's make sure we have good data (also keeps TypeScript happy).
180
175
  */
181
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'initialEntries' does not exist on type 'Readonly<{ initialEntries: LocationDescriptor<unknown>[] | undefined; initialIndex?: number | undefined; getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void) | undefined; path?: string | undefined; } | { ...; } | { ...; }>'.
182
- if (typeof config.initialEntries === "undefined") {
176
+ if (!("initialEntries" in config) || config.initialEntries === undefined) {
183
177
  throw new Error(
184
178
  "A location or initial history entries must be provided.",
185
179
  );
@@ -191,25 +185,19 @@ export const adapter: TestHarnessAdapter<Config> = (
191
185
  * we want, so let's ensure we always have our default location at least.
192
186
  */
193
187
  const entries =
194
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'initialEntries' does not exist on type 'Readonly<{ initialEntries: LocationDescriptor<unknown>[] | undefined; initialIndex?: number | undefined; getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void) | undefined; path?: string | undefined; } | { ...; } | { ...; }>'.
195
188
  config.initialEntries.length === 0
196
189
  ? [defaultConfig.location]
197
- : // @ts-expect-error [FEI-5019] - TS2339 - Property 'initialEntries' does not exist on type 'Readonly<{ initialEntries: LocationDescriptor<unknown>[] | undefined; initialIndex?: number | undefined; getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void) | undefined; path?: string | undefined; } | { ...; } | { ...; }>'.
198
- config.initialEntries;
190
+ : config.initialEntries;
199
191
 
200
192
  // Memory router doesn't allow us to pass maybe types in its TypeScript types.
201
193
  // So let's build props then spread them.
202
194
  const routerProps: MemoryRouterProps = {
203
195
  initialEntries: entries,
204
196
  };
205
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'initialIndex' does not exist on type 'Readonly<{ initialEntries: LocationDescriptor<unknown>[] | undefined; initialIndex?: number | undefined; getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void) | undefined; path?: string | undefined; } | { ...; } | { ...; }>'.
206
197
  if (config.initialIndex != null) {
207
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'initialIndex' does not exist on type 'Readonly<{ initialEntries: LocationDescriptor<unknown>[] | undefined; initialIndex?: number | undefined; getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void) | undefined; path?: string | undefined; } | { ...; } | { ...; }>'.
208
198
  routerProps.initialIndex = config.initialIndex;
209
199
  }
210
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'getUserConfirmation' does not exist on type 'Readonly<{ initialEntries: LocationDescriptor<unknown>[] | undefined; initialIndex?: number | undefined; getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void) | undefined; path?: string | undefined; } | { ...; } | { ...; }>'.
211
200
  if (config.getUserConfirmation != null) {
212
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'getUserConfirmation' does not exist on type 'Readonly<{ initialEntries: LocationDescriptor<unknown>[] | undefined; initialIndex?: number | undefined; getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void) | undefined; path?: string | undefined; } | { ...; } | { ...; }>'.
213
201
  routerProps.getUserConfirmation = config.getUserConfirmation;
214
202
  }
215
203
 
@@ -0,0 +1,33 @@
1
+ import * as React from "react";
2
+ import {KindError, Errors} from "@khanacademy/wonder-stuff-core";
3
+ import {RenderStateRoot} from "@khanacademy/wonder-blocks-core";
4
+
5
+ import type {TestHarnessAdapter} from "../types";
6
+
7
+ // We only support one configuration for this adapter; the default
8
+ // behavior - it's either on or off.
9
+ type Config = true | null;
10
+
11
+ // The default configuration is off since this will likely cause state changes
12
+ // and add Testing Library act/waitFor calls in tests using the harness when
13
+ // its enabled.
14
+ export const defaultConfig: Config = null;
15
+
16
+ /**
17
+ * Test harness adapter for supporting portals.
18
+ *
19
+ * Some components rely on rendering with a React Portal. This adapter ensures
20
+ * that the DOM contains a mounting point for the portal with the expected
21
+ * identifier.
22
+ */
23
+ export const adapter: TestHarnessAdapter<Config> = (
24
+ children: React.ReactNode,
25
+ config: Config,
26
+ ): React.ReactElement<any> => {
27
+ if (config !== true) {
28
+ throw new KindError("Unexpected configuraiton", Errors.InvalidInput, {
29
+ metadata: {config},
30
+ });
31
+ }
32
+ return <RenderStateRoot>{children}</RenderStateRoot>;
33
+ };
@@ -4,8 +4,9 @@ import {makeTestHarness} from "./make-test-harness";
4
4
 
5
5
  import type {TestHarnessAdapters, TestHarnessConfigs} from "./types";
6
6
 
7
- // @ts-expect-error [FEI-5019] - TS7031 - Binding element 'children' implicitly has an 'any' type.
8
- const HookHarness = ({children}) => children;
7
+ const HookHarness = ({
8
+ children,
9
+ }: React.PropsWithChildren<unknown>): React.ReactElement => <>{children}</>;
9
10
 
10
11
  /**
11
12
  * Create a test harness method for use with React hooks.
@@ -22,6 +22,5 @@ export const renderAdapters = <TAdapters extends TestHarnessAdapters>(
22
22
  currentChildren = adapter(currentChildren, config);
23
23
  }
24
24
  }
25
- // @ts-expect-error [FEI-5019] - TS2322 - Type 'ReactNode' is not assignable to type 'ReactElement<any, string | JSXElementConstructor<any>>'.
26
- return currentChildren;
25
+ return <>{currentChildren}</>;
27
26
  };
@@ -6,7 +6,7 @@ import * as React from "react";
6
6
  export type TestHarnessAdapter<TConfig> = (
7
7
  children: React.ReactNode,
8
8
  config: TConfig,
9
- ) => React.ReactElement<any>;
9
+ ) => React.ReactElement;
10
10
 
11
11
  /**
12
12
  * A general map of adapters by their identifiers.
@@ -4,23 +4,17 @@ import type {OperationMock, OperationMatcher, MockFn} from "./types";
4
4
  /**
5
5
  * A generic mock request function for using when mocking fetch or gqlFetch.
6
6
  */
7
- export const mockRequester = <
8
- TOperationType,
9
- TOperationMock extends OperationMock<TOperationType> = OperationMock<TOperationType>,
10
- >(
7
+ export const mockRequester = <TOperationType>(
11
8
  operationMatcher: OperationMatcher<any>,
12
- operationToString: (
13
- operationMock: TOperationMock,
14
- ...args: Array<any>
15
- ) => string,
9
+ operationToString: (...args: Array<any>) => string,
16
10
  ): MockFn<TOperationType> => {
17
11
  // We want this to work in jest and in fixtures to make life easy for folks.
18
12
  // This is the array of mocked operations that we will traverse and
19
13
  // manipulate.
20
14
  const mocks: Array<OperationMock<any>> = [];
21
15
 
22
- // What we return has to be a drop in for the fetch function that is
23
- // provided to `GqlRouter` which is how folks will then use this mock.
16
+ // What we return has to be a drop in replacement for the mocked function
17
+ // which is how folks will then use this mock.
24
18
  const mockFn: MockFn<TOperationType> = (
25
19
  ...args: Array<any>
26
20
  ): Promise<Response> => {
@@ -38,7 +32,6 @@ export const mockRequester = <
38
32
 
39
33
  // Default is to reject with some helpful info on what request
40
34
  // we rejected.
41
- // @ts-expect-error [FEI-5019] - TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
42
35
  const operation = operationToString(...args);
43
36
  return Promise.reject(
44
37
  new Error(`No matching mock response found for request:
@@ -228,7 +228,8 @@ const makeMockResponse = (
228
228
  if (process.env.NODE_ENV !== "production") {
229
229
  // If we're not in production, give an immediate signal that the
230
230
  // dev forgot to support this new type.
231
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'type' does not exist on type 'never'.
231
+ // @ts-expect-error TS knows we can't get here and so sees
232
+ // `response` as `never`.
232
233
  throw new Error(`Unknown response type: ${response.type}`);
233
234
  }
234
235
  // Production; assume a rejection.
@@ -4,8 +4,7 @@ import {SettleSignal} from "./settle-signal";
4
4
  * A controller for the `RespondWith` API to control response settlement.
5
5
  */
6
6
  export class SettleController {
7
- // @ts-expect-error [FEI-5019] - TS2564 - Property '#settleFn' has no initializer and is not definitely assigned in the constructor.
8
- private _settleFn: () => void;
7
+ private _settleFn: undefined | (() => void);
9
8
  private _signal: SettleSignal;
10
9
 
11
10
  constructor() {
@@ -30,6 +29,6 @@ export class SettleController {
30
29
  * @throws {Error} if the signal has already been settled.
31
30
  */
32
31
  settle(): void {
33
- this._settleFn();
32
+ this._settleFn?.();
34
33
  }
35
34
  }