Cypress: How to add functions to Mocha Context? - cypress

I am trying add functions to this (which is a Mocha Context) in tests, so I can do e.g.
describe('my spec', () => {
it('should work', function () {
this.sayHelloWorld();
})
})
In an empty folder I call
yarn add cypress
yarn cypress open
so that default config files are created. It also creates a sample test in cypress/e2e/spec.cy.js.
I can run the sample test without problem. But if I add
import { Context } from "mocha";
to cypress/support/e2e.js I get
Error: Webpack Compilation Error
./cypress/support/e2e.js
Module not found: Error: Can't resolve 'mocha' in '...\support'
resolve 'mocha' in '...\support'
Parsed request is a module
So I installed Mocha, the same version which is in devDependencies of Cypress (see package.json):
yarn add mocha#3.5.3
My package.json now looks like this:
{
"dependencies": {
"cypress": "^10.4.0",
"mocha": "3.5.3"
}
}
Now that import line passes. But this fails:
import { Context } from "mocha";
Context.prototype.sayHelloWorld = () => console.log("hello world");
Error:
> Cannot read properties of undefined (reading 'prototype')
Why is that? In comparison adding something to String.prototype works.
Also in comparison: Again in an empty folder:
yarn add mocha#3.5.3
And in test/test.js:
const { Context } = require("mocha");
it("should work", function () {
Context.prototype.sayHelloWorld = () => console.log("hello world");
this.sayHelloWorld();
});
Now yarn mocha works (says hello world).
What is going on in Cypress? Possibly a bug?

Solution:
no import { Context } from "mocha";
add functions like that:
Mocha.Context.prototype.sayHelloWorld = function () {
cy.log('hello world');
};

Related

How can I see `cy.log` output when using Cypress headlessly?

When running Cypress headlessly, I can see console.log output from the frontend code under test by using the DEBUG environment variable, like:
DEBUG='cypress:launcher' npx cypress run --browser chrome
However, I haven't found any similar way to see the output of cy.log from the Cypress test code when running headlessly. Even with DEBUG='cypress:*' I don't see them - they only seem to be visible in the interactive interface. It feels like there must be some way to see the cy.log output headlessly - can someone help with that?
The first step is to add a new task in your Cypress config file so that you can run console.log from Node:
import { defineConfig } from "cypress";
export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
on("task", {
log(args) {
console.log(...args);
return null;
}
});
},
},
});
Then, you can override cy.log so that it calls this task whenever you run the command in headless mode, and console.log when you're running in headed mode. You can do this by adding the following to your commands file:
Cypress.Commands.overwrite("log", function(log, ...args) {
if (Cypress.browser.isHeadless) {
return cy.task("log", args, { log: false }).then(() => {
return log(...args);
});
} else {
console.log(...args);
return log(...args);
}
});

Cypress asynchronous execution returns 4 same assertion

I have a question.
I am using Cypress for my automation and I started using async and await for my tests.
I am using POM design pattern.
My question:
If I execute the following test:
test.spec.ts class (test class)
import { login_po } from "../pom/1.Chiquito/login_po";
const pom = new login_po()
describe("Put some name here.", async() => {
it('TestCase1', async () => {
await pom.navigateTo();
});
});
My POM class.
export class login_po {
navigateTo() {
cy
.visit(`https://chiquito-qa.omnifitrgsites.co.uk/`)
.url()
.should('be.equal', 'https://chiquito-qa.omnifitrgsites.co.uk/').then(() => this.verifyAfterLogin());
}
verifyAfterLogin() {
cy.get('.header__logo-img');
}
}
When I execute the test - Cypress makes 4 (same) assertions.
If I remove 'async' - 'await' from the test class - Cypress makes 1 assertion.
import { login_po } from "../pom/1.Chiquito/login_po";
const pom = new login_po()
describe("Put some name here.", () => {
it('TestCase1', () => {
pom.navigateTo();
});
});
Why this is happening?
Cypress commands are not promises, and their interaction with async/await will not happen as you expect. Additionally, while POM is feasible and reasonable to do within Cypress, it is recommended that you use App Actions instead of a POM.

Cypress error: Could not find any test to run

I am doing a unit test. Cypress now gives an errror. it cannot find the test. but in the login.js file I have written code. I don't understand why it can't find the test, it does exist.
the testcode:
describe("login", () => {
beforeEach(() => {
cy.visit("http://localhost:8080");
});
});
The error:
integration\login.js
We could not detect any tests in the above file. Write some tests and re-run.
Path:
server/cypress/integration/pad/login.js
If this is all of your test code, it really doesn't have any test. Add any 'it' and cypress will recognize it as a test.
describe("login", () => {
beforeEach(() => {
cy.visit("http://localhost:8080");
});
it('Example test', () => {
expect(add(1, 2)).to.eq(3)
})
});
just edit the file... from your project's root folder to bypass cypress. Try that too to test, here it worked.
{
//... other file settings
"exclude": ["src/main/test/cypress"]
}
note: If you are using eslint, you will have to do one more configuration. Since eslint doesn't let us have a TypScrip file inside the project without being treated.
First: Create a file in the project root called tsconfig-eslint.json. It will extend the other tsconfig but ignore the deletion. Put the following content in it:
{
"extends": "./tsconfig.json",
"exclude": []
}
Second: modify the parseOptions of the .eslint.json file to point to the newly created file:
{
//... rest of the settings
"parserOptions": {
"project": "./tsconfig-eslint.json"
},
}

Reference Error :cy is not defined while running cypress test

Describe('The Login', function () {
beforeEach(function () {
cy.readFile(Cypress.env('test')).as("user")});
it("Login", () => {
cy.get("#user").then((user) =>
cy.login(user.username, user.password))})
FAIL cypress/integration/login.spec.js
● The Login Page ›
ReferenceError: cy is not defined
at Object.<anonymous> (cypress/integration/login.spec.js:4:5)
at new Promise (<anonymous>)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
To add some context to the answer by #sai, to resolve this eslint error all I had to do was install eslint-plugin-cypress from here.
npm install eslint-plugin-cypress --save-dev
Then, in my eslint config I added one line to my extends array.
Your config could be .eslintrc.json or the "eslintConfig" configuration object in your package.json
{
"extends": [
"plugin:cypress/recommended"
]
}
Testing locally, this should work for you. Change path of your json file, and use your custom command cy.login. In my example I just printed variables to console.
describe('The Login', () => {
beforeEach(() => {
cy.readFile('cypress/integration/test/test.json').as("user")});
it("Login", () => {
cy.get("#user").then((user) =>
cy.log(user.username, user.pass))
})
})
My test.json was:
{
"username":"test#test.com",
"pass":"pass"
}
The issue was related to eslint
Had to install few packages and made an update to eslintrc files

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