Skip to content

Commit

Permalink
Support integration tests
Browse files Browse the repository at this point in the history
Integration tests are slower than unit tests because they rely on
a database connection, so we want the ability to run them separately
depending on our environment.

Jest allows us to define different config files.  By creating a `base`
config we can define all of the common settings between unit and
integration tests, and then customize for each type in the respective
extended configs.

In addition to configuration this begins to define define some hooks
so that we can eventually run these tests in parallel.  Unfortunately
there is a bug in the migration library we're using which prevents that
kind of parallel migration within a single database / across multiple
schemas.  We have an open PR with a patch for that bug[1].

I took out the explicit running of migrations because our integration
tests should now cover that (as they do run migrations).

[1] ThomWright/postgres-migrations#93

Issue #43 Support integration tests
  • Loading branch information
slifty committed Jul 13, 2022
1 parent d15b9fc commit 3cef081
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 7 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ jobs:
- name: Run build
run: npm run build

- name: Run migrations
run: npm run migrate
- name: Run unit tests
run: npm run test:unit -- --coverage

- name: Run integration tests
run: npm run test:integration -- --coverage
env:
PGHOST: localhost
PGPORT: 5432
PGUSER: postgres
PGPASSWORD: postgres

- name: Run tests
run: npm run test -- --coverage

- name: Upload coverage
uses: codecov/codecov-action@v2
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ In order to run this software you need to set up a [Postgres 14](https://www.pos
edit .env
```

3. Run migrations
3. Set up test environment variables

```bash
cp .env.example .env.test
edit .env.test
```

4. Run migrations

```bash
npm run migrate:dev
Expand Down
1 change: 1 addition & 0 deletions jest.config.js → jest.config.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = {
},
collectCoverageFrom: ["src/**/*.ts"],
preset: 'ts-jest',
setupFiles: ['<rootDir>/src/test/setupEnv.ts'],
testEnvironment: 'node',
testPathIgnorePatterns: ["<rootDir>/dist/"],
silent: true,
Expand Down
4 changes: 4 additions & 0 deletions jest.config.int.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
var config = require('./jest.config.base.js');
config.testMatch = ['**/?(*.)+(int).(spec|test).[jt]s?(x)'];
config.setupFilesAfterEnv = ["<rootDir>/src/test/integrationSuiteSetup.ts"];
module.exports = config;
3 changes: 3 additions & 0 deletions jest.config.unit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var config = require('./jest.config.base.js');
config.testMatch = ['**/?(*.)+(unit).(spec|test).[jt]s?(x)'];
module.exports = config;
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
"lint": "eslint ./src --ext .ts",
"migrate": "node -r dotenv/config dist/scripts/migrate.js",
"migrate:dev": "ts-node -r dotenv/config src/scripts/migrate.ts | pino-pretty",
"test": "jest",
"test": "npm run test:unit && npm run test:integration",
"test:unit": "jest --config=jest.config.unit.js",
"test:integration": "jest --config=jest.config.int.js --runInBand",
"start": "node dist/index.js",
"start:dev": "ts-node src/index.ts | pino-pretty"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import request from 'supertest';
import { app } from '../app';
import {
prepareDatabaseForCurrentWorker,
cleanupDatabaseForCurrentWorker,
} from '../test/utils';

const agent = request.agent(app);

describe('/canonicalFields', () => {
describe('/', () => {
it('should return HTTP Status Code 200 OK', async () => {
await prepareDatabaseForCurrentWorker();
await agent
.get('/canonicalFields')
.expect(200);
await cleanupDatabaseForCurrentWorker();
});
});
});
5 changes: 5 additions & 0 deletions src/test/integrationSuiteSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { db } from '../database';

afterAll(async () => {
await db.close();
});
3 changes: 3 additions & 0 deletions src/test/setupEnv.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import dotenv from 'dotenv';

dotenv.config({ path: '.env.test' });
40 changes: 40 additions & 0 deletions src/test/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {
db,
migrate,
} from '../database';

const generateSchemaName = (workerId: string): string => `test_${workerId}`;

const getSchemaNameForCurrentTestWorker = (): string => {
if (process.env.NODE_ENV !== 'test') {
throw new Error('You cannot get a test schema name outside of a test environment.');
}
if (process.env.JEST_WORKER_ID === undefined) {
throw new Error('You cannot get a test schema name if jest has not specified a worker ID.');
}
return generateSchemaName(process.env.JEST_WORKER_ID);
};

const createSchema = async (schemaName: string): Promise<void> => {
await db.query(`CREATE SCHEMA IF NOT EXISTS ${schemaName};`);
};

const setSchema = async (schemaName: string): Promise<void> => {
await db.query(`SET search_path TO ${schemaName};`);
};

const dropSchema = async (schemaName: string): Promise<void> => {
await db.query(`DROP SCHEMA ${schemaName} CASCADE;`);
};

export const prepareDatabaseForCurrentWorker = async (): Promise<void> => {
const schemaName = getSchemaNameForCurrentTestWorker();
await createSchema(schemaName);
await setSchema(schemaName);
await migrate();
};

export const cleanupDatabaseForCurrentWorker = async (): Promise<void> => {
const schemaName = getSchemaNameForCurrentTestWorker();
await dropSchema(schemaName);
};

0 comments on commit 3cef081

Please sign in to comment.