Skip to content

Commit

Permalink
update tests to match new testRequest logic
Browse files Browse the repository at this point in the history
  • Loading branch information
manwaring committed Nov 26, 2020
1 parent dbe759c commit 58d7423
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 140 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html)

## [4.4.2]  (2020-11-25)

### Fixed

- Update calculation of `testRequest` prop on api signature based on headers

## [4.4.1]  (2020-11-25)

### Changed
Expand Down Expand Up @@ -342,6 +348,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/),
- Update older libraries
- Now publish from Git tags instead of master pushes

[4.4.2]: https://github.com/manwaring/lambda-wrapper/compare/v4.4.1...v4.4.2
[4.4.1]: https://github.com/manwaring/lambda-wrapper/compare/v4.4.0...v4.4.1
[4.4.0]: https://github.com/manwaring/lambda-wrapper/compare/v4.3.0...v4.4.0
[4.3.0]: https://github.com/manwaring/lambda-wrapper/compare/v4.2.0...v4.3.0
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

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

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@manwaring/lambda-wrapper",
"description": "A lambda handler wrapper to abstract common functionality and provide useful defaults",
"version": "4.4.1",
"version": "4.4.2",
"scripts": {
"publish-please-dry-run": "publish-please --dry-run",
"publish-please": "publish-please",
Expand All @@ -23,7 +23,7 @@
"@types/aws-lambda": "^8.10.64",
"@types/cfn-response": "^1.0.4",
"@types/jest": "^26.0.15",
"@types/node": "^14.14.9",
"@types/node": "^14.14.10",
"@typescript-eslint/eslint-plugin": "^4.8.2",
"@typescript-eslint/parser": "^4.8.2",
"aws-lambda": "^1.0.6",
Expand Down
62 changes: 31 additions & 31 deletions src/api/v1/parser.test.ts
Original file line number Diff line number Diff line change
@@ -1,72 +1,72 @@
import { stringify } from 'querystring';
import { apiGatewayEvent } from 'serverless-plugin-test-helper';
import { Request, Body } from './parser';
import { stringify } from "querystring";
import { apiGatewayEvent } from "serverless-plugin-test-helper";
import { Request, Body } from "./parser";

describe('Body parsing', () => {
it('Parses json body', () => {
const json = { hello: 'world' };
const headers = { 'content-type': 'application/json' };
describe("Body parsing", () => {
it("Parses json body", () => {
const json = { hello: "world" };
const headers = { "content-type": "application/json" };
const body = new Body(JSON.stringify(json), headers).getParsedBody();
expect(body).toEqual(json);
});

it('Parses json body when charset is also defined in the content-type', () => {
const json = { hello: 'world' };
const headers = { 'content-type': 'application/json;charset=UTF-8' };
it("Parses json body when charset is also defined in the content-type", () => {
const json = { hello: "world" };
const headers = { "content-type": "application/json;charset=UTF-8" };
const body = new Body(JSON.stringify(json), headers).getParsedBody();
expect(body).toEqual(json);
});

it('Parses form url encoded body', () => {
const form = { hello: 'world' };
const headers = { 'content-type': 'application/x-www-form-urlencoded' };
it("Parses form url encoded body", () => {
const form = { hello: "world" };
const headers = { "content-type": "application/x-www-form-urlencoded" };
const body = new Body(stringify(form), headers).getParsedBody();
expect(body).toEqual(form);
});

it('Parses form url encoded body when charset is also defined in the content-type', () => {
const form = { hello: 'world' };
const headers = { 'content-type': 'application/x-www-form-urlencoded;charset=UTF-8' };
it("Parses form url encoded body when charset is also defined in the content-type", () => {
const form = { hello: "world" };
const headers = { "content-type": "application/x-www-form-urlencoded;charset=UTF-8" };
const body = new Body(stringify(form), headers).getParsedBody();
expect(body).toEqual(form);
});

it("Tries to parse body as JSON when content type isn't specified", () => {
const json = { hello: 'world' };
const json = { hello: "world" };
const headers = undefined;
const body = new Body(JSON.stringify(json), headers).getParsedBody();
expect(body).toEqual(json);
});

it("Errors when encoding and content-type don't match", () => {
const invalid = '2["test" : 123]4}{';
const headers = { 'content-type': 'application/json' };
const headers = { "content-type": "application/json" };
const body = new Body(invalid, headers).getParsedBody();
expect(body).toEqual(invalid);
});

it('Returns empty body when none given', () => {
it("Returns empty body when none given", () => {
let empty;
const headers = { 'content-type': 'application/x-www-form-urlencoded' };
const headers = { "content-type": "application/x-www-form-urlencoded" };
const body = new Body(empty, headers).getParsedBody();
expect(body).toEqual(empty);
});
});

describe('Request parsing', () => {
it('Gets all fields with optional parameters', () => {
describe("Request parsing", () => {
it("Gets all fields with optional parameters", () => {
const event = apiGatewayEvent({
body: JSON.stringify({ hello: 'world' }),
pathParameters: { proxy: 'not today' },
queryStringParameters: { name: 'a test' },
headers: { 'content-type': 'application/json', 'Test-Request': 'true' },
body: JSON.stringify({ hello: "world" }),
pathParameters: { proxy: "not today" },
queryStringParameters: { name: "a test" },
headers: { "content-type": "application/json", "test-request": "true" },
});
const { body, path, query, auth, headers, testRequest } = new Request(event).getProperties();

expect(body).toEqual({ hello: 'world' });
expect(path).toEqual({ proxy: 'not today' });
expect(query).toEqual({ name: 'a test' });
expect(headers['content-type']).toEqual('application/json');
expect(body).toEqual({ hello: "world" });
expect(path).toEqual({ proxy: "not today" });
expect(query).toEqual({ name: "a test" });
expect(headers["content-type"]).toEqual("application/json");
expect(testRequest).toEqual(true);
expect(auth).toBeTruthy();
});
Expand All @@ -87,7 +87,7 @@ describe('Request parsing', () => {
expect(testRequest).toBeFalsy();
});

it('Supports default values in method signature', () => {
it("Supports default values in method signature", () => {
const event = apiGatewayEvent();
delete event.body;
delete event.headers;
Expand Down
21 changes: 11 additions & 10 deletions src/api/v1/parser.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { APIGatewayEvent } from 'aws-lambda';
import { parse } from 'querystring';
import { Metrics, logger } from '../../common';
import { APIGatewayEvent } from "aws-lambda";
import { parse } from "querystring";
import { Metrics, logger } from "../../common";

const metrics = new Metrics('API Gateway');
const metrics = new Metrics("API Gateway");

export class Request {
constructor(private event: APIGatewayEvent) {}
Expand All @@ -15,7 +15,7 @@ export class Request {
const auth = this.getAuth();
const headers = event.headers ? event.headers : undefined;
const body = new Body(event.body, headers).getParsedBody();
const TEST_REQUEST_HEADER = process.env.TEST_REQUEST_HEADER || 'Test-Request';
const TEST_REQUEST_HEADER = process.env.TEST_REQUEST_HEADER || "test-request";
const testRequest = headers && headers[TEST_REQUEST_HEADER] ? JSON.parse(headers[TEST_REQUEST_HEADER]) : false;
const parsed = { body, websocket, path, query, auth, headers, testRequest };
metrics.common(parsed, event);
Expand All @@ -24,6 +24,7 @@ export class Request {

private getAuth() {
const authorizer = this.event?.requestContext?.authorizer;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const httpApiAuth = this.event.auth;
return authorizer ? authorizer : httpApiAuth;
Expand All @@ -43,11 +44,11 @@ export class Body {
} else if (this.isJSON(contentType)) {
parsedBody = JSON.parse(this.body);
} else {
logger.error('Content-Type header not found, attempting to parse as JSON');
logger.error("Content-Type header not found, attempting to parse as JSON");
parsedBody = JSON.parse(this.body);
}
} catch (err) {
logger.error('Error parsing body, returning as-is', err, this.body);
logger.error("Error parsing body, returning as-is", err, this.body);
parsedBody = this.body;
}
}
Expand All @@ -56,15 +57,15 @@ export class Body {

private getContentType(): string {
return (
this.headers && (this.headers['Content-Type'] || this.headers['CONTENT-TYPE'] || this.headers['content-type'])
this.headers && (this.headers["Content-Type"] || this.headers["CONTENT-TYPE"] || this.headers["content-type"])
);
}

private isFormUrlEncoded(contentType?: string): boolean {
return contentType?.toUpperCase().includes('APPLICATION/X-WWW-FORM-URLENCODED');
return contentType?.toUpperCase().includes("APPLICATION/X-WWW-FORM-URLENCODED");
}

private isJSON(contentType: string): boolean {
return contentType?.toUpperCase().includes('APPLICATION/JSON');
return contentType?.toUpperCase().includes("APPLICATION/JSON");
}
}
58 changes: 29 additions & 29 deletions src/api/v1/wrapper.test.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import { apiGatewayEvent } from 'serverless-plugin-test-helper';
import { api, ApiSignature } from './wrapper';
import { apiGatewayEvent } from "serverless-plugin-test-helper";
import { api, ApiSignature } from "./wrapper";

describe('API wrapper', () => {
describe("API wrapper", () => {
const requestEvent = apiGatewayEvent({
body: JSON.stringify({ hello: 'world' }),
pathParameters: { proxy: 'not today' },
queryStringParameters: { name: 'a test' },
headers: { 'content-type': 'application/json', 'Test-Request': 'true' },
body: JSON.stringify({ hello: "world" }),
pathParameters: { proxy: "not today" },
queryStringParameters: { name: "a test" },
headers: { "content-type": "application/json", "test-request": "true" },
requestContext: {
connectionId: 'abc-123',
connectionId: "abc-123",
},
});
const context = {
callbackWaitsForEmptyEventLoop: false,
functionName: 'function-name',
functionVersion: '$LATEST',
invokedFunctionArn: 'arn:',
memoryLimitInMB: '128',
awsRequestId: 'request',
logGroupName: 'group',
logStreamName: 'stream',
functionName: "function-name",
functionVersion: "$LATEST",
invokedFunctionArn: "arn:",
memoryLimitInMB: "128",
awsRequestId: "request",
logGroupName: "group",
logStreamName: "stream",
getRemainingTimeInMillis: () => 2,
done: () => {},
fail: () => {},
succeed: () => {},
};
const callback = jest.fn((err, result) => (err ? new Error(err) : result));

it('Has expected properties and response functions', () => {
it("Has expected properties and response functions", () => {
function customHandler({
event,
websocket,
Expand All @@ -47,11 +47,11 @@ describe('API wrapper', () => {
custom,
}: ApiSignature) {
expect(event).toEqual(requestEvent);
expect(websocket.connectionId).toEqual('abc-123');
expect(body).toEqual({ hello: 'world' });
expect(path).toEqual({ proxy: 'not today' });
expect(query).toEqual({ name: 'a test' });
expect(headers['content-type']).toEqual('application/json');
expect(websocket.connectionId).toEqual("abc-123");
expect(body).toEqual({ hello: "world" });
expect(path).toEqual({ proxy: "not today" });
expect(query).toEqual({ name: "a test" });
expect(headers["content-type"]).toEqual("application/json");
expect(testRequest).toEqual(true);
expect(auth).toBeTruthy();
expect(success).toBeInstanceOf(Function);
Expand All @@ -61,12 +61,12 @@ describe('API wrapper', () => {
expect(redirect).toBeInstanceOf(Function);
expect(error).toBeInstanceOf(Function);
expect(custom).toBeInstanceOf(Function);
success({ body: 'success' });
success({ body: "success" });
}
api(customHandler)(requestEvent, context, callback);
});

it('Has expected properties and response functions with optional generic type', () => {
it("Has expected properties and response functions with optional generic type", () => {
interface CustomType {
Message: string;
Id: number;
Expand All @@ -89,11 +89,11 @@ describe('API wrapper', () => {
custom,
}: ApiSignature<CustomType>) {
expect(event).toEqual(requestEvent);
expect(websocket.connectionId).toEqual('abc-123');
expect(body).toEqual({ hello: 'world' });
expect(path).toEqual({ proxy: 'not today' });
expect(query).toEqual({ name: 'a test' });
expect(headers['content-type']).toEqual('application/json');
expect(websocket.connectionId).toEqual("abc-123");
expect(body).toEqual({ hello: "world" });
expect(path).toEqual({ proxy: "not today" });
expect(query).toEqual({ name: "a test" });
expect(headers["content-type"]).toEqual("application/json");
expect(testRequest).toEqual(true);
expect(auth).toBeTruthy();
expect(success).toBeInstanceOf(Function);
Expand All @@ -103,7 +103,7 @@ describe('API wrapper', () => {
expect(redirect).toBeInstanceOf(Function);
expect(error).toBeInstanceOf(Function);
expect(custom).toBeInstanceOf(Function);
success({ body: 'success' });
success({ body: "success" });
}
api(customHandler)(requestEvent, context, callback);
});
Expand Down
Loading

0 comments on commit 58d7423

Please sign in to comment.