Urql: Testing urql-wrapped components

Created on 2 Jul 2018  路  3Comments  路  Source: FormidableLabs/urql

I realise this may not be the right place to ask, but I'm only getting started with GraphQL and urql, so sorry if this is an obvious question.

I have a index.tsx which sets up the urql Provider and Connect and subsequently renders MyComponent:

import { Connect, Provider, UrqlProps } from "urql";

const myMutationString = `string here`;

interface Mutations {
  myMutation: (text: string) => void;
}

<Provider client={client}>
  <Connect
    mutation={{myMutation: mutation(myMutationString)}}
    children={(urqlProps: UrqlProps<{}, Mutations>) => (
      <MyComponent
        {...urqlProps}
        myProp="123"
      />
    )}
  />
</Provider>

Subsequently I've typed the Props from MyComponent as an intersection between UrqlProps<{}, Mutations> and the props specific to MyComponent (such as myProp in the example above).

The nice way about setting it up this way (I got the idea from the Redux community and how they separate redux containers that do the connect and the component itself), is that MyComponent doesn't need to know that the loaded, data, etc props came from urql, and can simply use these props as it sees fit.

Now the hitch: I'm trying to test MyComponent using enzyme and jest, and trying to simply pass it the urql props it's actually using (in this case, just myMutation):

const component = shallow(
    <MyComponent
      myMutation={jest.fn()}
      myProp="123"
    />
)

...but I'm of course running into a Typescript error for not passing down everything defined by urql (such as cache, fetching, etc, as defined here)

Does anyone have any advice about typing urql-wrapped components and subsequently testing them? Thanks in advanced 馃槃

Most helpful comment

Hey @nicollecastrog :wave:

I'd recommend not typing props as an intersection or spreading urql's props, and instead explicitly pass just the props MyComponent needs. If you can avoid your component knowing about urql it'll make testing a whole lot easier.

The same is true of redux HOC's where you might export a component separately from the connected one for testing.

All 3 comments

I am probably not going to be much help as I've not used Jest, Enzyme or even TypeScript all that much but couldn't writing just your tests in JS be a workaround for these typing issues?

Hey @nicollecastrog :wave:

I'd recommend not typing props as an intersection or spreading urql's props, and instead explicitly pass just the props MyComponent needs. If you can avoid your component knowing about urql it'll make testing a whole lot easier.

The same is true of redux HOC's where you might export a component separately from the connected one for testing.

Hey @imranolas long time no see! 馃憢馃槃

I see your point, and I did try that before, but unlike redux where the things you are passing down to the component are defined in your application itself (actions and app state), with urql these are specific props that are the same _every time_ I wrap a component with urql.

It ends up meaning that I'm copying across types defined in urql's own UrqlProps<Data, Mutations = {}> for my own MyComponent's Props definition... But really, having thought about it, that's not a that big deal, so I've given it a shot below 馃憤

Based on your advice, I figured this is the best way leverage urql's own props and still keep MyComponent ignorant of urql's presence:

...
    children={({ data, loaded, myMutation }: UrqlProps<Data, Mutations>) => (
      <MyComponent
        data={data}
        loaded={loaded}
        myMutation={myMutation}
        myProp="123"
      />
    )}
...

...with Props definition for MyComponent:

interface Data { ... }
interface MyMutation { ... }

interface Props {
  data: Data | null;    // these are the bits I was trying to avoid typing by doing the intersection
  loaded: boolean;    // and this, etc
  myMutation: MyMutation;
  myProp: string;
}

Thanks for your help! 馃専

Was this page helpful?
0 / 5 - 0 ratings