Something went wrong. Try again.
Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
Something went wrong. Try again.
8.7 kB · 341 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342// @vitest-environment jsdom
import { renderHook, testEffect } from '@solidjs/testing-library';import { OperationResult, OperationResultSource, createClient, createRequest, gql,} from '@urql/core';import { expect, it, describe, vi } from 'vitest';import { makeSubject } from 'wonka';import { CreateSubscriptionState, createSubscription,} from './createSubscription';import { createEffect, createSignal } from 'solid-js';
const QUERY = gql` subscription { value }`;
const client = createClient({ url: '/graphql', exchanges: [], suspense: false,});
vi.mock('./context', () => { const useClient = () => { return client!; };
return { useClient };});
// Given that it is not possible to directly listen to all store changes it is necessary// to access all relevant parts on which `createEffect` should listen onconst markStateDependencies = (state: CreateSubscriptionState<any, any>) => { state.data; state.error; state.extensions; state.fetching; state.operation; state.stale;};
describe('createSubscription', () => { it('should receive data', () => { return testEffect(done => { const subject = makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>(); const executeQuery = vi .spyOn(client, 'executeSubscription') .mockImplementation( () => subject.source as OperationResultSource<OperationResult> );
const request = createRequest(QUERY, undefined); const operation = client.createRequestOperation('subscription', request);
const [state] = createSubscription< { value: number }, { value: number }, { variable: number } >({ query: QUERY, });
createEffect((run: number = 0) => { markStateDependencies(state);
switch (run) { case 0: { expect(state).toMatchObject({ data: undefined, stale: false, operation: operation, error: undefined, extensions: undefined, fetching: true, }); expect(executeQuery).toEqual(expect.any(Function)); expect(executeQuery).toHaveBeenCalledOnce(); expect(client.executeSubscription).toBeCalledWith( { key: expect.any(Number), query: expect.any(Object), variables: {}, }, undefined ); subject.next({ data: { value: 0 } }); break; } case 1: { expect(state.data).toEqual({ value: 0 }); subject.next({ data: { value: 1 } }); break; } case 2: { expect(state.data).toEqual({ value: 1 }); // expect(state.fetching).toEqual(true); subject.complete(); break; } case 3: { expect(state.fetching).toEqual(false); expect(state.data).toEqual({ value: 1 }); done(); } }
return run + 1; }); }); });
it('should call handler', () => { const handler = vi.fn(); const subject = makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>(); vi.spyOn(client, 'executeSubscription').mockImplementation( () => subject.source as OperationResultSource<OperationResult> );
return testEffect(done => { const [state] = createSubscription< { value: number }, { value: number }, { variable: number } >( { query: QUERY, }, handler );
createEffect((run: number = 0) => { markStateDependencies(state); switch (run) { case 0: { expect(state.fetching).toEqual(true); subject.next({ data: { value: 0 } });
break; } case 1: { expect(handler).toHaveBeenCalledOnce(); expect(handler).toBeCalledWith(undefined, { value: 0 }); done(); break; } }
return run + 1; }); }); });
it('should unsubscribe on teardown', () => { const subject = makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>(); vi.spyOn(client, 'executeSubscription').mockImplementation( () => subject.source as OperationResultSource<OperationResult> );
const { result: [state], cleanup, } = renderHook(() => createSubscription<{ value: number }, { variable: number }>({ query: QUERY, }) );
return testEffect(done => createEffect((run: number = 0) => { if (run === 0) { expect(state.fetching).toEqual(true); cleanup(); }
if (run === 1) { expect(state.fetching).toEqual(false); done(); }
return run + 1; }) ); });
it('should skip executing query when paused', () => { const subject = makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>(); vi.spyOn(client, 'executeSubscription').mockImplementation( () => subject.source as OperationResultSource<OperationResult> );
return testEffect(done => { const [pause, setPause] = createSignal<boolean>(true);
const [state] = createSubscription< { value: number }, { value: number }, { variable: number } >({ query: QUERY, pause: pause });
createEffect((run: number = 0) => { switch (run) { case 0: { expect(state.fetching).toBe(false); setPause(false); break; } case 1: { expect(state.fetching).toBe(true); expect(state.data).toBeUndefined(); subject.next({ data: { value: 1 } });
break; } case 2: { expect(state.data).toStrictEqual({ value: 1 }); done(); break; } }
return run + 1; }); }); });
it('should override pause when execute executeSubscription', () => { const subject = makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>(); const executeQuery = vi .spyOn(client, 'executeSubscription') .mockImplementation( () => subject.source as OperationResultSource<OperationResult> );
return testEffect(done => { const [state, executeSubscription] = createSubscription< { value: number }, { value: number }, { variable: number } >({ query: QUERY, pause: true, });
createEffect((run: number = 0) => { markStateDependencies(state);
switch (run) { case 0: { expect(state.fetching).toEqual(false); expect(executeQuery).not.toBeCalled();
executeSubscription();
break; } case 1: { expect(state.fetching).toEqual(true); expect(executeQuery).toHaveBeenCalledOnce(); subject.next({ data: { value: 1 } }); break; } case 2: { expect(state.data).toStrictEqual({ value: 1 }); done(); break; } }
return run + 1; }); }); });
it('should aggregate results', () => { const subject = makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>(); vi.spyOn(client, 'executeSubscription').mockImplementation( () => subject.source as OperationResultSource<OperationResult> );
return testEffect(done => { const [state] = createSubscription< { value: number }, { merged: number }, { variable: number } >( { query: QUERY, }, (prev, next) => { if (prev === undefined) { return { merged: 0 + next.value, }; }
return { merged: prev.merged + next.value }; } );
createEffect((run: number = 0) => { markStateDependencies(state); switch (run) { case 0: { expect(state.fetching).toEqual(true); subject.next({ data: { value: 1 } });
break; } case 1: { expect(state.data).toEqual({ merged: 1 }); subject.next({ data: { value: 2 } });
break; } case 2: { expect(state.data).toEqual({ merged: 3 });
done(); break; } }
return run + 1; }); }); });});