Testing
gql.tada/testing has a set of testing helpers to make test data type-safe. With fragment masking, fragments are opaque and isolated at the type-level, which enforces that a parent never sees the data its children selected. This helps in app code, but complicates tests. Mock data written by hand has the shape of the unmasked fragment result, which won't match the masked types the document expects.
The gql.tada/testing entrypoint exports three helpers to bridge this gap. They are meant for tests, stories, fixtures, and cache updaters.
TIP
Reach for these only at the boundary where you construct mock data. Inside the component or function under test, keep using readFragment() as you normally would.
Masking a fragment's data
maskFragments() takes a list of fragments and the (unmasked) data for them, and returns that data typed as a masked fragment reference. This is the helper you want when a component under test accepts a FragmentOf<typeof fragment> prop and you need to hand it a fixture:
import { graphql } from 'gql.tada';
import { maskFragments } from 'gql.tada/testing';
const pokemonItemFragment = graphql(`
fragment PokemonItem on Pokemon {
id
name
}
`);
// Ready to pass as a prop:
const data = maskFragments([pokemonItemFragment], {
id: '001',
name: 'Bulbasaur',
});maskFragments() also accepts null, undefined, and arrays of data, so you can build fixtures for nullable or list-typed fragment props directly.
Building a document's result
readResult() builds a type-safe fixture for a whole document. You pass it the document, the data with fragment fields inlined, and the list of fragments the document uses. It resolves the references so your data is fully type checked, including fragments that themselves spread other fragments.
import { graphql } from 'gql.tada';
import { readResult } from 'gql.tada/testing';
const pokemonNameFragment = graphql(`
fragment PokemonName on Pokemon {
name
}
`);
const pokemonItemFragment = graphql(`
fragment PokemonItem on Pokemon {
id
...PokemonName
}
`, [pokemonNameFragment]);
const query = graphql(`
query {
pokemon(id: "001") {
...PokemonItem
}
}
`, [pokemonItemFragment]);
// Fully type-checked, including nested fragments:
const data = readResult(
query,
{ pokemon: { id: '001', name: 'Bulbasaur' } },
[pokemonItemFragment, pokemonNameFragment]
);Pass every fragment you want inlined, including ones spread transitively by other fragments. Any fragment you leave out of the list stays masked: instead of inlined fields, it shows up as a still-masked reference in the expected data.
This is handy when you'd rather build part of the result with maskFragments(). Leave that fragment out, and slot the masked value in instead, if you already have mocked data for an individual fragment.
Casting results unsafely
unsafe_readResult() casts data to a document's result type without type checking the data nested inside fragment references. It's a slightly safer alternative to as any as ResultOf<typeof query>.
import { graphql } from 'gql.tada';
import { unsafe_readResult } from 'gql.tada/testing';
const pokemonItemFragment = graphql(`
fragment PokemonItem on Pokemon {
id
name
}
`);
const query = graphql(
`
query {
pokemon(id: "001") {
...PokemonItem
}
}
`,
[pokemonItemFragment]
);
// ⚠️ data is cast to the result type WITHOUT checking the fragment fields:
const data = unsafe_readResult(query, {
pokemon: { id: '001', name: 'Bulbasaur' },
});CAUTION
Because unsafe_readResult() doesn't check the data inside fragment masks, a typo or missing field won't be caught. Prefer readResult() whenever you can, and reach for this only when listing every fragment is impractical.
Testing Functions
See the full API reference for these helpers