1import { pipe, map, fromValue, toPromise, take } from 'wonka';
2import { vi, expect, it, beforeEach } from 'vitest';
3import { GraphQLError } from 'graphql';
4
5import {
6 gql,
7 createClient,
8 Operation,
9 ExchangeIO,
10 Client,
11 CombinedError,
12} from '@urql/core';
13
14import { throwOnErrorExchange } from './throwOnErrorExchange';
15
16const dispatchDebug = vi.fn();
17
18const query = gql`
19 {
20 topLevel
21 topLevelList
22 object {
23 inner
24 }
25 objectList {
26 inner
27 }
28 }
29`;
30const mockData = {
31 topLevel: 'topLevel',
32 topLevelList: ['topLevelList'],
33 object: { inner: 'inner' },
34 objectList: [{ inner: 'inner' }],
35};
36
37let client: Client, op: Operation;
38beforeEach(() => {
39 client = createClient({
40 url: 'http://0.0.0.0',
41 exchanges: [],
42 });
43 op = client.createRequestOperation('query', { key: 1, query, variables: {} });
44});
45
46it('throws on top level field error', async () => {
47 const forward: ExchangeIO = ops$ =>
48 pipe(
49 ops$,
50 map(
51 operation =>
52 ({
53 operation,
54 data: {
55 ...mockData,
56 topLevel: null,
57 },
58 error: new CombinedError({
59 graphQLErrors: [
60 new GraphQLError('top level error', { path: ['topLevel'] }),
61 ],
62 }),
63 }) as any
64 )
65 );
66
67 const res = await pipe(
68 fromValue(op),
69 throwOnErrorExchange()({ forward, client, dispatchDebug }),
70 take(1),
71 toPromise
72 );
73
74 expect(() => res.data?.topLevel).toThrow('top level error');
75 expect(() => res.data).not.toThrow();
76 expect(() => res.data?.topLevelList[0]).not.toThrow();
77});
78
79it('throws on top level list element error', async () => {
80 const forward: ExchangeIO = ops$ =>
81 pipe(
82 ops$,
83 map(
84 operation =>
85 ({
86 operation,
87 data: {
88 ...mockData,
89 topLevelList: ['topLevelList', null],
90 },
91 error: new CombinedError({
92 graphQLErrors: [
93 new GraphQLError('top level list error', {
94 path: ['topLevelList', 1],
95 }),
96 ],
97 }),
98 }) as any
99 )
100 );
101
102 const res = await pipe(
103 fromValue(op),
104 throwOnErrorExchange()({ forward, client, dispatchDebug }),
105 take(1),
106 toPromise
107 );
108
109 expect(() => res.data?.topLevelList[1]).toThrow('top level list error');
110 expect(() => res.data).not.toThrow();
111 expect(() => res.data?.topLevelList[0]).not.toThrow();
112});
113
114it('throws on object field error', async () => {
115 const forward: ExchangeIO = ops$ =>
116 pipe(
117 ops$,
118 map(
119 operation =>
120 ({
121 operation,
122 data: {
123 ...mockData,
124 object: null,
125 },
126 error: new CombinedError({
127 graphQLErrors: [
128 new GraphQLError('object field error', { path: ['object'] }),
129 ],
130 }),
131 }) as any
132 )
133 );
134
135 const res = await pipe(
136 fromValue(op),
137 throwOnErrorExchange()({ forward, client, dispatchDebug }),
138 take(1),
139 toPromise
140 );
141
142 expect(() => res.data?.object).toThrow('object field error');
143 expect(() => res.data?.object.inner).toThrow('object field error');
144 expect(() => res.data).not.toThrow();
145 expect(() => res.data?.topLevel).not.toThrow();
146});
147
148it('throws on object inner field error', async () => {
149 const forward: ExchangeIO = ops$ =>
150 pipe(
151 ops$,
152 map(
153 operation =>
154 ({
155 operation,
156 data: {
157 ...mockData,
158 object: {
159 inner: null,
160 },
161 },
162 error: new CombinedError({
163 graphQLErrors: [
164 new GraphQLError('object inner field error', {
165 path: ['object', 'inner'],
166 }),
167 ],
168 }),
169 }) as any
170 )
171 );
172
173 const res = await pipe(
174 fromValue(op),
175 throwOnErrorExchange()({ forward, client, dispatchDebug }),
176 take(1),
177 toPromise
178 );
179
180 expect(() => res.data?.object.inner).toThrow('object inner field error');
181 expect(() => res.data).not.toThrow();
182 expect(() => res.data?.object).not.toThrow();
183});
184
185it('throws on object list field error', async () => {
186 const forward: ExchangeIO = ops$ =>
187 pipe(
188 ops$,
189 map(
190 operation =>
191 ({
192 operation,
193 data: {
194 ...mockData,
195 objectList: null,
196 },
197 error: new CombinedError({
198 graphQLErrors: [
199 new GraphQLError('object list field error', {
200 path: ['objectList'],
201 }),
202 ],
203 }),
204 }) as any
205 )
206 );
207
208 const res = await pipe(
209 fromValue(op),
210 throwOnErrorExchange()({ forward, client, dispatchDebug }),
211 take(1),
212 toPromise
213 );
214
215 expect(() => res.data?.objectList).toThrow('object list field error');
216 expect(() => res.data?.objectList[0]).toThrow('object list field error');
217 expect(() => res.data?.objectList[0].inner).toThrow(
218 'object list field error'
219 );
220 expect(() => res.data).not.toThrow();
221 expect(() => res.data?.topLevel).not.toThrow();
222});
223
224it('throws on object inner field error', async () => {
225 const forward: ExchangeIO = ops$ =>
226 pipe(
227 ops$,
228 map(
229 operation =>
230 ({
231 operation,
232 data: {
233 ...mockData,
234 objectList: [{ inner: 'inner' }, { inner: null }],
235 },
236 error: new CombinedError({
237 graphQLErrors: [
238 new GraphQLError('object list inner field error', {
239 path: ['objectList', 1, 'inner'],
240 }),
241 ],
242 }),
243 }) as any
244 )
245 );
246
247 const res = await pipe(
248 fromValue(op),
249 throwOnErrorExchange()({ forward, client, dispatchDebug }),
250 take(1),
251 toPromise
252 );
253
254 expect(() => res.data?.objectList[1].inner).toThrow(
255 'object list inner field error'
256 );
257 expect(() => res.data).not.toThrow();
258 expect(() => res.data?.objectList[0].inner).not.toThrow();
259});