Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
at main 7.0 kB view raw
1// @vitest-environment jsdom 2 3import { expect, it, describe, vi } from 'vitest'; 4import { CreateQueryState, createQuery } from './createQuery'; 5import { renderHook, testEffect } from '@solidjs/testing-library'; 6import { createClient } from '@urql/core'; 7import { createEffect, createSignal } from 'solid-js'; 8import { makeSubject } from 'wonka'; 9import { OperationResult, OperationResultSource } from '@urql/core'; 10 11const client = createClient({ 12 url: '/graphql', 13 exchanges: [], 14 suspense: false, 15}); 16 17vi.mock('./context', () => { 18 const useClient = () => { 19 return client!; 20 }; 21 22 return { useClient }; 23}); 24 25// Given that it is not possible to directly listen to all store changes it is necessary 26// to access all relevant parts on which `createEffect` should listen on 27const markStateDependencies = (state: CreateQueryState<any, any>) => { 28 state.data; 29 state.error; 30 state.extensions; 31 state.fetching; 32 state.operation; 33 state.stale; 34}; 35 36describe('createQuery', () => { 37 it('should fetch when query is resumed', () => { 38 const subject = 39 makeSubject<Pick<OperationResult<{ test: boolean }, any>, 'data'>>(); 40 const executeQuery = vi 41 .spyOn(client, 'executeQuery') 42 .mockImplementation( 43 () => subject.source as OperationResultSource<OperationResult> 44 ); 45 46 return testEffect(done => { 47 const [pause, setPause] = createSignal<boolean>(true); 48 const [state] = createQuery<{ test: boolean }, { variable: number }>({ 49 query: '{ test }', 50 pause: pause, 51 }); 52 53 createEffect((run: number = 0) => { 54 markStateDependencies(state); 55 56 switch (run) { 57 case 0: { 58 expect(state.fetching).toEqual(false); 59 expect(executeQuery).not.toHaveBeenCalled(); 60 setPause(false); 61 break; 62 } 63 case 1: { 64 expect(state.fetching).toEqual(true); 65 expect(executeQuery).toHaveBeenCalledOnce(); 66 subject.next({ data: { test: true } }); 67 break; 68 } 69 case 2: { 70 expect(state.fetching).toEqual(false); 71 expect(state.data).toStrictEqual({ test: true }); 72 done(); 73 break; 74 } 75 } 76 77 return run + 1; 78 }); 79 }); 80 }); 81 82 it('should override pause when execute via refetch', () => { 83 const subject = 84 makeSubject<Pick<OperationResult<{ test: boolean }, any>, 'data'>>(); 85 const executeQuery = vi 86 .spyOn(client, 'executeQuery') 87 .mockImplementation( 88 () => subject.source as OperationResultSource<OperationResult> 89 ); 90 91 return testEffect(done => { 92 const [state, refetch] = createQuery< 93 { test: boolean }, 94 { variable: number } 95 >({ 96 query: '{ test }', 97 pause: true, 98 }); 99 100 createEffect((run: number = 0) => { 101 markStateDependencies(state); 102 103 switch (run) { 104 case 0: { 105 expect(state.fetching).toEqual(false); 106 expect(executeQuery).not.toBeCalled(); 107 refetch(); 108 break; 109 } 110 case 1: { 111 expect(state.fetching).toEqual(true); 112 expect(executeQuery).toHaveBeenCalledOnce(); 113 subject.next({ data: { test: true } }); 114 break; 115 } 116 case 2: { 117 expect(state.fetching).toEqual(false); 118 expect(state.data).toStrictEqual({ test: true }); 119 done(); 120 break; 121 } 122 } 123 124 return run + 1; 125 }); 126 }); 127 }); 128 129 it('should trigger refetch on variables change', () => { 130 const subject = 131 makeSubject<Pick<OperationResult<{ test: boolean }, any>, 'data'>>(); 132 const executeQuery = vi 133 .spyOn(client, 'executeQuery') 134 .mockImplementation( 135 () => subject.source as OperationResultSource<OperationResult> 136 ); 137 138 return testEffect(done => { 139 const [variables, setVariables] = createSignal<{ variable: number }>({ 140 variable: 1, 141 }); 142 143 const [state] = createQuery<{ test: boolean }, { variable: number }>({ 144 query: '{ test }', 145 variables: variables, 146 }); 147 148 createEffect((run: number = 0) => { 149 markStateDependencies(state); 150 151 switch (run) { 152 case 0: { 153 expect(state.fetching).toEqual(true); 154 155 subject.next({ data: { test: true } }); 156 157 break; 158 } 159 case 1: { 160 expect(state.fetching).toEqual(false); 161 expect(state.data).toEqual({ test: true }); 162 setVariables({ variable: 2 }); 163 break; 164 } 165 case 2: { 166 expect(state.fetching).toEqual(true); 167 expect(executeQuery).toHaveBeenCalledTimes(2); 168 169 subject.next({ data: { test: false } }); 170 break; 171 } 172 case 3: { 173 expect(state.fetching).toEqual(false); 174 expect(state.data).toEqual({ test: false }); 175 done(); 176 break; 177 } 178 } 179 180 return run + 1; 181 }); 182 }); 183 }); 184 185 it('should receive data', () => { 186 const subject = 187 makeSubject<Pick<OperationResult<{ test: boolean }, any>, 'data'>>(); 188 const executeQuery = vi 189 .spyOn(client, 'executeQuery') 190 .mockImplementation( 191 () => subject.source as OperationResultSource<OperationResult> 192 ); 193 194 return testEffect(done => { 195 const [state] = createQuery<{ test: boolean }, { variable: number }>({ 196 query: '{ test }', 197 }); 198 199 createEffect((run: number = 0) => { 200 markStateDependencies(state); 201 202 switch (run) { 203 case 0: { 204 expect(state.fetching).toEqual(true); 205 expect(state.data).toBeUndefined(); 206 207 subject.next({ data: { test: true } }); 208 break; 209 } 210 211 case 1: { 212 expect(state.fetching).toEqual(false); 213 expect(state.data).toStrictEqual({ test: true }); 214 expect(executeQuery).toHaveBeenCalledTimes(1); 215 done(); 216 break; 217 } 218 } 219 220 return run + 1; 221 }); 222 }); 223 }); 224 225 it('should unsubscribe on teardown', () => { 226 const subject = 227 makeSubject<Pick<OperationResult<{ value: number }, any>, 'data'>>(); 228 vi.spyOn(client, 'executeQuery').mockImplementation( 229 () => subject.source as OperationResultSource<OperationResult> 230 ); 231 232 const { 233 result: [state], 234 cleanup, 235 } = renderHook(() => 236 createQuery<{ test: number }, { variable: number }>({ 237 query: '{ test }', 238 }) 239 ); 240 241 return testEffect(done => { 242 markStateDependencies(state); 243 244 createEffect((run: number = 0) => { 245 switch (run) { 246 case 0: { 247 expect(state.fetching).toEqual(true); 248 cleanup(); 249 break; 250 } 251 case 1: { 252 expect(state.fetching).toEqual(false); 253 done(); 254 break; 255 } 256 } 257 258 return run + 1; 259 }); 260 }); 261 }); 262});