mirror of
https://github.com/directus/directus.git
synced 2026-02-07 11:55:12 -05: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>
636 lines
17 KiB
TypeScript
636 lines
17 KiB
TypeScript
import { getUrl } from '@common/config';
|
|
import request from 'supertest';
|
|
import vendors from '@common/get-dbs-to-test';
|
|
import * as common from '@common/index';
|
|
import { collectionName, collectionNameM2O, collectionNameO2M } from './common.seed';
|
|
|
|
describe('Common', () => {
|
|
describe('createRole()', () => {
|
|
describe('Creates default admin role', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const roleName = common.ROLE.ADMIN.NAME;
|
|
const options: common.OptionsCreateRole = {
|
|
name: roleName,
|
|
appAccessEnabled: true,
|
|
adminAccessEnabled: true,
|
|
};
|
|
|
|
// Action
|
|
await common.CreateRole(vendor, options);
|
|
|
|
// Assert
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/roles`)
|
|
.query({
|
|
filter: { name: { _eq: roleName } },
|
|
fields: ['id', 'name', 'app_access', 'admin_access'],
|
|
limit: 1,
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
expect(response.body.data).toEqual([
|
|
{
|
|
id: expect.any(String),
|
|
name: roleName,
|
|
app_access: true,
|
|
admin_access: true,
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('Creates default app access role', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const roleName = common.ROLE.APP_ACCESS.NAME;
|
|
const options: common.OptionsCreateRole = {
|
|
name: roleName,
|
|
appAccessEnabled: true,
|
|
adminAccessEnabled: false,
|
|
};
|
|
|
|
// Action
|
|
await common.CreateRole(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/roles`)
|
|
.query({
|
|
filter: { name: { _eq: roleName } },
|
|
fields: ['id', 'name', 'app_access', 'admin_access'],
|
|
limit: 1,
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
expect(response.body.data).toEqual([
|
|
{
|
|
id: expect.any(String),
|
|
name: roleName,
|
|
app_access: true,
|
|
admin_access: false,
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('Creates default API only role', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const roleName = common.ROLE.API_ONLY.NAME;
|
|
const options: common.OptionsCreateRole = {
|
|
name: roleName,
|
|
appAccessEnabled: false,
|
|
adminAccessEnabled: false,
|
|
};
|
|
|
|
// Action
|
|
await common.CreateRole(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/roles`)
|
|
.query({
|
|
filter: { name: { _eq: roleName } },
|
|
fields: ['id', 'name', 'app_access', 'admin_access'],
|
|
limit: 1,
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
expect(response.body.data).toEqual([
|
|
{
|
|
id: expect.any(String),
|
|
name: roleName,
|
|
app_access: false,
|
|
admin_access: false,
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createUser()', () => {
|
|
describe('Creates default admin user', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const token = common.USER.ADMIN.TOKEN;
|
|
const email = common.USER.ADMIN.EMAIL;
|
|
const password = common.USER.ADMIN.PASSWORD;
|
|
const name = common.USER.ADMIN.NAME;
|
|
const roleName = common.ROLE.ADMIN.NAME;
|
|
const options: common.OptionsCreateUser = {
|
|
token,
|
|
email,
|
|
password,
|
|
name,
|
|
roleName,
|
|
};
|
|
|
|
// Action
|
|
await common.CreateUser(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/users`)
|
|
.query({
|
|
filter: { email: { _eq: email } },
|
|
fields: ['id', 'email', 'token', 'role'],
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
expect(response.body.data).toEqual([
|
|
{
|
|
id: expect.any(String),
|
|
email: email,
|
|
token: expect.any(String),
|
|
role: expect.any(String),
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('Creates default app access user', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const token = common.USER.APP_ACCESS.TOKEN;
|
|
const email = common.USER.APP_ACCESS.EMAIL;
|
|
const password = common.USER.APP_ACCESS.PASSWORD;
|
|
const name = common.USER.APP_ACCESS.NAME;
|
|
const roleName = common.ROLE.APP_ACCESS.NAME;
|
|
const options: common.OptionsCreateUser = {
|
|
token,
|
|
email,
|
|
password,
|
|
name,
|
|
roleName,
|
|
};
|
|
|
|
// Action
|
|
await common.CreateUser(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/users`)
|
|
.query({
|
|
filter: { email: { _eq: email } },
|
|
fields: ['id', 'email', 'token', 'role'],
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
expect(response.body.data).toEqual([
|
|
{
|
|
id: expect.any(String),
|
|
email: email,
|
|
token: expect.any(String),
|
|
role: expect.any(String),
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('Creates default API only user', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const token = common.USER.API_ONLY.TOKEN;
|
|
const email = common.USER.API_ONLY.EMAIL;
|
|
const password = common.USER.API_ONLY.PASSWORD;
|
|
const name = common.USER.API_ONLY.NAME;
|
|
const roleName = common.ROLE.API_ONLY.NAME;
|
|
const options: common.OptionsCreateUser = {
|
|
token,
|
|
email,
|
|
password,
|
|
name,
|
|
roleName,
|
|
};
|
|
|
|
// Action
|
|
await common.CreateUser(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/users`)
|
|
.query({
|
|
filter: { email: { _eq: email } },
|
|
fields: ['id', 'email', 'token', 'role'],
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
expect(response.body.data).toEqual([
|
|
{
|
|
id: expect.any(String),
|
|
email: email,
|
|
token: expect.any(String),
|
|
role: expect.any(String),
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('Creates default no-role user', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const token = common.USER.NO_ROLE.TOKEN;
|
|
const email = common.USER.NO_ROLE.EMAIL;
|
|
const password = common.USER.NO_ROLE.PASSWORD;
|
|
const name = common.USER.NO_ROLE.NAME;
|
|
const options: common.OptionsCreateUser = {
|
|
token,
|
|
email,
|
|
password,
|
|
name,
|
|
};
|
|
|
|
// Action
|
|
await common.CreateUser(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/users`)
|
|
.query({
|
|
filter: { email: { _eq: email } },
|
|
fields: ['id', 'email', 'token', 'role'],
|
|
})
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
expect(response.body.data).toEqual([
|
|
{
|
|
id: expect.any(String),
|
|
email: email,
|
|
token: expect.any(String),
|
|
role: null,
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createCollection()', () => {
|
|
describe('Creates a new collection', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const options: common.OptionsCreateCollection = {
|
|
collection: collectionName,
|
|
};
|
|
|
|
// Action
|
|
await common.CreateCollection(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/collections/${collectionName}`)
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
expect(response.body.data).toEqual({
|
|
collection: collectionName,
|
|
meta: expect.objectContaining({
|
|
collection: collectionName,
|
|
}),
|
|
schema: expect.objectContaining({
|
|
name: collectionName,
|
|
}),
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createField()', () => {
|
|
describe('Creates a new field', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const fieldName = 'sample_field';
|
|
const fieldType = 'string';
|
|
const options: common.OptionsCreateField = {
|
|
collection: collectionName,
|
|
field: fieldName,
|
|
type: fieldType,
|
|
};
|
|
|
|
// Action
|
|
await common.CreateField(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/fields/${collectionName}/${fieldName}`)
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
expect(response.body.data).toEqual({
|
|
collection: collectionName,
|
|
field: fieldName,
|
|
type: fieldType,
|
|
meta: expect.anything(),
|
|
schema: expect.anything(),
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createFieldM2O()', () => {
|
|
describe('Creates a new M2O field', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const fieldName = 'm2o_field';
|
|
const primaryKeyType = 'integer';
|
|
const collectionOptions: common.OptionsCreateCollection = {
|
|
collection: collectionNameM2O,
|
|
primaryKeyType,
|
|
};
|
|
await common.CreateCollection(vendor, collectionOptions);
|
|
|
|
const options: common.OptionsCreateFieldM2O = {
|
|
collection: collectionName,
|
|
field: fieldName,
|
|
otherCollection: collectionNameM2O,
|
|
primaryKeyType: primaryKeyType,
|
|
};
|
|
|
|
// Action
|
|
await common.CreateFieldM2O(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/fields/${collectionName}/${fieldName}`)
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
expect(response.body.data).toEqual({
|
|
collection: collectionName,
|
|
field: fieldName,
|
|
type: primaryKeyType,
|
|
meta: expect.objectContaining({
|
|
special: expect.arrayContaining(['m2o']),
|
|
}),
|
|
schema: expect.anything(),
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createFieldO2M()', () => {
|
|
describe('Creates a new O2M field', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const fieldName = 'o2m_field';
|
|
const otherFieldName = 'm2o_field';
|
|
const primaryKeyType = 'integer';
|
|
const collectionOptions: common.OptionsCreateCollection = {
|
|
collection: collectionNameO2M,
|
|
primaryKeyType,
|
|
};
|
|
await common.CreateCollection(vendor, collectionOptions);
|
|
|
|
const options: common.OptionsCreateFieldO2M = {
|
|
collection: collectionName,
|
|
field: fieldName,
|
|
otherField: otherFieldName,
|
|
otherCollection: collectionNameO2M,
|
|
primaryKeyType: primaryKeyType,
|
|
};
|
|
|
|
// Action
|
|
await common.CreateFieldO2M(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/fields/${collectionName}/${fieldName}`)
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
expect(response.body.data).toEqual({
|
|
collection: collectionName,
|
|
field: fieldName,
|
|
type: 'alias',
|
|
meta: expect.anything(),
|
|
schema: null,
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('createItem()', () => {
|
|
describe('Creates a new item', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const options: common.OptionsCreateItem = {
|
|
collection: collectionName,
|
|
item: {
|
|
sample_field: 'sample_value',
|
|
},
|
|
};
|
|
|
|
// Action
|
|
const createdItem = await common.CreateItem(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/items/${collectionName}/${createdItem.id}`)
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
expect(response.body.data).toEqual(
|
|
expect.objectContaining({
|
|
id: createdItem.id,
|
|
sample_field: 'sample_value',
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('Creates a new M2O item', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const options: common.OptionsCreateItem = {
|
|
collection: collectionName,
|
|
item: {
|
|
sample_field: 'sample_value',
|
|
m2o_field: {},
|
|
},
|
|
};
|
|
|
|
// Action
|
|
const createdItem = await common.CreateItem(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/items/${collectionName}/${createdItem.id}`)
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
expect(response.body.data).toEqual(
|
|
expect.objectContaining({
|
|
id: createdItem.id,
|
|
sample_field: 'sample_value',
|
|
m2o_field: expect.any(Number),
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('Creates a new O2M item', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const options: common.OptionsCreateItem = {
|
|
collection: collectionName,
|
|
item: {
|
|
sample_field: 'sample_value',
|
|
o2m_field: {
|
|
create: [{}],
|
|
update: [],
|
|
delete: [],
|
|
},
|
|
},
|
|
};
|
|
|
|
// Action
|
|
const createdItem = await common.CreateItem(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/items/${collectionName}/${createdItem.id}`)
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
expect(response.body.data).toEqual(
|
|
expect.objectContaining({
|
|
id: createdItem.id,
|
|
sample_field: 'sample_value',
|
|
o2m_field: [expect.any(Number)],
|
|
})
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('deleteField()', () => {
|
|
describe('Deletes an O2M field', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const fieldName = 'o2m_field';
|
|
const options: common.OptionsDeleteField = {
|
|
collection: collectionName,
|
|
field: fieldName,
|
|
};
|
|
|
|
// Action
|
|
await common.DeleteField(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/fields/${collectionName}`)
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
for (const child of response.body.data) {
|
|
expect(child.field).not.toEqual(fieldName);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('Deletes other M2O field', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const fieldName = 'm2o_field';
|
|
const options: common.OptionsDeleteField = {
|
|
collection: collectionNameO2M,
|
|
field: fieldName,
|
|
};
|
|
|
|
// Action
|
|
await common.DeleteField(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/fields/${collectionNameO2M}`)
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
for (const child of response.body.data) {
|
|
expect(child.field).not.toEqual(fieldName);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('Deletes an M2O field', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const fieldName = 'm2o_field';
|
|
const options: common.OptionsDeleteField = {
|
|
collection: collectionName,
|
|
field: fieldName,
|
|
};
|
|
|
|
// Action
|
|
await common.DeleteField(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/fields/${collectionName}`)
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
for (const child of response.body.data) {
|
|
expect(child.field).not.toEqual(fieldName);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('Deletes a field', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const fieldName = 'sample_field';
|
|
const options: common.OptionsDeleteField = {
|
|
collection: collectionName,
|
|
field: fieldName,
|
|
};
|
|
|
|
// Action
|
|
await common.DeleteField(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/fields/${collectionName}`)
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
for (const child of response.body.data) {
|
|
expect(child.field).not.toEqual(fieldName);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('deleteCollection()', () => {
|
|
describe('Deletes a collection', () => {
|
|
it.each(vendors)('%s', async (vendor) => {
|
|
// Setup
|
|
const options: common.OptionsDeleteCollection = {
|
|
collection: collectionName,
|
|
};
|
|
|
|
// Action
|
|
await common.DeleteCollection(vendor, options);
|
|
const response = await request(getUrl(vendor))
|
|
.get(`/collections`)
|
|
.set('Authorization', `Bearer ${common.USER.TESTS_FLOW.TOKEN}`)
|
|
.expect('Content-Type', /application\/json/)
|
|
.expect(200);
|
|
|
|
// Assert
|
|
for (const child of response.body.data) {
|
|
expect(child.collection).not.toEqual(collectionName);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|