// @vitest-environment jsdom import { expect, it, describe, vi } from 'vitest'; import { CreateQueryState, createQuery } from './createQuery'; import { renderHook, testEffect } from '@solidjs/testing-library'; import { createClient } from '@urql/core'; import { createEffect, createSignal } from 'solid-js'; import { makeSubject } from 'wonka'; import { OperationResult, OperationResultSource } from '@urql/core'; 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 on const markStateDependencies = (state: CreateQueryState) => { state.data; state.error; state.extensions; state.fetching; state.operation; state.stale; }; describe('createQuery', () => { it('should fetch when query is resumed', () => { const subject = makeSubject, 'data'>>(); const executeQuery = vi .spyOn(client, 'executeQuery') .mockImplementation( () => subject.source as OperationResultSource ); return testEffect(done => { const [pause, setPause] = createSignal(true); const [state] = createQuery<{ test: boolean }, { variable: number }>({ query: '{ test }', pause: pause, }); createEffect((run: number = 0) => { markStateDependencies(state); switch (run) { case 0: { expect(state.fetching).toEqual(false); expect(executeQuery).not.toHaveBeenCalled(); setPause(false); break; } case 1: { expect(state.fetching).toEqual(true); expect(executeQuery).toHaveBeenCalledOnce(); subject.next({ data: { test: true } }); break; } case 2: { expect(state.fetching).toEqual(false); expect(state.data).toStrictEqual({ test: true }); done(); break; } } return run + 1; }); }); }); it('should override pause when execute via refetch', () => { const subject = makeSubject, 'data'>>(); const executeQuery = vi .spyOn(client, 'executeQuery') .mockImplementation( () => subject.source as OperationResultSource ); return testEffect(done => { const [state, refetch] = createQuery< { test: boolean }, { variable: number } >({ query: '{ test }', pause: true, }); createEffect((run: number = 0) => { markStateDependencies(state); switch (run) { case 0: { expect(state.fetching).toEqual(false); expect(executeQuery).not.toBeCalled(); refetch(); break; } case 1: { expect(state.fetching).toEqual(true); expect(executeQuery).toHaveBeenCalledOnce(); subject.next({ data: { test: true } }); break; } case 2: { expect(state.fetching).toEqual(false); expect(state.data).toStrictEqual({ test: true }); done(); break; } } return run + 1; }); }); }); it('should trigger refetch on variables change', () => { const subject = makeSubject, 'data'>>(); const executeQuery = vi .spyOn(client, 'executeQuery') .mockImplementation( () => subject.source as OperationResultSource ); return testEffect(done => { const [variables, setVariables] = createSignal<{ variable: number }>({ variable: 1, }); const [state] = createQuery<{ test: boolean }, { variable: number }>({ query: '{ test }', variables: variables, }); createEffect((run: number = 0) => { markStateDependencies(state); switch (run) { case 0: { expect(state.fetching).toEqual(true); subject.next({ data: { test: true } }); break; } case 1: { expect(state.fetching).toEqual(false); expect(state.data).toEqual({ test: true }); setVariables({ variable: 2 }); break; } case 2: { expect(state.fetching).toEqual(true); expect(executeQuery).toHaveBeenCalledTimes(2); subject.next({ data: { test: false } }); break; } case 3: { expect(state.fetching).toEqual(false); expect(state.data).toEqual({ test: false }); done(); break; } } return run + 1; }); }); }); it('should receive data', () => { const subject = makeSubject, 'data'>>(); const executeQuery = vi .spyOn(client, 'executeQuery') .mockImplementation( () => subject.source as OperationResultSource ); return testEffect(done => { const [state] = createQuery<{ test: boolean }, { variable: number }>({ query: '{ test }', }); createEffect((run: number = 0) => { markStateDependencies(state); switch (run) { case 0: { expect(state.fetching).toEqual(true); expect(state.data).toBeUndefined(); subject.next({ data: { test: true } }); break; } case 1: { expect(state.fetching).toEqual(false); expect(state.data).toStrictEqual({ test: true }); expect(executeQuery).toHaveBeenCalledTimes(1); done(); break; } } return run + 1; }); }); }); it('should unsubscribe on teardown', () => { const subject = makeSubject, 'data'>>(); vi.spyOn(client, 'executeQuery').mockImplementation( () => subject.source as OperationResultSource ); const { result: [state], cleanup, } = renderHook(() => createQuery<{ test: number }, { variable: number }>({ query: '{ test }', }) ); return testEffect(done => { markStateDependencies(state); createEffect((run: number = 0) => { switch (run) { case 0: { expect(state.fetching).toEqual(true); cleanup(); break; } case 1: { expect(state.fetching).toEqual(false); done(); break; } } return run + 1; }); }); }); });