HW Siew
HW Siew

Reputation: 1003

Jest Run All Tests(include only/skip) in CI

While in development we occasionally use skip or only to debug a particular test or test suit. Accidentally, we might forget to revert the cases and push the code for PR. I am looking for a way to detect or automatically run all tests even for skip and only tests in our CI pipeline(using Github action). It can be in either case as follow.

  1. Fail the test when there are skip or only tests.
  2. Run all tests even for skip and only.

Very much appreciate any help.

Upvotes: 6

Views: 1721

Answers (1)

Panczur
Panczur

Reputation: 653

I came up with a solution for the second part of the question about running all tests even for skip and only. I don't think it's elegant solution, but it works and it's easy to implement.

First of all you need to change test runner to jest-circus if you work with jest bellow 27.x version. We need it so our custom test environment will use handleTestEvent function to watch for setup events. To do so, install jest-circus with npm i jest-circus and then in your jest.config.js set testRunner property:

//jest.config.js

module.exports = {
    testRunner: 'jest-circus/runner',
    ...
}

From Jest 27.0 they changed default test runner to jest-circus so you can skip this step if you have this or higher version.

Then you have to write custom test environment. I suggest to write it based on jsdom so for example we also have access to window object in tests and etc. To do so run in terminal npm i jest-environment-jsdom and then create custom environment like so:

//custom-jsdom-environment.js

const JsDomEnvironment = require('jest-environment-jsdom')

class CustomJsDomEnvironment extends JsDomEnvironment {

    async handleTestEvent(event, state) {
        if(process.env.IS_CI === 'true' && event.name === 'setup') {
            this.global.describe.only = this.global.describe
            this.global.describe.skip = this.global.describe
            this.global.fdescribe = this.global.describe
            this.global.xdescribe = this.global.describe

            this.global.it.only = this.global.it
            this.global.it.skip = this.global.it
            this.global.fit = this.global.it
            this.global.xit = this.global.it

            this.global.test.only = this.global.test
            this.global.test.skip = this.global.test
            this.global.ftest = this.global.test
            this.global.xtest = this.global.test
        }
    }
}

module.exports = CustomJsDomEnvironment

And inform jest to properly use it:

//jest.config.js

module.exports = {
    testRunner: 'jest-circus/runner',
    testEnvironment: 'path/to/custom/jsdom/environment.js',
    ...
}

Then you just have to setup custom environment value IS_CI in your CI pipeline and from now on all your skipped tests will run.

Also in custom test environment you could watch for skipped test and throw an error when your runner find skip/only. Unfortunately throwing an error in this place won't fail a test. You would need to find a way to fail a test outside of a test.

//custom-jsdom-environment.js

const JsDomEnvironment = require('jest-environment-jsdom')
const path = require('path')

class CustomJsDomEnvironment extends JsDomEnvironment {

    constructor(config, context) {
        super(config, context)
        const testPath = context.testPath
        this.testFile = path.basename(testPath)
    }

    async handleTestEvent(event, state) {
        if(process.env.IS_CI === 'true' && event.name === 'add_test') {
            if(event.mode === 'skip' || event.mode === 'only') {
                const msg = `Run ${event.mode} test: '${event.testName}' in ${this.testFile}`
                throw new Error(msg)
            }
        }
    }
}

module.exports = CustomJsDomEnvironment

Upvotes: 5

Related Questions