@trackunit/react-graphql-tools 1.11.78 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/package.json +3 -3
- package/src/executors/createHooks/scrubMockFile.js +271 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 1.12.1 (2026-03-20)
|
|
2
|
+
|
|
3
|
+
### 🧱 Updated Dependencies
|
|
4
|
+
|
|
5
|
+
- Updated react-test-setup to 1.8.76
|
|
6
|
+
|
|
7
|
+
## 1.12.0 (2026-03-19)
|
|
8
|
+
|
|
9
|
+
### 🚀 Features
|
|
10
|
+
|
|
11
|
+
- improve GraphQL mock generation for tests ([#22330](https://github.com/Trackunit/manager/pull/22330))
|
|
12
|
+
|
|
13
|
+
### ❤️ Thank You
|
|
14
|
+
|
|
15
|
+
- Kieran Prince @kpr-trackunit
|
|
16
|
+
|
|
1
17
|
## 1.11.78 (2026-03-19)
|
|
2
18
|
|
|
3
19
|
### 🧱 Updated Dependencies
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-graphql-tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.1",
|
|
4
4
|
"main": "src/index.js",
|
|
5
5
|
"executors": "./executors.json",
|
|
6
6
|
"generators": "./generators.json",
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
"node": ">=24.x"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@nx/devkit": "22.4.4",
|
|
14
13
|
"@graphql-codegen/cli": "^5.0.3",
|
|
15
14
|
"@graphql-codegen/client-preset": "^4.5.1",
|
|
16
15
|
"prettier": "^3.4.2",
|
|
17
16
|
"ts-morph": "^20.0.0",
|
|
18
17
|
"@faker-js/faker": "^8.4.1",
|
|
19
18
|
"win-ca": "^3.5.1",
|
|
20
|
-
"tslib": "^2.6.2"
|
|
19
|
+
"tslib": "^2.6.2",
|
|
20
|
+
"@nx/devkit": "22.4.4"
|
|
21
21
|
},
|
|
22
22
|
"types": "./src/index.d.ts",
|
|
23
23
|
"type": "commonjs"
|
|
@@ -4,6 +4,215 @@ exports.scrubMockFileContent = void 0;
|
|
|
4
4
|
/* eslint-disable no-console */
|
|
5
5
|
const faker_1 = require("@faker-js/faker");
|
|
6
6
|
const ts_morph_1 = require("ts-morph");
|
|
7
|
+
const UNDEFINED_SENTINEL = "__UNDEFINED__";
|
|
8
|
+
/**
|
|
9
|
+
* Strips surrounding double-quotes from a ts-morph property name.
|
|
10
|
+
* Codegen may emit JSON-style keys (`"kind"`) whose getName() includes the quotes.
|
|
11
|
+
*/
|
|
12
|
+
const stripQuotes = (name) => (name.startsWith('"') && name.endsWith('"') ? name.slice(1, -1) : name);
|
|
13
|
+
/**
|
|
14
|
+
* Finds a property in an object literal by name, handling both quoted and unquoted keys.
|
|
15
|
+
*/
|
|
16
|
+
const findProperty = (obj, name) => obj.getProperty(name) ?? obj.getProperty(`"${name}"`);
|
|
17
|
+
/**
|
|
18
|
+
* Resolves the type of a property symbol in the context of a source file.
|
|
19
|
+
* Uses the TypeChecker to correctly handle mapped types like Exact<{...}>.
|
|
20
|
+
*/
|
|
21
|
+
const getPropertyType = (prop, sourceFile) => {
|
|
22
|
+
return sourceFile.getProject().getTypeChecker().getTypeOfSymbolAtLocation(prop, sourceFile);
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Checks whether a type is an InputMaybe union (contains null or undefined members).
|
|
26
|
+
* Required unions like `string | string[]` or enums do NOT match.
|
|
27
|
+
*/
|
|
28
|
+
const isInputMaybe = (type) => type.isUnion() && type.getUnionTypes().some(m => m.isNull() || m.isUndefined());
|
|
29
|
+
/**
|
|
30
|
+
* Returns the names of required variable fields (those whose type is NOT
|
|
31
|
+
* wrapped in InputMaybe, i.e. not a union containing null/undefined).
|
|
32
|
+
*/
|
|
33
|
+
const getRequiredVariableKeys = (variablesType, sourceFile) => {
|
|
34
|
+
return variablesType
|
|
35
|
+
.getProperties()
|
|
36
|
+
.filter(prop => !isInputMaybe(getPropertyType(prop, sourceFile)))
|
|
37
|
+
.map(prop => prop.getName());
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Generates default variable values for GraphQL query/mutation variables.
|
|
41
|
+
*
|
|
42
|
+
* - InputMaybe<T> (union with null/undefined) -> UNDEFINED_SENTINEL
|
|
43
|
+
* - Required union (e.g. string | string[], enums) -> faker value from first concrete member
|
|
44
|
+
* - Required scalar -> faker value
|
|
45
|
+
* - Required object -> recursively expanded
|
|
46
|
+
*/
|
|
47
|
+
const generateDefaultFromInputType = (type, sourceFile, depth = 0) => {
|
|
48
|
+
if (depth > 10)
|
|
49
|
+
return UNDEFINED_SENTINEL;
|
|
50
|
+
if (isInputMaybe(type)) {
|
|
51
|
+
return UNDEFINED_SENTINEL;
|
|
52
|
+
}
|
|
53
|
+
if (type.isUnion()) {
|
|
54
|
+
const firstMember = type.getUnionTypes()[0];
|
|
55
|
+
if (!firstMember)
|
|
56
|
+
return UNDEFINED_SENTINEL;
|
|
57
|
+
return generateDefaultFromInputType(firstMember, sourceFile, depth);
|
|
58
|
+
}
|
|
59
|
+
if (type.isArray()) {
|
|
60
|
+
const elementType = type.getArrayElementType();
|
|
61
|
+
if (!elementType)
|
|
62
|
+
return UNDEFINED_SENTINEL;
|
|
63
|
+
const elementDefault = generateDefaultFromInputType(elementType, sourceFile, depth + 1);
|
|
64
|
+
if (elementDefault === UNDEFINED_SENTINEL)
|
|
65
|
+
return [];
|
|
66
|
+
return [elementDefault];
|
|
67
|
+
}
|
|
68
|
+
if (type.isObject()) {
|
|
69
|
+
const properties = type.getProperties();
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
71
|
+
const obj = {};
|
|
72
|
+
for (const prop of properties) {
|
|
73
|
+
const propType = getPropertyType(prop, sourceFile);
|
|
74
|
+
obj[prop.getName()] = generateDefaultFromInputType(propType, sourceFile, depth + 1);
|
|
75
|
+
}
|
|
76
|
+
return obj;
|
|
77
|
+
}
|
|
78
|
+
if (type.isStringLiteral())
|
|
79
|
+
return type.getLiteralValue();
|
|
80
|
+
if (type.isNumberLiteral())
|
|
81
|
+
return type.getLiteralValue();
|
|
82
|
+
if (type.isBooleanLiteral())
|
|
83
|
+
return type.getText() === "true";
|
|
84
|
+
const typeText = type.getText();
|
|
85
|
+
if (typeText === "string" || typeText === "number" || typeText === "boolean") {
|
|
86
|
+
faker_1.faker.seed(123);
|
|
87
|
+
if (typeText === "string")
|
|
88
|
+
return faker_1.faker.lorem.word();
|
|
89
|
+
if (typeText === "number")
|
|
90
|
+
return faker_1.faker.number.int();
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
return UNDEFINED_SENTINEL;
|
|
94
|
+
};
|
|
95
|
+
const parseGraphqlDefaultValue = (kind, rawValue) => {
|
|
96
|
+
switch (kind) {
|
|
97
|
+
case "BooleanValue":
|
|
98
|
+
return rawValue === "true";
|
|
99
|
+
case "IntValue":
|
|
100
|
+
return rawValue ? parseInt(rawValue.replace(/"/g, ""), 10) : 0;
|
|
101
|
+
case "FloatValue":
|
|
102
|
+
return rawValue ? parseFloat(rawValue.replace(/"/g, "")) : 0;
|
|
103
|
+
case "StringValue":
|
|
104
|
+
return rawValue ? rawValue.replace(/^"|"$/g, "") : "";
|
|
105
|
+
case "EnumValue":
|
|
106
|
+
return rawValue ? rawValue.replace(/^"|"$/g, "") : undefined;
|
|
107
|
+
case "NullValue":
|
|
108
|
+
return null;
|
|
109
|
+
default:
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Navigates variable -> name -> value inside a VariableDefinition object literal
|
|
115
|
+
* to extract the GraphQL variable name.
|
|
116
|
+
*/
|
|
117
|
+
const extractVarDefName = (obj) => {
|
|
118
|
+
const varProp = obj
|
|
119
|
+
.getChildrenOfKind(ts_morph_1.SyntaxKind.PropertyAssignment)
|
|
120
|
+
.find(p => stripQuotes(p.getName()) === "variable");
|
|
121
|
+
if (!varProp)
|
|
122
|
+
return undefined;
|
|
123
|
+
const varInit = varProp.getInitializer();
|
|
124
|
+
if (!varInit || !ts_morph_1.Node.isObjectLiteralExpression(varInit))
|
|
125
|
+
return undefined;
|
|
126
|
+
const namePropInner = varInit
|
|
127
|
+
.getChildrenOfKind(ts_morph_1.SyntaxKind.PropertyAssignment)
|
|
128
|
+
.find(p => stripQuotes(p.getName()) === "name");
|
|
129
|
+
if (!namePropInner)
|
|
130
|
+
return undefined;
|
|
131
|
+
const nameInit = namePropInner.getInitializer();
|
|
132
|
+
if (!nameInit || !ts_morph_1.Node.isObjectLiteralExpression(nameInit))
|
|
133
|
+
return undefined;
|
|
134
|
+
const valuePropInner = nameInit
|
|
135
|
+
.getChildrenOfKind(ts_morph_1.SyntaxKind.PropertyAssignment)
|
|
136
|
+
.find(p => stripQuotes(p.getName()) === "value");
|
|
137
|
+
if (!valuePropInner)
|
|
138
|
+
return undefined;
|
|
139
|
+
return valuePropInner.getInitializer()?.getText().replace(/"/g, "");
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Extracts GraphQL-level default values from the DocumentNode AST constant.
|
|
143
|
+
* e.g. `$withValues: Boolean = true` produces
|
|
144
|
+
* `defaultValue: { kind: "BooleanValue", value: true }` in the generated TypeScript.
|
|
145
|
+
*/
|
|
146
|
+
const extractGraphqlDefaultValues = (sourceFile, documentName) => {
|
|
147
|
+
const defaults = {};
|
|
148
|
+
const decl = sourceFile.getVariableDeclaration(documentName);
|
|
149
|
+
if (!decl)
|
|
150
|
+
return defaults;
|
|
151
|
+
const objectLiterals = decl.getDescendantsOfKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
152
|
+
for (const obj of objectLiterals) {
|
|
153
|
+
const kindProp = findProperty(obj, "kind");
|
|
154
|
+
if (!kindProp || !ts_morph_1.Node.isPropertyAssignment(kindProp))
|
|
155
|
+
continue;
|
|
156
|
+
if (kindProp.getInitializer()?.getText() !== '"VariableDefinition"')
|
|
157
|
+
continue;
|
|
158
|
+
const dvProp = findProperty(obj, "defaultValue");
|
|
159
|
+
if (!dvProp || !ts_morph_1.Node.isPropertyAssignment(dvProp))
|
|
160
|
+
continue;
|
|
161
|
+
const dvInit = dvProp.getInitializer();
|
|
162
|
+
if (!dvInit || !ts_morph_1.Node.isObjectLiteralExpression(dvInit))
|
|
163
|
+
continue;
|
|
164
|
+
const varName = extractVarDefName(obj);
|
|
165
|
+
if (!varName)
|
|
166
|
+
continue;
|
|
167
|
+
const dvKindProp = findProperty(dvInit, "kind");
|
|
168
|
+
if (!dvKindProp || !ts_morph_1.Node.isPropertyAssignment(dvKindProp))
|
|
169
|
+
continue;
|
|
170
|
+
const dvKind = dvKindProp.getInitializer()?.getText().replace(/"/g, "");
|
|
171
|
+
let dvValue;
|
|
172
|
+
const dvValueProp = findProperty(dvInit, "value");
|
|
173
|
+
if (dvValueProp && ts_morph_1.Node.isPropertyAssignment(dvValueProp)) {
|
|
174
|
+
dvValue = dvValueProp.getInitializer()?.getText();
|
|
175
|
+
}
|
|
176
|
+
const parsed = parseGraphqlDefaultValue(dvKind, dvValue);
|
|
177
|
+
if (parsed !== undefined) {
|
|
178
|
+
defaults[varName] = parsed;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return defaults;
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* Serializes a value to JavaScript source code, emitting `undefined` for sentinel values.
|
|
185
|
+
* JSON.stringify drops undefined, so we need a custom serializer.
|
|
186
|
+
*/
|
|
187
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
188
|
+
const serializeToSource = (value, indent = 0) => {
|
|
189
|
+
const pad = " ".repeat(indent);
|
|
190
|
+
const innerPad = " ".repeat(indent + 4);
|
|
191
|
+
if (value === UNDEFINED_SENTINEL)
|
|
192
|
+
return "undefined";
|
|
193
|
+
if (value === null)
|
|
194
|
+
return "null";
|
|
195
|
+
if (typeof value === "string")
|
|
196
|
+
return JSON.stringify(value);
|
|
197
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
198
|
+
return String(value);
|
|
199
|
+
if (Array.isArray(value)) {
|
|
200
|
+
if (value.length === 0)
|
|
201
|
+
return "[]";
|
|
202
|
+
const items = value.map(v => `${innerPad}${serializeToSource(v, indent + 4)}`).join(",\n");
|
|
203
|
+
return `[\n${items}\n${pad}]`;
|
|
204
|
+
}
|
|
205
|
+
if (typeof value === "object") {
|
|
206
|
+
const entries = Object.entries(value);
|
|
207
|
+
if (entries.length === 0)
|
|
208
|
+
return "{}";
|
|
209
|
+
const props = entries
|
|
210
|
+
.map(([k, v]) => `${innerPad}${JSON.stringify(k)}: ${serializeToSource(v, indent + 4)}`)
|
|
211
|
+
.join(",\n");
|
|
212
|
+
return `{\n${props}\n${pad}}`;
|
|
213
|
+
}
|
|
214
|
+
return "undefined";
|
|
215
|
+
};
|
|
7
216
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
217
|
const generateMockFromType = (type, text) => {
|
|
9
218
|
faker_1.faker.seed(123);
|
|
@@ -16,13 +225,13 @@ const generateMockFromType = (type, text) => {
|
|
|
16
225
|
if (rightSideText.startsWith("[number, number] | [number, number][] | [number, number][][]")) {
|
|
17
226
|
return "[[1, 2], [3, 4]]";
|
|
18
227
|
}
|
|
19
|
-
if (type.isStringLiteral()) {
|
|
228
|
+
if (Boolean(type.isStringLiteral())) {
|
|
20
229
|
return type.compilerType.value; // Get the value of the string literal
|
|
21
230
|
}
|
|
22
|
-
if (type.isNumberLiteral()) {
|
|
231
|
+
if (Boolean(type.isNumberLiteral())) {
|
|
23
232
|
return parseFloat(type.compilerType.value);
|
|
24
233
|
}
|
|
25
|
-
if (type.isBooleanLiteral()) {
|
|
234
|
+
if (Boolean(type.isBooleanLiteral())) {
|
|
26
235
|
return type.compilerType.value === "true";
|
|
27
236
|
}
|
|
28
237
|
if (type.getText() === "string") {
|
|
@@ -34,14 +243,14 @@ const generateMockFromType = (type, text) => {
|
|
|
34
243
|
if (type.getText() === "Date" || type.getText() === "DateTime") {
|
|
35
244
|
return "2023-01-22T15:08:12.527Z";
|
|
36
245
|
}
|
|
37
|
-
if (type.isUnion()) {
|
|
38
|
-
|
|
39
|
-
return generateMockFromType(type.getUnionTypes()[0], "");
|
|
246
|
+
if (Boolean(type.isUnion())) {
|
|
247
|
+
const nonNullish = type.getUnionTypes().filter((m) => !m.isNull() && !m.isUndefined());
|
|
248
|
+
return generateMockFromType(nonNullish[0] ?? type.getUnionTypes()[0], "");
|
|
40
249
|
}
|
|
41
|
-
if (type.isArray()) {
|
|
250
|
+
if (Boolean(type.isArray())) {
|
|
42
251
|
return [generateMockFromType(type.getArrayElementTypeOrThrow(), "")];
|
|
43
252
|
}
|
|
44
|
-
if (type.isObject()) {
|
|
253
|
+
if (Boolean(type.isObject())) {
|
|
45
254
|
const properties = type.getProperties();
|
|
46
255
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
47
256
|
const obj = {};
|
|
@@ -49,7 +258,17 @@ const generateMockFromType = (type, text) => {
|
|
|
49
258
|
const declaration = prop.getValueDeclarationOrThrow();
|
|
50
259
|
const propType = declaration.getType();
|
|
51
260
|
if (prop.getName() === "__typename") {
|
|
52
|
-
|
|
261
|
+
let typenameType = propType;
|
|
262
|
+
if (Boolean(typenameType.isUnion())) {
|
|
263
|
+
const real = typenameType.getUnionTypes().filter((m) => !m.isNull() && !m.isUndefined());
|
|
264
|
+
typenameType = real[0] ?? typenameType;
|
|
265
|
+
}
|
|
266
|
+
obj[prop.getName()] = Boolean(typenameType.isStringLiteral())
|
|
267
|
+
? typenameType.compilerType.value
|
|
268
|
+
: typenameType
|
|
269
|
+
.getText()
|
|
270
|
+
.replace(/"/g, "")
|
|
271
|
+
.replace(/ \| undefined/g, "");
|
|
53
272
|
}
|
|
54
273
|
else {
|
|
55
274
|
obj[prop.getName()] = generateMockFromType(propType, declaration.getText());
|
|
@@ -68,6 +287,7 @@ const scrubMockFileContent = async (fileContent, nxRoot, isVerbose) => {
|
|
|
68
287
|
compilerOptions: {
|
|
69
288
|
noUnusedLocals: true,
|
|
70
289
|
noUnusedParameters: true,
|
|
290
|
+
strictNullChecks: true,
|
|
71
291
|
},
|
|
72
292
|
});
|
|
73
293
|
const generatedFile = project.createSourceFile("tmpMock.ts", fileContent);
|
|
@@ -89,10 +309,46 @@ const scrubMockFileContent = async (fileContent, nxRoot, isVerbose) => {
|
|
|
89
309
|
}
|
|
90
310
|
const mock = mockThese.map(mocker => {
|
|
91
311
|
const postFix = (mocker.getName().includes("Query") ? "Query" : "Mutation").length;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
312
|
+
const variablesTypeName = `${mocker.getName()}Variables`;
|
|
313
|
+
const variablesTypeAlias = generatedFile.getTypeAlias(variablesTypeName);
|
|
314
|
+
const docName = mocker.getName().substring(0, mocker.getName().length - postFix);
|
|
315
|
+
const typeDefaults = variablesTypeAlias
|
|
316
|
+
? generateDefaultFromInputType(variablesTypeAlias.getType(), generatedFile)
|
|
317
|
+
: {};
|
|
318
|
+
const graphqlDefaults = extractGraphqlDefaultValues(generatedFile, `${docName}Document`);
|
|
319
|
+
const defaultVars = Object.keys(graphqlDefaults).length > 0 &&
|
|
320
|
+
typeDefaults &&
|
|
321
|
+
typeof typeDefaults === "object" &&
|
|
322
|
+
!Array.isArray(typeDefaults)
|
|
323
|
+
? Object.assign({}, typeDefaults, graphqlDefaults)
|
|
324
|
+
: typeDefaults;
|
|
325
|
+
const requiredKeys = variablesTypeAlias ? getRequiredVariableKeys(variablesTypeAlias.getType(), generatedFile) : [];
|
|
326
|
+
let variablesParam;
|
|
327
|
+
if (requiredKeys.length === 0) {
|
|
328
|
+
variablesParam = `variables?: DeepPartialNullable<gql.${variablesTypeName}>`;
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
const keysUnion = requiredKeys.map(k => `"${k}"`).join(" | ");
|
|
332
|
+
const requiredDeepPartial = `PickDeepPartialNullable<gql.${variablesTypeName}, ${keysUnion}>`;
|
|
333
|
+
const hasOptionalKeys = variablesTypeAlias
|
|
334
|
+
? variablesTypeAlias.getType().getProperties().length > requiredKeys.length
|
|
335
|
+
: false;
|
|
336
|
+
const varType = hasOptionalKeys
|
|
337
|
+
? `${requiredDeepPartial} & DeepPartialNullable<Omit<gql.${variablesTypeName}, ${keysUnion}>>`
|
|
338
|
+
: requiredDeepPartial;
|
|
339
|
+
variablesParam = `variables: ${varType}`;
|
|
340
|
+
}
|
|
341
|
+
const defaultVarsSource = serializeToSource(defaultVars, 4);
|
|
342
|
+
const isEmptyDefault = defaultVarsSource === "{}";
|
|
343
|
+
const defaultVarsRef = isEmptyDefault ? "{}" : `default${mocker.getName()}Variables`;
|
|
344
|
+
const constBlock = isEmptyDefault
|
|
345
|
+
? ""
|
|
346
|
+
: `
|
|
347
|
+
const default${mocker.getName()}Variables: gql.${variablesTypeName} = ${defaultVarsSource};
|
|
348
|
+
`;
|
|
349
|
+
return `${constBlock}
|
|
350
|
+
export const mockFor${mocker.getName()} = (${variablesParam}, data?: DeepPartialNullable<gql.${mocker.getName()}> ) => {
|
|
351
|
+
return queryFor(gql.${docName}Document, mergeDeepVars(${defaultVarsRef}, variables),
|
|
96
352
|
mergeDeep(
|
|
97
353
|
${JSON.stringify(generateMockFromType(mocker.getType(), ""), null, 4)}
|
|
98
354
|
, data || {}) as gql.${mocker.getName()}
|
|
@@ -100,11 +356,10 @@ const scrubMockFileContent = async (fileContent, nxRoot, isVerbose) => {
|
|
|
100
356
|
}`;
|
|
101
357
|
});
|
|
102
358
|
return `
|
|
103
|
-
import { OperationVariables } from "@apollo/client";
|
|
104
359
|
import { mergeDeep } from "@apollo/client/utilities";
|
|
105
|
-
import { queryFor, DeepPartialNullable } from "@trackunit/react-core-contexts-test";
|
|
360
|
+
import { mergeDeepVars, queryFor, DeepPartialNullable, PickDeepPartialNullable } from "@trackunit/react-core-contexts-test";
|
|
106
361
|
import * as gql from "./graphql";
|
|
107
|
-
|
|
362
|
+
|
|
108
363
|
${mock.join("\n")}
|
|
109
364
|
`;
|
|
110
365
|
};
|