Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I writing specs for a component using "useReadQuery" #354

Closed
EfstathiadisD opened this issue Aug 26, 2024 · 3 comments
Closed

How can I writing specs for a component using "useReadQuery" #354

EfstathiadisD opened this issue Aug 26, 2024 · 3 comments

Comments

@EfstathiadisD
Copy link

EfstathiadisD commented Aug 26, 2024

I have a Server and Client component combo. The server has the following..

<PreloadQuery query={ProfileDocument}>
  {(queryRef) => (
    <Suspense fallback={null}>
      <Account queryRef={queryRef} />
    </Suspense>
  )}
</PreloadQuery>

The Client is reading it..

export const Account = ({ queryRef }: AccountProps) => {
  const t = useTranslations("PROFILE");

  const { data } = useReadQuery<Profile>(queryRef);

  const { name, initials } = useMemo(() => {
    const firstName = data.me.customer.firstName;
    const lastName = data.me.customer.lastName;

    return {
      name: `${firstName} ${lastName}`,
      initials: `${firstName.charAt(0)}${lastName.charAt(0)}`,
    };
  }, [data]);

  ...
}

That works as expected. Now I am trying to write some tests.. I am using MockProvider and when I am passing the following object as queryRef to the component which I copy pasted from the console. I get the error..

 Expected a QueryRef object, but got something else instead.

I tried a few cause it seems what I get on the server is different from the one on the client.

export const makeMockedQueryRef = createFixture<Record<string, unknown>>({
  __transportedQueryRef: true,
  options: {
    query: ProfileDocument,
    fetchPolicy: "cache-first",
    returnPartialData: false,
  },
  queryKey: "2a304dd6-a152-40a9-ab3f-87f6b98e0d45",
});
export const makeMockedProfileQueryRef = createFixture<Record<string, unknown>>(
  {
    __transportedQueryRef: { toPromise: () => vi.fn() },
    options: {
      query: ProfileDocument,
      fetchPolicy: "cache-first",
      returnPartialData: false,
    },
    queryKey: "2a304dd6-a152-40a9-ab3f-87f6b98e0d45",
  },
);

The ProfileDocument is correct. I checked. I am not sure of two things..

  1. How can I make the test work and the component to render in the specs.
  2. How can I ensure that the queryRef is correct. I tried to find the TS Def for it, but I don't think the correct one is being exported as both PreloadQueryRef, and QueryRef doesn't seem to be what I want..

It would be nice if someone can link to an example where such specs are written or a README as I couldn't find anything in the DOCS. Thank y!

PS: There is some warning re. the toPromise() with NextJS as well. It tells me that it should pass pure objects btwn Client and Server components. And toPromise() isn't as far as I can tell. It works on runtime, but I am thinking this isn't what I am mocking correct since it could be far more complicated that it looks on the surface. Maybe wrong?

@apollographql apollographql deleted a comment Aug 26, 2024
@phryneas
Copy link
Member

phryneas commented Aug 26, 2024

Hi @EfstathiadisD!

The queryRef you are seeing is only a partial transport object - in parallel, the data of that will also be streamed into the browser, injected into the DOM as a script tag, and simulate an ongoing request in your actual ApolloClient instance. The "transport query Ref" will then at some point (usually when consumed by a hook) be turned back into a real queryRef, latching onto that simulated ongoing request.

That said, I wouldn't try to replicate all of that in a test ;)

Instead, you can create a real queryRef by using the @apollo/client core api createQueryPreloader.

That could look like this:

const mockLink = new MockLink([
   /* Your mocks here */
]);
const client = new ApolloClient({
  link: mockLink,
  cache: new InMemoryCache(),
})
const preloader = createQueryPreloader(client);
const queryRef = preloader(query, { variables: { id: 1 } });

PS: There is some warning re. the toPromise() with NextJS as well. It tells me that it should pass pure objects btwn Client and Server components. And toPromise() isn't as far as I can tell. It works on runtime, but I am thinking this isn't what I am mocking correct since it could be far more complicated that it looks on the surface. Maybe wrong?

We're removing toPromise in the next release because of that warning, but it's really just a warning from React that's a bit too eager, you can ignore it for now.

@apollographql apollographql deleted a comment Aug 26, 2024
@EfstathiadisD
Copy link
Author

Thanks! That solve the issue.

Copy link

Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo Client usage and allow us to serve you better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants