Skip to content

Commit 90dd8bf

Browse files
committed
fix: whileFetching used prepend value to both prepend and append.
test: Enhanced test coverage
1 parent 3a594a5 commit 90dd8bf

File tree

5 files changed

+242
-41
lines changed

5 files changed

+242
-41
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@ryfylke-react/rtk-query-loader",
3-
"version": "0.3.31",
3+
"version": "0.3.32",
44
"description": "Lets you create loaders that contain multiple RTK queries.",
55
"main": "./dist/cjs/index.js",
66
"module": "./dist/esm/index.js",

src/withLoader.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export const withLoader = <
4949
props,
5050
query?.data
5151
),
52-
append: args.whileFetching?.prepend?.(
52+
append: args.whileFetching?.append?.(
5353
props,
5454
query?.data
5555
),

testing-app/src/testComponents.tsx

+56-28
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { useRef, useState } from "react";
33
import { aggregateToQuery } from "../../src/aggregateToQuery";
44
import { createLoader } from "../../src/createLoader";
5+
import { InferLoaderData } from "../../src/types";
56
import { withLoader } from "../../src/withLoader";
67
import {
78
Pokemon,
@@ -85,40 +86,67 @@ export const FailTester = withLoader(
8586
})
8687
);
8788

88-
export const FetchTestComponent = () => {
89+
const fetchTestBaseLoader = createLoader({
90+
queries: (name: string) =>
91+
[useGetPokemonByNameQuery(name)] as const,
92+
queriesArg: (props: {
93+
name: string;
94+
onChange: (name: string) => void;
95+
}) => props.name,
96+
onLoading: () => <div>Loading</div>,
97+
onFetching: () => <div>Fetching</div>,
98+
});
99+
100+
type FetchTestLoader = InferLoaderData<
101+
typeof fetchTestBaseLoader
102+
>;
103+
104+
const FetchTesterComponent = (
105+
props: {
106+
name: string;
107+
onChange: (name: string) => void;
108+
},
109+
loaderData: FetchTestLoader
110+
) => {
111+
const inputRef = useRef<HTMLInputElement>(null);
112+
return (
113+
<div>
114+
#{loaderData[0].data.id}
115+
<br />
116+
<form
117+
onSubmit={(e) => {
118+
e.preventDefault();
119+
props.onChange(inputRef.current?.value ?? "");
120+
}}
121+
>
122+
<input type="text" ref={inputRef} />
123+
<button>Go</button>
124+
</form>
125+
</div>
126+
);
127+
};
128+
129+
export const FetchTestRenderer = (props: {
130+
while?: boolean;
131+
}) => {
89132
const [name, setName] = useState("charizard");
90133

134+
if (props.while) {
135+
return <WhileFetchTester name={name} onChange={setName} />;
136+
}
91137
return <FetchTester name={name} onChange={setName} />;
92138
};
93139

94140
export const FetchTester = withLoader(
95-
(props, loaderData) => {
96-
const inputRef = useRef<HTMLInputElement>(null);
97-
return (
98-
<div>
99-
#{loaderData[0].data.id}
100-
<br />
101-
<form
102-
onSubmit={(e) => {
103-
e.preventDefault();
104-
props.onChange(inputRef.current?.value ?? "");
105-
}}
106-
>
107-
<input type="text" ref={inputRef} />
108-
<button>Go</button>
109-
</form>
110-
</div>
111-
);
112-
},
113-
createLoader({
114-
queries: (name: string) =>
115-
[useGetPokemonByNameQuery(name)] as const,
116-
queriesArg: (props: {
117-
name: string;
118-
onChange: (name: string) => void;
119-
}) => props.name,
120-
onLoading: () => <div>Loading</div>,
121-
onFetching: () => <div>Fetching</div>,
141+
FetchTesterComponent,
142+
fetchTestBaseLoader
143+
);
144+
145+
export const WhileFetchTester = withLoader(
146+
FetchTesterComponent,
147+
fetchTestBaseLoader.extend({
148+
whileFetching: { prepend: () => <div>FetchingWhile</div> },
149+
onFetching: undefined,
122150
})
123151
);
124152

testing-app/src/tests.test.tsx

+180-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
/* eslint-disable react-hooks/rules-of-hooks */
22
import userEvent from "@testing-library/user-event";
3+
import { useState } from "react";
4+
import { createLoader } from "../../src/createLoader";
5+
import { withLoader } from "../../src/withLoader";
6+
import {
7+
useGetPokemonByNameQuery,
8+
useGetPokemonsQuery,
9+
} from "./store";
310
import {
411
ExtendedLoaderComponent,
512
FailTester,
6-
FetchTestComponent,
13+
FetchTestRenderer,
714
LoadPokemon,
815
SimpleLoadedComponent,
916
TestAggregateComponent,
@@ -51,7 +58,7 @@ describe("withLoader", () => {
5158
});
5259

5360
test("onFetching renders when applicable", async () => {
54-
render(<FetchTestComponent />);
61+
render(<FetchTestRenderer />);
5562
expect(screen.getByText("Loading")).toBeVisible();
5663
await waitFor(() =>
5764
expect(screen.getByRole("textbox")).toBeVisible()
@@ -66,6 +73,24 @@ describe("withLoader", () => {
6673
);
6774
});
6875

76+
test("whileFetching renders when applicable", async () => {
77+
render(<FetchTestRenderer while />);
78+
expect(screen.getByText("Loading")).toBeVisible();
79+
await waitFor(() =>
80+
expect(screen.getByRole("textbox")).toBeVisible()
81+
);
82+
const input = screen.getByRole("textbox");
83+
userEvent.type(input, "Abc{Enter}");
84+
await waitFor(
85+
() =>
86+
expect(screen.getByText("FetchingWhile")).toBeVisible(),
87+
{ interval: 20 }
88+
);
89+
await waitFor(() =>
90+
expect(screen.getByText("#3")).toBeVisible()
91+
);
92+
});
93+
6994
test("Can transform the output of the loader", async () => {
7095
render(<TestTransformed />);
7196
await waitFor(() =>
@@ -78,5 +103,158 @@ describe("withLoader", () => {
78103
render(<ExtendedLoaderComponent />);
79104
expect(screen.getByText("Extended loading")).toBeVisible();
80105
});
106+
107+
test("Can extend onError", async () => {
108+
const Component = withLoader(
109+
(props, loaderData) => {
110+
return <div>Success</div>;
111+
},
112+
createLoader({
113+
queries: () =>
114+
[useGetPokemonByNameQuery("error")] as const,
115+
onLoading: () => <div>Loading</div>,
116+
onError: () => <div>Error</div>,
117+
}).extend({
118+
onError: () => <div>Extended Error</div>,
119+
})
120+
);
121+
render(<Component />);
122+
expect(screen.getByText("Loading")).toBeVisible();
123+
await waitFor(() =>
124+
expect(screen.getByText("Extended Error")).toBeVisible()
125+
);
126+
});
127+
128+
test("Can extend onFetching", async () => {
129+
const loader = createLoader({
130+
queries: (arg: string) =>
131+
[useGetPokemonByNameQuery(arg)] as const,
132+
queriesArg: (props: {
133+
name: string;
134+
onChange: (name: string) => void;
135+
}) => props.name,
136+
onLoading: () => <div>Loading</div>,
137+
onFetching: () => <div>Fetching</div>,
138+
}).extend({
139+
onFetching: () => <div>Extended Fetching</div>,
140+
});
141+
142+
const Component = withLoader((props, loaderData) => {
143+
return (
144+
<div>
145+
Success <span>{loaderData[0].data.name}</span>
146+
<button
147+
onClick={() => props.onChange(props.name + "a")}
148+
>
149+
Refetch
150+
</button>
151+
</div>
152+
);
153+
}, loader);
154+
155+
const Controller = () => {
156+
const [name, setName] = useState("a");
157+
return <Component name={name} onChange={setName} />;
158+
};
159+
160+
render(<Controller />);
161+
expect(screen.getByText("Loading")).toBeVisible();
162+
await waitFor(() =>
163+
expect(screen.getByRole("button")).toBeVisible()
164+
);
165+
await userEvent.click(screen.getByRole("button"));
166+
await waitFor(() =>
167+
expect(
168+
screen.getByText("Extended Fetching")
169+
).toBeVisible()
170+
);
171+
});
172+
173+
test("Can extend whileFetching", async () => {
174+
const loader = createLoader({
175+
queries: (arg: string) =>
176+
[useGetPokemonByNameQuery(arg)] as const,
177+
queriesArg: (props: {
178+
name: string;
179+
onChange: (name: string) => void;
180+
}) => props.name,
181+
onLoading: () => <div>Loading</div>,
182+
whileFetching: {
183+
prepend: () => <div>Fetching</div>,
184+
},
185+
}).extend({
186+
whileFetching: {
187+
prepend: () => <span>Extended Fetching</span>,
188+
},
189+
});
190+
expect(loader.whileFetching?.prepend).not.toBeUndefined();
191+
192+
const Component = withLoader((props, loaderData) => {
193+
return (
194+
<div>
195+
Success <span>{loaderData[0].data.name}</span>
196+
<button
197+
onClick={() => props.onChange(props.name + "a")}
198+
>
199+
Refetch
200+
</button>
201+
</div>
202+
);
203+
}, loader);
204+
205+
const Controller = () => {
206+
const [name, setName] = useState("a");
207+
return <Component name={name} onChange={setName} />;
208+
};
209+
210+
render(<Controller />);
211+
expect(screen.getByText("Loading")).toBeVisible();
212+
await waitFor(() =>
213+
expect(screen.getByRole("button")).toBeVisible()
214+
);
215+
await userEvent.click(screen.getByRole("button"));
216+
await waitFor(() =>
217+
expect(
218+
screen.queryByText(/extended fetching/i)
219+
).toBeVisible()
220+
);
221+
});
222+
223+
test("Can extend queries", async () => {
224+
const loader = createLoader({
225+
queries: (arg: string) =>
226+
[useGetPokemonByNameQuery(arg)] as const,
227+
queriesArg: (props: { name: string }) => props.name,
228+
onLoading: () => <div>Loading</div>,
229+
}).extend({
230+
queries: (arg: string) =>
231+
[
232+
useGetPokemonByNameQuery(arg),
233+
useGetPokemonsQuery(undefined),
234+
] as const,
235+
transform: (q) => q,
236+
});
237+
238+
const Component = withLoader((props, loaderData) => {
239+
return (
240+
<div>
241+
<ul>
242+
<li>{loaderData[0].data.name}</li>
243+
{loaderData[1].data.results.map((pokemon) => (
244+
<li>{pokemon.name}</li>
245+
))}
246+
</ul>
247+
</div>
248+
);
249+
}, loader);
250+
251+
render(<Component name="test" />);
252+
expect(screen.getByText("Loading")).toBeVisible();
253+
await waitFor(() =>
254+
expect(screen.getByText("test")).toBeVisible()
255+
);
256+
expect(screen.getByText(/charizard/i)).toBeVisible();
257+
expect(screen.getByText(/pikachu/i)).toBeVisible();
258+
});
81259
});
82260
});

testing-app/yarn.lock

+4-9
Original file line numberDiff line numberDiff line change
@@ -1636,12 +1636,7 @@
16361636

16371637
"@ryfylke-react/rtk-query-loader@file:..":
16381638
"resolved" "file:.."
1639-
"version" "0.3.26"
1640-
dependencies:
1641-
"@reduxjs/toolkit" "^1.6.2"
1642-
"@types/react" "^18.0.21"
1643-
"react" "^18.2.0"
1644-
"tslib" "^2.4.0"
1639+
"version" "0.3.31"
16451640

16461641
"@sinclair/typebox@^0.24.1":
16471642
"integrity" "sha512-k8ETQOOQDg5FtK7y9KJWpsGLik+QlPmIi8zzl/dGUgshV2QitprkFlCR/AemjWOTyKn9UwSSGRTzLVotvgCjYQ=="
@@ -2398,9 +2393,9 @@
23982393
"@xtuc/long" "4.2.2"
23992394

24002395
"@xmldom/xmldom@^0.8.3":
2401-
"integrity" "sha512-Lv2vySXypg4nfa51LY1nU8yDAGo/5YwF+EY/rUZgIbfvwVARcd67ttCM8SMsTeJy51YhHYavEq+FS6R0hW9PFQ=="
2402-
"resolved" "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.3.tgz"
2403-
"version" "0.8.3"
2396+
"integrity" "sha512-JIsjTbWBWJHb2t1D4UNZIJ6ohlRYCdoGzeHSzTorMH2zOq3UKlSBzFBMBdFK3xnUD/ANHw/SUzl/vx0z0JrqRw=="
2397+
"resolved" "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.4.tgz"
2398+
"version" "0.8.4"
24042399

24052400
"@xtuc/ieee754@^1.2.0":
24062401
"integrity" "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="

0 commit comments

Comments
 (0)