Skip to content

Commit

Permalink
Merge fix-792-handler-context-error
Browse files Browse the repository at this point in the history
  • Loading branch information
Travis committed Apr 12, 2020
2 parents 5943da4 + 5b22542 commit bb8ad15
Show file tree
Hide file tree
Showing 13 changed files with 186 additions and 81 deletions.
8 changes: 4 additions & 4 deletions .nycrc
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
"lcov"
],
"check-coverage": true,
"lines": 99.16,
"statements": 99.16,
"functions": 98.58,
"branches": 85.41
"lines": 99.25,
"statements": 99.24,
"functions": 98.9,
"branches": 88.13
}
11 changes: 7 additions & 4 deletions packages/common/src/mvc/decorators/params/request.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {RequestContext} from "@tsed/common";
import {Type} from "@tsed/core";
import {IParamOptions} from "../../interfaces/IParamOptions";
import {ParamTypes} from "../../models/ParamTypes";
Expand All @@ -7,13 +6,17 @@ import {UseFilter} from "./useFilter";

declare global {
namespace TsED {
export interface Request {}
export interface Request {
aborted: boolean;
}
}
}

export interface Request extends TsED.Request {}
export interface Request extends TsED.Request {
}

export interface Req extends TsED.Request {}
export interface Req extends TsED.Request {
}

/**
* Request service.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
import {Type} from "@tsed/core";
import {InjectorService} from "@tsed/di";
import {PlatformApplication} from "../../platform/services/PlatformApplication";

export function createPlatformApplication(injector: InjectorService, useClass?: Type<any>): void {
if (useClass) {
injector.addProvider(PlatformApplication, {
useClass
});

injector.invoke(PlatformApplication);
} else {
injector.forkProvider(PlatformApplication);
}
export function createPlatformApplication(injector: InjectorService): void {
injector.forkProvider(PlatformApplication);
}
53 changes: 52 additions & 1 deletion packages/common/src/platform/domain/HandlerContext.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,16 @@ async function getHandlerContext({token, propertyKey, args}: any = {}) {
});
const request: any = new FakeRequest();
const response: any = new FakeResponse();
const next = () => {
};

const handlerContext: HandlerContext = new HandlerContext({
injector,
metadata,
request,
response,
args
args,
next
});

return {
Expand Down Expand Up @@ -255,4 +258,52 @@ describe("HandlerContext", () => {
expect(request.ctx.data).to.eq(undefined);
expect(response.headersSent).to.eq(true);
});
it("should do when request is aborted", async () => {
const {request, handlerContext} = await getHandlerContext({
token: Test,
propertyKey: "getValue",
args: []
});

request.aborted = true;
Sinon.stub(handlerContext, "next");

// WHEN
handlerContext.done(null, {});

// THEN
return handlerContext.next.should.not.have.been.called;
});
it("should do when request is detached", async () => {
const {request, handlerContext} = await getHandlerContext({
token: Test,
propertyKey: "getValue",
args: []
});

delete handlerContext.request;
Sinon.stub(handlerContext, "next");

// WHEN
handlerContext.done(null, {});

// THEN
return handlerContext.next.should.not.have.been.called;
});
it("should do when response is detached", async () => {
const {request, handlerContext} = await getHandlerContext({
token: Test,
propertyKey: "getValue",
args: []
});

delete handlerContext.response;
Sinon.stub(handlerContext, "next");

// WHEN
handlerContext.done(null, {});

// THEN
return handlerContext.next.should.not.have.been.called;
});
});
39 changes: 28 additions & 11 deletions packages/common/src/platform/domain/HandlerContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,25 @@ import {isObservable} from "rxjs";
import {HandlerMetadata} from "../../mvc/models/HandlerMetadata";
import {IHandlerContext} from "../interfaces/IHandlerContext";

const isFinish = (request: TsED.Request, response: TsED.Response) => {
if (!response || !request) {
return true;
}

return request.aborted || response.headersSent || response.writableEnded || response.writableFinished;
};

export class HandlerContext {
public injector: InjectorService;
public metadata: HandlerMetadata;
public request: any;
public response: any;
public request: TsED.Request;
public response: TsED.Response;
public err: any;
public args: any[];
private _isDone: boolean = false;
private _next: any;

constructor({injector, request, response, next, err, metadata, args}: Partial<IHandlerContext>) {
constructor({injector, request, response, next, err, metadata, args}: IHandlerContext) {
this.injector = injector!;
this.request = request;
this.response = response;
Expand All @@ -27,14 +35,25 @@ export class HandlerContext {
}

get isDone(): boolean {
const {response, request} = this;

// @ts-ignore
if (!this._isDone && (isFinish(request, response))) {
this.destroy();
}

return this._isDone;
}

get container() {
return this.request.ctx.container;
return this.request?.ctx?.container;
}

done(error: any, result?: any) {
if (this.isDone) {
return;
}

const {
metadata: {hasNextFunction},
request: {ctx}
Expand All @@ -45,8 +64,7 @@ export class HandlerContext {
}

if (!hasNextFunction) {
// @ts-ignore
if (!this.nextIsCalled && result !== undefined) {
if (!result !== undefined) {
ctx.data = result;
}
this.next();
Expand Down Expand Up @@ -82,6 +100,7 @@ export class HandlerContext {
}

if (isFunction(process)) {

// when process return a middleware
return process(request, response, next.bind(this));
}
Expand Down Expand Up @@ -114,13 +133,11 @@ export class HandlerContext {
}

next(error?: any) {
if (!this.isDone) {
const {response, _next} = this;
const {_next: next} = this;

this.destroy();
this.destroy();

return !response.headersSent ? _next(error) : undefined;
}
return next && next(error);
}

destroy() {
Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/platform/interfaces/IHandlerContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {HandlerMetadata, ParamMetadata} from "../../mvc";

export interface IHandlerContext {
injector: InjectorService;
request: TsED.Response;
request: TsED.Request;
response: TsED.Response;
next: TsED.NextFunction;
metadata: HandlerMetadata;
Expand Down
22 changes: 22 additions & 0 deletions packages/common/src/platform/services/FakeRawDriver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export const createFakeRawDriver = () => {
// istanbul ignore next
function FakeRawDriver() {
}

// istanbul ignore next
function use() {
return this;
}

FakeRawDriver.use = use;
FakeRawDriver.all = use;
FakeRawDriver.get = use;
FakeRawDriver.patch = use;
FakeRawDriver.post = use;
FakeRawDriver.put = use;
FakeRawDriver.head = use;
FakeRawDriver.delete = use;
FakeRawDriver.options = use;

return FakeRawDriver;
};
22 changes: 4 additions & 18 deletions packages/common/src/platform/services/PlatformApplication.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import {Injectable, ProviderScope} from "@tsed/di";
import {createFakeRawDriver} from "./FakeRawDriver";
import {PlatformDriver} from "./PlatformDriver";
import {PlatformHandler} from "./PlatformHandler";

declare global {
namespace TsED {
export interface Application {}
export interface Application {
}
}
}

Expand All @@ -21,22 +23,6 @@ export class PlatformApplication extends PlatformDriver<TsED.Application> {
}

protected static createRawApp(): any {
function fakeApp() {}

function use() {
return this;
}

fakeApp.use = use;
fakeApp.all = use;
fakeApp.get = use;
fakeApp.patch = use;
fakeApp.post = use;
fakeApp.put = use;
fakeApp.head = use;
fakeApp.delete = use;
fakeApp.options = use;

return fakeApp;
return createFakeRawDriver();
}
}
39 changes: 36 additions & 3 deletions packages/common/src/platform/services/PlatformHandler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import {PlatformHandler} from "./PlatformHandler";

function build(injector: InjectorService, type: string | ParamTypes | Type<any>, {expression, required}: any = {}) {
class Test {
test() {}
test() {
}
}

const param = new ParamMetadata({target: Test, propertyKey: "test", index: 0});
Expand All @@ -35,6 +36,7 @@ function build(injector: InjectorService, type: string | ParamTypes | Type<any>,
request,
response,
next,
args: [],
metadata: {} as any
});

Expand Down Expand Up @@ -66,7 +68,8 @@ class Test {
return error;
}

useErr(err: any, req: any, res: any, next: any) {}
useErr(err: any, req: any, res: any, next: any) {
}
}

describe("PlatformHandler", () => {
Expand Down Expand Up @@ -120,7 +123,8 @@ describe("PlatformHandler", () => {
sandbox.stub(injector, "getProvider").returns(undefined);

// WHEN
const handlerMetadata = platformHandler.createHandlerMetadata(() => {});
const handlerMetadata = platformHandler.createHandlerMetadata(() => {
});

// THEN
handlerMetadata.type.should.eq(HandlerType.FUNCTION);
Expand Down Expand Up @@ -211,6 +215,35 @@ describe("PlatformHandler", () => {
request.ctx.data.should.deep.eq(error);
}
));

it("should do nothing when request is aborted", inject(
[InjectorService, PlatformHandler],
async (injector: InjectorService, platformHandler: PlatformHandler) => {
// GIVEN
sandbox.stub(Test.prototype, "get").callsFake(o => o);
sandbox.stub(injector, "invoke").callsFake(() => new Test());

const request = new FakeRequest();
request.aborted = true;
const response = new FakeRequest();

const handlerMetadata = new HandlerMetadata({
token: Test,
target: Test,
type: HandlerType.CONTROLLER,
propertyKey: "get"
});

// WHEN
const handler = platformHandler.createHandler(handlerMetadata);
const next = Sinon.stub();

handler(request, response, next);

// THEN
return next.should.not.have.been.called;
}
));
});
describe("getParam()", () => {
it("should return REQUEST", inject(
Expand Down
Loading

0 comments on commit bb8ad15

Please sign in to comment.