#[SOLVED] Integration Test (Black Box) Coverage w/ NYC

1 messages · Page 1 of 1 (latest)

hollow mountain
#

Has anyone by chance been able to get code coverage with the integration (or e2e), when running their tests against a server not started in the tests?

For example with the following script I'd hope to achieve coverage:

nyc --silent npm run start & sleep 5 && npm run test:e2e && npx kill-port 3000 && nyc report

I created a sample repo, perhaps I'm configuring incorrectly? Any help would be hugely appreciated.

https://github.com/sethtomy/nest-coverage-test

GitHub

Contribute to sethtomy/nest-coverage-test development by creating an account on GitHub.

hollow mountain
#

Bump in case anyone here happens to know how to do this.

old jetty
#

Ah, found the issue. You need to import the source-map-support package, either via command line or in the main.ts file. Just adding import 'source-map-support' to your main.ts I was able to get this output:

> jest --config ./test/jest-e2e.json

 PASS  test/app.e2e-spec.ts
  ✓ Query Server (20 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.63 s, estimated 2 s
Ran all test suites.
Process on port 3000 killed
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   77.27 |      100 |      25 |   68.75 |                   
 app.controller.ts |    87.5 |      100 |      50 |   83.33 | 10                
 app.module.ts     |     100 |      100 |     100 |     100 |                   
 app.service.ts    |      80 |      100 |       0 |   66.66 | 6                 
 main.ts           |       0 |      100 |       0 |       0 | 7-10              
-------------------|---------|----------|---------|---------|-------------------

=============================== Coverage summary ===============================
Statements   : 77.27% ( 17/22 )
Branches     : 100% ( 0/0 )
Functions    : 25% ( 1/4 )
Lines        : 68.75% ( 11/16 )
================================================================================
hollow mountain
#

@old jetty thank you so much for looking!!

I added import 'source-map-support'; to line 1 of main.js with no luck along with other suggested imports from their documentation https://github.com/evanw/node-source-map-support.

Was there anything else you had to add to get coverage by chance? In case it's any help at all I'm running Node 16.19.0 on both Windows and macOS.

old jetty
#

Oh interesting. So, I think I had ended up running the server using node dist/main rather than nest start which seems to make a difference here, probably due to how node gets called under the hood of the nest start command. I want to try something different here and if it works I'll let you know

#

Nope. That didn't fix it either. However, having the server already up and running did for some reason

old jetty
#

Question: do you need to run the server in a separate process entirely?

hollow mountain
#

Not necessarily. The real goal here is that I can use the same test suite(s) for both integration (PRs and Code Coverage) and acceptance testing. So as long as I can achieve that I'm 👌🏼

old jetty
#

Okay. So, the important thing is that the test framework actually imports the server files (and I believe to some extent runs them) so that the coverage tracker library can properly track it

#

I've had success with uvu in the past as a fast test runner. I want to see if I can get this working for you though

hollow mountain
#

Thank you! I had similar setups in the past for other applications. (express + mocha + nyc, grpc + cucumber-js + nyc, and mali(grpc) + cucumber-js + nyc). I'm now a Nest lifer though NestJS so was hoping to get a similar thing going.

old jetty
#

Jest collects coverage on its own, by the way. If I can configure it to do that will that be enough?

hollow mountain
#

I think so?

For integration tests everything (server, tests, database) run in a docker compose. I need the tests to propagate failure and an lcov report generated.

For acceptance tests the tests target an external server. Here I only need test success/failure.

old jetty
#

Okay. I've got something working where jest starts and runs the server as well as closes it out afterwards if that's okay. If you absolutely need it running in a separate process I can try to get something working for that

#

Jest config:

{
  "moduleFileExtensions": ["js", "json", "ts"],
  "rootDir": "..",
  "testEnvironment": "node",
  "testRegex": "test/.*\\.e2e-spec\\.ts$",
  "transform": {
    "^.+\\.(t|j)s$": "ts-jest"
  },
  "collectCoverage": true,
  "collectCoverageFrom": ["<rootDir>/src/**/*.ts"],
  "coverageProvider": "v8"
}

test

import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';

import { AppModule } from '../src/app.module';

describe('E2E Suite', () => {
  let app: INestApplication;
  let httpClient: ReturnType<typeof request>;
  beforeAll(async () => {
    const modRef = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();
    app = modRef.createNestApplication();
    await app.listen(0);
    const address = await app.getUrl();
    httpClient = request(address);
  });
  describe('suites', () => {
    test('Query Server', async () => {
      const res = await httpClient.get('/');
      expect(res.status).toBe(200);
      expect(res.text).toBe('Hello World!');
    });
  });
  afterAll(async () => {
    await app.close();
  });
});
#

Then just using jest --config test/jest-e2e.json gets the coverage generated

hollow mountain
#

This will work great for my use case.

I had thought of this and then conditionally wrapping the address here (app instantiated in beforeAll vs one running elsewhere). Perhaps I was just being lazy in wanting a "pure" blackbox and avoiding the conditional.

beforeAll(async () => {
    let address: string;
    if (process.env.NODE_ENV === 'integration') {
      const modRef = await Test.createTestingModule({
        imports: [AppModule],
      }).compile();
      app = modRef.createNestApplication();
      await app.listen(0);
      address = await app.getUrl();
    } else {
      address = 'localhost:3000';
    }
    httpClient = request(address);
  });

Thank you again for all your help, is there an emoji I can use to consider the thread done?

old jetty
#

I had thought of this and then conditionally wrapping the address here (app instantiated in beforeAll vs one running elsewhere
You could migrate all of your tests out to separate files and let this one be the main delegator, it calls off to the other tests as necessary and passes things like the httpClient or at leat the address. That way you can still have some separation of responsibilities.

#

is there an emoji I can use to consider the thread done?
We can modify the title and close the post 🙂