directus

Форк
0
/
apply-snapshot.test.ts 
451 строка · 12.2 Кб
1
import type { Knex } from 'knex';
2
import knex from 'knex';
3
import { createTracker, MockClient, Tracker } from 'knex-mock-client';
4
import type { MockedFunction } from 'vitest';
5
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
6
import { snapshotApplyTestSchema } from '../__utils__/schemas.js';
7
import {
8
	snapshotBeforeCreateCollection,
9
	snapshotBeforeDeleteCollection,
10
	snapshotCreateCollection,
11
	snapshotCreateCollectionNotNested,
12
} from '../__utils__/snapshots.js';
13
import { CollectionsService, FieldsService } from '../services/index.js';
14
import type { Snapshot, SnapshotField } from '../types/index.js';
15
import { applySnapshot } from './apply-snapshot.js';
16
import * as getSchema from './get-schema.js';
17

18
class Client_PG extends MockClient {}
19

20
describe('applySnapshot', () => {
21
	let db: MockedFunction<Knex>;
22
	let tracker: Tracker;
23

24
	const mutationOptions = {
25
		autoPurgeSystemCache: false,
26
		bypassEmitAction: expect.any(Function),
27
		bypassLimits: true,
28
	};
29

30
	beforeEach(() => {
31
		db = vi.mocked(knex.default({ client: Client_PG }));
32
		tracker = createTracker(db);
33
	});
34

35
	afterEach(() => {
36
		tracker.reset();
37
		vi.clearAllMocks();
38
	});
39

40
	describe('Creating new collection(s)', () => {
41
		it('Creates new top-level collection(s)', async () => {
42
			const expected = {
43
				collection: 'test_table_2',
44
				meta: {
45
					accountability: 'all',
46
					collection: 'test_table_2',
47
					group: null,
48
					hidden: true,
49
					icon: 'import_export',
50
					item_duplication_fields: null,
51
					note: null,
52
					singleton: false,
53
					translations: {},
54
					versioning: false,
55
				},
56
				schema: { name: 'test_table_2' },
57
				fields: [
58
					{
59
						collection: 'test_table_2',
60
						field: 'id',
61
						meta: {
62
							collection: 'test_table_2',
63
							conditions: null,
64
							display: null,
65
							display_options: null,
66
							field: 'id',
67
							group: null,
68
							hidden: true,
69
							interface: null,
70
							note: null,
71
							options: null,
72
							readonly: false,
73
							required: false,
74
							sort: null,
75
							special: null,
76
							translations: {},
77
							validation: null,
78
							validation_message: null,
79
							width: 'full',
80
						},
81
						schema: {
82
							data_type: 'uuid',
83
							default_value: null,
84
							foreign_key_column: null,
85
							foreign_key_table: null,
86
							generation_expression: null,
87
							has_auto_increment: false,
88
							is_generated: false,
89
							is_nullable: false,
90
							is_primary_key: true,
91
							is_unique: true,
92
							max_length: null,
93
							name: 'id',
94
							numeric_precision: null,
95
							numeric_scale: null,
96
							table: 'test_table_2',
97
						},
98
						type: 'uuid',
99
					},
100
				],
101
			};
102

103
			// Stop call to db later on in apply-snapshot
104
			vi.spyOn(getSchema, 'getSchema').mockReturnValue(Promise.resolve(snapshotApplyTestSchema));
105
			// We are not actually testing that createOne works, just that it is called correctly
106
			const createOneCollectionSpy = vi.spyOn(CollectionsService.prototype, 'createOne').mockResolvedValue('test');
107
			const createFieldSpy = vi.spyOn(FieldsService.prototype, 'createField').mockResolvedValue();
108

109
			await applySnapshot(snapshotCreateCollectionNotNested, {
110
				database: db,
111
				current: snapshotBeforeCreateCollection,
112
				schema: snapshotApplyTestSchema,
113
			});
114

115
			expect(createOneCollectionSpy).toHaveBeenCalledTimes(1);
116
			expect(createOneCollectionSpy).toHaveBeenCalledWith(expected, mutationOptions);
117

118
			// There should be no fields left to create
119
			// they will get filtered in createCollections
120
			expect(createFieldSpy).toHaveBeenCalledTimes(0);
121
		});
122

123
		it('Creates the highest-level nested collection(s) with existing parents and any children', async () => {
124
			const expected = {
125
				collection: 'test_table_2',
126
				meta: {
127
					accountability: 'all',
128
					collection: 'test_table_2',
129
					group: 'test_table',
130
					hidden: true,
131
					icon: 'import_export',
132
					item_duplication_fields: null,
133
					note: null,
134
					singleton: false,
135
					translations: {},
136
					versioning: false,
137
				},
138
				schema: { name: 'test_table_2' },
139
				fields: [
140
					{
141
						collection: 'test_table_2',
142
						field: 'id',
143
						meta: {
144
							collection: 'test_table_2',
145
							conditions: null,
146
							display: null,
147
							display_options: null,
148
							field: 'id',
149
							group: null,
150
							hidden: true,
151
							interface: null,
152
							note: null,
153
							options: null,
154
							readonly: false,
155
							required: false,
156
							sort: null,
157
							special: null,
158
							translations: {},
159
							validation: null,
160
							validation_message: null,
161
							width: 'full',
162
						},
163
						schema: {
164
							data_type: 'uuid',
165
							default_value: null,
166
							foreign_key_column: null,
167
							foreign_key_table: null,
168
							generation_expression: null,
169
							has_auto_increment: false,
170
							is_generated: false,
171
							is_nullable: false,
172
							is_primary_key: true,
173
							is_unique: true,
174
							max_length: null,
175
							name: 'id',
176
							numeric_precision: null,
177
							numeric_scale: null,
178
							table: 'test_table_2',
179
						},
180
						type: 'uuid',
181
					},
182
				],
183
			};
184

185
			const expected2 = {
186
				collection: 'test_table_3',
187
				fields: [
188
					{
189
						collection: 'test_table_3',
190
						field: 'id',
191
						meta: {
192
							collection: 'test_table_3',
193
							conditions: null,
194
							display: null,
195
							display_options: null,
196
							field: 'id',
197
							group: null,
198
							hidden: true,
199
							interface: null,
200
							note: null,
201
							options: null,
202
							readonly: false,
203
							required: false,
204
							sort: null,
205
							special: null,
206
							translations: {},
207
							validation: null,
208
							validation_message: null,
209
							width: 'full',
210
						},
211
						schema: {
212
							data_type: 'uuid',
213
							default_value: null,
214
							foreign_key_column: null,
215
							foreign_key_table: null,
216
							generation_expression: null,
217
							has_auto_increment: false,
218
							is_generated: false,
219
							is_nullable: false,
220
							is_primary_key: true,
221
							is_unique: true,
222
							max_length: null,
223
							name: 'id',
224
							numeric_precision: null,
225
							numeric_scale: null,
226
							table: 'test_table_3',
227
						},
228
						type: 'uuid',
229
					},
230
				],
231
				meta: {
232
					accountability: 'all',
233
					collection: 'test_table_3',
234
					group: 'test_table_2',
235
					hidden: true,
236
					icon: 'import_export',
237
					item_duplication_fields: null,
238
					note: null,
239
					singleton: false,
240
					translations: {},
241
					versioning: false,
242
				},
243
				schema: { name: 'test_table_3' },
244
			};
245

246
			// Stop call to db later on in apply-snapshot
247
			vi.spyOn(getSchema, 'getSchema').mockReturnValue(Promise.resolve(snapshotApplyTestSchema));
248
			// We are not actually testing that createOne works, just that it is called correctly
249
			const createOneCollectionSpy = vi.spyOn(CollectionsService.prototype, 'createOne').mockResolvedValue('test');
250
			const createFieldSpy = vi.spyOn(FieldsService.prototype, 'createField').mockResolvedValue();
251

252
			await applySnapshot(snapshotCreateCollection, {
253
				database: db,
254
				current: snapshotBeforeCreateCollection,
255
				schema: snapshotApplyTestSchema,
256
			});
257

258
			expect(createOneCollectionSpy).toHaveBeenCalledTimes(2);
259
			expect(createOneCollectionSpy).toHaveBeenCalledWith(expected, mutationOptions);
260
			expect(createOneCollectionSpy).toHaveBeenCalledWith(expected2, mutationOptions);
261

262
			// There should be no fields left to create
263
			// they will get filtered in createCollections
264
			expect(createFieldSpy).toHaveBeenCalledTimes(0);
265
		});
266
	});
267

268
	describe('Creating new collection with UUID primary key field', () => {
269
		const fieldSchemaMaxLength = 36;
270

271
		it.each(['char', 'varchar'])(
272
			'casts non-postgres schema snapshots of UUID fields as %s(36) to UUID type',
273
			async (fieldSchemaDataType) => {
274
				const snapshotToApply: Snapshot = {
275
					version: 1,
276
					directus: '0.0.0',
277
					collections: [
278
						{
279
							collection: 'test_uuid_table',
280
							meta: {
281
								accountability: 'all',
282
								collection: 'test_uuid_table',
283
								group: null,
284
								hidden: true,
285
								icon: 'box',
286
								item_duplication_fields: null,
287
								note: null,
288
								singleton: false,
289
								translations: {},
290
							},
291
							schema: { name: 'test_uuid_table' },
292
						},
293
					],
294
					fields: [
295
						{
296
							collection: 'test_uuid_table',
297
							field: 'id',
298
							meta: {
299
								collection: 'test_uuid_table',
300
								conditions: null,
301
								display: null,
302
								display_options: null,
303
								field: 'id',
304
								group: null,
305
								hidden: true,
306
								interface: null,
307
								note: null,
308
								options: null,
309
								readonly: false,
310
								required: false,
311
								sort: null,
312
								special: null,
313
								translations: {},
314
								validation: null,
315
								validation_message: null,
316
								width: 'full',
317
							},
318
							schema: {
319
								comment: null,
320
								data_type: fieldSchemaDataType,
321
								default_value: null,
322
								foreign_key_column: null,
323
								foreign_key_schema: null,
324
								foreign_key_table: null,
325
								generation_expression: null,
326
								has_auto_increment: false,
327
								is_generated: false,
328
								is_nullable: false,
329
								is_primary_key: true,
330
								is_unique: true,
331
								max_length: fieldSchemaMaxLength,
332
								name: 'id',
333
								numeric_precision: null,
334
								numeric_scale: null,
335
								table: 'test_uuid_table',
336
							},
337
							type: 'uuid',
338
						} as SnapshotField,
339
					],
340
					relations: [],
341
				};
342

343
				const expected = {
344
					collection: 'test_uuid_table',
345
					meta: {
346
						accountability: 'all',
347
						collection: 'test_uuid_table',
348
						group: null,
349
						hidden: true,
350
						icon: 'box',
351
						item_duplication_fields: null,
352
						note: null,
353
						singleton: false,
354
						translations: {},
355
					},
356
					schema: { name: 'test_uuid_table' },
357
					fields: [
358
						{
359
							collection: 'test_uuid_table',
360
							field: 'id',
361
							meta: {
362
								collection: 'test_uuid_table',
363
								conditions: null,
364
								display: null,
365
								display_options: null,
366
								field: 'id',
367
								group: null,
368
								hidden: true,
369
								interface: null,
370
								note: null,
371
								options: null,
372
								readonly: false,
373
								required: false,
374
								sort: null,
375
								special: null,
376
								translations: {},
377
								validation: null,
378
								validation_message: null,
379
								width: 'full',
380
							},
381
							schema: {
382
								data_type: 'uuid',
383
								default_value: null,
384
								foreign_key_column: null,
385
								foreign_key_table: null,
386
								generation_expression: null,
387
								has_auto_increment: false,
388
								is_generated: false,
389
								is_nullable: false,
390
								is_primary_key: true,
391
								is_unique: true,
392
								max_length: null,
393
								name: 'id',
394
								numeric_precision: null,
395
								numeric_scale: null,
396
								table: 'test_uuid_table',
397
							},
398
							type: 'uuid',
399
						},
400
					],
401
				};
402

403
				// Stop call to db later on in apply-snapshot
404
				vi.spyOn(getSchema, 'getSchema').mockReturnValue(Promise.resolve(snapshotApplyTestSchema));
405
				// We are not actually testing that createOne works, just that it is called with the right data type
406
				const createOneCollectionSpy = vi.spyOn(CollectionsService.prototype, 'createOne').mockResolvedValue('test');
407
				vi.spyOn(FieldsService.prototype, 'createField').mockResolvedValue();
408

409
				await applySnapshot(snapshotToApply, {
410
					database: db,
411
					current: {
412
						version: 1,
413
						directus: '0.0.0',
414
						collections: [],
415
						fields: [],
416
						relations: [],
417
					},
418
					schema: snapshotApplyTestSchema,
419
				});
420

421
				expect(createOneCollectionSpy).toHaveBeenCalledOnce();
422
				expect(createOneCollectionSpy).toHaveBeenCalledWith(expected, mutationOptions);
423
			},
424
		);
425
	});
426

427
	describe('Delete collections', () => {
428
		it('Deletes interrelated collections', async () => {
429
			const snapshotToApply: Snapshot = {
430
				version: 1,
431
				directus: '0.0.0',
432
				collections: [],
433
				fields: [],
434
				relations: [],
435
			};
436

437
			// Stop call to db later on in apply-snapshot
438
			vi.spyOn(getSchema, 'getSchema').mockReturnValue(Promise.resolve(snapshotApplyTestSchema));
439
			// We are not actually testing that deleteOne works, just that it is called correctly
440
			const deleteOneCollectionSpy = vi.spyOn(CollectionsService.prototype, 'deleteOne').mockResolvedValue('test');
441

442
			await applySnapshot(snapshotToApply, {
443
				database: db,
444
				current: snapshotBeforeDeleteCollection,
445
				schema: snapshotApplyTestSchema,
446
			});
447

448
			expect(deleteOneCollectionSpy).toHaveBeenCalledTimes(3);
449
		});
450
	});
451
});
452

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.