-
Notifications
You must be signed in to change notification settings - Fork 189
/
utils.ts
128 lines (113 loc) · 4.03 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import Ajv, { Options as AjvOptions } from "ajv";
import addFormats from "ajv-formats";
import { readFileSync, writeFileSync } from "fs";
import { resolve } from "path";
import stringify from "safe-stable-stringify";
import ts from "typescript";
import { createFormatter } from "../factory/formatter";
import { createParser } from "../factory/parser";
import { createProgram } from "../factory/program";
import { Config } from "../src/Config";
import { UnknownTypeError } from "../src/Error/UnknownTypeError";
import { SchemaGenerator } from "../src/SchemaGenerator";
import { BaseType } from "../src/Type/BaseType";
const validator = new Ajv({ discriminator: true });
addFormats(validator);
const basePath = "test/valid-data";
export function createGenerator(config: Config): SchemaGenerator {
const program: ts.Program = createProgram(config);
return new SchemaGenerator(program, createParser(program, config), createFormatter(config), config);
}
export function assertValidSchema(
relativePath: string,
type?: string,
jsDoc: Config["jsDoc"] = "none",
extraTags?: Config["extraTags"],
schemaId?: Config["schemaId"],
options?: {
/**
* Array of sample data
* that should
* successfully validate.
*/
validSamples?: any[];
/**
* Array of sample data
* that should
* fail to validate.
*/
invalidSamples?: any[];
/**
* Options to pass to Ajv
* when creating the Ajv
* instance.
*
* @default {strict:false}
*/
ajvOptions?: AjvOptions;
},
discriminatorType?: Config["discriminatorType"]
) {
return (): void => {
const config: Config = {
path: `${basePath}/${relativePath}/*.ts`,
type,
jsDoc,
extraTags,
discriminatorType,
skipTypeCheck: !!process.env.FAST_TEST,
};
if (schemaId) {
config.schemaId = schemaId;
}
const generator = createGenerator(config);
const schema = generator.createSchema(type);
const schemaFile = resolve(`${basePath}/${relativePath}/schema.json`);
if (process.env.UPDATE_SCHEMA) {
writeFileSync(schemaFile, stringify(schema, null, 2) + "\n", "utf8");
}
const expected: any = JSON.parse(readFileSync(schemaFile, "utf8"));
const actual: any = JSON.parse(JSON.stringify(schema));
expect(typeof actual).toBe("object");
expect(actual).toEqual(expected);
let localValidator = validator;
if (extraTags) {
localValidator = new Ajv(options?.ajvOptions || { strict: false });
addFormats(localValidator);
}
localValidator.validateSchema(actual);
expect(localValidator.errors).toBeNull();
// Compile in all cases to detect MissingRef errors
const validate = localValidator.compile(actual);
// Use the compiled validator if there
// are any samples.
if (options?.invalidSamples) {
for (const sample of options.invalidSamples) {
const isValid = validate(sample);
if (isValid) {
console.log("Unexpectedly Valid:", sample);
}
expect(isValid).toBe(false);
}
}
if (options?.validSamples) {
for (const sample of options.validSamples) {
const isValid = validate(sample);
if (!isValid) {
console.log("Unexpectedly Invalid:", sample);
console.log("AJV Errors:", validate.errors);
}
expect(isValid).toBe(true);
}
}
};
}
export function assertMissingFormatterFor(missingType: BaseType, relativePath: string, type?: string) {
return (): void => {
try {
assertValidSchema(relativePath, type)();
} catch (error) {
expect(error).toEqual(new UnknownTypeError(missingType));
}
};
}