Mocha hook for each test and test file - mocha.js

Is it possible to add a hook in mocha 8.1 for each test and test file?
Ex: I want to set a startup delay before each each in all the test files

export const mochaHooks = {
beforeEach(done) {
// do something before every test
done();
}
};
https://mochajs.org/#available-root-hooks

Related

When a before hook fails; the tests within that suite are skipped; how could i reliably get the list of those skipped tests?

When a before hook fails; the tests within that suite are skipped; how could i reliably get the list of those skipped tests ?
I tried to listen to the EVENT_TEST_FAIL on the Mocha runner and extract the information from there:
const Mocha = require('mocha');
const {
EVENT_TEST_FAIL,
} = Mocha.Runner.constants;
class MyReporter {
constructor(runner) {
runner
.on(EVENT_TEST_FAIL, (test, err) => {
console.log(err, test);
console.log("failed tests", test.parent.tests.map(t => t.fullTitle()));
});
}
}
module.exports = MyReporter;
But only issue is that, this code cannot distinguish between a failure in the before hook and a failure in a particular test case.
As a result, this code reports all tests in the suite as failed, even when only one test is failed.

Cypress 10 - How can I run test files in order

Previously it should be set up in cypress.json.
Like
testFiles: [
"e2e/register.cy.ts",
"e2e/buyGiftCertificate.cy.ts",
"e2e/buyMembershipCertificate.cy.ts"
]
But after migrating to Cypress 10 the place for it is cypress.config.ts
There should be a pattern but how to order tests it's not clear
If you are using npx cypress run, you can do exactly the same thing, except use specPattern instead of testFiles.
The following will run the test (only these tests) in the order spec2.cy.js, spec3.cy.js, spec1.cy.js
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
specPattern: [
"cypress/e2e/spec2.cy.js",
"cypress/e2e/spec3.cy.js",
"cypress/e2e/spec1.cy.js",
]
},
});
Create a file inside your e2e folder as tests-in-order.cy.ts and inside that file import the tests in order you want them to execute:
//Run tests in the intended order
import './register.cy.ts'
import './buyGiftCertificate.cy.ts'
import './buyMembershipCertificate.cy.ts'
And then execute the file using the command (from cli):
npx cypress run --spec=cypress/e2e/tests-in-order.cy.ts
For Test Runner, just click on the file to execute.

How do I change the filename of the Junit XML report that Nightwatch.js generates?

I have a Nightwatch.js test suite running. When it completes, I've configured the output directory using the output_folder setting. It produces JUnit XML files in that directory correctly. I have an existing automation tool which scans the directory for JUnit test XML files and reports on them. Unfortunately it only matches files in the directory with a naming scheme: TEST-.xml. Let's assume that I can't change the matching rules on my automation tool. I'm looking for a way to add "TEST-" as a prefix to my tests. Ideally I can do this by configuring Nightwatch. Does Nightwatch support this configuration? I can't find any such options.
I ended up changing my test scripts in package.json so that they did a rename after the test was run. Here is what they were before:
{
// ...
"scripts": {
"integ-tests": "<some nightwatch command>"
}
// ...
}
Here is what they were after:
{
// ...
"scripts": {
"rename-integ-tests": "node -e \"require('fs').readdir('<my test directory>', (err, files) => { files.forEach(file => { if(file.endsWith('.xml') && ! file.startsWith('TEST-')) { fs.rename('<my test directory>' + file, '<my test directory>/TEST-' + file, function(err) { if (err) console.log(err); console.log('Renamed Smoke Test: ' + file + ' to TEST-' + file) }) } }); });\"",
"private-integ-tests": "<some nightwatch command>",
"integ-tests": "npm run private-integ-tests && npm run rename-integ-tests"
}
// ...
}

Cypress: How do I conditionally skip a test by checking the URL

How do I conditionally skip a test if the URL contains "xyz"?
some tests that run in the QA environment "abc" should not be run in Production "xyz" environment.
I've not been able to find a good example of conditionally checking for environment to trigger a test. The baseURL needs to be checked dynamically and the test skipped preferably in the beforeEach.
running cypress 6.2.0
beforeEach(() => {
login.loginByUser('TomJones');
cy.visit(`${environment.getBaseUrl()}${route}`);
});
it('test page', function () {
if environment.getBaseUrl().contains("xyz")
then *skip test*
else
cy.intercept('GET', '**/some-api/v1/test*').as('Test'););
cy.get('#submitButton').click();
})
Potential Solution (tested and tried successfully):
I used a combination of filtering (grouping) and folder structures via CLI
I set folders /integrations/smokeTest/QA and /integrations/smokeTest/Prod/
1.QA Test Run:
npm run *cy:filter:qa* --spec "cypresss/integration/smokeTests/QA/*-spec.ts"
2.Run All (both QA and PROD tests)
npm run cypress:open --spec "cypresss/integration/smokeTests/*/*-spec.ts"
3. Prod Test Run:
npm run cy:filter:prod --spec "cypresss/integration/smokeTests/PROD*/*-spec.ts"
Normally I wouldn't write a custom command just to exercise one Cypress command, but in this case it's useful to obtain the global test context this.
Using the function form of callback with the custom command allows access to this, then you are free to use arrow functions on the test themselves.
Cypress.Commands.add('skipWhen', function (expression) {
if (expression) {
this.skip()
}
})
it('test skipping with arrow function', () => {
cy.skipWhen(Cypress.config('baseUrl').includes('localhost'));
// NOTE: a "naked" expect() will not be skipped
// if you call your custom command within the test
// Wrap it in a .then() to make sure it executes on the command queue
cy.then(() => {
expect('this.stackOverflow.answer').to.eq('a.better.example')
})
})
I would add a helper method which you can call from any Mocha.Context (at the time of writing, any it, describe, or context block).
// commands.ts
declare global {
// eslint-disable-next-line #typescript-eslint/no-namespace
namespace Cypress {
interface Chainable {
/**
* Custom command which will skip a test or context based on a boolean expression.
*
* You can call this command from anywhere, just make sure to pass in the the it, describe, or context block you wish to skip.
*
* #example cy.skipIf(yourCondition, this);
*/
skipIf(expression: boolean, context: Mocha.Context): void;
}
}
}
Cypress.Commands.add(
'skipIf',
(expression: boolean, context: Mocha.Context) => {
if (expression) context.skip.bind(context)();
}
);
And from your spec:
describe('Events', () => {
const url = `${environment.getBaseUrl()}${route}`;
before(function () {
cy.visit(url);
cy.skipIf(url.includes('xyz'), this);
});
context('Nested context', () => {
it('test', function () {
cy.skipIf(url.includes('abc'), this);
expect(this.stackOverflow.answer).to.be('accepted');
});
});
});
Now you have a reusable custom command that you can call from anywhere to conditionally skip tests based on any expression that evaluates to a boolean. Careful of classic JS equality and definition gotchas (read more about equality in JS here).

Testing Yeoman generator with bowerInstall and/or npmInstall

I have a Yeoman generator that uses this.bowerInstall()
When I test it, it tries to install all the bower dependencies that I initialized this way. Is there a way to mock this function ?
The same goes for the this.npmInstall() function.
I eventually went with a different approach. The method from drorb's answer works if you are bootstrapping the test generators manually. If you use the RunContext based setup (as described on the Yeoman (testing page)[http://yeoman.io/authoring/testing.html]), the before block of the test looks something like this.
before(function (done) {
helpers.run(path.join( __dirname, '../app'))
.inDir(path.join( __dirname, './tmp')) // Clear the directory and set it as the CWD
.withOptions({ foo: 'bar' }) // Mock options passed in
.withArguments(['name-x']) // Mock the arguments
.withPrompt({ coffee: false }) // Mock the prompt answers
.on('ready', function (generator) {
// this is called right before `generator.run()`
})
.on('end', done);
})
You can add mock functions to the generator in the 'ready' callback, like so:
.on('ready', function(generator) {
generator.bowerInstall = function(args) {
// Do something when generator runs bower install
};
})
The other way is to include an option in the generator itself. Such as:
installAngular: function() {
if (!this.options['skip-install']) {
this.bowerInstall('angular', {
'save': true
});
}
}
finalInstall: function() {
this.installDependencies({
skipInstall: this.options['skip-install']
});
}
Now since you run the test with the 'skip-install' option, the dependencies are not installed. This has the added advantage of ensuring the command line skip-install argument works as expected. In the alternate case, even if you run the generator with the skip-install argument, the bowerInstall and npmInstall functions from your generator are executed even though, the installDependencies function is not (as it is usually configured as above)
Take a look at the tests for the Bootstrap generator, it contains an example of mocking the bowerInstall() function:
beforeEach(function (done) {
this.bowerInstallCalls = [];
// Mock bower install and track the function calls.
this.app.bowerInstall = function () {
this.bowerInstallCalls.push(arguments);
}.bind(this);
}.bind(this));

Resources