1 | 'use strict'
|
2 |
|
3 | const t = require('tap')
|
4 | const test = t.test
|
5 |
|
6 | const Ajv = require('ajv')
|
7 | const ajv = new Ajv({ coerceTypes: true })
|
8 |
|
9 | const validation = require('../../lib/validation')
|
10 | const { Schemas } = require('../../lib/schemas')
|
11 | const symbols = require('../../lib/validation').symbols
|
12 |
|
13 | test('Symbols', t => {
|
14 | t.plan(5)
|
15 | t.is(typeof symbols.responseSchema, 'symbol')
|
16 | t.is(typeof symbols.bodySchema, 'symbol')
|
17 | t.is(typeof symbols.querystringSchema, 'symbol')
|
18 | t.is(typeof symbols.paramsSchema, 'symbol')
|
19 | t.is(typeof symbols.headersSchema, 'symbol')
|
20 | })
|
21 |
|
22 | test('build schema - missing schema', t => {
|
23 | t.plan(1)
|
24 | const opts = {}
|
25 | validation.build(opts)
|
26 | t.is(typeof opts[symbols.responseSchema], 'undefined')
|
27 | })
|
28 |
|
29 | test('build schema - missing output schema', t => {
|
30 | t.plan(1)
|
31 | const opts = { schema: {} }
|
32 | validation.build(opts, null, new Schemas())
|
33 | t.is(typeof opts[symbols.responseSchema], 'undefined')
|
34 | })
|
35 |
|
36 | test('build schema - output schema', t => {
|
37 | t.plan(2)
|
38 | const opts = {
|
39 | schema: {
|
40 | response: {
|
41 | '2xx': {
|
42 | type: 'object',
|
43 | properties: {
|
44 | hello: { type: 'string' }
|
45 | }
|
46 | },
|
47 | 201: {
|
48 | type: 'object',
|
49 | properties: {
|
50 | hello: { type: 'number' }
|
51 | }
|
52 | }
|
53 | }
|
54 | }
|
55 | }
|
56 | validation.build(opts, schema => ajv.compile(schema), new Schemas())
|
57 | t.is(typeof opts[symbols.responseSchema]['2xx'], 'function')
|
58 | t.is(typeof opts[symbols.responseSchema]['201'], 'function')
|
59 | })
|
60 |
|
61 | test('build schema - payload schema', t => {
|
62 | t.plan(1)
|
63 | const opts = {
|
64 | schema: {
|
65 | body: {
|
66 | type: 'object',
|
67 | properties: {
|
68 | hello: { type: 'string' }
|
69 | }
|
70 | }
|
71 | }
|
72 | }
|
73 | validation.build(opts, schema => ajv.compile(schema), new Schemas())
|
74 | t.is(typeof opts[symbols.bodySchema], 'function')
|
75 | })
|
76 |
|
77 | test('build schema - query schema', t => {
|
78 | t.plan(2)
|
79 | const opts = {
|
80 | schema: {
|
81 | query: {
|
82 | type: 'object',
|
83 | properties: {
|
84 | hello: { type: 'string' }
|
85 | }
|
86 | }
|
87 | }
|
88 | }
|
89 | validation.build(opts, schema => ajv.compile(schema), new Schemas())
|
90 | t.type(opts[symbols.querystringSchema].schema.type, 'string')
|
91 | t.is(typeof opts[symbols.querystringSchema], 'function')
|
92 | })
|
93 |
|
94 | test('build schema - query schema abbreviated', t => {
|
95 | t.plan(2)
|
96 | const opts = {
|
97 | schema: {
|
98 | query: {
|
99 | hello: { type: 'string' }
|
100 | }
|
101 | }
|
102 | }
|
103 | validation.build(opts, schema => ajv.compile(schema), new Schemas())
|
104 | t.type(opts[symbols.querystringSchema].schema.type, 'string')
|
105 | t.is(typeof opts[symbols.querystringSchema], 'function')
|
106 | })
|
107 |
|
108 | test('build schema - querystring schema', t => {
|
109 | t.plan(2)
|
110 | const opts = {
|
111 | schema: {
|
112 | querystring: {
|
113 | type: 'object',
|
114 | properties: {
|
115 | hello: { type: 'string' }
|
116 | }
|
117 | }
|
118 | }
|
119 | }
|
120 | validation.build(opts, schema => ajv.compile(schema), new Schemas())
|
121 | t.type(opts[symbols.querystringSchema].schema.type, 'string')
|
122 | t.is(typeof opts[symbols.querystringSchema], 'function')
|
123 | })
|
124 |
|
125 | test('build schema - querystring schema abbreviated', t => {
|
126 | t.plan(2)
|
127 | const opts = {
|
128 | schema: {
|
129 | querystring: {
|
130 | hello: { type: 'string' }
|
131 | }
|
132 | }
|
133 | }
|
134 | validation.build(opts, schema => ajv.compile(schema), new Schemas())
|
135 | t.type(opts[symbols.querystringSchema].schema.type, 'string')
|
136 | t.is(typeof opts[symbols.querystringSchema], 'function')
|
137 | })
|
138 |
|
139 | test('build schema - must throw if querystring and query schema exist', t => {
|
140 | t.plan(2)
|
141 | try {
|
142 | const opts = {
|
143 | schema: {
|
144 | query: {
|
145 | type: 'object',
|
146 | properties: {
|
147 | hello: { type: 'string' }
|
148 | }
|
149 | },
|
150 | querystring: {
|
151 | type: 'object',
|
152 | properties: {
|
153 | hello: { type: 'string' }
|
154 | }
|
155 | }
|
156 | }
|
157 | }
|
158 | validation.build(opts, schema => ajv.compile(schema), new Schemas())
|
159 | } catch (err) {
|
160 | t.is(err.code, 'FST_ERR_SCH_DUPLICATE')
|
161 | t.is(err.message, 'FST_ERR_SCH_DUPLICATE: Schema with \'querystring\' already present!')
|
162 | }
|
163 | })
|
164 |
|
165 | test('build schema - params schema', t => {
|
166 | t.plan(1)
|
167 | const opts = {
|
168 | schema: {
|
169 | params: {
|
170 | type: 'object',
|
171 | properties: {
|
172 | hello: { type: 'string' }
|
173 | }
|
174 | }
|
175 | }
|
176 | }
|
177 | validation.build(opts, schema => ajv.compile(schema), new Schemas())
|
178 | t.is(typeof opts[symbols.paramsSchema], 'function')
|
179 | })
|
180 |
|
181 | test('build schema - headers schema', t => {
|
182 | t.plan(1)
|
183 | const opts = {
|
184 | schema: {
|
185 | headers: {
|
186 | type: 'object',
|
187 | properties: {
|
188 | 'content-type': { type: 'string' }
|
189 | }
|
190 | }
|
191 | }
|
192 | }
|
193 | validation.build(opts, schema => ajv.compile(schema), new Schemas())
|
194 | t.is(typeof opts[symbols.headersSchema], 'function')
|
195 | })
|
196 |
|
197 | test('build schema - headers are lowercase', t => {
|
198 | t.plan(1)
|
199 | const opts = {
|
200 | schema: {
|
201 | headers: {
|
202 | type: 'object',
|
203 | properties: {
|
204 | 'Content-Type': { type: 'string' }
|
205 | }
|
206 | }
|
207 | }
|
208 | }
|
209 | validation.build(opts, schema => {
|
210 | t.ok(schema.properties['content-type'], 'lowercase content-type exists')
|
211 | return () => {}
|
212 | }, new Schemas())
|
213 | })
|
214 |
|
215 | test('build schema - headers are not lowercased in case of custom object', t => {
|
216 | t.plan(1)
|
217 |
|
218 | class Headers {}
|
219 | const opts = {
|
220 | schema: {
|
221 | headers: new Headers()
|
222 | }
|
223 | }
|
224 | validation.build(opts, schema => {
|
225 | t.type(schema, Headers)
|
226 | return () => {}
|
227 | }, new Schemas())
|
228 | })
|
229 |
|
230 | test('build schema - uppercased headers are not included', t => {
|
231 | t.plan(1)
|
232 | const opts = {
|
233 | schema: {
|
234 | headers: {
|
235 | type: 'object',
|
236 | properties: {
|
237 | 'Content-Type': { type: 'string' }
|
238 | }
|
239 | }
|
240 | }
|
241 | }
|
242 | validation.build(opts, schema => {
|
243 | t.notOk('Content-Type' in schema.properties, 'uppercase does not exist')
|
244 | return () => {}
|
245 | }, new Schemas())
|
246 | })
|