Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
at main 6.9 kB view raw
1import { map, tap, pipe, fromValue, toArray, toPromise } from 'wonka'; 2import { vi, expect, describe, it } from 'vitest'; 3 4import { Client } from '../client'; 5import { queryResponse, queryOperation } from '../test-utils'; 6import { Operation } from '../types'; 7import { mapExchange } from './map'; 8 9import { 10 makeOperation, 11 makeErrorResult, 12 makeResult, 13 CombinedError, 14} from '../utils'; 15 16describe('onOperation', () => { 17 it('triggers and maps on operations', () => { 18 const mockOperation = makeOperation('query', queryOperation, { 19 ...queryOperation.context, 20 mock: true, 21 }); 22 23 const onOperation = vi.fn().mockReturnValue(mockOperation); 24 const onExchangeResult = vi.fn(); 25 26 const exchangeArgs = { 27 forward: op$ => 28 pipe( 29 op$, 30 tap(onExchangeResult), 31 map((operation: Operation) => makeResult(operation, { data: null })) 32 ), 33 client: {} as Client, 34 dispatchDebug: () => null, 35 }; 36 37 pipe( 38 fromValue(queryOperation), 39 mapExchange({ onOperation })(exchangeArgs), 40 toArray 41 ); 42 43 expect(onOperation).toBeCalledTimes(1); 44 expect(onOperation).toBeCalledWith(queryOperation); 45 expect(onExchangeResult).toBeCalledTimes(1); 46 expect(onExchangeResult).toBeCalledWith(mockOperation); 47 }); 48 49 it('triggers and forwards identity when returning undefined', () => { 50 const onOperation = vi.fn().mockReturnValue(undefined); 51 const onExchangeResult = vi.fn(); 52 53 const exchangeArgs = { 54 forward: op$ => 55 pipe( 56 op$, 57 tap(onExchangeResult), 58 map((operation: Operation) => makeResult(operation, { data: null })) 59 ), 60 client: {} as Client, 61 dispatchDebug: () => null, 62 }; 63 64 pipe( 65 fromValue(queryOperation), 66 mapExchange({ onOperation })(exchangeArgs), 67 toArray 68 ); 69 70 expect(onOperation).toBeCalledTimes(1); 71 expect(onOperation).toBeCalledWith(queryOperation); 72 expect(onExchangeResult).toBeCalledTimes(1); 73 expect(onExchangeResult).toBeCalledWith(queryOperation); 74 }); 75 76 it('awaits returned promises as needed', async () => { 77 const mockOperation = makeOperation('query', queryOperation, { 78 ...queryOperation.context, 79 mock: true, 80 }); 81 82 const onOperation = vi.fn().mockResolvedValue(mockOperation); 83 const onExchangeResult = vi.fn(); 84 85 const exchangeArgs = { 86 forward: op$ => 87 pipe( 88 op$, 89 tap(onExchangeResult), 90 map((operation: Operation) => makeResult(operation, { data: null })) 91 ), 92 client: {} as Client, 93 dispatchDebug: () => null, 94 }; 95 96 await pipe( 97 fromValue(queryOperation), 98 mapExchange({ onOperation })(exchangeArgs), 99 toPromise 100 ); 101 102 expect(onOperation).toBeCalledTimes(1); 103 expect(onOperation).toBeCalledWith(queryOperation); 104 expect(onExchangeResult).toBeCalledTimes(1); 105 expect(onExchangeResult).toBeCalledWith(mockOperation); 106 }); 107}); 108 109describe('onResult', () => { 110 it('triggers and maps on results', async () => { 111 const mockOperation = makeOperation('query', queryOperation, { 112 ...queryOperation.context, 113 mock: true, 114 }); 115 116 const mockResult = makeErrorResult(mockOperation, new Error('Mock')); 117 const onResult = vi.fn().mockReturnValue(mockResult); 118 const onExchangeResult = vi.fn(); 119 120 const exchangeArgs = { 121 forward: op$ => 122 pipe( 123 op$, 124 map((operation: Operation) => makeResult(operation, { data: null })) 125 ), 126 client: {} as Client, 127 dispatchDebug: () => null, 128 }; 129 130 pipe( 131 fromValue(queryOperation), 132 mapExchange({ onResult })(exchangeArgs), 133 tap(onExchangeResult), 134 toArray 135 ); 136 137 expect(onResult).toBeCalledTimes(1); 138 expect(onResult).toBeCalledWith(makeResult(queryOperation, { data: null })); 139 expect(onExchangeResult).toBeCalledTimes(1); 140 expect(onExchangeResult).toBeCalledWith(mockResult); 141 }); 142 143 it('triggers and forwards identity when returning undefined', async () => { 144 const onResult = vi.fn().mockReturnValue(undefined); 145 const onExchangeResult = vi.fn(); 146 147 const exchangeArgs = { 148 forward: op$ => 149 pipe( 150 op$, 151 map((operation: Operation) => makeResult(operation, { data: null })) 152 ), 153 client: {} as Client, 154 dispatchDebug: () => null, 155 }; 156 157 pipe( 158 fromValue(queryOperation), 159 mapExchange({ onResult })(exchangeArgs), 160 tap(onExchangeResult), 161 toArray 162 ); 163 164 const result = makeResult(queryOperation, { data: null }); 165 expect(onResult).toBeCalledTimes(1); 166 expect(onResult).toBeCalledWith(result); 167 expect(onExchangeResult).toBeCalledTimes(1); 168 expect(onExchangeResult).toBeCalledWith(result); 169 }); 170 171 it('awaits returned promises as needed', async () => { 172 const mockOperation = makeOperation('query', queryOperation, { 173 ...queryOperation.context, 174 mock: true, 175 }); 176 177 const mockResult = makeErrorResult(mockOperation, new Error('Mock')); 178 const onResult = vi.fn().mockResolvedValue(mockResult); 179 const onExchangeResult = vi.fn(); 180 181 const exchangeArgs = { 182 forward: op$ => 183 pipe( 184 op$, 185 map((operation: Operation) => makeResult(operation, { data: null })) 186 ), 187 client: {} as Client, 188 dispatchDebug: () => null, 189 }; 190 191 await pipe( 192 fromValue(queryOperation), 193 mapExchange({ onResult })(exchangeArgs), 194 tap(onExchangeResult), 195 toPromise 196 ); 197 198 expect(onResult).toBeCalledTimes(1); 199 expect(onResult).toBeCalledWith(makeResult(queryOperation, { data: null })); 200 expect(onExchangeResult).toBeCalledTimes(1); 201 expect(onExchangeResult).toBeCalledWith(mockResult); 202 }); 203}); 204 205describe('onError', () => { 206 it('does not trigger when there are no errors', async () => { 207 const onError = vi.fn(); 208 209 const exchangeArgs = { 210 forward: op$ => 211 pipe( 212 op$, 213 map((operation: Operation) => ({ ...queryResponse, operation })) 214 ), 215 client: {} as Client, 216 dispatchDebug: () => null, 217 }; 218 219 pipe( 220 fromValue(queryOperation), 221 mapExchange({ onError })(exchangeArgs), 222 toArray 223 ); 224 225 expect(onError).toBeCalledTimes(0); 226 }); 227 228 it('triggers correctly when the operations has an error', async () => { 229 const onError = vi.fn(); 230 const error = new Error('Sad times'); 231 232 const exchangeArgs = { 233 forward: op$ => 234 pipe( 235 op$, 236 map((operation: Operation) => makeErrorResult(operation, error)) 237 ), 238 client: {} as Client, 239 dispatchDebug: () => null, 240 }; 241 242 pipe( 243 fromValue(queryOperation), 244 mapExchange({ onError })(exchangeArgs), 245 toArray 246 ); 247 248 expect(onError).toBeCalledTimes(1); 249 expect(onError).toBeCalledWith( 250 new CombinedError({ networkError: error }), 251 queryOperation 252 ); 253 }); 254});