@storyous/test-utils 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/__tests__/testUtils.test.js +48 -0
- package/__tests__/testUtils.test.ts +27 -0
- package/lib/mockTransport.js +53 -0
- package/lib/mockTransport.ts +64 -0
- package/lib/testUtils.js +85 -0
- package/lib/testUtils.ts +100 -0
- package/package.json +42 -0
- package/tsconfig.json +8 -0
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# `testUtils`
|
|
2
|
+
|
|
3
|
+
## Usage
|
|
4
|
+
|
|
5
|
+
``` typescript
|
|
6
|
+
import * as assert from 'assert';
|
|
7
|
+
import Koa from 'koa';
|
|
8
|
+
import { describe, it } from 'mocha';
|
|
9
|
+
import mailer from '@storyous/mailer';
|
|
10
|
+
import testUtils from '@storyous/test-utils';
|
|
11
|
+
|
|
12
|
+
testUtils.init(
|
|
13
|
+
() => new Koa(),
|
|
14
|
+
testUtils.uniqueDatabase('mongodb://127.0.0.0:27017/test'),
|
|
15
|
+
mailer,
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
describe('some test', async () => {
|
|
19
|
+
|
|
20
|
+
it('should do some request', async () => {
|
|
21
|
+
await testUtils.request().get('/').expect(200);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should getSent emails', async () => {
|
|
25
|
+
await mailer.sendMail({});
|
|
26
|
+
assert.deepStrictEqual(testUtils.getSentMails(), []);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
const mailer_1 = __importDefault(require("@storyous/mailer"));
|
|
30
|
+
const assert = __importStar(require("assert"));
|
|
31
|
+
const koa_1 = __importDefault(require("koa"));
|
|
32
|
+
const mocha_1 = require("mocha");
|
|
33
|
+
const testUtils_1 = __importDefault(require("../lib/testUtils"));
|
|
34
|
+
testUtils_1.default.init(() => new koa_1.default(), 'mongodb://127.0.0.1/testing', mailer_1.default);
|
|
35
|
+
(0, mocha_1.describe)('packages/testUtils', async () => {
|
|
36
|
+
(0, mocha_1.it)('should do some request', async () => {
|
|
37
|
+
await testUtils_1.default.request().get('/').expect(404);
|
|
38
|
+
});
|
|
39
|
+
(0, mocha_1.it)('should getSent emails', async () => {
|
|
40
|
+
assert.deepStrictEqual(testUtils_1.default.getSentMails(), []);
|
|
41
|
+
});
|
|
42
|
+
(0, mocha_1.it)('should generate uniqueDatabase', () => {
|
|
43
|
+
testUtils_1.default.init(() => new koa_1.default());
|
|
44
|
+
assert.deepStrictEqual(testUtils_1.default.uniqueDatabase(), null);
|
|
45
|
+
assert.deepStrictEqual(testUtils_1.default.uniqueDatabase('mongodb://127.0.0.0:27017/test')?.startsWith('mongodb://127.0.0.0:27017/test___'), true);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdFV0aWxzLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ0ZXN0VXRpbHMudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsOERBQXNDO0FBQ3RDLCtDQUFpQztBQUNqQyw4Q0FBc0I7QUFDdEIsaUNBQXFDO0FBQ3JDLGlFQUF5QztBQUV6QyxtQkFBUyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLGFBQUcsRUFBRSxFQUFFLDZCQUE2QixFQUFFLGdCQUFNLENBQUMsQ0FBQztBQUV2RSxJQUFBLGdCQUFRLEVBQUMsb0JBQW9CLEVBQUUsS0FBSyxJQUFJLEVBQUU7SUFFdEMsSUFBQSxVQUFFLEVBQUMsd0JBQXdCLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDcEMsTUFBTSxtQkFBUyxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDbkQsQ0FBQyxDQUFDLENBQUM7SUFFSCxJQUFBLFVBQUUsRUFBQyx1QkFBdUIsRUFBRSxLQUFLLElBQUksRUFBRTtRQUNuQyxNQUFNLENBQUMsZUFBZSxDQUFDLG1CQUFTLENBQUMsWUFBWSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDekQsQ0FBQyxDQUFDLENBQUM7SUFFSCxJQUFBLFVBQUUsRUFBQyxnQ0FBZ0MsRUFBRSxHQUFHLEVBQUU7UUFDdEMsbUJBQVMsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxhQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ2hDLE1BQU0sQ0FBQyxlQUFlLENBQUMsbUJBQVMsQ0FBQyxjQUFjLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUN6RCxNQUFNLENBQUMsZUFBZSxDQUNsQixtQkFBUyxDQUFDLGNBQWMsQ0FBQyxnQ0FBZ0MsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxtQ0FBbUMsQ0FBQyxFQUMzRyxJQUFJLENBQ1AsQ0FBQztJQUNOLENBQUMsQ0FBQyxDQUFDO0FBQ1AsQ0FBQyxDQUFDLENBQUMifQ==
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import mailer from '@storyous/mailer';
|
|
2
|
+
import * as assert from 'assert';
|
|
3
|
+
import Koa from 'koa';
|
|
4
|
+
import { describe, it } from 'mocha';
|
|
5
|
+
import testUtils from '../lib/testUtils';
|
|
6
|
+
|
|
7
|
+
testUtils.init(() => new Koa(), 'mongodb://127.0.0.1/testing', mailer);
|
|
8
|
+
|
|
9
|
+
describe('packages/testUtils', async () => {
|
|
10
|
+
|
|
11
|
+
it('should do some request', async () => {
|
|
12
|
+
await testUtils.request().get('/').expect(404);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should getSent emails', async () => {
|
|
16
|
+
assert.deepStrictEqual(testUtils.getSentMails(), []);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should generate uniqueDatabase', () => {
|
|
20
|
+
testUtils.init(() => new Koa());
|
|
21
|
+
assert.deepStrictEqual(testUtils.uniqueDatabase(), null);
|
|
22
|
+
assert.deepStrictEqual(
|
|
23
|
+
testUtils.uniqueDatabase('mongodb://127.0.0.0:27017/test')?.startsWith('mongodb://127.0.0.0:27017/test___'),
|
|
24
|
+
true,
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class MockTransport {
|
|
4
|
+
constructor() {
|
|
5
|
+
this._sentMail = [];
|
|
6
|
+
this._validate = (address) => {
|
|
7
|
+
if (!address) {
|
|
8
|
+
return new Error('Error validating address.');
|
|
9
|
+
}
|
|
10
|
+
if (typeof address !== 'string') {
|
|
11
|
+
address = address.address;
|
|
12
|
+
}
|
|
13
|
+
if (address.length > 254) {
|
|
14
|
+
return new Error('Error validating address.');
|
|
15
|
+
}
|
|
16
|
+
if (!address.match(/^[^@]+@.+\..+$/)) {
|
|
17
|
+
return new Error('Error validating address.');
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
getSentMail() {
|
|
23
|
+
return this._sentMail;
|
|
24
|
+
}
|
|
25
|
+
send(mail, callback) {
|
|
26
|
+
let err;
|
|
27
|
+
if (!mail.data.to) {
|
|
28
|
+
callback(new Error('I need to know who this email is being sent to :-('));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (Array.isArray(mail.data.to)) {
|
|
32
|
+
for (let i = 0; i < mail.data.to.length; i++) {
|
|
33
|
+
const address = mail.data.to[i];
|
|
34
|
+
err = this._validate(address);
|
|
35
|
+
if (err !== null) {
|
|
36
|
+
callback(err);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
err = this._validate(mail.data.to);
|
|
43
|
+
if (err !== null) {
|
|
44
|
+
callback(err);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
this._sentMail.push(mail);
|
|
49
|
+
callback(null, { accepted: [mail.data.to] });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.default = MockTransport;
|
|
53
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9ja1RyYW5zcG9ydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIm1vY2tUcmFuc3BvcnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFJQSxNQUFxQixhQUFhO0lBQWxDO1FBQ1ksY0FBUyxHQUF1QixFQUFFLENBQUM7UUF1Q25DLGNBQVMsR0FBRyxDQUFDLE9BQTBCLEVBQUUsRUFBRTtZQUMvQyxJQUFJLENBQUMsT0FBTyxFQUFFO2dCQUNWLE9BQU8sSUFBSSxLQUFLLENBQUMsMkJBQTJCLENBQUMsQ0FBQzthQUNqRDtZQUVELElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxFQUFFO2dCQUM3QixPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQzthQUM3QjtZQUVELElBQUksT0FBTyxDQUFDLE1BQU0sR0FBRyxHQUFHLEVBQUU7Z0JBQ3RCLE9BQU8sSUFBSSxLQUFLLENBQUMsMkJBQTJCLENBQUMsQ0FBQzthQUNqRDtZQUVELElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLGdCQUFnQixDQUFDLEVBQUU7Z0JBQ2xDLE9BQU8sSUFBSSxLQUFLLENBQUMsMkJBQTJCLENBQUMsQ0FBQzthQUNqRDtZQUVELE9BQU8sSUFBSSxDQUFDO1FBQ2hCLENBQUMsQ0FBQztJQUNOLENBQUM7SUFwREcsV0FBVztRQUNQLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQztJQUMxQixDQUFDO0lBRU0sSUFBSSxDQUFFLElBQXNCLEVBQUUsUUFBaUQ7UUFDbEYsSUFBSSxHQUFHLENBQUM7UUFFUixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUU7WUFDZixRQUFRLENBQUMsSUFBSSxLQUFLLENBQUMsb0RBQW9ELENBQUMsQ0FBQyxDQUFDO1lBQzFFLE9BQU87U0FDVjtRQUVELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFO1lBQzdCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7Z0JBQzFDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUNoQyxHQUFHLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDOUIsSUFBSSxHQUFHLEtBQUssSUFBSSxFQUFFO29CQUNkLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztvQkFDZCxPQUFPO2lCQUNWO2FBQ0o7U0FDSjthQUFNO1lBQ0gsR0FBRyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUNuQyxJQUFJLEdBQUcsS0FBSyxJQUFJLEVBQUU7Z0JBQ2QsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUNkLE9BQU87YUFDVjtTQUNKO1FBRUQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDMUIsUUFBUSxDQUFDLElBQUksRUFBRSxFQUFFLFFBQVEsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2pELENBQUM7Q0FxQko7QUEzREQsZ0NBMkRDIn0=
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Transport } from 'nodemailer';
|
|
2
|
+
import { Address } from 'nodemailer/lib/mailer';
|
|
3
|
+
import MailMessage from 'nodemailer/lib/mailer/mail-message';
|
|
4
|
+
|
|
5
|
+
export default class MockTransport implements Transport {
|
|
6
|
+
private _sentMail: MailMessage<any>[] = [];
|
|
7
|
+
|
|
8
|
+
public readonly name: 'Mock';
|
|
9
|
+
|
|
10
|
+
public readonly version: '1.0.0';
|
|
11
|
+
|
|
12
|
+
getSentMail () {
|
|
13
|
+
return this._sentMail;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public send (mail: MailMessage<any>, callback: (err: Error | null, info?: any) => void): void {
|
|
17
|
+
let err;
|
|
18
|
+
|
|
19
|
+
if (!mail.data.to) {
|
|
20
|
+
callback(new Error('I need to know who this email is being sent to :-('));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (Array.isArray(mail.data.to)) {
|
|
25
|
+
for (let i = 0; i < mail.data.to.length; i++) {
|
|
26
|
+
const address = mail.data.to[i];
|
|
27
|
+
err = this._validate(address);
|
|
28
|
+
if (err !== null) {
|
|
29
|
+
callback(err);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
err = this._validate(mail.data.to);
|
|
35
|
+
if (err !== null) {
|
|
36
|
+
callback(err);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this._sentMail.push(mail);
|
|
42
|
+
callback(null, { accepted: [mail.data.to] });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private _validate = (address?: string | Address) => {
|
|
46
|
+
if (!address) {
|
|
47
|
+
return new Error('Error validating address.');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (typeof address !== 'string') {
|
|
51
|
+
address = address.address;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (address.length > 254) {
|
|
55
|
+
return new Error('Error validating address.');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!address.match(/^[^@]+@.+\..+$/)) {
|
|
59
|
+
return new Error('Error validating address.');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return null;
|
|
63
|
+
};
|
|
64
|
+
}
|
package/lib/testUtils.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const http_1 = __importDefault(require("http"));
|
|
7
|
+
const mocha_1 = require("mocha");
|
|
8
|
+
const mongodb_1 = require("mongodb");
|
|
9
|
+
const nodemailer_1 = __importDefault(require("nodemailer"));
|
|
10
|
+
const supertest_1 = __importDefault(require("supertest"));
|
|
11
|
+
const mockTransport_1 = __importDefault(require("./mockTransport"));
|
|
12
|
+
const testUtils = {
|
|
13
|
+
_app: null,
|
|
14
|
+
_originalTransporter: undefined,
|
|
15
|
+
_mockTransporter: undefined,
|
|
16
|
+
init(app, cleanDatabaseUrl, mailer) {
|
|
17
|
+
(0, mocha_1.before)(async () => {
|
|
18
|
+
if (cleanDatabaseUrl) {
|
|
19
|
+
await this.cleanTestingDatabases(cleanDatabaseUrl);
|
|
20
|
+
}
|
|
21
|
+
if (app) {
|
|
22
|
+
this._app = http_1.default.createServer((await app()).callback());
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
(0, mocha_1.beforeEach)(() => {
|
|
26
|
+
if (mailer) {
|
|
27
|
+
this._originalTransporter = mailer._transporter;
|
|
28
|
+
this._mockTransporter = new mockTransport_1.default();
|
|
29
|
+
mailer._transporter = nodemailer_1.default.createTransport(this._mockTransporter);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
(0, mocha_1.afterEach)(() => {
|
|
33
|
+
if (mailer) {
|
|
34
|
+
mailer._transporter = this._originalTransporter;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
getSentMails() {
|
|
39
|
+
if (!this._mockTransporter) {
|
|
40
|
+
throw new Error('The Email Transporter is not initialized yet!');
|
|
41
|
+
}
|
|
42
|
+
return this._mockTransporter.getSentMail();
|
|
43
|
+
},
|
|
44
|
+
request() {
|
|
45
|
+
if (!this._app) {
|
|
46
|
+
throw new Error('The app is not initialized yet!');
|
|
47
|
+
}
|
|
48
|
+
return supertest_1.default.agent(this._app);
|
|
49
|
+
},
|
|
50
|
+
uniqueDatabase(mongodbUrl) {
|
|
51
|
+
if (!mongodbUrl) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const parsed = new URL(mongodbUrl);
|
|
55
|
+
parsed.pathname = `${parsed.pathname}___${Date.now()}`;
|
|
56
|
+
return parsed.toString();
|
|
57
|
+
},
|
|
58
|
+
async cleanTestingDatabases(mongodbUrl) {
|
|
59
|
+
const client = new mongodb_1.MongoClient(mongodbUrl, { directConnection: true });
|
|
60
|
+
await client.connect();
|
|
61
|
+
const db = client.db();
|
|
62
|
+
const { databaseName } = db;
|
|
63
|
+
if (!/testing/i.test(databaseName)) {
|
|
64
|
+
throw new Error('The database name has to contains the "testing" keyword.');
|
|
65
|
+
}
|
|
66
|
+
const postfixMatcher = /___([0-9]{12,})/;
|
|
67
|
+
const baseName = databaseName.replace(postfixMatcher, '');
|
|
68
|
+
const matcher = new RegExp(`^${baseName}(${postfixMatcher.source})?$`);
|
|
69
|
+
const adminDb = db.admin();
|
|
70
|
+
const { databases } = await adminDb.listDatabases({ nameOnly: true });
|
|
71
|
+
const maxAgeDate = new Date();
|
|
72
|
+
maxAgeDate.setMinutes(maxAgeDate.getMinutes() - 15);
|
|
73
|
+
await Promise.all(databases.map(async ({ name }) => {
|
|
74
|
+
const [match, , timestamp] = name.match(matcher) || [];
|
|
75
|
+
if (match && (!timestamp || new Date(parseInt(timestamp, 10)) < maxAgeDate)) {
|
|
76
|
+
// eslint-disable-next-line no-console
|
|
77
|
+
console.log(`DROPPING OLD TESTING database ${name}`);
|
|
78
|
+
await client.db(name).dropDatabase();
|
|
79
|
+
}
|
|
80
|
+
}));
|
|
81
|
+
await client.close();
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
exports.default = testUtils;
|
|
85
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdFV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidGVzdFV0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsZ0RBQW9DO0FBRXBDLGlDQUFzRDtBQUN0RCxxQ0FBc0M7QUFDdEMsNERBQXFEO0FBRXJELDBEQUFzRDtBQUN0RCxvRUFBNEM7QUFFNUMsTUFBTSxTQUFTLEdBQUc7SUFDZCxJQUFJLEVBQWdCLElBQUk7SUFDeEIsb0JBQW9CLEVBQTBCLFNBQVM7SUFDdkQsZ0JBQWdCLEVBQTRCLFNBQVM7SUFFckQsSUFBSSxDQUFFLEdBQWUsRUFBRSxnQkFBeUIsRUFBRSxNQUE0QjtRQUMxRSxJQUFBLGNBQU0sRUFBQyxLQUFLLElBQUksRUFBRTtZQUNkLElBQUksZ0JBQWdCLEVBQUU7Z0JBQ2xCLE1BQU0sSUFBSSxDQUFDLHFCQUFxQixDQUFDLGdCQUFnQixDQUFDLENBQUM7YUFDdEQ7WUFFRCxJQUFJLEdBQUcsRUFBRTtnQkFDTCxJQUFJLENBQUMsSUFBSSxHQUFHLGNBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxNQUFNLEdBQUcsRUFBRSxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQzthQUMzRDtRQUNMLENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBQSxrQkFBVSxFQUFDLEdBQUcsRUFBRTtZQUNaLElBQUksTUFBTSxFQUFFO2dCQUNSLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDO2dCQUNoRCxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSx1QkFBYSxFQUFFLENBQUM7Z0JBQzVDLE1BQU0sQ0FBQyxZQUFZLEdBQUcsb0JBQVUsQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7YUFDM0U7UUFDTCxDQUFDLENBQUMsQ0FBQztRQUVILElBQUEsaUJBQVMsRUFBQyxHQUFHLEVBQUU7WUFDWCxJQUFJLE1BQU0sRUFBRTtnQkFDUixNQUFNLENBQUMsWUFBWSxHQUFH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
|
package/lib/testUtils.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import http, { Server } from 'http';
|
|
2
|
+
import Koa from 'koa';
|
|
3
|
+
import { afterEach, before, beforeEach } from 'mocha';
|
|
4
|
+
import { MongoClient } from 'mongodb';
|
|
5
|
+
import nodemailer, { Transporter } from 'nodemailer';
|
|
6
|
+
import MailMessage from 'nodemailer/lib/mailer/mail-message';
|
|
7
|
+
import supertest, { SuperAgentTest } from 'supertest';
|
|
8
|
+
import MockTransport from './mockTransport';
|
|
9
|
+
|
|
10
|
+
const testUtils = {
|
|
11
|
+
_app: <Server|null> null,
|
|
12
|
+
_originalTransporter: <Transporter|undefined> undefined,
|
|
13
|
+
_mockTransporter: <MockTransport|undefined> undefined,
|
|
14
|
+
|
|
15
|
+
init (app?: () => Koa, cleanDatabaseUrl?: string, mailer?: {_transporter: any}) {
|
|
16
|
+
before(async () => {
|
|
17
|
+
if (cleanDatabaseUrl) {
|
|
18
|
+
await this.cleanTestingDatabases(cleanDatabaseUrl);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (app) {
|
|
22
|
+
this._app = http.createServer((await app()).callback());
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
if (mailer) {
|
|
28
|
+
this._originalTransporter = mailer._transporter;
|
|
29
|
+
this._mockTransporter = new MockTransport();
|
|
30
|
+
mailer._transporter = nodemailer.createTransport(this._mockTransporter);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
if (mailer) {
|
|
36
|
+
mailer._transporter = this._originalTransporter;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
getSentMails (): MailMessage<any>[] {
|
|
42
|
+
if (!this._mockTransporter) {
|
|
43
|
+
throw new Error('The Email Transporter is not initialized yet!');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return this._mockTransporter.getSentMail();
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
request (): SuperAgentTest {
|
|
50
|
+
if (!this._app) {
|
|
51
|
+
throw new Error('The app is not initialized yet!');
|
|
52
|
+
}
|
|
53
|
+
return supertest.agent(this._app);
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
uniqueDatabase (mongodbUrl?: string): string|null {
|
|
57
|
+
|
|
58
|
+
if (!mongodbUrl) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const parsed = new URL(mongodbUrl);
|
|
63
|
+
parsed.pathname = `${parsed.pathname}___${Date.now()}`;
|
|
64
|
+
return parsed.toString();
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
async cleanTestingDatabases (mongodbUrl: string): Promise<void> {
|
|
68
|
+
const client = new MongoClient(mongodbUrl, { directConnection: true });
|
|
69
|
+
await client.connect();
|
|
70
|
+
const db = client.db();
|
|
71
|
+
const { databaseName } = db;
|
|
72
|
+
|
|
73
|
+
if (!/testing/i.test(databaseName)) {
|
|
74
|
+
throw new Error('The database name has to contains the "testing" keyword.');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const postfixMatcher = /___([0-9]{12,})/;
|
|
78
|
+
const baseName = databaseName.replace(postfixMatcher, '');
|
|
79
|
+
|
|
80
|
+
const matcher = new RegExp(`^${baseName}(${postfixMatcher.source})?$`);
|
|
81
|
+
const adminDb = db.admin();
|
|
82
|
+
const { databases } = await adminDb.listDatabases({ nameOnly: true });
|
|
83
|
+
|
|
84
|
+
const maxAgeDate = new Date();
|
|
85
|
+
maxAgeDate.setMinutes(maxAgeDate.getMinutes() - 15);
|
|
86
|
+
|
|
87
|
+
await Promise.all(databases.map(async ({ name }) => {
|
|
88
|
+
const [match,, timestamp] = name.match(matcher) || [];
|
|
89
|
+
if (match && (!timestamp || new Date(parseInt(timestamp, 10)) < maxAgeDate)) {
|
|
90
|
+
// eslint-disable-next-line no-console
|
|
91
|
+
console.log(`DROPPING OLD TESTING database ${name}`);
|
|
92
|
+
await client.db(name).dropDatabase();
|
|
93
|
+
}
|
|
94
|
+
}));
|
|
95
|
+
|
|
96
|
+
await client.close();
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export default testUtils;
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@storyous/test-utils",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"homepage": "https://github.com/Storyous/mono-utils#readme",
|
|
6
|
+
"license": "ISC",
|
|
7
|
+
"main": "lib/testUtils.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"start": "tsc",
|
|
10
|
+
"build": "tsc && npm publish"
|
|
11
|
+
},
|
|
12
|
+
"mocha": {
|
|
13
|
+
"recursive": true,
|
|
14
|
+
"timeout": 15000,
|
|
15
|
+
"extension": [
|
|
16
|
+
"ts"
|
|
17
|
+
],
|
|
18
|
+
"exit": true,
|
|
19
|
+
"require": "ts-node/register"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/Storyous/mono-utils.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/Storyous/mono-utils/issues"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public",
|
|
30
|
+
"registry": "https://registry.npmjs.org/"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"koa": "^2.13.4",
|
|
34
|
+
"mocha": "^9.2.2",
|
|
35
|
+
"mongodb": "^4.5.0",
|
|
36
|
+
"nodemailer": "^6.7.3",
|
|
37
|
+
"supertest": "^6.2.2"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@storyous/mailer": "^1.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|