DEV Community

Anish Karandikar
Anish Karandikar

Posted on • Edited on

Code coverage for a running Deno server

Deno (a modern Rust based TypeScript runtime) comes with code coverage measurement built in. Unfortunately, right now, its only supported for deno test but not for deno run.

This seems unnecessarily limiting, since it makes measuring coverage in a running Deno server by running API tests against it convoluted - but not impossible. This blog outlines a workaround that lets you achieve just this. Thanks to an idea from zachauten.

Let's say you had a bunch of Postman API tests written up for testing a Deno HTTP REST API server that you execute using the excellent newman CLI collection runner. Further, lets say you wanted to measure code coverage from running these API tests.

You would think you would be able to do something like this:

# Start Deno HTTP server and put it in background
deno run --coverage ./main.ts &
export PID=$!

# Run Postman API tests using newman
npx newman run ./api-tests.postman.json  

# Kill server to generate coverage
kill $PID
Enter fullscreen mode Exit fullscreen mode

Unfortunately, the above does not work because deno run --coverage is not supported.

Instead, the trick is to do all these steps (start server, run API tests, stop server) inside a Deno test and then use deno test --coverage. Sigh 😞. Seems labyrinthine but here is how to do it.

Step 1: Make your server a testable module

Make sure that your server is in a form that can be consumed from a Deno test and started and stopped there. For example a simple server can look like:

// server.ts
export function requestHandler(_req: Request): Promise<Response> {
  return Promise.resolve(new Response("Hello, world!"));
}
Enter fullscreen mode Exit fullscreen mode

This server can also be consumed from your main entry point thus:

// main.ts
import { serve } from "std/http/server.ts";
import { requestHandler } from "./server.ts";

serve(requestHandler);
Enter fullscreen mode Exit fullscreen mode

Step 2: Write a test that calls the server

Now write a test that does the following:

  1. Start server with abort controller
  2. Shell out to run newman API tests
  3. Stop server using abort controller

For example:

// server_test.ts
import { assert } from "std/testing/asserts.ts";
import { serve } from "std/http/server.ts";
import { requestHandler } from "./server.ts";

Deno.test("API Tests", async () => {
  // Start server (with abort controller)
  const controller = new AbortController();
  const { signal } = controller;
  const server = serve(requestHandler, { signal });

  // Run API tests
  const p = Deno.run({
    cmd: ["npx", "newman", "run", "./api-tests.postman.json"],
  });
  const { success } = await p.status();
  p.close();
  assert(success);

  // Stop server (using abort controller)
  controller.abort();

  // Wait for server to be closed
  await server;
});

Enter fullscreen mode Exit fullscreen mode

Step 3: Run test in coverage mode

Finally, we can run the server test with the --coverage flag.

deno test --allow-net --allow-run --coverage=coverage ./server_test.ts
Enter fullscreen mode Exit fullscreen mode

This will run the outer server_test.ts in coverage mode, generating code coverage in the coverage folder which can be further processed. See help on Deno coverage.

Conclusion

Hopefully, in the long run, Deno will introduce a deno run --coverage option. Till then, this workaround will have to do.

For a more fleshed out version of the code in this post, please see:

GitHub logo anishkny / deno-api-tests-coverage

Measure code coverage of a Deno server when running Postman (newman) API tests

Deno API Tests Coverage

Coverage Status

Demonstrates code coverage measurement of a Deno server when running Postman (newman) API tests.

See accompanying blog post for more details.

Requirements

Deno v1.26 (or higher) installed and available on path.

Usage

Clone this repository and execute:

deno task test
Enter fullscreen mode Exit fullscreen mode

This runs the test file ./test/server_test.ts and collects resulting code coverage.

The test file takes the following steps:

  1. Start the Deno server to be tested (src/server.ts).
  2. Run Postman API tests using newman in a subprocess.
  3. Stop the server.

Background

Deno lacks a way to measure code coverage of a server when running API tests. See this discussion on the Deno repo.

Ideally, there would be a way to start a server thus:

deno run --coverage=coverage src/server.ts # Doesn't work
# Run API tests
# Kill server
Enter fullscreen mode Exit fullscreen mode

Instead you have to start the server, run API tests by shelling out to a process…

Top comments (0)