DEV Community

Cover image for How to test server in vanilla Deno?
WJH
WJH

Posted on

5

How to test server in vanilla Deno?

DISCLAIMER: the method provided in this article uses unstable API of Deno.

Overview

In this article, we will discuss how to test a server in Deno without using any 3rd party library, just vanilla Deno.

Prerequisite

Make sure you are using Deno v1.1.1.

Server

Suppose we have a file named server.ts with the following content:

import { serve } from "https://deno.land/std@v0.57.0/http/server.ts";

const server = serve({ port: 8000 });
console.log("Server listing on http://localhost:8000/");
for await (const request of server) {
  if(request.url === '/404') {
    request.respond({ 
      body: new TextEncoder().encode("Oops")
    });
  }
  else {
    request.respond({ 
      body: new TextEncoder().encode("Hello world!")
    });
  }
}

This file describe a very simple server, which will return "Hello world!" for any request, regardless of the method or URL, but will return "Oops" when that URL is "404".

You can try out this server by running:

deno run --allow-net server.ts

Then visit http://localhost:8000 and http://localhost:8000/404 in your browser, you should see Hello world! and Oops respectively.

Testing

To write the test, we will use:

  1. Deno.test for creating test cases
  2. assertEquals to make assertions
  3. Worker to spawn our server (note that Worker is unstable as of Deno@v1.1.1).
  4. fetch to make request

For our server, mainly we want to test out two things:

  1. GET /404 should return "Oops"
  2. GET any other URL should return "Hello world!"

Below is the code for testing, which should be stored in a file named server.test.ts:

import { assertEquals } from "https://deno.land/std@0.57.0/testing/asserts.ts";


const serverPath = new URL("./server.ts", import.meta.url).href;

// Spawn the server in a worker thread
const worker = new Worker(serverPath, { type: "module", deno: true })

// Wait for a moment to let the server start (this is a little hacky actually) 
await new Promise((resolve) => setTimeout(resolve, 3000));

// Write our test cases, note that we store them in a variable
// This is necessary such that we can keep track of how many test are there
// And so we can terminate the server properly after every test finished
const tests: {
  name: string;
  fn: () => Promise<void>;
}[] = [
    {
      name: 'GET /* should return "Hello world!"',
      fn: async () => {

        const response = await fetch("http://localhost:8000/");
        assertEquals(await response.text(), "Hello world!");
      }
    },
    {
      name: 'GET /404 should return "Oops"',
      fn: async () => {

        const response = await fetch("http://localhost:8000/404");
        assertEquals(await response.text(), "Oops");
      }
    }
  ]

// Utility function to keep track of number of ran tests
let numberOfRanTest = 0;
const done = () => {
  numberOfRanTest++;
  if (numberOfRanTest === tests.length) {
    worker.terminate();
  }
};

// Run the test
tests.forEach((test) => {
  Deno.test({
    name: test.name,

    // Note that we invoke `done` when the test fn finished
    fn: () => test.fn().then(done),

    // We need to set these options to false such that the test can exit with status 0
    sanitizeOps: false,
    sanitizeResources: false,
  });
});

To run the test:

deno test --unstable --allow-net --allow-read server.test.ts

You should see the following output after running the test:

Compile file:///Users/wongjiahau/repos/levo/core/.deno.test.ts
Server listing on http://localhost:8000/
running 2 tests
test GET /* should return "Hello world!" ... ok (13ms)
test GET /404 should return "Oops" ... ok (5ms)

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (18ms)

Conclusion

The method I presented here might be a little hacky, but it will be great if you're looking to test server without using any 3rd party libraries or framework.
If you have any questions feel free to post in comments. Thanks for reading! :D

Do your career a big favor. Join DEV. (The website you're on right now)

It takes one minute, it's free, and is worth it for your career.

Get started

Community matters

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

đź‘‹ Kindness is contagious

Immerse yourself in a wealth of knowledge with this piece, supported by the inclusive DEV Community—every developer, no matter where they are in their journey, is invited to contribute to our collective wisdom.

A simple “thank you” goes a long way—express your gratitude below in the comments!

Gathering insights enriches our journey on DEV and fortifies our community ties. Did you find this article valuable? Taking a moment to thank the author can have a significant impact.

Okay