-
Notifications
You must be signed in to change notification settings - Fork 187
/
utils.ts
126 lines (111 loc) · 3.95 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
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;
}
) {
return (): void => {
const config: Config = {
path: `${basePath}/${relativePath}/*.ts`,
type,
jsDoc,
extraTags,
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));
}
};
}