@whook/whook
Version:
Build strong and efficient REST web services.
263 lines • 10.8 kB
JavaScript
/* eslint-disable @typescript-eslint/no-explicit-any */
import { describe, test, beforeEach, jest, expect } from '@jest/globals';
import streamtest from 'streamtest';
import { YError } from 'yerror';
import initHTTPTransaction from './httpTransaction.js';
function streamifyBody(response) {
return response
? Object.assign({}, response, {
body: streamtest.fromChunks([
Buffer.from(JSON.stringify(response.body)),
]),
})
: { status: 418 };
}
describe('initHTTPTransaction', () => {
const log = jest.fn();
const apm = jest.fn();
const time = jest.fn();
const uniqueId = jest.fn();
const delay = {
create: jest.fn(),
clear: jest.fn(),
};
const obfuscator = {
obfuscate: jest.fn(),
obfuscateSensibleProps: jest.fn(),
obfuscateSensibleHeaders: jest.fn(),
};
beforeEach(() => {
log.mockReset();
apm.mockReset();
time.mockReset();
uniqueId.mockReset();
delay.create.mockReset();
delay.clear.mockReset();
obfuscator.obfuscate.mockReset();
obfuscator.obfuscateSensibleProps.mockReset();
obfuscator.obfuscateSensibleHeaders.mockReset();
});
test('should work', async () => {
const httpTransaction = await initHTTPTransaction({
obfuscator,
log,
apm,
time,
delay,
uniqueId,
});
expect(httpTransaction).toBeTruthy();
expect({
logCalls: log.mock.calls.filter(([type]) => !type.endsWith('stack')),
apmCalls: apm.mock.calls,
timeCalls: time.mock.calls,
uniqueIdCalls: uniqueId.mock.calls,
delayCreateCalls: delay.create.mock.calls,
delayClearCalls: delay.clear.mock.calls,
obfuscateCalls: obfuscator.obfuscate.mock.calls,
obfuscateSensiblePropsCalls: obfuscator.obfuscateSensibleProps.mock.calls,
obfuscateSensibleHeadersCalls: obfuscator.obfuscateSensibleHeaders.mock.calls,
}).toMatchSnapshot();
});
describe('httpTransaction', () => {
const buildResponse = jest.fn();
beforeEach(() => {
buildResponse.mockReset();
});
test('should work', async () => {
time.mockReturnValue(new Date('2012-01-15T00:00:00.000Z').getTime());
uniqueId.mockReturnValue('[id]');
delay.create.mockReturnValueOnce(new Promise(() => undefined));
delay.clear.mockResolvedValue('cancel');
const httpTransaction = await initHTTPTransaction({
obfuscator,
log,
apm,
time,
delay,
uniqueId,
});
const req = {
connection: { encrypted: true },
ts: 1000000,
ip: '127.0.0.1',
method: 'GET',
url: '/v1/users/1?extended=true',
headers: {
'x-forwarded-for': '127.0.0.1',
},
socket: {
bytesRead: 16,
bytesWritten: 64,
},
};
const [res, resBodyPromise] = streamtest.toText();
const writeHead = jest.fn();
res.writeHead = writeHead;
buildResponse.mockResolvedValueOnce({
body: streamtest.fromChunks([
Buffer.from(JSON.stringify({
id: 1,
name: 'John Doe',
})),
]),
headers: {
'Content-Type': 'application/json',
},
status: 200,
});
const { request, transaction } = await httpTransaction(req, res);
const response = await transaction.start(buildResponse);
await transaction.end(response, 'theOperationId');
expect(request.url).toEqual('/v1/users/1?extended=true');
expect(request.method).toEqual('get');
expect(request.headers).toEqual({
'x-forwarded-for': '127.0.0.1',
});
expect(request.body).toEqual(req);
expect(writeHead.mock.calls).toEqual([
[
200,
'OK',
{
'Content-Type': 'application/json',
'Transaction-Id': '[id]',
},
],
]);
const text = await resBodyPromise;
expect(text).toEqual('{"id":1,"name":"John Doe"}');
expect({
request,
buildResponseCalls: buildResponse.mock.calls,
logCalls: log.mock.calls.filter(([type]) => !type.endsWith('stack')),
apmCalls: apm.mock.calls,
timeCalls: time.mock.calls,
uniqueIdCalls: uniqueId.mock.calls,
delayCreateCalls: delay.create.mock.calls,
delayClearCalls: delay.clear.mock.calls,
obfuscateCalls: obfuscator.obfuscate.mock.calls,
obfuscateSensiblePropsCalls: obfuscator.obfuscateSensibleProps.mock.calls,
obfuscateSensibleHeadersCalls: obfuscator.obfuscateSensibleHeaders.mock.calls,
}).toMatchSnapshot();
});
test('should fail on timeout', async () => {
time.mockReturnValue(new Date('2012-01-15T00:00:00.000Z').getTime());
uniqueId.mockReturnValue('[id]');
delay.create.mockResolvedValueOnce('timeout');
delay.clear.mockResolvedValueOnce('timeout');
let request;
try {
const httpTransaction = await initHTTPTransaction({
obfuscator,
log,
apm,
time,
delay,
uniqueId,
});
const req = {
connection: { encrypted: true },
ts: 1000000,
ip: '127.0.0.1',
method: 'GET',
url: '/v1/users/1?extended=true',
headers: {
'x-forwarded-for': '127.0.0.1',
},
socket: {
bytesRead: 16,
bytesWritten: 64,
},
};
const [res, resBodyPromise] = streamtest.toText();
const writeHead = jest.fn();
res.writeHead =
writeHead;
buildResponse.mockReturnValueOnce(new Promise(() => undefined));
const { request: _request, transaction } = await httpTransaction(req, res);
request = _request;
await transaction.start(buildResponse);
await transaction.end({ status: 200 });
await resBodyPromise;
throw new YError('E_UNEXPECTED_SUCCESS');
}
catch (err) {
expect(err.code).toEqual('E_TRANSACTION_TIMEOUT');
expect(err.httpCode).toEqual(504);
expect({
request,
logCalls: log.mock.calls.filter(([type]) => !type.endsWith('stack')),
apmCalls: apm.mock.calls,
timeCalls: time.mock.calls,
uniqueIdCalls: uniqueId.mock.calls,
delayCreateCalls: delay.create.mock.calls,
delayClearCalls: delay.clear.mock.calls,
obfuscateCalls: obfuscator.obfuscate.mock.calls,
obfuscateSensiblePropsCalls: obfuscator.obfuscateSensibleProps.mock.calls,
obfuscateSensibleHeadersCalls: obfuscator.obfuscateSensibleHeaders.mock.calls,
}).toMatchSnapshot();
}
});
test('should fail with non-unique transaction id', async () => {
time.mockReturnValue(new Date('2012-01-15T00:00:00.000Z').getTime());
uniqueId.mockReturnValue('[id]');
delay.create.mockReturnValueOnce(new Promise(() => 'cancel'));
delay.clear.mockResolvedValue('cancel');
try {
const httpTransaction = await initHTTPTransaction({
obfuscator,
log,
apm,
time,
delay,
uniqueId,
TRANSACTIONS: { lol: {} },
});
const req = {
connection: { encrypted: true },
ts: 1000000,
ip: '127.0.0.1',
method: 'GET',
url: '/v1/users/1?extended=true',
headers: {
'x-forwarded-for': '127.0.0.1',
'transaction-id': 'lol',
},
socket: {
bytesRead: 16,
bytesWritten: 64,
},
};
const [res, resBodyPromise] = streamtest.toText();
const writeHead = jest.fn();
res.writeHead =
writeHead;
buildResponse.mockReturnValueOnce(Promise.resolve());
const { transaction } = await httpTransaction(req, res);
await transaction
.start(buildResponse)
.catch(transaction.catch)
.then(streamifyBody)
.then(transaction.end);
await resBodyPromise;
throw new YError('E_UNEXPECTED_SUCCESS');
}
catch (err) {
expect(err.code).toEqual('E_TRANSACTION_ID_NOT_UNIQUE');
expect(err.httpCode).toEqual(400);
expect({
logCalls: log.mock.calls.filter(([type]) => !type.endsWith('stack')),
timeCalls: time.mock.calls,
uniqueIdCalls: uniqueId.mock.calls,
delayCreateCalls: delay.create.mock.calls,
delayClearCalls: delay.clear.mock.calls,
obfuscateCalls: obfuscator.obfuscate.mock.calls,
obfuscateSensiblePropsCalls: obfuscator.obfuscateSensibleProps.mock.calls,
obfuscateSensibleHeadersCalls: obfuscator.obfuscateSensibleHeaders.mock.calls,
}).toMatchSnapshot();
}
});
});
});
//# sourceMappingURL=httpTransaction.test.js.map