Skip to content

Commit

Permalink
New: adds cls context resolver for supertest #20
Browse files Browse the repository at this point in the history
  • Loading branch information
pustovitDmytro committed May 19, 2021
1 parent 9c6623e commit ca1f96e
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 7 deletions.
41 changes: 38 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -86,6 +86,7 @@
"dependencies": {
"axios": "0.21.1",
"chalk": "4.1.1",
"cls-hooked": "4.2.2",
"dot-prop": "6.0.1",
"fs-extra": "10.0.0",
"handlebars": "4.7.7",
Expand Down
1 change: 1 addition & 0 deletions src/constants/index.js
@@ -1,3 +1,4 @@
export * from './http';
export const DEFAULT_JSON_OFFSET = 4;
export const DEFAULT_STATUS_CODE = 200;
export const DEFAULT_CLS_CONTEXT_KEY = 'chronicle-context';
13 changes: 13 additions & 0 deletions src/modules/Chronicle.js
@@ -1,6 +1,8 @@
import path from 'path';
import fs from 'fs-extra';
import cls from 'cls-hooked';
import reporters from '../reporters';
import { DEFAULT_CLS_CONTEXT_KEY } from '../constants';
import Action from './Action';

export default class Chronicle {
Expand All @@ -9,6 +11,17 @@ export default class Chronicle {
this.setConfig(config);
}

useCLS(namespace, contextKey = DEFAULT_CLS_CONTEXT_KEY) {
this.clsEnabled = true;
this._cls = { namespace, contextKey };
}

getCLSContext() {
const namespace = cls.getNamespace(this._cls.namespace);

return namespace.get(this._cls.contextKey);
}

contextBuilder = c => c

setContextBuilder(fn) {
Expand Down
17 changes: 15 additions & 2 deletions src/requests/Supertest.js
Expand Up @@ -28,11 +28,18 @@ export default class Supertest {
return decorate(target, this);
}

_setContext(context) {
this._with = context;
this._isContextSet = true;
}

_process(response) {
if (!this._with) return;
if (!this._isContextSet || !this._with) return;
const action = this._chronicle.action(this._with);

this._with = null;
this._isContextSet = false;

const { request, res } = response;

action.request = {
Expand All @@ -58,7 +65,7 @@ export default class Supertest {
}

with = (params) => {
this._with = params;
this._setContext(params);

return this._decorate(supertest(this._app));
}
Expand All @@ -85,6 +92,12 @@ export default class Supertest {
}

_proxy = ({ result }) => {
if (!this._isContextSet && this._chronicle.clsEnabled) {
const clsContext = this._chronicle.getCLSContext();

if (clsContext) this._setContext(clsContext);
}

return this._decorate(result);
}

Expand Down
7 changes: 7 additions & 0 deletions tests/Test.js
Expand Up @@ -39,6 +39,13 @@ export default class Test {
return action;
}

getActions({ title, group }) {
return this._chronicle._actions
.filter(a =>
(title ? a.context.title === title : true) &&
(group ? a.context.group === group : true));
}

findAction({ title, group }) {
const action = this._chronicle._actions
.find(a =>
Expand Down
90 changes: 88 additions & 2 deletions tests/requests/supertest.client.test.js
@@ -1,8 +1,10 @@
import { assert } from 'chai';
import cls from 'cls-hooked';
import chronicle, { supertest } from '../entry';
import { fixtures } from '../mock';
import Test from '../Test';

const ns = cls.createNamespace('cls-supertest-ns');
const { users } = fixtures;
const factory = new Test(chronicle);
const request = supertest(factory.mockApp);
Expand All @@ -12,6 +14,7 @@ suite('Supertest');
before(async () => {
await factory.startMockApp();
await factory.cleanup();
chronicle.useCLS('cls-supertest-ns');
});

test('Supertest usage without chronicle', async function () {
Expand Down Expand Up @@ -65,6 +68,7 @@ test('Supertest with .end resolving', async function () {
.with(context)
.patch('/api/users/4')
.send(data)
.set('X-API-Key', 'foobar')
.expect('Content-Type', /json/)
.expect(200)
.expect(({ body }) => {
Expand All @@ -80,13 +84,95 @@ test('Supertest with .end resolving', async function () {
});
});

const action = factory.ensureAction(context, {
method : 'PATCH',
path : '/api/users/4'
});

assert.deepEqual(action.response.body, actualbody);
assert.deepOwnInclude(action.request.headers, { 'X-API-Key': 'foobar' });
});


test('Supertest load context from cls without with', async function () {
const user = users.find(u => u.id === 3);
const context = { title: 'grandfather', group: 3 };
const data = { 'first_name': 'Susie' };

await new Promise((res, rej) => {
ns.run(async () => {
ns.set('chronicle-context', context);
await request
.patch('/api/users/3')
.send(data)
.expect('Content-Type', /json/)
.expect(200)
.expect(({ body }) => {
assert.deepOwnInclude(body, {
...user,
...data
});
res();
})
.catch(rej);
});
});

factory.ensureAction(context, {
method : 'PATCH',
path : '/api/users/4',
body : actualbody
path : '/api/users/3',
body : data
});
});

test('Clear with for second request', async function () {
const context = { title: 'first request', group: 9 };

await request
.with(context)
.get('/api/users/1')
.expect('Content-Type', /json/)
.expect(200)
.expect(({ body }) => {
assert.deepEqual(body, users[0]);
});

factory.ensureAction(context, {
method : 'GET',
path : '/api/users/1'
});

await request
.get('/api/users/1')
.expect('Content-Type', /json/)
.expect(200)
.expect(({ body }) => {
assert.deepEqual(body, users[0]);
});

await request
.with(null)
.get('/api/users/1')
.expect('Content-Type', /json/)
.expect(200)
.expect(({ body }) => {
assert.deepEqual(body, users[0]);
});

assert.lengthOf(factory.getActions(context), 1);

await request
.with(context)
.get('/api/users/2')
.expect('Content-Type', /json/)
.expect(200)
.expect(({ body }) => {
assert.deepEqual(body, users[1]);
});

assert.lengthOf(factory.getActions(context), 2);
});

after(async () => {
await factory.cleanup();
});

0 comments on commit ca1f96e

Please sign in to comment.