@simtlix/simfinity-js 1.9.0 → 2.0.0
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/README.md +121 -5
- package/package.json +2 -2
- package/simtlix-simfinity-js-1.9.1.tgz +0 -0
- package/src/index.js +76 -38
- package/tests/scalar-naming.test.js +125 -0
- package/tests/validated-scalar.test.js +1 -1
package/README.md
CHANGED
|
@@ -204,6 +204,122 @@ query {
|
|
|
204
204
|
- `NIN` - Not in array
|
|
205
205
|
- `BTW` - Between two values
|
|
206
206
|
|
|
207
|
+
### Collection Field Filtering
|
|
208
|
+
|
|
209
|
+
Simfinity.js now supports filtering collection fields (one-to-many relationships) using the same powerful query format. This allows you to filter related objects directly within your GraphQL queries.
|
|
210
|
+
|
|
211
|
+
#### Basic Collection Filtering
|
|
212
|
+
|
|
213
|
+
Filter collection fields using the same operators and format as main queries:
|
|
214
|
+
|
|
215
|
+
```graphql
|
|
216
|
+
query {
|
|
217
|
+
series {
|
|
218
|
+
seasons(number: { operator: EQ, value: 1 }) {
|
|
219
|
+
number
|
|
220
|
+
id
|
|
221
|
+
year
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
#### Advanced Collection Filtering
|
|
228
|
+
|
|
229
|
+
You can use complex filtering with nested object properties:
|
|
230
|
+
|
|
231
|
+
```graphql
|
|
232
|
+
query {
|
|
233
|
+
series {
|
|
234
|
+
seasons(
|
|
235
|
+
year: { operator: GTE, value: 2020 }
|
|
236
|
+
episodes: {
|
|
237
|
+
terms: [
|
|
238
|
+
{
|
|
239
|
+
path: "name",
|
|
240
|
+
operator: LIKE,
|
|
241
|
+
value: "Pilot"
|
|
242
|
+
}
|
|
243
|
+
]
|
|
244
|
+
}
|
|
245
|
+
) {
|
|
246
|
+
number
|
|
247
|
+
year
|
|
248
|
+
episodes {
|
|
249
|
+
name
|
|
250
|
+
date
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
#### Collection Filtering with Multiple Conditions
|
|
258
|
+
|
|
259
|
+
Combine multiple filter conditions for collection fields:
|
|
260
|
+
|
|
261
|
+
```graphql
|
|
262
|
+
query {
|
|
263
|
+
series {
|
|
264
|
+
seasons(
|
|
265
|
+
number: { operator: GT, value: 1 }
|
|
266
|
+
year: { operator: BTW, value: [2015, 2023] }
|
|
267
|
+
) {
|
|
268
|
+
number
|
|
269
|
+
year
|
|
270
|
+
state
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
#### Nested Collection Filtering
|
|
277
|
+
|
|
278
|
+
Filter deeply nested collections using dot notation:
|
|
279
|
+
|
|
280
|
+
```graphql
|
|
281
|
+
query {
|
|
282
|
+
series {
|
|
283
|
+
seasons(
|
|
284
|
+
episodes: {
|
|
285
|
+
terms: [
|
|
286
|
+
{
|
|
287
|
+
path: "name",
|
|
288
|
+
operator: LIKE,
|
|
289
|
+
value: "Final"
|
|
290
|
+
}
|
|
291
|
+
]
|
|
292
|
+
}
|
|
293
|
+
) {
|
|
294
|
+
number
|
|
295
|
+
episodes {
|
|
296
|
+
name
|
|
297
|
+
date
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### Collection Filtering with Array Operations
|
|
305
|
+
|
|
306
|
+
Use array operations for collection fields:
|
|
307
|
+
|
|
308
|
+
```graphql
|
|
309
|
+
query {
|
|
310
|
+
series {
|
|
311
|
+
seasons(
|
|
312
|
+
categories: { operator: IN, value: ["Drama", "Crime"] }
|
|
313
|
+
) {
|
|
314
|
+
number
|
|
315
|
+
categories
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
**Note**: Collection field filtering uses the exact same format as main query filtering, ensuring consistency across your GraphQL API. All available operators (`EQ`, `NE`, `GT`, `LT`, `GTE`, `LTE`, `LIKE`, `IN`, `NIN`, `BTW`) work with collection fields.
|
|
322
|
+
|
|
207
323
|
## 🔧 Middlewares
|
|
208
324
|
|
|
209
325
|
Middlewares provide a powerful way to intercept and process all GraphQL operations before they execute. Use them for cross-cutting concerns like authentication, logging, validation, and performance monitoring.
|
|
@@ -1072,13 +1188,13 @@ const OrderType = new GraphQLObjectType({
|
|
|
1072
1188
|
|
|
1073
1189
|
### Custom Validated Scalar Types
|
|
1074
1190
|
|
|
1075
|
-
Create custom scalar types with built-in validation
|
|
1191
|
+
Create custom scalar types with built-in validation. The generated type names follow the pattern `{name}_{baseScalarTypeName}`:
|
|
1076
1192
|
|
|
1077
1193
|
```javascript
|
|
1078
1194
|
const { GraphQLString, GraphQLInt } = require('graphql');
|
|
1079
1195
|
const { createValidatedScalar } = require('@simtlix/simfinity-js');
|
|
1080
1196
|
|
|
1081
|
-
// Email scalar with validation
|
|
1197
|
+
// Email scalar with validation (generates type name: Email_String)
|
|
1082
1198
|
const EmailScalar = createValidatedScalar(
|
|
1083
1199
|
'Email',
|
|
1084
1200
|
'A valid email address',
|
|
@@ -1091,7 +1207,7 @@ const EmailScalar = createValidatedScalar(
|
|
|
1091
1207
|
}
|
|
1092
1208
|
);
|
|
1093
1209
|
|
|
1094
|
-
// Positive integer scalar
|
|
1210
|
+
// Positive integer scalar (generates type name: PositiveInt_Int)
|
|
1095
1211
|
const PositiveIntScalar = createValidatedScalar(
|
|
1096
1212
|
'PositiveInt',
|
|
1097
1213
|
'A positive integer',
|
|
@@ -1108,8 +1224,8 @@ const UserType = new GraphQLObjectType({
|
|
|
1108
1224
|
name: 'User',
|
|
1109
1225
|
fields: () => ({
|
|
1110
1226
|
id: { type: GraphQLID },
|
|
1111
|
-
email: { type: EmailScalar },
|
|
1112
|
-
age: { type: PositiveIntScalar },
|
|
1227
|
+
email: { type: EmailScalar }, // Type name: Email_String
|
|
1228
|
+
age: { type: PositiveIntScalar }, // Type name: PositiveInt_Int
|
|
1113
1229
|
}),
|
|
1114
1230
|
});
|
|
1115
1231
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simtlix/simfinity-js",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"license": "Apache-2.0",
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|
|
21
|
-
"url": "https://github.com/simtlix/simfinity.git"
|
|
21
|
+
"url": "git+https://github.com/simtlix/simfinity.git"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"graphql": "^16.11.0",
|
|
Binary file
|
package/src/index.js
CHANGED
|
@@ -202,7 +202,7 @@ function createValidatedScalar(name, description, baseScalarType, validate) {
|
|
|
202
202
|
const baseKind = kindMap[baseScalarType.name] || Kind.STRING;
|
|
203
203
|
|
|
204
204
|
const scalar = new GraphQLScalarType({
|
|
205
|
-
name
|
|
205
|
+
name: `${name}_${baseScalarType.name}`,
|
|
206
206
|
description,
|
|
207
207
|
serialize(value) {
|
|
208
208
|
validate(value);
|
|
@@ -214,7 +214,7 @@ function createValidatedScalar(name, description, baseScalarType, validate) {
|
|
|
214
214
|
},
|
|
215
215
|
parseLiteral(ast, variables) {
|
|
216
216
|
if (ast.kind !== baseKind) {
|
|
217
|
-
throw new Error(`${name} must be a ${baseScalarType.name}`);
|
|
217
|
+
throw new Error(`${name}_${baseScalarType.name} must be a ${baseScalarType.name}`);
|
|
218
218
|
}
|
|
219
219
|
const value = baseScalarType.parseLiteral(ast, variables);
|
|
220
220
|
validate(value);
|
|
@@ -1516,37 +1516,7 @@ const buildRootQuery = (name, includedTypes) => {
|
|
|
1516
1516
|
|
|
1517
1517
|
const argTypes = type.gqltype.getFields();
|
|
1518
1518
|
|
|
1519
|
-
const argsObject =
|
|
1520
|
-
|
|
1521
|
-
for (const [fieldEntryName, fieldEntry] of Object.entries(argTypes)) {
|
|
1522
|
-
argsObject[fieldEntryName] = {};
|
|
1523
|
-
|
|
1524
|
-
if (fieldEntry.type instanceof GraphQLScalarType
|
|
1525
|
-
|| isNonNullOfType(fieldEntry.type, GraphQLScalarType)
|
|
1526
|
-
|| fieldEntry.type instanceof GraphQLEnumType
|
|
1527
|
-
|| isNonNullOfType(fieldEntry.type, GraphQLEnumType)) {
|
|
1528
|
-
argsObject[fieldEntryName].type = QLFilter;
|
|
1529
|
-
} else if (fieldEntry.type instanceof GraphQLObjectType
|
|
1530
|
-
|| isNonNullOfType(fieldEntry.type, GraphQLObjectType)) {
|
|
1531
|
-
argsObject[fieldEntryName].type = QLTypeFilterExpression;
|
|
1532
|
-
} else if (fieldEntry.type instanceof GraphQLList) {
|
|
1533
|
-
const listOfType = fieldEntry.type.ofType;
|
|
1534
|
-
if (listOfType instanceof GraphQLScalarType
|
|
1535
|
-
|| isNonNullOfType(listOfType, GraphQLScalarType)
|
|
1536
|
-
|| listOfType instanceof GraphQLEnumType
|
|
1537
|
-
|| isNonNullOfType(listOfType, GraphQLEnumType)) {
|
|
1538
|
-
argsObject[fieldEntryName].type = QLFilter;
|
|
1539
|
-
} else {
|
|
1540
|
-
argsObject[fieldEntryName].type = QLTypeFilterExpression;
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
|
|
1545
|
-
argsObject.pagination = {};
|
|
1546
|
-
argsObject.pagination.type = QLPagination;
|
|
1547
|
-
|
|
1548
|
-
argsObject.sort = {};
|
|
1549
|
-
argsObject.sort.type = QLSortExpression;
|
|
1519
|
+
const argsObject = createArgsForQuery(argTypes);
|
|
1550
1520
|
|
|
1551
1521
|
rootQueryArgs.fields[type.listEntitiesEndpointName] = {
|
|
1552
1522
|
type: new GraphQLList(type.gqltype),
|
|
@@ -1656,18 +1626,39 @@ const autoGenerateResolvers = (gqltype) => {
|
|
|
1656
1626
|
if (!relation.embedded) {
|
|
1657
1627
|
if (fieldEntry.type instanceof GraphQLList) {
|
|
1658
1628
|
// Collection field - generate resolve for one-to-many relationship
|
|
1629
|
+
//This is a one-to-many resolver that will return a list of related objects. Also this one allows to filter the related objects as is in the find endpoint.
|
|
1659
1630
|
const relatedType = fieldEntry.type.ofType;
|
|
1660
1631
|
const connectionField = relation.connectionField || fieldName;
|
|
1632
|
+
const relatedTypeInfo = typesDict.types[relatedType.name];
|
|
1633
|
+
const argsObject = createArgsForQuery(relatedTypeInfo.gqltype.getFields());
|
|
1634
|
+
|
|
1635
|
+
delete argsObject[connectionField];
|
|
1636
|
+
const argsArray = Object.entries(argsObject);
|
|
1637
|
+
|
|
1661
1638
|
|
|
1662
|
-
|
|
1639
|
+
const graphqlArgs = formatArgs(argsArray);
|
|
1640
|
+
|
|
1641
|
+
fieldEntry.args = graphqlArgs;
|
|
1642
|
+
|
|
1643
|
+
fieldEntry.resolve = async (parent, args) => {
|
|
1663
1644
|
// Lazy lookup of the related model
|
|
1664
|
-
|
|
1645
|
+
|
|
1665
1646
|
if (!relatedTypeInfo || !relatedTypeInfo.model) {
|
|
1666
1647
|
throw new Error(`Related type ${relatedType.name} not found or not connected. Make sure it's connected with simfinity.connect() or simfinity.addNoEndpointType().`);
|
|
1667
1648
|
}
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1649
|
+
|
|
1650
|
+
args[connectionField] = {
|
|
1651
|
+
terms: [{
|
|
1652
|
+
path: 'id',
|
|
1653
|
+
operator: 'EQ',
|
|
1654
|
+
value: parent.id || parent._id,
|
|
1655
|
+
}],
|
|
1656
|
+
};
|
|
1657
|
+
|
|
1658
|
+
|
|
1659
|
+
const aggregateClauses = await buildQuery(args, relatedTypeInfo.gqltype);
|
|
1660
|
+
|
|
1661
|
+
return await relatedTypeInfo.model.aggregate(aggregateClauses);
|
|
1671
1662
|
};
|
|
1672
1663
|
} else if (fieldEntry.type instanceof GraphQLObjectType
|
|
1673
1664
|
|| (fieldEntry.type instanceof GraphQLNonNull && fieldEntry.type.ofType instanceof GraphQLObjectType)) {
|
|
@@ -1741,3 +1732,50 @@ export const addNoEndpointType = (gqltype) => {
|
|
|
1741
1732
|
};
|
|
1742
1733
|
|
|
1743
1734
|
export { createValidatedScalar };
|
|
1735
|
+
|
|
1736
|
+
const createArgsForQuery = (argTypes) => {
|
|
1737
|
+
const argsObject = {};
|
|
1738
|
+
|
|
1739
|
+
for (const [fieldEntryName, fieldEntry] of Object.entries(argTypes)) {
|
|
1740
|
+
argsObject[fieldEntryName] = {};
|
|
1741
|
+
|
|
1742
|
+
if (fieldEntry.type instanceof GraphQLScalarType
|
|
1743
|
+
|| isNonNullOfType(fieldEntry.type, GraphQLScalarType)
|
|
1744
|
+
|| fieldEntry.type instanceof GraphQLEnumType
|
|
1745
|
+
|| isNonNullOfType(fieldEntry.type, GraphQLEnumType)) {
|
|
1746
|
+
argsObject[fieldEntryName].type = QLFilter;
|
|
1747
|
+
} else if (fieldEntry.type instanceof GraphQLObjectType
|
|
1748
|
+
|| isNonNullOfType(fieldEntry.type, GraphQLObjectType)) {
|
|
1749
|
+
argsObject[fieldEntryName].type = QLTypeFilterExpression;
|
|
1750
|
+
} else if (fieldEntry.type instanceof GraphQLList) {
|
|
1751
|
+
const listOfType = fieldEntry.type.ofType;
|
|
1752
|
+
if (listOfType instanceof GraphQLScalarType
|
|
1753
|
+
|| isNonNullOfType(listOfType, GraphQLScalarType)
|
|
1754
|
+
|| listOfType instanceof GraphQLEnumType
|
|
1755
|
+
|| isNonNullOfType(listOfType, GraphQLEnumType)) {
|
|
1756
|
+
argsObject[fieldEntryName].type = QLFilter;
|
|
1757
|
+
} else {
|
|
1758
|
+
argsObject[fieldEntryName].type = QLTypeFilterExpression;
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
argsObject.pagination = {};
|
|
1764
|
+
argsObject.pagination.type = QLPagination;
|
|
1765
|
+
|
|
1766
|
+
argsObject.sort = {};
|
|
1767
|
+
argsObject.sort.type = QLSortExpression;
|
|
1768
|
+
return argsObject;
|
|
1769
|
+
};
|
|
1770
|
+
|
|
1771
|
+
function formatArgs(argsArray) {
|
|
1772
|
+
const graphqlArgs = [];
|
|
1773
|
+
for (const [key, value] of argsArray) {
|
|
1774
|
+
const item = {
|
|
1775
|
+
name: key,
|
|
1776
|
+
type: value.type,
|
|
1777
|
+
};
|
|
1778
|
+
graphqlArgs.push(item);
|
|
1779
|
+
}
|
|
1780
|
+
return graphqlArgs;
|
|
1781
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describe, test, expect,
|
|
3
|
+
} from 'vitest';
|
|
4
|
+
import { GraphQLString, GraphQLInt, GraphQLFloat, GraphQLBoolean, GraphQLID } from 'graphql';
|
|
5
|
+
import { createValidatedScalar } from '../src/index.js';
|
|
6
|
+
|
|
7
|
+
describe('Validated Scalar Naming Convention', () => {
|
|
8
|
+
test('should generate correct type names with base scalar type suffix', () => {
|
|
9
|
+
const EmailScalar = createValidatedScalar(
|
|
10
|
+
'Email',
|
|
11
|
+
'A valid email address',
|
|
12
|
+
GraphQLString,
|
|
13
|
+
(value) => {
|
|
14
|
+
if (!value.includes('@')) {
|
|
15
|
+
throw new Error('Invalid email format');
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const EpisodeNumberScalar = createValidatedScalar(
|
|
21
|
+
'EpisodeNumber',
|
|
22
|
+
'A valid episode number',
|
|
23
|
+
GraphQLInt,
|
|
24
|
+
(value) => {
|
|
25
|
+
if (value <= 0) {
|
|
26
|
+
throw new Error('Episode number must be positive');
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const RatingScalar = createValidatedScalar(
|
|
32
|
+
'Rating',
|
|
33
|
+
'A valid rating between 0 and 10',
|
|
34
|
+
GraphQLFloat,
|
|
35
|
+
(value) => {
|
|
36
|
+
if (value < 0 || value > 10) {
|
|
37
|
+
throw new Error('Rating must be between 0 and 10');
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const IsActiveScalar = createValidatedScalar(
|
|
43
|
+
'IsActive',
|
|
44
|
+
'A boolean indicating if something is active',
|
|
45
|
+
GraphQLBoolean,
|
|
46
|
+
(value) => {
|
|
47
|
+
// Boolean validation is usually not needed, but this is for testing
|
|
48
|
+
if (typeof value !== 'boolean') {
|
|
49
|
+
throw new Error('Must be a boolean value');
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const CustomIdScalar = createValidatedScalar(
|
|
55
|
+
'CustomId',
|
|
56
|
+
'A custom ID with specific format',
|
|
57
|
+
GraphQLID,
|
|
58
|
+
(value) => {
|
|
59
|
+
if (!value.startsWith('CUST_')) {
|
|
60
|
+
throw new Error('Custom ID must start with CUST_');
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Test the naming convention
|
|
66
|
+
expect(EmailScalar.name).toBe('Email_String');
|
|
67
|
+
expect(EpisodeNumberScalar.name).toBe('EpisodeNumber_Int');
|
|
68
|
+
expect(RatingScalar.name).toBe('Rating_Float');
|
|
69
|
+
expect(IsActiveScalar.name).toBe('IsActive_Boolean');
|
|
70
|
+
expect(CustomIdScalar.name).toBe('CustomId_ID');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('should maintain baseScalarType property', () => {
|
|
74
|
+
const EmailScalar = createValidatedScalar(
|
|
75
|
+
'Email',
|
|
76
|
+
'A valid email address',
|
|
77
|
+
GraphQLString,
|
|
78
|
+
(value) => {
|
|
79
|
+
if (!value.includes('@')) {
|
|
80
|
+
throw new Error('Invalid email format');
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(EmailScalar.baseScalarType).toBe(GraphQLString);
|
|
86
|
+
expect(EmailScalar.name).toBe('Email_String');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('should work with validation functions', () => {
|
|
90
|
+
const EpisodeNumberScalar = createValidatedScalar(
|
|
91
|
+
'EpisodeNumber',
|
|
92
|
+
'A valid episode number',
|
|
93
|
+
GraphQLInt,
|
|
94
|
+
(value) => {
|
|
95
|
+
if (value <= 0) {
|
|
96
|
+
throw new Error('Episode number must be positive');
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// Test valid value
|
|
102
|
+
expect(() => EpisodeNumberScalar.serialize(5)).not.toThrow();
|
|
103
|
+
expect(EpisodeNumberScalar.serialize(5)).toBe(5);
|
|
104
|
+
|
|
105
|
+
// Test invalid value
|
|
106
|
+
expect(() => EpisodeNumberScalar.serialize(0)).toThrow('Episode number must be positive');
|
|
107
|
+
expect(() => EpisodeNumberScalar.serialize(-1)).toThrow('Episode number must be positive');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('should generate error messages with correct type names', () => {
|
|
111
|
+
const EpisodeNumberScalar = createValidatedScalar(
|
|
112
|
+
'EpisodeNumber',
|
|
113
|
+
'A valid episode number',
|
|
114
|
+
GraphQLInt,
|
|
115
|
+
(value) => {
|
|
116
|
+
if (value <= 0) {
|
|
117
|
+
throw new Error('Episode number must be positive');
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// The error message should include the full type name
|
|
123
|
+
expect(() => EpisodeNumberScalar.serialize(0)).toThrow('Episode number must be positive');
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -70,7 +70,7 @@ describe('Custom Validated Scalar Types', () => {
|
|
|
70
70
|
describe('createValidatedScalar function', () => {
|
|
71
71
|
test('should create a valid scalar type with baseScalarType property', () => {
|
|
72
72
|
expect(EmailScalar).toBeDefined();
|
|
73
|
-
expect(EmailScalar.name).toBe('
|
|
73
|
+
expect(EmailScalar.name).toBe('Email_String');
|
|
74
74
|
expect(EmailScalar.baseScalarType).toBe(GraphQLString);
|
|
75
75
|
expect(EmailScalar.serialize).toBeDefined();
|
|
76
76
|
expect(EmailScalar.parseValue).toBeDefined();
|