avatarMarcos Henrique da Silva

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

8572

Abstract

a file called <code>tsconfig.json</code> and paste the following:</p><div id="e4d6"><pre><span class="hljs-punctuation">{</span> <span class="hljs-attr">"compilerOptions"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span> <span class="hljs-attr">"target"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"es2016"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"module"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"commonjs"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"outDir"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"./dist"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"strict"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"esModuleInterop"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"inlineSourceMap"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"include"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-string">"app//*.ts"</span> <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"exclude"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-string">"node_modules"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"test//*.ts"</span> <span class="hljs-punctuation">]</span> <span class="hljs-punctuation">}</span></pre></div><p id="2bd9">Now we have everything that we need to start coding our tests. For that, again at the root folder let’s create a folder called <code>test</code> and inside it a file called <code>app.test.ts</code> with the following:</p><div id="4dd9"><pre><span class="hljs-keyword">import</span> {expect} <span class="hljs-keyword">from</span> <span class="hljs-string">'chai'</span>;</pre></div><div id="1ce7"><pre>describe(<span class="hljs-string">"Index Test"</span>, () => { it('should always pass', function () { expect(<span class="hljs-name">true</span>).to.equal(<span class="hljs-name">true</span>)<span class="hljs-comment">;</span> })<span class="hljs-comment">;</span> })<span class="hljs-comment">;</span></pre></div><p id="6550">What we want here is just to make sure that we <b>configured</b> everything correctly. When we will run <code>npm run test-dev</code> we are now expecting to execute the <code>Index Test</code> describe function and to use <code>expect</code> from chai to see that everything is working. Made it? good!</p><p id="9ad5">Now, at the <code>test</code> folder, let’s create an <code>users</code> folder and a <code>users.test.ts</code> file. Here is a place that we will start to code the tests for the users. Let’s add now the following code:</p><div id="485b"><pre><span class="hljs-keyword">import</span> app <span class="hljs-keyword">from</span> <span class="hljs-string">'../../app/app'</span>; <span class="hljs-keyword">import</span> {agent <span class="hljs-keyword">as</span> request} <span class="hljs-keyword">from</span> <span class="hljs-string">'supertest'</span>; <span class="hljs-keyword">import</span> {expect} <span class="hljs-keyword">from</span> <span class="hljs-string">'chai'</span>;</pre></div><div id="9e4a"><pre><span class="hljs-attribute">let firstUserIdTest</span> = <span class="hljs-string">''</span>; <span class="hljs-attribute">let firstUserBody</span> = { <span class="hljs-string">"name"</span> : <span class="hljs-string">"Marcos Silva"</span>, <span class="hljs-string">"email"</span> : <span class="hljs-string">"[email protected]"</span>, <span class="hljs-string">"password"</span> : <span class="hljs-string">"Pass#your!word"</span> };</pre></div><div id="e080"><pre>it('should POST /users', async function () { const res = await request(<span class="hljs-name">app</span>) .post('/users').send(<span class="hljs-name">firstUserBody</span>)<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.status).to.equal(<span class="hljs-number">201</span>)<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.body).not.to.be.empty<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.body).to.be.an(<span class="hljs-string">"object"</span>)<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.body.id).to.be.an('string')<span class="hljs-comment">;</span> firstUserIdTest = res.body.id<span class="hljs-comment">;</span> })<span class="hljs-comment">;</span></pre></div><div id="8e7d"><pre>it(should GET /users/<span class="hljs-symbol">:userId</span>, async function () { const res = await request(<span class="hljs-name">app</span>) .get(/users/${firstUserIdTest}).send()<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.status).to.equal(<span class="hljs-number">200</span>)<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.body).not.to.be.empty<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.body).to.be.an(<span class="hljs-string">"object"</span>)<span class="hljs-comment">;</span></pre></div><div id="b313"><pre><span class="hljs-built_in">expect</span>(res.body.id)<span class="hljs-selector-class">.to</span><span class="hljs-selector-class">.be</span><span class="hljs-selector-class">.an</span>('string'); <span class="hljs-built_in">expect</span>(res.body.name)<span class="hljs-selector-class">.to</span><span class="hljs-selector-class">.be</span><span class="hljs-selector-class">.equals</span>(firstUserBody.name); <span class="hljs-built_in">expect</span>(res.body.email)<span class="hljs-selector-class">.to</span><span class="hljs-selector-class">.be</span><span class="hljs-selector-class">.equals</span>(firstUserBody.email); <span class="hljs-built_in">expect</span>(res.body.id)<span class="hljs-selector-class">.to</span><span class="hljs-selector-class">.be</span><span class="hljs-selector-class">.equals</span>(firstUserIdTest); });</pre></div><div id="c9ec"><pre>it(should GET /users, async function () { const res = await request(<span class="hljs-name">app</span>) .get(/users).send()<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.status).to.equal(<span class="hljs-number">200</span>)<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.body).not.to.be.empty<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.body).to.be.an(<span class="hljs-string">"array"</span>)<span class="hljs-comment">;</span></pre></div><div id="8dbc"><pre><span class="hljs-built_in">expect</span>(res.body[<span class="hljs-number">0</span>].id)<span class="hljs-selector-class">.to</span><span class="hljs-selector-class">.be</span><span class="hljs-selector-class">.an</span>('string'); <span class="hljs-built_in">expect</span>(res.body[<span class="hljs-number">0</span>].name)<span class="hljs-selector-class">.to</span><span class="hljs-selector-class">.be</span><span class="hljs-selector-class">.equals</span>(firstUserBody.name); <span class="hljs-built_in">expect</span>(res.body[<span class="hljs-number">0</span>].email)<span class="hljs-selector-class">.to</span><span class="hljs-selector-class">.be</span><span class="hljs-selector-class">.equals</span>(firstUserBody.email); <span class="hljs-built_in">expect</span>(res.body[<span class="hljs-number">0</span>].id)<span class="hljs-selector-class">.to</span><span class="hljs-selector-class">.be</span><span class="hljs-selector-class">.equals</span>(firstUserIdTest); });</pre></div><div id="460f"><pre><span class="hljs-title function_">it</span>(<span class="hljs-string">'should PUT /users/:userId'</span>, <span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) { <span class="hljs-key

Options

word">const</span> name = <span class="hljs-string">'Jose'</span>; <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> <span class="hljs-title function_">request</span>(app) .<span class="hljs-title function_">put</span>(<span class="hljs-string">/users/<span class="hljs-subst">${firstUserIdTest}</span></span>).<span class="hljs-title function_">send</span>({ <span class="hljs-attr">name</span>: name, <span class="hljs-attr">email</span>: firstUserBody.<span class="hljs-property">email</span> }); <span class="hljs-title function_">expect</span>(res.<span class="hljs-property">status</span>).<span class="hljs-property">to</span>.<span class="hljs-title function_">equal</span>(<span class="hljs-number">204</span>); });</pre></div><div id="de72"><pre><span class="hljs-literal">it</span>(should GET <span class="hljs-regexp">/users/</span>:userId <span class="hljs-keyword">to</span> have a <span class="hljs-keyword">new</span> name, <span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> () { <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app) .get(<span class="hljs-regexp">/users/</span>${firstUserIdTest}).send(); expect(res.status).<span class="hljs-keyword">to</span>.equal(<span class="hljs-number">200</span>); expect(res.body).<span class="hljs-keyword">not</span>.<span class="hljs-keyword">to</span>.be.empty; expect(res.body).<span class="hljs-keyword">to</span>.be.an(<span class="hljs-string">"object"</span>);</pre></div><div id="e768"><pre><span class="hljs-built_in">expect</span>(res.body.id)<span class="hljs-selector-class">.to</span><span class="hljs-selector-class">.be</span><span class="hljs-selector-class">.an</span>('string'); <span class="hljs-built_in">expect</span>(res.body.name)<span class="hljs-selector-class">.to</span><span class="hljs-selector-class">.be</span><span class="hljs-selector-class">.not</span><span class="hljs-selector-class">.equals</span>(firstUserBody.name); <span class="hljs-built_in">expect</span>(res.body.email)<span class="hljs-selector-class">.to</span><span class="hljs-selector-class">.be</span><span class="hljs-selector-class">.equals</span>(firstUserBody.email); <span class="hljs-built_in">expect</span>(res.body.id)<span class="hljs-selector-class">.to</span><span class="hljs-selector-class">.be</span><span class="hljs-selector-class">.equals</span>(firstUserIdTest); });</pre></div><div id="977b"><pre><span class="hljs-title function_">it</span>(<span class="hljs-string">'should PATCH /users/:userId'</span>, <span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) { <span class="hljs-keyword">let</span> newField = {<span class="hljs-attr">description</span>: <span class="hljs-string">'My user description'</span>}; <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> <span class="hljs-title function_">request</span>(app) .<span class="hljs-title function_">patch</span>(<span class="hljs-string">/users/<span class="hljs-subst">${firstUserIdTest}</span></span>).<span class="hljs-title function_">send</span>(newField); <span class="hljs-title function_">expect</span>(res.<span class="hljs-property">status</span>).<span class="hljs-property">to</span>.<span class="hljs-title function_">equal</span>(<span class="hljs-number">204</span>); });</pre></div><div id="4a12"><pre>it(should GET /users/<span class="hljs-symbol">:userId</span> to have a new field called description, async function () { const res = await request(<span class="hljs-name">app</span>) .get(/users/${firstUserIdTest}).send()<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.status).to.equal(<span class="hljs-number">200</span>)<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.body).not.to.be.empty<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.body).to.be.an(<span class="hljs-string">"object"</span>)<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.body.id).to.be.an('string')<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.body.description).to.be.equals('My user description')<span class="hljs-comment">;</span> })<span class="hljs-comment">;</span></pre></div><div id="ce18"><pre>it('should DELETE /users/<span class="hljs-symbol">:userId</span>', async function () { const res = await request(<span class="hljs-name">app</span>) .delete(/users/${firstUserIdTest}).send()<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.status).to.equal(<span class="hljs-number">204</span>)<span class="hljs-comment">;</span> })<span class="hljs-comment">;</span></pre></div><div id="158b"><pre>it(should GET /users, async function () { const res = await request(<span class="hljs-name">app</span>) .get(/users).send()<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.status).to.equal(<span class="hljs-number">200</span>)<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.body).to.be.an(<span class="hljs-string">"array"</span>)<span class="hljs-comment">;</span> expect(<span class="hljs-name">res</span>.body).to.be.empty<span class="hljs-comment">;</span> })<span class="hljs-comment">;</span></pre></div><p id="2c89">What we aim here is to test our endpoints, first creating a testing user, testing it and after removing him. <b>BUT</b> before running, we need to add a final touch at our <b>app.ts</b> file adding at the end of the file the following</p><div id="6684"><pre><span class="hljs-built_in">export</span><span class="hljs-built_in"> default </span>app;</pre></div><p id="14d9">And that’s it. You can run now <code>npm start test-dev</code> and see the results. I will not be in a deep explanation on how everything works and my highly suggestion is to read each of <code>it</code> functions that are calling a different endpoint at our API, and try to understand how the <b>expect</b> function is being used. Also, try to change the API code to not work as you expect and you will see the errors that Mocha will give.</p><p id="ba9b">In this article we configured the tests, trying to be as much as direct as possible with a lack of hundreds of line of explanation. Each library here could be an entire article just to explain the basics. If you are curious enough please go for their websites and read more about each of it:</p><ul><li><a href="https://www.chaijs.com/">chai</a></li><li><a href="https://mochajs.org/">mocha</a></li><li><a href="https://nodemon.io/">nodemon</a></li><li><a href="https://github.com/visionmedia/supertest">supertest</a></li></ul><p id="d9b4">If you have any doubts on how to use please feel free to set some comments on this article.</p><p id="4f40">Thanks for reading and see you at the <a href="https://readmedium.com/another-expressjs-api-tutorial-for-2020-part-08-auth-module-fa896463c216">next article</a>!</p><div id="13fc" class="link-block"> <a href="https://readmedium.com/another-expressjs-api-tutorial-for-2020-part-08-auth-module-fa896463c216"> <div> <div> <h2>Another ExpressJS API tutorial for 2020, part 08 — Auth module</h2> <div><h3>We reached the part number 8 of how to build an API using ExpressJS and Typescript. Today is time to configure our…</h3></div> <div><p>medium.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*eWYm3Dm7s0t8lLWYRW4pow.jpeg)"></div> </div> </div> </a> </div><p id="d093">tips:</p><ul><li>the full code of this article is <a href="https://github.com/makinhs/expressjs-api-tutorial/tree/007-configurando-testes">here</a></li><li>don’t forget to use a nice app to test your API such as <a href="https://www.postman.com/">Postman</a> or <a href="https://insomnia.rest/">Insomnia</a></li><li>I know you still didn’t… Read the ExpressJS <a href="https://expressjs.com/en/4x/api.html">documentation</a>!</li><li>Complete project is <a href="https://github.com/makinhs/expressjs-api-tutorial">here</a>! (Includes even the non existing articles yet)</li></ul></article></body>

Another ExpressJS API tutorial for 2021, part 07 — Your first tests

We already configured some routes, some services and middlewares, now it is time to introduce some testings to our API

Hi there, if it is your first time arriving here we are creating a series on how to build an API using ExpressJS and Typescript. The first article can be found here.

Just as a quick overview, here is the series of articles that we are writing:

In this articles we are going to configure our project to run tests and make sure that our implementation is working as how we are expecting. First of all, the code to continue on this article is here.

Let’s update our package.json first:

{
  "name": "expressjs-api-tutorial",
  "version": "0.0.1",
  "description": "Tutorial of how to create a REST API using ExpressJS",
  "main": "dist/app.js",
  "scripts": {
    "tsc": "tsc",
    "start": "npm run tsc && node ./dist/app.js",
    "test-dev": "nodemon --watch . --ext ts --exec \"mocha -r ts-node/register test/**/*.test.ts\"",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/makinhs/expressjs-api-tutorial.git"
  },
  "keywords": [
    "REST",
    "API",
    "ExpressJS",
    "NodeJS"
  ],
  "author": "Marcos Silva",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/makinhs/expressjs-api-tutorial/issues"
  },
  "homepage": "https://github.com/makinhs/expressjs-api-tutorial#readme",
  "dependencies": {
    "argon2-pass": "^1.0.2",
    "express": "^4.17.1",
    "short-uuid": "^3.1.1"
  },
  "devDependencies": {
    "@types/chai": "^4.2.8",
    "@types/express": "^4.17.2",
    "@types/mocha": "^7.0.1",
    "@types/mongoose": "^5.7.0",
    "@types/node": "^13.5.2",
    "@types/supertest": "^2.0.8",
    "chai": "^4.2.0",
    "mocha": "^7.0.1",
    "nodemon": "^2.0.2",
    "source-map-support": "^0.5.16",
    "supertest": "^4.0.2",
    "ts-node": "^8.6.2",
    "tslint": "^6.0.0",
    "typescript": "^3.7.5"
  }
}

Everything that we are going to use in this article are in the devDependencies which are used locally and not when the app will be running. The @types are installed to help our IDE to understand the signature of what we are using, which will speed up the way we are coding.

For testing we are going to use:

We are going to use these libraries combined to make our tests to run. Mocha will manage our application to run the tests which their library, meanwhile we are going to use chai to validate some testings, supertest to do end to end testing, calling our API, and nodemon to rerun our tests every time that we will change our source code. It seems complicated but it is super easy.

Another part that is very important is the script we added at the npm:

"test-dev": "nodemon --watch . --ext ts --exec \"mocha -r ts-node/register test/**/*.test.ts\"",

We configured now a command that when we will run at our terminal npm run test-dev then our node application will use nodemon to build the application, run mocha to execute all the tests inside a folder called test (that we will create) and then run the application.

Now let’s continue configuring what we need.

At your root folder, create a file called tsconfig.json and paste the following:

{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "outDir": "./dist",
    "strict": true,
    "esModuleInterop": true,
    "inlineSourceMap": true,
  },
  "include": [
    "app/**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "test/**/*.ts"
  ]
}

Now we have everything that we need to start coding our tests. For that, again at the root folder let’s create a folder called test and inside it a file called app.test.ts with the following:

import {expect} from 'chai';
describe("Index Test", () => {
    it('should always pass', function () {
        expect(true).to.equal(true);
    });
});

What we want here is just to make sure that we configured everything correctly. When we will run npm run test-dev we are now expecting to execute the Index Test describe function and to use expect from chai to see that everything is working. Made it? good!

Now, at the test folder, let’s create an users folder and a users.test.ts file. Here is a place that we will start to code the tests for the users. Let’s add now the following code:

import app from '../../app/app';
import {agent as request} from 'supertest';
import {expect} from 'chai';
let firstUserIdTest = '';
let firstUserBody = {
    "name" : "Marcos Silva",
    "email" : "[email protected]",
    "password" : "Pass#your!word"
};
it('should POST /users', async function () {
    const res = await request(app)
        .post('/users').send(firstUserBody);
    expect(res.status).to.equal(201);
    expect(res.body).not.to.be.empty;
    expect(res.body).to.be.an("object");
    expect(res.body.id).to.be.an('string');
    firstUserIdTest = res.body.id;
});
it(`should GET /users/:userId`, async function () {
    const res = await request(app)
        .get(`/users/${firstUserIdTest}`).send();
    expect(res.status).to.equal(200);
    expect(res.body).not.to.be.empty;
    expect(res.body).to.be.an("object");
expect(res.body.id).to.be.an('string');
    expect(res.body.name).to.be.equals(firstUserBody.name);
    expect(res.body.email).to.be.equals(firstUserBody.email);
    expect(res.body.id).to.be.equals(firstUserIdTest);
});
it(`should GET /users`, async function () {
    const res = await request(app)
        .get(`/users`).send();
    expect(res.status).to.equal(200);
    expect(res.body).not.to.be.empty;
    expect(res.body).to.be.an("array");
expect(res.body[0].id).to.be.an('string');
    expect(res.body[0].name).to.be.equals(firstUserBody.name);
    expect(res.body[0].email).to.be.equals(firstUserBody.email);
    expect(res.body[0].id).to.be.equals(firstUserIdTest);
});
it('should PUT /users/:userId', async function () {
    const name = 'Jose';
    const res = await request(app)
        .put(`/users/${firstUserIdTest}`).send({
            name: name,
            email: firstUserBody.email
        });
    expect(res.status).to.equal(204);
});
it(`should GET /users/:userId to have a new name`, async function () {
    const res = await request(app)
        .get(`/users/${firstUserIdTest}`).send();
    expect(res.status).to.equal(200);
    expect(res.body).not.to.be.empty;
    expect(res.body).to.be.an("object");
expect(res.body.id).to.be.an('string');
    expect(res.body.name).to.be.not.equals(firstUserBody.name);
    expect(res.body.email).to.be.equals(firstUserBody.email);
    expect(res.body.id).to.be.equals(firstUserIdTest);
});
it('should PATCH /users/:userId', async function () {
    let newField = {description: 'My user description'};
    const res = await request(app)
        .patch(`/users/${firstUserIdTest}`).send(newField);
    expect(res.status).to.equal(204);
});
it(`should GET /users/:userId to have a new field called description`, async function () {
    const res = await request(app)
        .get(`/users/${firstUserIdTest}`).send();
    expect(res.status).to.equal(200);
    expect(res.body).not.to.be.empty;
    expect(res.body).to.be.an("object");
    expect(res.body.id).to.be.an('string');
    expect(res.body.description).to.be.equals('My user description');
});
it('should DELETE /users/:userId', async function () {
    const res = await request(app)
        .delete(`/users/${firstUserIdTest}`).send();
    expect(res.status).to.equal(204);
});
it(`should GET /users`, async function () {
    const res = await request(app)
        .get(`/users`).send();
    expect(res.status).to.equal(200);
    expect(res.body).to.be.an("array");
    expect(res.body).to.be.empty;
});

What we aim here is to test our endpoints, first creating a testing user, testing it and after removing him. BUT before running, we need to add a final touch at our app.ts file adding at the end of the file the following

export default app;

And that’s it. You can run now npm start test-dev and see the results. I will not be in a deep explanation on how everything works and my highly suggestion is to read each of it functions that are calling a different endpoint at our API, and try to understand how the expect function is being used. Also, try to change the API code to not work as you expect and you will see the errors that Mocha will give.

In this article we configured the tests, trying to be as much as direct as possible with a lack of hundreds of line of explanation. Each library here could be an entire article just to explain the basics. If you are curious enough please go for their websites and read more about each of it:

If you have any doubts on how to use please feel free to set some comments on this article.

Thanks for reading and see you at the next article!

tips:

  • the full code of this article is here
  • don’t forget to use a nice app to test your API such as Postman or Insomnia
  • I know you still didn’t… Read the ExpressJS documentation!
  • Complete project is here! (Includes even the non existing articles yet)
Expressjs
Typescript
Tutorial
Api Development
Nodejs
Recommended from ReadMedium