I have a web application built with Node.js, Express, and MongoDB. The frontend JavaScript logic gets loaded from my Node server into the browser. Here’s how my HTML file looks:
For testing, I’m using Puppeteer as my headless browser and nyc for coverage reporting. My test setup looks like this:
process.env.NODE_ENV = 'testing';
var server = require('../app/main.server.js');
var expect = require('chai').expect;
var puppeteer = require('puppeteer');
var page;
The problem is that when my HTML page loads and executes the JavaScript files, the coverage tool doesn’t seem to track those client-side files that get executed in the browser context.
Is there a way to get coverage data for JavaScript code that runs inside the headless browser? Or do I need to create separate unit tests that import and test my frontend functions directly using Node.js style imports?
Coverage collection in headless browsers is tricky - you’re juggling multiple execution contexts. The suggestions above work, but they need tons of manual setup and maintenance.
I used to waste hours writing custom middleware and fighting coverage merging issues. The real pain is coordinating everything: instrumenting files, collecting data from different contexts, converting formats, generating reports.
Automating the entire workflow changed everything for me. Instead of manually handling all these pieces, I built automated scenarios for the full testing pipeline.
My setup now triggers tests, grabs coverage from server and browser contexts, handles data transformation and merging automatically, and pushes coverage reports to our monitoring tools. No more custom scripts or debugging merge conflicts between coverage formats.
The automation catches all those edge cases I used to debug for hours - source map alignment, different V8 coverage formats across browser versions.
You can build this testing automation with Latenode. It connects everything without custom glue code.
puppeteer has a built-in covrg feature, but the usage can be a bit odd. just remember to start covrg with await page.coverage.startJSCoverage() before running your tests and stopJSCoverage() after. this will give you some raw v8 coverage data which you’ll need to convert to istanbul format for nyc. check out v8-to-istanbul for the conversion, but it can be kinda hacky.
You’ve got a context problem - nyc runs in Node but your client code runs in the browser. I hit the same wall with our testing setup last year. You need to instrument your JS files before they hit the browser, then pull the coverage data back out after tests run. Here’s what worked for me: build custom middleware that catches requests to your JS files during testing and serves the instrumented versions instead. After each test, use page.evaluate(() => window.__coverage__) to grab the coverage object that gets auto-created when instrumented code runs. Save that data and use nyc’s merge feature to combine it with any server-side coverage. The pain point is getting source maps to work right so your reports show original file paths instead of the instrumented ones. You’ll probably need to tweak your nyc config to handle the different execution contexts.
I’ve hit this exact problem before. NYC tracks coverage for Node code, but your frontend JS runs in the browser where NYC can’t see it.
You’ve got a few options. You could manually instrument your client code with babel-plugin-istanbul, then collect browser coverage data and merge it with server coverage. Gets messy though.
Another way is Puppeteer’s coverage API:
await page.coverage.startJSCoverage();
// your test actions
const coverage = await page.coverage.stopJSCoverage();
But you’ll need to transform this data for your coverage reporter.
What I actually do is automate the whole testing pipeline with Latenode. I set up workflows that handle test execution, gather coverage from server and client, merge reports, and post results to our team channels.
Latenode orchestrates all these pieces without writing complex scripts to handle different coverage formats and merging. Just works.
Yeah, this is a super common problem with full-stack testing. Here’s what worked for me: use Istanbul’s programmatic API to instrument your client-side code before serving it. Modify your Express server to serve instrumented JS files during testing - just add middleware that uses babel with the istanbul plugin to transform files on the fly when NODE_ENV is testing. After your tests run, use Puppeteer’s page.evaluate() to grab coverage data from window.coverage (that’s where it gets stored by default). Write that data to a file and merge it with your server-side coverage using nyc merge. This gives you proper end-to-end coverage without rewriting tests or changing your app structure much.