@zendesk/laika
Version:
Test, mock, intercept and modify Apollo Client's operations — in both browser and unit tests!
220 lines (175 loc) • 5.54 kB
text/typescript
import {
ApolloClient,
ApolloLink,
gql,
InMemoryCache,
Observable,
} from '@apollo/client'
import { Laika } from './laika'
const realData = {
data: { sample: 'not mocked' },
}
const mockedData = {
data: { sample: 'mocked' },
}
const alternateMockedData = { data: { sample: 'also mocked' } }
const query = gql`
query sampleQuery {
sample
}
`
const subscriptionQuery = gql`
subscription sampleSubscription {
number
}
`
const sampleLink = new ApolloLink(
() =>
new Observable((observer) => {
observer.next(realData)
observer.complete()
}),
)
const setup = () => {
const laika = new Laika()
const link = laika.createLink()
const client = new ApolloClient({
cache: new InMemoryCache(),
link: ApolloLink.from([link, sampleLink]),
defaultOptions: { query: { fetchPolicy: 'no-cache' } },
})
return [laika, client] as const
}
describe('Apollo Client integration', () => {
it('returns the original value when not mocked', async () => {
const [laika, client] = setup()
const intercept = laika.intercept()
expect.assertions(3)
await expect(client.query({ query })).resolves.toMatchObject(realData)
await expect(client.query({ query })).resolves.toMatchObject(realData)
expect(intercept.calls).toHaveLength(2)
})
it('returns a mocked value with mockResult', async () => {
const [laika, client] = setup()
const intercept = laika.intercept()
intercept.mockResult({ result: mockedData })
expect.assertions(3)
await expect(client.query({ query })).resolves.toMatchObject(mockedData)
await expect(client.query({ query })).resolves.toMatchObject(mockedData)
expect(intercept.calls).toHaveLength(2)
})
it('returns queued mockResultOnce values before falling back', async () => {
const [laika, client] = setup()
const intercept = laika.intercept()
intercept
.mockResultOnce({ result: mockedData })
.mockResultOnce({ result: alternateMockedData })
expect.assertions(4)
await expect(client.query({ query })).resolves.toMatchObject(mockedData)
await expect(client.query({ query })).resolves.toMatchObject(
alternateMockedData,
)
await expect(client.query({ query })).resolves.toMatchObject(realData)
expect(intercept.calls).toHaveLength(3)
})
it('supports mockResultOnce followed by a persistent mockResult', async () => {
const [laika, client] = setup()
const intercept = laika.intercept()
intercept
.mockResultOnce({ result: mockedData })
.mockResult({ result: alternateMockedData })
expect.assertions(4)
await expect(client.query({ query })).resolves.toMatchObject(mockedData)
await expect(client.query({ query })).resolves.toMatchObject(
alternateMockedData,
)
await expect(client.query({ query })).resolves.toMatchObject(
alternateMockedData,
)
expect(intercept.calls).toHaveLength(3)
})
it('rejects queries with mocked errors', async () => {
const [laika, client] = setup()
const intercept = laika.intercept()
intercept.mockResult({ error: new Error('An error occurred') })
await expect(client.query({ query })).rejects.toThrow('An error occurred')
})
it('modifies remote results', async () => {
const [laika, client] = setup()
const enhancedQuery = gql`
query sampleQuery {
sample
modifiedValue
}
`
expect.assertions(3)
laika.modifyRemote(
{ operationName: 'sampleQuery' },
(result, operation) => {
expect(result).toMatchObject(realData)
expect(operation.operationName).toBe('sampleQuery')
return {
...result,
data: {
...result.data,
modifiedValue: 'present',
},
}
},
)
await expect(client.query({ query: enhancedQuery })).resolves.toMatchObject(
{
data: { modifiedValue: 'present', sample: 'not mocked' },
},
)
})
it('mockRestoreAll removes modifyRemote interceptors', async () => {
const [laika, client] = setup()
laika.modifyRemote({ operationName: 'sampleQuery' }, (result) => ({
...result,
data: {
...result.data,
sample: 'modified',
},
}))
await expect(client.query({ query })).resolves.toMatchObject({
data: { sample: 'modified' },
})
laika.mockRestoreAll()
await expect(client.query({ query })).resolves.toMatchObject(realData)
})
it('pushes subscription updates and errors', async () => {
const [laika, client] = setup()
const intercept = laika.intercept()
const next = jest.fn()
const error = jest.fn()
const subscription = client
.subscribe({ query: subscriptionQuery })
.subscribe({
next,
error,
})
await intercept.waitForActiveSubscription()
intercept.fireSubscriptionUpdate({
result: {
data: { number: 1 },
},
})
intercept.fireSubscriptionUpdate({
result: {
data: { number: 2 },
},
})
intercept.fireSubscriptionUpdate({
error: new Error('An error occurred'),
})
expect(next).toHaveBeenNthCalledWith(1, { data: { number: 1 } })
expect(next).toHaveBeenNthCalledWith(2, { data: { number: 2 } })
expect([
error.mock.calls[0]?.[0],
next.mock.calls[2]?.[0]?.error,
]).toContainEqual(new Error('An error occurred'))
expect([2, 3]).toContain(next.mock.calls.length)
subscription.unsubscribe()
})
})