Files
directus/tests/setup/setup.ts
Jay Cammarano 43b0b9c62e E2E tests for the /items/:collection endpoint (#8549)
* added faker.js for testing

* edited env vars removed sqlite from testing (temp)

* getMany endpoint working with no data

* converted to faker

* getOne test passing

* schema for relations, item creation => factory

* many to many test working, factory refactored

* faker as dev dep

* new schema, tests passing postgres json exception

* tests passing

* upgrade tedious

* images

* removed images, rebuilt package-lock.json

* added users and schema map(WIP)

* user => artist m2o relation working on fields

* downgrade tedious

* user => guest, each => all

* items/:collection/invalid_id test

* items/invalid_collection/:id test added

* /:collection POST createOne test

* createMany factory, createMany endpoint test

* error handling tests

* create many with a many to one

* createMany with options to link relations

* some more describe sorting

* factory tests working

* tests passing
2021-10-20 23:20:50 +00:00

311 lines
7.9 KiB
TypeScript

/* eslint-disable no-console */
import Dockerode, { ContainerSpec } from 'dockerode';
import knex from 'knex';
import { awaitDatabaseConnection, awaitDirectusConnection } from './utils/await-connection';
import Listr, { ListrTask } from 'listr';
import { getDBsToTest } from '../get-dbs-to-test';
import config, { CONTAINER_PERSISTENCE_FILE } from '../config';
import globby from 'globby';
import path from 'path';
import { GlobalConfigTsJest } from 'ts-jest/dist/types';
import { writeFileSync } from 'fs';
import global from './global';
const docker = new Dockerode();
let started = false;
export default async (jestConfig: GlobalConfigTsJest): Promise<void> => {
if (started) return;
started = true;
console.log('\n\n');
console.log(`👮‍♀️ Starting tests!\n`);
const vendors = getDBsToTest();
const NODE_VERSION = process.env.TEST_NODE_VERSION || '16-alpine';
await new Listr([
{
title: 'Create Directus Docker Image',
task: async (_, task) => {
const result = await globby(['**/*', '!node_modules', '!**/node_modules', '!**/src', '!tests', '!**/tests'], {
cwd: path.resolve(__dirname, '..', '..'),
});
const stream = await docker.buildImage(
{
context: path.resolve(__dirname, '..', '..'),
src: ['Dockerfile', ...result],
},
{
t: 'directus-test-image',
buildargs: { NODE_VERSION },
cachefrom: ['directus-test-image'], // Docker now requires this to be an actual array, but Dockerode's types haven't been updated yet
} as unknown as Dockerode.ImageBuildOptions
);
await new Promise((resolve, reject) => {
docker.modem.followProgress(
stream,
(err, res) => {
if (err) {
reject(err);
} else {
resolve(res);
}
},
(event: any) => {
if (event.stream?.startsWith('Step')) {
task.output = event.stream;
}
}
);
});
},
},
{
title: 'Pulling Required Images',
task: () => {
return new Listr(
vendors
.map((vendor) => {
return {
title: config.names[vendor]!,
task: async (_, task) => {
const image =
config.containerConfig[vendor]! &&
(config.containerConfig[vendor]! as Dockerode.ContainerSpec).Image;
if (!image) return;
const stream = await docker.pull(image);
await new Promise((resolve, reject) => {
docker.modem.followProgress(
stream,
(err, res) => {
if (err) {
reject(err);
} else {
resolve(res);
}
},
(event: any) => {
if (event.stream?.startsWith('Step')) {
task.output = event.stream;
}
}
);
});
},
} as ListrTask;
})
.filter((t) => t),
{ concurrent: true }
);
},
},
{
title: 'Create Docker containers',
task: () => {
return new Listr(
vendors.map((vendor) => {
return {
title: config.names[vendor]!,
task: () => {
return new Listr([
{
title: 'Database',
task: async () => {
if (!config.containerConfig[vendor] || config.containerConfig[vendor] === false) return;
const container = await docker.createContainer(config.containerConfig[vendor]! as ContainerSpec);
global.databaseContainers.push({
vendor,
container,
});
},
},
{
title: 'Directus',
task: async () => {
const container = await docker.createContainer({
name: `directus-test-directus-${vendor}-${process.pid}`,
Image: 'directus-test-image',
Env: [
...config.envs[vendor]!,
'ADMIN_EMAIL=admin@example.com',
'ADMIN_PASSWORD=password',
'KEY=directus-test',
'SECRET=directus-test',
'TELEMETRY=false',
'CACHE_SCHEMA=false',
'CACHE_ENABLED=false',
'RATE_LIMITER_ENABLED=false',
],
HostConfig: {
Links:
vendor === 'sqlite3'
? undefined
: [
`directus-test-database-${vendor}-${process.pid}:directus-test-database-${vendor}-${process.pid}`,
],
PortBindings: {
'8055/tcp': [{ HostPort: String(config.ports[vendor]!) }],
},
},
} as ContainerSpec);
global.directusContainers.push({
vendor,
container,
});
},
},
]);
},
};
}),
{ concurrent: true }
);
},
},
{
title: 'Start Database Docker containers',
task: () => {
return new Listr(
global.databaseContainers.map(({ vendor, container }) => {
return {
title: config.names[vendor]!,
task: async () => await container.start(),
};
}),
{ concurrent: true }
);
},
},
{
title: 'Create Knex instances',
task: () => {
return new Listr(
vendors.map((vendor) => {
return {
title: config.names[vendor]!,
task: () => {
global.knexInstances.push({ vendor, knex: knex(config.knexConfig[vendor]!) });
},
};
}),
{ concurrent: true }
);
},
},
{
title: 'Wait for databases to be ready',
task: async () => {
return new Listr(
global.knexInstances.map(({ vendor, knex }) => {
return {
title: config.names[vendor]!,
task: async () => await awaitDatabaseConnection(knex, config.knexConfig[vendor]!.waitTestSQL),
};
}),
{ concurrent: true }
);
},
},
{
title: 'Close Knex instances',
task: () => {
return new Listr(
global.knexInstances.map(({ vendor, knex }) => {
return {
title: config.names[vendor]!,
task: async () => await knex.destroy(),
};
}),
{ concurrent: true }
);
},
},
{
title: 'Start Directus Docker containers',
task: () => {
return new Listr(
global.directusContainers.map(({ vendor, container }) => {
return {
title: config.names[vendor]!,
task: async () => await container.start(),
};
}),
{ concurrent: true }
);
},
},
{
title: 'Wait for Directus to be ready',
task: async () => {
return new Listr(
vendors.map((vendor) => {
return {
title: config.names[vendor]!,
task: async () => {
try {
await awaitDirectusConnection(config.ports[vendor]!);
} catch {
const container = global.directusContainers.find(
({ vendor: containerVendor }) => containerVendor === vendor
);
const logBuffer = await container?.container?.logs({ follow: false, stderr: true, tail: 50 });
const logString = logBuffer ? '\n\n' + logBuffer.toString() + '\n\n' : `Directus couldn't start.`;
throw new Error(logString);
}
},
};
}),
{ concurrent: true }
);
},
},
{
title: 'Migrate and seed databases',
task: async () => {
return new Listr(
global.knexInstances.map(({ vendor }) => {
return {
title: config.names[vendor]!,
task: async () => {
const database = knex(config.knexConfig[vendor]!);
await database.migrate.latest();
await database.seed.run();
},
};
}),
{ concurrent: true }
);
},
},
{
skip: () => !jestConfig.watch,
title: 'Persist container info',
task: () => {
const persistContainer = ({ container, vendor }: { container: Dockerode.Container; vendor: string }) => ({
id: container.id,
vendor,
});
const containers = {
db: global.databaseContainers.map(persistContainer),
directus: global.directusContainers.map(persistContainer),
};
writeFileSync(CONTAINER_PERSISTENCE_FILE, JSON.stringify(containers));
},
},
]).run();
console.log('\n');
};