1import { Kind, parse, print } from '@0no-co/graphql.web';
2import { describe, it, expect } from 'vitest';
3import { createRequest } from './request';
4import { formatDocument } from './formatDocument';
5
6const formatTypeNames = (query: string) => {
7 const typedNode = formatDocument(parse(query));
8 return print(typedNode);
9};
10
11describe('formatDocument', () => {
12 it('creates a new instance when adding typenames', () => {
13 const doc = parse(`{ id todos { id } }`) as any;
14 const newDoc = formatDocument(doc) as any;
15 expect(doc).not.toBe(newDoc);
16 expect(doc.definitions).not.toBe(newDoc.definitions);
17 expect(doc.definitions[0]).not.toBe(newDoc.definitions[0]);
18 expect(doc.definitions[0].selectionSet).not.toBe(
19 newDoc.definitions[0].selectionSet
20 );
21 expect(doc.definitions[0].selectionSet.selections).not.toBe(
22 newDoc.definitions[0].selectionSet.selections
23 );
24 // Here we're equal again:
25 expect(doc.definitions[0].selectionSet.selections[0]).toBe(
26 newDoc.definitions[0].selectionSet.selections[0]
27 );
28 // Not equal again:
29 expect(doc.definitions[0].selectionSet.selections[1]).not.toBe(
30 newDoc.definitions[0].selectionSet.selections[1]
31 );
32 expect(doc.definitions[0].selectionSet.selections[1].selectionSet).not.toBe(
33 newDoc.definitions[0].selectionSet.selections[1].selectionSet
34 );
35 // Equal again:
36 expect(
37 doc.definitions[0].selectionSet.selections[1].selectionSet.selections[0]
38 ).toBe(
39 newDoc.definitions[0].selectionSet.selections[1].selectionSet
40 .selections[0]
41 );
42 });
43
44 it('preserves the hashed key of the resulting query', () => {
45 const doc = parse(`{ id todos { id } }`) as any;
46 const expectedKey = createRequest(doc, undefined).key;
47 const formattedDoc = formatDocument(doc);
48 expect(formattedDoc).not.toBe(doc);
49 const actualKey = createRequest(formattedDoc, undefined).key;
50 expect(expectedKey).toBe(actualKey);
51 });
52
53 it('does not preserve the referential integrity with a cloned object', () => {
54 const doc = parse(`{ id todos { id } }`);
55 const formattedDoc = formatDocument(doc);
56 expect(formattedDoc).not.toBe(doc);
57 const query = { ...formattedDoc };
58 const reformattedDoc = formatDocument(query);
59 expect(reformattedDoc).not.toBe(doc);
60 });
61
62 it('preserves custom properties', () => {
63 const doc = parse(`{ todos { id } }`) as any;
64 doc.documentId = '123';
65 expect((formatDocument(doc) as any).documentId).toBe(doc.documentId);
66 });
67
68 it('adds typenames to a query string', () => {
69 expect(formatTypeNames(`{ todos { id } }`)).toMatchInlineSnapshot(`
70 "{
71 todos {
72 id
73 __typename
74 }
75 }"
76 `);
77 });
78
79 it('does not duplicate typenames', () => {
80 expect(
81 formatTypeNames(`{
82 todos {
83 id
84 __typename
85 }
86 }`)
87 ).toMatchInlineSnapshot(`
88 "{
89 todos {
90 id
91 __typename
92 }
93 }"
94 `);
95 });
96
97 it('does add typenames when it is aliased', () => {
98 expect(
99 formatTypeNames(`{
100 todos {
101 id
102 typename: __typename
103 }
104 }`)
105 ).toMatchInlineSnapshot(`
106 "{
107 todos {
108 id
109 typename: __typename
110 __typename
111 }
112 }"
113 `);
114 });
115
116 it('processes directives', () => {
117 const document = `
118 {
119 todos @skip {
120 id @_test
121 }
122 }
123 `;
124
125 const node = formatDocument(parse(document));
126
127 expect(node).toHaveProperty(
128 'definitions.0.selectionSet.selections.0.selectionSet.selections.0._directives',
129 {
130 test: {
131 kind: Kind.DIRECTIVE,
132 arguments: undefined,
133 name: {
134 kind: Kind.NAME,
135 value: '_test',
136 },
137 },
138 }
139 );
140
141 expect(formatTypeNames(document)).toMatchInlineSnapshot(`
142 "{
143 todos @skip {
144 id
145 __typename
146 }
147 }"
148 `);
149 });
150});