1
import type { Knex } from 'knex';
2
import knex from 'knex';
3
import { MockClient, Tracker, createTracker } from 'knex-mock-client';
4
import type { MockedFunction } from 'vitest';
5
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
6
import type { Helpers } from '../database/helpers/index.js';
7
import { getHelpers } from '../database/helpers/index.js';
8
import { PayloadService } from './index.js';
10
vi.mock('../../src/database/index', () => ({
11
getDatabaseClient: vi.fn().mockReturnValue('postgres'),
14
describe('Integration Tests', () => {
15
let db: MockedFunction<Knex>;
18
beforeAll(async () => {
19
db = vi.mocked(knex.default({ client: MockClient }));
20
tracker = createTracker(db);
27
describe('Services / PayloadService', () => {
28
describe('transformers', () => {
29
let service: PayloadService;
33
service = new PayloadService('test', {
35
schema: { collections: {}, relations: [] },
38
helpers = getHelpers(db);
41
describe('csv', () => {
42
test('Returns undefined for illegal values', async () => {
43
const result = await service.transformers['cast-csv']!({
47
accountability: { role: null },
52
expect(result).toBe(undefined);
55
test('Returns [] for empty strings', async () => {
56
const result = await service.transformers['cast-csv']!({
60
accountability: { role: null },
65
expect(result).toMatchObject([]);
68
test('Returns array values as is', async () => {
69
const result = await service.transformers['cast-csv']!({
70
value: ['test', 'directus'],
73
accountability: { role: null },
78
expect(result).toEqual(['test', 'directus']);
81
test('Splits the CSV string', async () => {
82
const result = await service.transformers['cast-csv']!({
83
value: 'test,directus',
86
accountability: { role: null },
91
expect(result).toMatchObject(['test', 'directus']);
94
test('Saves array values as joined string', async () => {
95
const result = await service.transformers['cast-csv']!({
96
value: ['test', 'directus'],
99
accountability: { role: null },
104
expect(result).toBe('test,directus');
107
test('Saves string values as is', async () => {
108
const result = await service.transformers['cast-csv']!({
109
value: 'test,directus',
112
accountability: { role: null },
117
expect(result).toBe('test,directus');
122
describe('processDates', () => {
123
let service: PayloadService;
125
const dateFieldId = 'date_field';
126
const dateTimeFieldId = 'datetime_field';
127
const timestampFieldId = 'timestamp_field';
130
service = new PayloadService('test', {
140
accountability: null,
157
field: dateTimeFieldId,
170
[timestampFieldId]: {
171
field: timestampFieldId,
192
describe('processes dates', () => {
193
test('with zero values', () => {
194
const result = service.processDates(
197
[dateFieldId]: '0000-00-00',
198
[dateTimeFieldId]: '0000-00-00 00:00:00',
199
[timestampFieldId]: '0000-00-00 00:00:00.000',
205
expect(result).toMatchObject([
208
[dateTimeFieldId]: null,
209
[timestampFieldId]: null,
214
test('with typical values', () => {
215
const result = service.processDates(
218
[dateFieldId]: '2022-01-10',
219
[dateTimeFieldId]: '2021-09-31 12:34:56',
220
[timestampFieldId]: '1980-12-08 00:11:22.333',
226
expect(result).toMatchObject([
228
[dateFieldId]: '2022-01-10',
229
[dateTimeFieldId]: '2021-10-01T12:34:56',
230
[timestampFieldId]: new Date('1980-12-08 00:11:22.333').toISOString(),
235
test('with date object values', () => {
236
const result = service.processDates(
239
[dateFieldId]: new Date(1666777777000),
240
[dateTimeFieldId]: new Date(1666666666000),
241
[timestampFieldId]: new Date(1666555444333),
247
expect(result).toMatchObject([
249
[dateFieldId]: toLocalISOString(new Date(1666777777000)).slice(0, 10),
250
[dateTimeFieldId]: toLocalISOString(new Date(1666666666000)),
251
[timestampFieldId]: new Date(1666555444333).toISOString(),
258
describe('processValues', () => {
259
let service: PayloadService;
261
const concealedField = 'hidden';
262
const stringField = 'string';
263
const REDACT_STR = '**********';
266
service = new PayloadService('test', {
276
accountability: null,
279
field: concealedField,
287
special: ['hash', 'conceal'],
314
test('processing special fields', async () => {
315
const result = await service.processValues('read', {
316
string: 'not-redacted',
320
expect(result).toMatchObject({ string: 'not-redacted', hidden: REDACT_STR });
323
test('processing aliassed special fields', async () => {
324
const result = await service.processValues(
327
other_string: 'not-redacted',
328
other_hidden: 'secret',
330
{ other_string: 'string', other_hidden: 'hidden' },
333
expect(result).toMatchObject({ other_string: 'not-redacted', other_hidden: REDACT_STR });
339
function toLocalISOString(date: Date) {
340
const year = String(date.getFullYear());
341
const month = String(date.getMonth() + 1).padStart(2, '0');
342
const day = String(date.getDate()).padStart(2, '0');
343
const hours = String(date.getHours()).padStart(2, '0');
344
const minutes = String(date.getMinutes()).padStart(2, '0');
345
const seconds = String(date.getSeconds()).padStart(2, '0');
347
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`;