Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

(graphcache) - Clean error stacks (#751)

authored by

Jovi De Croock and committed by
GitHub
6d39091a 160cd03c

+71 -20
+5
.changeset/spotty-maps-kick.md
··· 1 + --- 2 + '@urql/exchange-graphcache': patch 3 + --- 4 + 5 + Improve warning and error console output in development by cleaning up the GraphQL trace stack.
+2
exchanges/graphcache/src/helpers/help.ts
··· 32 32 33 33 export const currentDebugStack: string[] = []; 34 34 35 + export const popDebugNode = () => currentDebugStack.pop(); 36 + 35 37 export const pushDebugNode = (typename: void | string, node: DebugNode) => { 36 38 let identifier = ''; 37 39 if (node.kind === Kind.INLINE_FRAGMENT) {
+30 -14
exchanges/graphcache/src/operations/query.test.ts
··· 4 4 import { query } from './query'; 5 5 6 6 const TODO_QUERY = gql` 7 - query todos { 7 + query Todos { 8 8 todos { 9 9 id 10 10 text ··· 22 22 23 23 describe('Query', () => { 24 24 let schema, store, alteredRoot; 25 - const spy: { console?: any } = {}; 26 25 27 26 beforeAll(() => { 28 27 schema = require('../test-utils/simple_schema.json'); 29 28 alteredRoot = require('../test-utils/altered_root_schema.json'); 30 29 }); 31 30 32 - afterEach(() => { 33 - spy.console.mockRestore(); 34 - }); 35 - 36 31 beforeEach(() => { 37 32 store = new Store({ schema }); 38 33 write( ··· 46 41 ], 47 42 } 48 43 ); 49 - spy.console = jest.spyOn(console, 'warn'); 44 + 45 + jest.resetAllMocks(); 50 46 }); 51 47 52 48 it('test partial results', () => { ··· 75 71 76 72 it('should warn once for invalid fields on an entity', () => { 77 73 const INVALID_TODO_QUERY = gql` 78 - query { 74 + query InvalidTodo { 79 75 todos { 80 76 id 81 77 text ··· 83 79 } 84 80 } 85 81 `; 82 + 86 83 query(store, { query: INVALID_TODO_QUERY }); 87 84 expect(console.warn).toHaveBeenCalledTimes(1); 85 + expect((console.warn as any).mock.calls[0][0]).toMatch( 86 + /Caused At: "InvalidTodo" query/ 87 + ); 88 + 88 89 query(store, { query: INVALID_TODO_QUERY }); 89 90 expect(console.warn).toHaveBeenCalledTimes(1); 91 + 90 92 expect((console.warn as any).mock.calls[0][0]).toMatch(/incomplete/); 91 93 }); 92 94 93 - it('should warn once for invalid sub-entities on an entity', () => { 95 + it('should warn once for invalid sub-entities on an entity at the right stack', () => { 94 96 const INVALID_TODO_QUERY = gql` 95 - query { 97 + query InvalidTodo { 96 98 todos { 99 + ...ValidTodo 100 + ...InvalidFields 101 + } 102 + } 103 + 104 + fragment ValidTodo on Todo { 105 + id 106 + text 107 + } 108 + 109 + fragment InvalidFields on Todo { 110 + id 111 + writer { 97 112 id 98 - text 99 - writer { 100 - id 101 - } 102 113 } 103 114 } 104 115 `; 116 + 105 117 query(store, { query: INVALID_TODO_QUERY }); 106 118 expect(console.warn).toHaveBeenCalledTimes(1); 119 + expect((console.warn as any).mock.calls[0][0]).toMatch( 120 + /Caused At: "InvalidTodo" query, "InvalidFields" Fragment/ 121 + ); 122 + 107 123 query(store, { query: INVALID_TODO_QUERY }); 108 124 expect(console.warn).toHaveBeenCalledTimes(1); 109 125 expect((console.warn as any).mock.calls[0][0]).toMatch(/writer/);
+14 -4
exchanges/graphcache/src/operations/query.ts
··· 35 35 } from '../store'; 36 36 37 37 import * as InMemoryData from '../store/data'; 38 - import { warn, pushDebugNode } from '../helpers/help'; 38 + import { warn, pushDebugNode, popDebugNode } from '../helpers/help'; 39 39 40 40 import { 41 41 Context, ··· 94 94 rootKey !== ctx.store.rootFields['query'] 95 95 ? readRoot(ctx, rootKey, rootSelect, data) 96 96 : readSelection(ctx, rootKey, rootSelect, data); 97 + 98 + if (process.env.NODE_ENV !== 'production') { 99 + popDebugNode(); 100 + } 97 101 98 102 return { 99 103 dependencies: getCurrentDependencies(), ··· 210 214 entityKey 211 215 ); 212 216 213 - return ( 214 - readSelection(ctx, entityKey, getSelectionSet(fragment), {} as Data) || null 215 - ); 217 + const result = 218 + readSelection(ctx, entityKey, getSelectionSet(fragment), {} as Data) || 219 + null; 220 + 221 + if (process.env.NODE_ENV !== 'production') { 222 + popDebugNode(); 223 + } 224 + 225 + return result; 216 226 }; 217 227 218 228 const readSelection = (
+4 -1
exchanges/graphcache/src/operations/shared.ts
··· 7 7 SelectionSet, 8 8 isFieldNode, 9 9 } from '../ast'; 10 - import { warn, pushDebugNode } from '../helpers/help'; 10 + import { warn, pushDebugNode, popDebugNode } from '../helpers/help'; 11 11 12 12 import { hasField } from '../store/data'; 13 13 import { Store, keyOfField } from '../store'; ··· 118 118 if (index >= select.length) { 119 119 this.indexStack.pop(); 120 120 this.selectionStack.pop(); 121 + if (process.env.NODE_ENV !== 'production') { 122 + popDebugNode(); 123 + } 121 124 continue; 122 125 } else { 123 126 const node = select[index];
+16 -1
exchanges/graphcache/src/operations/write.ts
··· 13 13 getFieldAlias, 14 14 } from '../ast'; 15 15 16 - import { invariant, warn, pushDebugNode } from '../helpers/help'; 16 + import { invariant, warn, pushDebugNode, popDebugNode } from '../helpers/help'; 17 17 18 18 import { 19 19 NullArray, ··· 82 82 } 83 83 84 84 writeSelection(ctx, operationName, getSelectionSet(operation), data); 85 + 86 + if (process.env.NODE_ENV !== 'production') { 87 + popDebugNode(); 88 + } 89 + 85 90 return result; 86 91 }; 87 92 ··· 120 125 ); 121 126 122 127 writeSelection(ctx, operationName, getSelectionSet(operation), result.data!); 128 + 129 + if (process.env.NODE_ENV !== 'production') { 130 + popDebugNode(); 131 + } 132 + 123 133 clearDataState(); 124 134 return result; 125 135 }; ··· 167 177 ); 168 178 169 179 writeSelection(ctx, entityKey, getSelectionSet(fragment), writeData); 180 + 181 + if (process.env.NODE_ENV !== 'production') { 182 + popDebugNode(); 183 + } 170 184 }; 171 185 172 186 const writeSelection = ( ··· 228 242 229 243 if (ctx.optimistic && isRoot) { 230 244 const resolver = ctx.store.optimisticMutations[fieldName]; 245 + 231 246 if (!resolver) continue; 232 247 // We have to update the context to reflect up-to-date ResolveInfo 233 248 updateContext(ctx, typename, typename, fieldKey, fieldName);