Skip to content

Commit 1bd093c

Browse files
committed
Examples with fastify added and working. Fixed the nyc issue (all: true does not work..)
1 parent 4fd4419 commit 1bd093c

File tree

15 files changed

+129
-79
lines changed

15 files changed

+129
-79
lines changed

.mocharc.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,9 @@ require:
55
recursive: true
66
color: true
77
exit: true
8+
extension:
9+
- ts
10+
- test.ts
11+
ignore:
12+
# this is so that mocha doesn'T auto execute app.ts before the tests does load it.
13+
- "**/src/app.ts"

.nycrc.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# according to https://github.com/istanbuljs/istanbuljs/tree/master/packages/nyc-config-typescript
22
extends: "@istanbuljs/nyc-config-typescript"
3-
all: true
43

54
reporter:
65
- html
@@ -13,7 +12,7 @@ report-dir: coverage
1312

1413
# Coverage gates
1514
check-coverage: true
16-
functions: 90
15+
functions: 80
1716
lines: 80
1817
statements: 80
1918
branches: 70

.vscode/launch.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
2323
"args": [
2424
"--no-timeouts",
25-
"${workspaceFolder}/src/**/*.test.ts",
26-
"${workspaceFolder}/test/**/*.ts"
25+
"${workspaceFolder}/src",
26+
"${workspaceFolder}/test"
2727
],
2828
"internalConsoleOptions": "openOnSessionStart"
2929
},

README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,7 @@ Whilst working with typescript for a while now I found that most examples on the
3737
* Out of the box VsCode config for debugging app + tests no matter where with proper sourcemaps
3838
* Multi stage docker build
3939
* All type infos needed as well
40-
41-
I will probably extend to show off:
42-
43-
* Fastify with native async await in Typescript
40+
* Fastify with native async await in Typescript, including mocked / stubbed and spy tests as well as using inject to test the calls
4441
* Sinon for mocking / stubbing
4542

4643
The biggest challenge was trying to make code coverage work without ts-node which unfortunately wasn't really possible. It kindof worked but did not track any files that were not called in any test counteracting the purpose of finding uncovered code. So this template uses ts-node for all test execution and a transpiled build (no ts-node hence for "prod") to run the app.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"lint": "eslint src",
1010
"build": "npm run clean && npm run lint && tsc -p .",
1111
"start": "npm run build && node build/app.js",
12-
"test": "npm run lint && nyc mocha src/**/*.test.ts test/**/*.ts" ,
12+
"test": "npm run lint && nyc mocha src test",
1313
"docker": "docker build -t typescript-node-template ."
1414
},
1515
"repository": {

src/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ export async function stop(): Promise<void> {
1818
await app.server.close();
1919
}
2020

21-
// start();
21+
start();

src/handler/Persons.test.ts

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/handler/hello.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
import { expect } from "chai";
3+
import { hello } from "./hello";
4+
import { fastify} from "fastify";
5+
6+
describe("Hello", () => {
7+
it("handler", async () => {
8+
const app = fastify();
9+
app.get("/", hello);
10+
const response = await app.inject({
11+
method: "GET",
12+
url: "/",
13+
});
14+
expect(response.statusCode).to.equal(200);
15+
expect(response.headers["content-type"]).to.equal("text/html; charset=utf-8");
16+
expect(response.body).to.contain("Hallo!");
17+
});
18+
});

src/handler/hello.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { FastifyRequest, FastifyReply } from "fastify";
2+
3+
export async function hello(req: FastifyRequest, reply: FastifyReply): Promise<string> {
4+
reply.type("text/html; charset=utf-8").code(200);
5+
return "<h1>Hallo!</h1><a href='/persons'>Fetch persons here</a>";
6+
}

src/handler/persons.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
import { expect } from "chai";
3+
import { getAll } from "./persons";
4+
import { fastify} from "fastify";
5+
6+
describe("Persons", () => {
7+
it("handler", async () => {
8+
const app = fastify();
9+
app.get("/", getAll);
10+
const response = await app.inject({
11+
method: "GET",
12+
url: "/",
13+
});
14+
expect(response.statusCode).to.equal(200);
15+
expect(response.headers["content-type"]).to.equal("application/json; charset=utf-8");
16+
const persons = JSON.parse(response.body);
17+
expect(persons.length).to.equal(1);
18+
expect(persons[0].firstName).to.equal("Rick");
19+
expect(persons[0].lastName).to.equal("Sanchez");
20+
});
21+
});

src/handler/persons.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
// import { FastifyRequest, FastifyReply } from "fastify";
1+
import { FastifyRequest, FastifyReply } from "fastify";
22
import { Person } from "../types/Person";
33

4-
export async function getAll(/* req: FastifyRequest, reply: FastifyReply */): Promise<Person[]> {
5-
// reply.type("application/json").code(200);
4+
export async function getAll(req: FastifyRequest, reply: FastifyReply): Promise<Person[]> {
5+
reply.type("application/json; charset=utf-8").code(200);
66
return [new Person({
77
firstName: "Rick",
88
lastName: "Sanchez",

src/routes.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { FastifyInstance } from "fastify";
2-
import * as persons from "./handler/persons";
2+
import { getAll } from "./handler/persons";
3+
import { hello } from "./handler/hello";
34

45
export function register(app: FastifyInstance): void {
5-
app.get("/persons", persons.getAll);
6+
app.get("/", hello);
7+
app.get("/persons", getAll);
68
}

src/unused.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// intentionally uncovered to show nyc corectly finds unused files as well.
2+
export function unused(): void {
3+
console.log("This should be uncovered code");
4+
}

test/app.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
import { expect, use } from "chai";
3+
import * as chaiAsPromised from "chai-as-promised";
4+
import * as sinon from "sinon";
5+
import * as routes from "../src/routes";
6+
import * as fastify from "fastify";
7+
8+
use(chaiAsPromised);
9+
describe("Integration", () => {
10+
11+
let sandbox: sinon.SinonSandbox;
12+
beforeEach(() => {
13+
sandbox = sinon.createSandbox();
14+
});
15+
16+
afterEach(() => {
17+
sandbox.restore();
18+
});
19+
20+
const fakeFastify: any = {
21+
listen: sinon.spy(),
22+
get: sinon.spy(),
23+
log: {
24+
error: sinon.spy(),
25+
},
26+
server: {
27+
close: sinon.spy(),
28+
},
29+
};
30+
31+
before(() => {
32+
const fastifyStub = sinon.stub(fastify, "fastify");
33+
fastifyStub.returns(fakeFastify);
34+
});
35+
36+
let app: any;
37+
it("Successful app startup", async () => {
38+
const mock = sandbox.mock(routes);
39+
40+
// conditional loading as we can only test this when module loads FIRST time as its auto executing!
41+
// This is just as app auto executes itself on start
42+
app = await import("../src/app");
43+
44+
mock.expects("register").calledOnce;
45+
expect(fakeFastify.listen.calledOnce, "listen called once").to.be.true;
46+
expect(fakeFastify.get.calledTwice, "get called twice").to.be.true;
47+
});
48+
49+
it("Failed app startup", async () => {
50+
const exitStub = sandbox.stub(process, "exit");
51+
fakeFastify.listen = () => { throw new Error(); };
52+
await app.start();
53+
expect(fakeFastify.log.error.calledOnce, "log.error called once").to.be.true;
54+
expect(exitStub.calledOnce, "process.exit called once").to.be.true;
55+
});
56+
57+
it("Close the server", async () => {
58+
await app.stop();
59+
expect(fakeFastify.server.close.calledOnce, "server close called once").to.be.true;
60+
});
61+
});

test/integration.ts

Lines changed: 0 additions & 53 deletions
This file was deleted.

0 commit comments

Comments
 (0)