|
| 1 | +/* eslint-disable testing-library/render-result-naming-convention */ |
1 | 2 | import React, { Fragment, StrictMode, Suspense, useTransition } from "react";
|
2 | 3 | import {
|
3 | 4 | act,
|
|
8 | 9 | RenderHookOptions,
|
9 | 10 | } from "@testing-library/react";
|
10 | 11 | import userEvent from "@testing-library/user-event";
|
11 |
| -import { ErrorBoundary } from "react-error-boundary"; |
| 12 | +import { ErrorBoundary, FallbackProps } from "react-error-boundary"; |
12 | 13 | import { GraphQLError } from "graphql";
|
13 | 14 | import { InvariantError } from "ts-invariant";
|
14 | 15 | import { equal } from "@wry/equality";
|
@@ -10571,6 +10572,125 @@ describe("useSuspenseQuery", () => {
|
10571 | 10572 | await expect(renderStream).not.toRerender();
|
10572 | 10573 | });
|
10573 | 10574 |
|
| 10575 | + // https://github.com/apollographql/apollo-client/issues/12103 |
| 10576 | + it("does not get stuck pending when `fetchMore` rejects with an error", async () => { |
| 10577 | + using _ = spyOnConsole("error"); |
| 10578 | + const { query, data } = setupPaginatedCase(); |
| 10579 | + |
| 10580 | + const link = new ApolloLink((operation) => { |
| 10581 | + const { offset = 0, limit = 2 } = operation.variables; |
| 10582 | + const letters = data.slice(offset, offset + limit); |
| 10583 | + |
| 10584 | + return new Observable((observer) => { |
| 10585 | + setTimeout(() => { |
| 10586 | + if (offset === 2) { |
| 10587 | + observer.next({ |
| 10588 | + data: null, |
| 10589 | + errors: [{ message: "Could not fetch letters" }], |
| 10590 | + }); |
| 10591 | + } else { |
| 10592 | + observer.next({ data: { letters } }); |
| 10593 | + } |
| 10594 | + observer.complete(); |
| 10595 | + }, 10); |
| 10596 | + }); |
| 10597 | + }); |
| 10598 | + |
| 10599 | + const client = new ApolloClient({ |
| 10600 | + cache: new InMemoryCache(), |
| 10601 | + link, |
| 10602 | + }); |
| 10603 | + |
| 10604 | + const renderStream = createRenderStream({ |
| 10605 | + initialSnapshot: { |
| 10606 | + result: null as UseSuspenseQueryResult< |
| 10607 | + PaginatedCaseData, |
| 10608 | + PaginatedCaseVariables |
| 10609 | + > | null, |
| 10610 | + error: null as ApolloError | null, |
| 10611 | + }, |
| 10612 | + }); |
| 10613 | + |
| 10614 | + function SuspenseFallback() { |
| 10615 | + useTrackRenders(); |
| 10616 | + |
| 10617 | + return <div>Loading...</div>; |
| 10618 | + } |
| 10619 | + |
| 10620 | + function ErrorFallback({ error }: FallbackProps) { |
| 10621 | + useTrackRenders(); |
| 10622 | + renderStream.mergeSnapshot({ error }); |
| 10623 | + |
| 10624 | + return <div>Error</div>; |
| 10625 | + } |
| 10626 | + |
| 10627 | + function App() { |
| 10628 | + useTrackRenders(); |
| 10629 | + const result = useSuspenseQuery(query, { |
| 10630 | + variables: { offset: 0, limit: 2 }, |
| 10631 | + }); |
| 10632 | + |
| 10633 | + renderStream.mergeSnapshot({ result }); |
| 10634 | + |
| 10635 | + return null; |
| 10636 | + } |
| 10637 | + |
| 10638 | + renderStream.render( |
| 10639 | + <Suspense fallback={<SuspenseFallback />}> |
| 10640 | + <ErrorBoundary FallbackComponent={ErrorFallback}> |
| 10641 | + <App /> |
| 10642 | + </ErrorBoundary> |
| 10643 | + </Suspense>, |
| 10644 | + { |
| 10645 | + wrapper: ({ children }) => ( |
| 10646 | + <ApolloProvider client={client}>{children}</ApolloProvider> |
| 10647 | + ), |
| 10648 | + } |
| 10649 | + ); |
| 10650 | + |
| 10651 | + { |
| 10652 | + const { renderedComponents } = await renderStream.takeRender(); |
| 10653 | + |
| 10654 | + expect(renderedComponents).toStrictEqual([SuspenseFallback]); |
| 10655 | + } |
| 10656 | + |
| 10657 | + { |
| 10658 | + const { snapshot, renderedComponents } = await renderStream.takeRender(); |
| 10659 | + |
| 10660 | + expect(renderedComponents).toStrictEqual([App]); |
| 10661 | + expect(snapshot.result?.data).toEqual({ |
| 10662 | + letters: [ |
| 10663 | + { __typename: "Letter", letter: "A", position: 1 }, |
| 10664 | + { __typename: "Letter", letter: "B", position: 2 }, |
| 10665 | + ], |
| 10666 | + }); |
| 10667 | + } |
| 10668 | + |
| 10669 | + const { snapshot } = renderStream.getCurrentRender(); |
| 10670 | + await act(() => |
| 10671 | + snapshot.result!.fetchMore({ variables: { offset: 2 } }).catch(() => {}) |
| 10672 | + ); |
| 10673 | + |
| 10674 | + { |
| 10675 | + const { renderedComponents } = await renderStream.takeRender(); |
| 10676 | + |
| 10677 | + expect(renderedComponents).toStrictEqual([SuspenseFallback]); |
| 10678 | + } |
| 10679 | + |
| 10680 | + { |
| 10681 | + const { snapshot, renderedComponents } = await renderStream.takeRender(); |
| 10682 | + |
| 10683 | + expect(renderedComponents).toStrictEqual([ErrorFallback]); |
| 10684 | + expect(snapshot.error).toEqual( |
| 10685 | + new ApolloError({ |
| 10686 | + graphQLErrors: [{ message: "Could not fetch letters" }], |
| 10687 | + }) |
| 10688 | + ); |
| 10689 | + } |
| 10690 | + |
| 10691 | + await expect(renderStream).not.toRerender(); |
| 10692 | + }); |
| 10693 | + |
10574 | 10694 | describe.skip("type tests", () => {
|
10575 | 10695 | it("returns unknown when TData cannot be inferred", () => {
|
10576 | 10696 | const query = gql`
|
|
0 commit comments