Skip to content

Commit baf33ba

Browse files
committed
fix(dev): add param to route css so it is not deduped by react
1 parent 1abe213 commit baf33ba

File tree

1 file changed

+136
-23
lines changed

1 file changed

+136
-23
lines changed

integration/bug-report-test.ts

Lines changed: 136 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { Fixture, AppFixture } from "./helpers/create-fixture.js";
55
import {
66
createAppFixture,
77
createFixture,
8+
css,
89
js,
910
} from "./helpers/create-fixture.js";
1011

@@ -64,27 +65,113 @@ test.beforeAll(async () => {
6465
// `createFixture` will make an app and run your tests against it.
6566
////////////////////////////////////////////////////////////////////////////
6667
files: {
67-
"app/routes/_index.tsx": js`
68-
import { useLoaderData, Link } from "react-router";
68+
"app/routes.ts": js`
69+
import { type RouteConfig, index, route } from "@react-router/dev/routes";
70+
71+
export default [
72+
index("routes/home.tsx"),
73+
route("company", "routes/layout.tsx", [
74+
route("books", "routes/books/route.tsx"),
75+
route("publishers", "routes/publishers/route.tsx"),
76+
]),
77+
] satisfies RouteConfig;
78+
`,
79+
80+
"app/components/Icon.module.css": css`
81+
.icon {
82+
width: 20px;
83+
height: 20px;
84+
background-color: green;
85+
}
86+
`,
87+
88+
"app/components/Icon.tsx": js`
89+
import styles from "./Icon.module.css";
6990
70-
export function loader() {
71-
return "pizza";
91+
export const Icon = () => {
92+
return <div data-testid="icon" className={styles.icon} />;
7293
}
94+
`,
95+
96+
"app/components/LazyIcon.tsx": js`
97+
import { lazy, Suspense } from "react";
98+
99+
const Icon = lazy(() =>
100+
import("../components/Icon").then((m) => ({ default: m.Icon }))
101+
);
102+
103+
const LazyIcon = ({ show }: { show: boolean }) => {
104+
if (!show) return null;
73105
74-
export default function Index() {
75-
let data = useLoaderData();
76106
return (
77-
<div>
78-
{data}
79-
<Link to="/burgers">Other Route</Link>
107+
<Suspense fallback={<div>Loading...</div>}>
108+
<Icon />
109+
</Suspense>
110+
);
111+
};
112+
113+
export { LazyIcon };
114+
`,
115+
116+
"app/routes/home.tsx": js`
117+
import { redirect } from "react-router";
118+
119+
export const loader = () => {
120+
return redirect("/company/books");
121+
};
122+
`,
123+
124+
"app/routes/layout.tsx": js`
125+
import { Link, Outlet } from "react-router";
126+
127+
import { LazyIcon } from "../components/LazyIcon";
128+
import { useState, useEffect } from "react";
129+
130+
export default function Layout() {
131+
const [hydrated, setHydrated] = useState(false);
132+
const [show, setShow] = useState(false);
133+
134+
useEffect(() => {
135+
setShow(true);
136+
},[])
137+
138+
return (
139+
<div style={{ border: "1px solid blue" }}>
140+
<h1>Layout</h1>
141+
<nav>
142+
<Link to="/company/books">Books</Link>
143+
<Link to="/company/publishers">Publishers</Link>
144+
</nav>
145+
<div>
146+
<LazyIcon show={show} />
147+
</div>
148+
<div style={{ border: "1px solid red" }}>
149+
<Outlet />
150+
</div>
80151
</div>
81-
)
152+
);
153+
}
154+
`,
155+
156+
"app/routes/books/route.tsx": js`
157+
import { Icon } from "../../components/Icon";
158+
159+
export default function BooksRoute() {
160+
return (
161+
<>
162+
<h1>Books</h1>
163+
<div>
164+
<Icon />
165+
</div>
166+
</>
167+
);
82168
}
169+
83170
`,
84171

85-
"app/routes/burgers.tsx": js`
86-
export default function Index() {
87-
return <div>cheeseburger</div>;
172+
"app/routes/publishers/route.tsx": js`
173+
export default function PublishersRoute() {
174+
return <h1>Publishers</h1>;
88175
}
89176
`,
90177
},
@@ -103,22 +190,48 @@ test.afterAll(() => {
103190
// add a good description for what you expect React Router to do 👇🏽
104191
////////////////////////////////////////////////////////////////////////////////
105192

106-
test("[description of what you expect it to do]", async ({ page }) => {
193+
test("should preserve the CSS from the lazy loaded component even when it's in the route css manifest", async ({
194+
page,
195+
}) => {
107196
let app = new PlaywrightFixture(appFixture, page);
108-
// You can test any request your app might get using `fixture`.
109-
let response = await fixture.requestDocument("/");
110-
expect(await response.text()).toMatch("pizza");
111197

112198
// If you need to test interactivity use the `app`
113199
await app.goto("/");
114-
await app.clickLink("/burgers");
115-
await page.waitForSelector("text=cheeseburger");
116200

117-
// If you're not sure what's going on, you can "poke" the app, it'll
118-
// automatically open up in your browser for 20 seconds, so be quick!
119-
// await app.poke(20);
201+
expect((await page.$$("data-testid=icon")).length).toBe(1);
202+
203+
// check the head for a link to the css that includes the word `Icon`
204+
const links1 = await page.$$("link");
205+
let found1 = false;
206+
for (const link of links1) {
207+
const href = await link.getAttribute("href");
208+
if (href?.includes("Icon") && href.includes("css")) {
209+
found1 = true;
210+
}
211+
}
212+
213+
expect(found1).toBe(true);
214+
215+
// wait for the loading to be gone
216+
await expect(page.getByText("Loading...")).toHaveCount(0);
217+
218+
// check there are two data-testid=icon elements
219+
expect(await page.getByTestId("icon").all()).toHaveLength(2);
220+
221+
await app.clickLink("/company/publishers");
222+
223+
expect(await page.getByTestId("icon").all()).toHaveLength(1);
224+
225+
const links2 = await page.$$("link");
226+
let found2 = false;
227+
for (const link of links2) {
228+
const href = await link.getAttribute("href");
229+
if (href?.includes("Icon") && href.includes("css")) {
230+
found2 = true;
231+
}
232+
}
120233

121-
// Go check out the other tests to see what else you can do.
234+
expect(found2).toBe(true);
122235
});
123236

124237
////////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)