Skip to content

Commit c2cd99f

Browse files
committed
test: add remaining tests for other primitives
1 parent 84ff641 commit c2cd99f

11 files changed

Lines changed: 1855 additions & 0 deletions

tests/createFragment.test.tsx

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
import {
2+
type ConcreteRequest,
3+
createOperationDescriptor,
4+
graphql,
5+
RecordSource,
6+
Store,
7+
} from "relay-runtime";
8+
import { createMockEnvironment, type MockEnvironment } from "relay-test-utils";
9+
import { createSignal, ErrorBoundary, Suspense, type JSXElement } from "solid-js";
10+
import {
11+
createFragment,
12+
createLazyLoadQuery,
13+
type DataStore,
14+
RelayEnvironmentProvider,
15+
} from "solid-relay";
16+
import { page } from "vitest/browser";
17+
import type {
18+
createFragmentTest_user$data,
19+
createFragmentTest_user$key,
20+
} from "./__generated__/createFragmentTest_user.graphql";
21+
import type { createFragmentTestOwnerQuery } from "./__generated__/createFragmentTestOwnerQuery.graphql";
22+
import { renderToBody, wait } from "./utils";
23+
24+
let environment: MockEnvironment;
25+
let store: DataStore<createFragmentTest_user$data | null | undefined> | undefined;
26+
27+
const View = (props: { children: JSXElement }) => (
28+
<RelayEnvironmentProvider environment={environment}>{props.children}</RelayEnvironmentProvider>
29+
);
30+
31+
describe("createFragment", () => {
32+
const ownerQuery = graphql`
33+
query createFragmentTestOwnerQuery($id: ID!) {
34+
node(id: $id) {
35+
id
36+
... on User {
37+
...createFragmentTest_user
38+
}
39+
}
40+
}
41+
` as ConcreteRequest;
42+
const fragment = graphql`
43+
fragment createFragmentTest_user on User {
44+
id
45+
name
46+
}
47+
`;
48+
const ownerOperation = createOperationDescriptor(ownerQuery, { id: "1" });
49+
50+
const Child = (props: {
51+
user: createFragmentTest_user$key | null | undefined;
52+
testId?: string;
53+
}) => {
54+
store = createFragment(fragment, () => props.user);
55+
return <h1 data-testid={props.testId ?? "name"}>{store()?.name}</h1>;
56+
};
57+
58+
const QueryScreen = (props: { user?: createFragmentTest_user$key | null | undefined }) => {
59+
const data = createLazyLoadQuery<createFragmentTestOwnerQuery>(ownerQuery, { id: "1" });
60+
return (
61+
<ErrorBoundary fallback={(err) => <h1 data-testid="error">{err.message}</h1>}>
62+
<Suspense fallback="Fallback">
63+
<Child user={props.user ?? data()?.node} />
64+
</Suspense>
65+
</ErrorBoundary>
66+
);
67+
};
68+
69+
beforeEach(() => {
70+
environment = createMockEnvironment({
71+
store: new Store(new RecordSource(), { gcReleaseBufferSize: 0 }),
72+
});
73+
store = undefined;
74+
});
75+
76+
it("reads fragment data from a parent query key", async () => {
77+
renderToBody(() => (
78+
<View>
79+
<QueryScreen />
80+
</View>
81+
));
82+
83+
await expect.element(page.getByText("Fallback")).toBeInTheDocument();
84+
environment.mock.resolve(ownerOperation, {
85+
data: { node: { __typename: "User", id: "1", name: "Alice" } },
86+
});
87+
await wait(2);
88+
await expect.element(page.getByTestId("name")).toHaveTextContent("Alice");
89+
await expect.element(page.getByText("Fallback")).not.toBeInTheDocument();
90+
});
91+
92+
it("exposes stable data store getters", async () => {
93+
const [showKey, setShowKey] = createSignal(false);
94+
95+
const Comp = () => {
96+
const data = createLazyLoadQuery<createFragmentTestOwnerQuery>(ownerQuery, { id: "1" });
97+
store = createFragment<createFragmentTest_user$key>(fragment, () =>
98+
showKey() ? data()?.node : undefined,
99+
);
100+
return <h1 data-testid="getter-name">{store()?.name}</h1>;
101+
};
102+
103+
renderToBody(() => (
104+
<View>
105+
<Comp />
106+
</View>
107+
));
108+
109+
expect(store).toBeDefined();
110+
expect(store?.pending).toBe(false);
111+
expect(store?.error).toBeUndefined();
112+
expect(store?.()).toBeUndefined();
113+
expect(store?.latest).toBeUndefined();
114+
await expect.element(page.getByTestId("getter-name")).toBeEmptyDOMElement();
115+
116+
const initialStore = store;
117+
environment.mock.resolve(ownerOperation, {
118+
data: { node: { __typename: "User", id: "1", name: "Alice" } },
119+
});
120+
121+
expect(store).toBe(initialStore);
122+
expect(store?.pending).toBe(false);
123+
expect(store?.error).toBeUndefined();
124+
expect(store?.()).toBeUndefined();
125+
expect(store?.latest).toBeUndefined();
126+
await expect.element(page.getByTestId("getter-name")).toBeEmptyDOMElement();
127+
128+
setShowKey(true);
129+
await wait(2);
130+
131+
expect(store).toBe(initialStore);
132+
expect(store?.pending).toBe(false);
133+
expect(store?.error).toBeUndefined();
134+
expect(store?.()?.name).toBe("Alice");
135+
expect(store?.latest?.name).toBe("Alice");
136+
await expect.element(page.getByTestId("getter-name")).toHaveTextContent("Alice");
137+
});
138+
139+
it("updates when the underlying Relay record changes", async () => {
140+
environment.commitPayload(ownerOperation, {
141+
node: { __typename: "User", id: "1", name: "Alice" },
142+
});
143+
144+
renderToBody(() => (
145+
<View>
146+
<QueryScreen />
147+
</View>
148+
));
149+
150+
await expect.element(page.getByTestId("name")).toHaveTextContent("Alice");
151+
152+
environment.commitPayload(ownerOperation, {
153+
node: { __typename: "User", id: "1", name: "Bob" },
154+
});
155+
await wait(2);
156+
157+
await expect.element(page.getByTestId("name")).toHaveTextContent("Bob");
158+
});
159+
160+
it("renders empty when the fragment key is null", async () => {
161+
renderToBody(() => (
162+
<View>
163+
<Child user={null} />
164+
</View>
165+
));
166+
167+
await expect.element(page.getByTestId("name")).toBeEmptyDOMElement();
168+
expect(store?.pending).toBe(false);
169+
expect(store?.latest).toBeUndefined();
170+
});
171+
172+
it("clears stale data when the key becomes undefined", async () => {
173+
environment.commitPayload(ownerOperation, {
174+
node: { __typename: "User", id: "1", name: "Alice" },
175+
});
176+
177+
const [fragmentKey, setFragmentKey] = createSignal<
178+
createFragmentTest_user$key | null | undefined
179+
>();
180+
let getOwnerKey: (() => createFragmentTest_user$key | null | undefined) | undefined;
181+
182+
const Comp = () => {
183+
const data = createLazyLoadQuery<createFragmentTestOwnerQuery>(
184+
ownerQuery,
185+
{ id: "1" },
186+
{ fetchPolicy: () => "store-only" },
187+
);
188+
getOwnerKey = () => data()?.node;
189+
store = createFragment(fragment, fragmentKey);
190+
return <h1 data-testid="name">{store()?.name}</h1>;
191+
};
192+
193+
renderToBody(() => (
194+
<View>
195+
<Comp />
196+
</View>
197+
));
198+
199+
setFragmentKey(getOwnerKey?.());
200+
await wait(2);
201+
202+
await expect.element(page.getByTestId("name")).toHaveTextContent("Alice");
203+
expect(store?.()?.name).toBe("Alice");
204+
205+
setFragmentKey(undefined);
206+
await wait(2);
207+
208+
await expect.element(page.getByTestId("name")).toBeEmptyDOMElement();
209+
expect(store?.()).toBeUndefined();
210+
expect(store?.latest).toBeUndefined();
211+
});
212+
});

0 commit comments

Comments
 (0)