mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
* Add black box tests * Revert docker compose file * Update workflow * Try use workflow from dev repo * Increase seedDB() timeout * Disable other checks for now * Change DB sequence * Update jest moduleNameMapper * Update workflow's docker-compose.yml path * Slice array first * Remove differentiation of status code * Delete field only after foreign key constraints are removed * Add checks for different types of primary key * Test global query filter for all field types * Increase timeout for m2o seeding * Add case insensitive string operators * Update filter check to run on relational fields * Enable time field checks * Add seeded random and fix relational seeding * Add casting for integer and bigInteger * Minor fixes * Reduce bigInt values * Separate seeding of DB structure from values * Add primaryKey seeding function * Use automatic IDs except for string pk * Try fix ci * Update package-lock.json * Update common.test for concealed user tokens * Use dynamic field type for m2o.test relational fields * Temporary disable missing nicontains for string type * Add support for alias type filtering * Fix relational filter operator checks * Add initial o2m test * Remove integer pk limit * Add empty checks for string and uuid null * Limit generated integer value to 4 bytes * Patch timezone tests for MSSQL * Remove sample query filter test * Fix timezone test for sqlite * Fix MSSQL uuids * Fix MSSQL timestamp inaccuracy * Cast datetime schema to milliseconds for comparison * Fix MySQL / Maria timestamp inaccuracy * Fix MySQL / Maria between operator inconsistency for float type * Fix missing time datatype in Oracle * Skip filter testing on Oracle * Enable o2m filter tests for other collections * Run tests only on SQLite for PRs unless the Full Tests label exists * Try fix actions * Refactor github actions * Update tests flow setup to use getURL() * Start postgres docker * Reinstate package-lock * Fix geometry test * Remove .gitkeep files * Add todo.md * Rename black box to blackbox Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
300 lines
8.9 KiB
TypeScript
300 lines
8.9 KiB
TypeScript
import { getUrl } from '@common/config';
|
|
import vendors from '@common/get-dbs-to-test';
|
|
import request from 'supertest';
|
|
import { cloneDeep } from 'lodash';
|
|
import { validateDateDifference } from '@utils/validate-date-difference';
|
|
import { CreateCollection, CreateField, DeleteCollection } from '@common/functions';
|
|
import * as common from '@common/index';
|
|
|
|
const collectionName = 'schema_timezone_tests';
|
|
|
|
type SchemaTimezoneTypesObject = {
|
|
date: string;
|
|
time?: string;
|
|
datetime: string;
|
|
timestamp: string;
|
|
};
|
|
|
|
type SchemaTimezoneTypesResponse = SchemaTimezoneTypesObject & {
|
|
date_created: string;
|
|
date_updated: string;
|
|
};
|
|
|
|
describe('schema', () => {
|
|
const sampleDates: SchemaTimezoneTypesObject[] = [];
|
|
|
|
for (let i = 0; i < 24; i++) {
|
|
const hour = i < 10 ? '0' + i : String(i);
|
|
sampleDates.push(
|
|
{
|
|
date: `2022-01-05`,
|
|
time: `${hour}:11:11`,
|
|
datetime: `2022-01-05T${hour}:11:11`,
|
|
timestamp: `2022-01-05T${hour}:11:11-01:00`,
|
|
},
|
|
{
|
|
date: `2022-01-10`,
|
|
time: `${hour}:22:22`,
|
|
datetime: `2022-01-10T${hour}:22:22`,
|
|
timestamp: `2022-01-10T${hour}:22:22Z`,
|
|
},
|
|
{
|
|
date: `2022-01-15`,
|
|
time: `${hour}:33:33`,
|
|
datetime: `2022-01-15T${hour}:33:33`,
|
|
timestamp: `2022-01-15T${hour}:33:33+02:00`,
|
|
}
|
|
);
|
|
}
|
|
|
|
describe('timezone', () => {
|
|
describe('update timezone field schema', () => {
|
|
it.each(vendors)(
|
|
'%s',
|
|
async (vendor) => {
|
|
// Delete the table in case it already exists
|
|
await DeleteCollection(vendor, { collection: collectionName });
|
|
|
|
const tableOptions = {
|
|
collection: collectionName,
|
|
schema: {},
|
|
meta: {},
|
|
};
|
|
await CreateCollection(vendor, tableOptions);
|
|
|
|
const fieldOptions = {
|
|
collection: collectionName,
|
|
field: 'date',
|
|
meta: {},
|
|
schema: {},
|
|
type: 'date',
|
|
};
|
|
await CreateField(vendor, fieldOptions);
|
|
|
|
fieldOptions.field = 'time';
|
|
fieldOptions.type = 'time';
|
|
await CreateField(vendor, fieldOptions);
|
|
|
|
fieldOptions.field = 'datetime';
|
|
fieldOptions.type = 'dateTime';
|
|
await CreateField(vendor, fieldOptions);
|
|
|
|
fieldOptions.field = 'timestamp';
|
|
fieldOptions.type = 'timestamp';
|
|
await CreateField(vendor, fieldOptions);
|
|
|
|
fieldOptions.field = 'date_created';
|
|
fieldOptions.type = 'timestamp';
|
|
await CreateField(vendor, fieldOptions);
|
|
|
|
fieldOptions.field = 'date_updated';
|
|
fieldOptions.type = 'timestamp';
|
|
await CreateField(vendor, fieldOptions);
|
|
|
|
await request(getUrl(vendor))
|
|
.patch(`/collections/${collectionName}`)
|
|
.send({
|
|
meta: {},
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.ADMIN.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
await request(getUrl(vendor))
|
|
.patch(`/fields/${collectionName}/date_created`)
|
|
.send({
|
|
meta: {
|
|
special: ['date-created'],
|
|
},
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.ADMIN.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
await request(getUrl(vendor))
|
|
.patch(`/fields/${collectionName}/date_updated`)
|
|
.send({
|
|
meta: {
|
|
special: ['date-updated'],
|
|
},
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.ADMIN.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
switch (vendor) {
|
|
case 'sqlite3':
|
|
await request(getUrl(vendor))
|
|
.patch(`/fields/${collectionName}/timestamp`)
|
|
.send({
|
|
meta: {
|
|
special: ['cast-timestamp'],
|
|
},
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.ADMIN.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
await request(getUrl(vendor))
|
|
.patch(`/fields/${collectionName}/date_created`)
|
|
.send({
|
|
meta: {
|
|
special: ['date-created', 'cast-timestamp'],
|
|
},
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.ADMIN.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
await request(getUrl(vendor))
|
|
.patch(`/fields/${collectionName}/date_updated`)
|
|
.send({
|
|
meta: {
|
|
special: ['date-updated', 'cast-timestamp'],
|
|
},
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.ADMIN.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
break;
|
|
case 'oracle':
|
|
await request(getUrl(vendor))
|
|
.patch(`/fields/${collectionName}/datetime`)
|
|
.send({
|
|
meta: {
|
|
special: ['cast-datetime'],
|
|
},
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.ADMIN.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
},
|
|
10000
|
|
);
|
|
});
|
|
|
|
describe('stores the correct timezone data', () => {
|
|
it.each(vendors)(
|
|
'%s',
|
|
async (vendor) => {
|
|
const dates = cloneDeep(sampleDates);
|
|
|
|
if (vendor === 'oracle') {
|
|
for (const date of dates) {
|
|
delete date.time;
|
|
}
|
|
}
|
|
|
|
const insertionStartTimestamp = new Date();
|
|
|
|
await request(getUrl(vendor))
|
|
.post(`/items/${collectionName}`)
|
|
.send(dates)
|
|
.set('Authorization', `Bearer ${common.USER.ADMIN.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
const insertionEndTimestamp = new Date();
|
|
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/items/${collectionName}?fields=*`)
|
|
.set('Authorization', `Bearer ${common.USER.ADMIN.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
expect(response.body.data.length).toBe(sampleDates.length);
|
|
|
|
for (let index = 0; index < sampleDates.length; index++) {
|
|
const responseObj = response.body.data[index] as SchemaTimezoneTypesResponse;
|
|
|
|
if (vendor === 'oracle') {
|
|
expect(responseObj.date).toBe(sampleDates[index]!.date);
|
|
expect(responseObj.datetime).toBe(sampleDates[index]!.datetime);
|
|
expect(responseObj.timestamp.substring(0, 19)).toBe(
|
|
new Date(sampleDates[index]!.timestamp).toISOString().substring(0, 19)
|
|
);
|
|
const dateCreated = new Date(responseObj.date_created);
|
|
expect(dateCreated.toISOString()).toBe(
|
|
validateDateDifference(
|
|
insertionStartTimestamp,
|
|
dateCreated,
|
|
insertionEndTimestamp.getTime() - insertionStartTimestamp.getTime()
|
|
).toISOString()
|
|
);
|
|
expect(responseObj.date_updated).toBeNull();
|
|
continue;
|
|
}
|
|
|
|
expect(responseObj.date).toBe(sampleDates[index]!.date);
|
|
expect(responseObj.time).toBe(sampleDates[index]!.time);
|
|
expect(responseObj.datetime).toBe(sampleDates[index]!.datetime);
|
|
expect(responseObj.timestamp.substring(0, 19)).toBe(
|
|
new Date(sampleDates[index]!.timestamp).toISOString().substring(0, 19)
|
|
);
|
|
const dateCreated = new Date(responseObj.date_created);
|
|
expect(dateCreated.toISOString()).toBe(
|
|
validateDateDifference(
|
|
insertionStartTimestamp,
|
|
dateCreated,
|
|
insertionEndTimestamp.getTime() - insertionStartTimestamp.getTime() + 1000
|
|
).toISOString()
|
|
);
|
|
expect(responseObj.date_updated).toBeNull();
|
|
}
|
|
},
|
|
10000
|
|
);
|
|
});
|
|
|
|
describe('stores the correct timezone data when updated', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
const payload = {
|
|
date: sampleDates[0]!.date,
|
|
};
|
|
|
|
const existingDataResponse = await request(getUrl(vendor))
|
|
.get(`/items/${collectionName}?fields=*&limit=1`)
|
|
.set('Authorization', `Bearer ${common.USER.ADMIN.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
const updateStartTimestamp = new Date();
|
|
|
|
await request(getUrl(vendor))
|
|
.patch(`/items/${collectionName}/${existingDataResponse.body.data[0].id}`)
|
|
.send(payload)
|
|
.set('Authorization', `Bearer ${common.USER.ADMIN.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
const updateEndTimestamp = new Date();
|
|
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/items/${collectionName}/${existingDataResponse.body.data[0].id}?fields=*`)
|
|
.set('Authorization', `Bearer ${common.USER.ADMIN.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
const responseObj = response.body.data as SchemaTimezoneTypesResponse;
|
|
|
|
expect(responseObj.date).toBe(sampleDates[0]!.date);
|
|
expect(responseObj.date_created).not.toBeNull();
|
|
expect(responseObj.date_updated).not.toBeNull();
|
|
const dateCreated = new Date(responseObj.date_created);
|
|
const dateUpdated = new Date(responseObj.date_updated);
|
|
expect(dateUpdated.toISOString()).not.toBe(dateCreated.toISOString());
|
|
expect(dateUpdated.toISOString()).toBe(
|
|
validateDateDifference(
|
|
updateStartTimestamp,
|
|
dateUpdated,
|
|
updateEndTimestamp.getTime() - updateStartTimestamp.getTime() + 1000
|
|
).toISOString()
|
|
);
|
|
});
|
|
});
|
|
});
|
|
});
|