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

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);
}
});

Related

Cypress: How to add functions to Mocha Context?

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');
};

Printing output to terminal from 'cypress run'

I'd like to print arbitrary outputs to the terminal per each test after calling cypress run. The outputs should appear regardless of each test's success/failure. I've followed the instructions from dozens of online answers - nothing worked for me.
I'm using Cypress 8.7.0. Thanks!
It's pretty much what #nozik linked to. In your cypress.config.js add:
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
on('task', {
log(message) {
// Then to see the log messages in the terminal
// cy.task("log", "my message");
console.log(message +'\n\n');
return null;
},
});
},
},
});
which can then be called in your tests with:
cy.task('log', 'Display some logging');

How to detect Development mode within Svelte code? [duplicate]

The dev mode using npm run dev, the release mode using npm build
How could i know that it's currently built on dev mode or not in the code, for example:
<script>
import {onMount} from 'svelte';
onMount(function(){
if(DEVMODE) { // --> what's the correct one?
console.log('this is x.svelte');
}
})
</script>
If you are using sveltekit:
import { dev } from '$app/environment';
if (dev) {
//do in dev mode
}
Not sure about the correct method. I share what I did on my project.
in rollup.config.js
import replace from "#rollup/plugin-replace";
const production = !process.env.ROLLUP_WATCH;
inside plugins:[ ] block add this
replace({
isProduction: production,
}),
rollup.config.js will look like this.
},
plugins: [
replace({
isProduction: production,
}),
svelte({
Then use isProduction inside components .
if (!isProduction){ console.log('Developement Mode'); }
If you are using Svelte with Vite, you may use:
import.meta.env.DEV - true in development environment.
import.meta.env.PROD - true in production environment.
import.meta.env.MODE - name of the mode, if you need more control.
See Vite docs on Env variables
I solved this problem by checking the hostname the application is running on.
You can also use other forms like, port or even msm a localStore browser variable.
Note that I check if the application is running on the client side before using the 'window'
const isProduction = (): boolean => {
// Check if is client side
if (typeof window !== 'undefined' && window.document !== undefined) {
// check production hostname
if (window?.location.hostname !== undefined &&
window.location.hostname === 'YOUR_PRODUCTION_HOSTNAME') {
return true
} else {
return false
}
} else {
return false
}
}
When using Svelte (not svelte-kit), this worked for me inside svelte components:
<script>
let isProduction = import.meta.env.MODE === 'production';
if (!isProduction) {
console.log("Developement Mode");
} else {
console.log("Production Mode");
}
</script>
Thanks timdeschryver for the reference

Directory path is incorrect when running from cypress test runner

When I login from normal browser the login is successful with the URL : http://neelesh.zapto.org:8084/EnrolMe/indHome.html
But when I run the script from Cypress the directory location is not appended and the new URL after login is formed as : http://neelesh.zapto.org:8084/__/indHome.html
I have tried setting cypress.json with
{
"chromeWebSecurity": false,
"modifyObstructiveCode" : false
}
I have tried on chrome/electron(head and headless).
Below is my code snippet:
describe('My First Test Suite', function() {
it('My First test case', function() {
cy.visit("http://neelesh.zapto.org:8084/EnrolMe")
cy.get("#login").click()
cy.get("input[value='Individual']").click()
cy.get("#username").type('1234567890')
cy.get("#pwd").type('0646')
Cypress.Cookies.debug(true)
cy.clearCookies()
cy.get("#login").click()
cy.wait(6000)
})
})
When I run the script from Cypress the directory location is not appended and the new URL after login is formed as : http://neelesh.zapto.org:8084/__/indHome.html
It should be redirected as : http://neelesh.zapto.org:8084/EnrolMe/indHome.html
Can anyone help me on this?
This sounds like an issue with "Frame Busting". There's a related discussion for Cypress GitHub Issue #992 which may lend some help.
Your application code may contain problematic frame busting code like the following:
if (window.top !== window.self) {
window.top.location.href = window.self.location.href;
}
You can get around this by changing your application code's reference to window.self from the Application Window to the Cypress Test Runner window (window.top).
Cypress emits a series of events as it runs in your browser. You can use the emitted window:before:load application event to ensure it's done before you attempt to login.
// cypress/support/index.js
Cypress.on('window:before:load', (win) => {
Object.defineProperty(win, 'self', {
get: () => {
return window.top
}
})
})

Protractor passing parameters in script run command

I need to pass the credentials in command running a script.
For now, I am using in protractor file following part:
onPrepare: function () {
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: true
}
}));
if (browser.params.Url == 'http://devel/') {
browser.params.webmaster='abc';
browser.params.webmaspass='foo';
}
//(other environments)
else {
console.log('-------------error during log in');
}*/
}
and it was working fine, but I need to change it - I can't pass credentials in this way. I thought about changing it to:
if (browser.params.Url == 'http://devel/') {
browser.params.webmaster='';
browser.params.webmaspass='';
}
and run the script using
npm run dev-script --browser.params.Url='http://devel/' --browser.params.webmaster='abc' --browser.params.webmaspass='foo'
where package.json I have:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev-script": "protractor --params.Url=http://devel/ --browser.params.webmaster='' --browser.params.webmaspass=''"
},
(or any variation) But it fails - I can't update params during running script, I need to write down the credentials in the code (which I find a little unsafe)
I found issues like Protractor needs password for login => insecure? but it about Google Auth problems
Any idea?
You need to remove the variable assignment in the onPrepare. You are overwriting what you are passing in from the command line by setting it to an empty string.
When you pass them in from the command line they will be availble on the params object. There is no need to set them again in your onPrepare. Add a console.log() in your onPrepare and you will see.
Run it from the command line like this: protractor conf.js --params.webmaster=abc --params.webmaspass=foo --params.url=http://devel/
Again, if you log them in your onPrepare you will see that it is working. The way you currently have it you are just overwriting the values you are passing in through the command line.
onPrepare: function () {
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: true
}
}));
if (browser.params.Url == 'http://devel/') {
consoel.log(browser.params.webmaster) //should be abc
console.log(browser.params.webmaspass) //should be foo
}
//(other environments)
else {
console.log('-------------error during log in');
}*/
}
Another way you can do this is to set some environment variables before your test run and then you can access them in your scripts by using process.env.envVariableName or ${envVariableName}. Both ways will work.
set DEVEL_WEBMASTER=abc
set DEVEL_WEBMASPASS=foo
onPrepare: function () {
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: true
}
}));
if (browser.params.Url == 'http://devel/') {
browser.params.webmaster=process.env.DEVEL_WEBMASTER;
browser.params.webmaspass=process.env.DEVEL_WEBMASPASS;
}
//(other environments)
else {
console.log('-------------error during log in');
}*/
}
Just remember that if you use this method you would have to set the variables for each session. If you are planning to automate these tests using a CI environment you can just add them there as secret variables (if you have that option) and they will always be there ready and waiting. There will be no need to set them manually during each build.
What I did it here was create the scripts in my package.json:
scripts: {
"automation-test": "concurrently --raw --kill-others \"./node_modules/.bin/webdriver-manager start\" \"sleep 5 && ./node_modules/.bin/protractor configuration/protractor.config.js\"",
"automation:pending": "TAGS=#pending npm run automation-test"
}
And in my protractor.conf.js I just assign the value to a variable so I can use in my config. Like this:
let tags = process.env.TAGS;
Then the command that I run is just this:
npm run automation:pending
but I could pass the TAGS like this as well:
npm run automation-test TAGS=#pending
I have not seen the configuration file on the parameters of the command line. you must specify the configuration file:
example: protractor config.js --params ......
Do this in your script file: i have added a config file after the command protractor
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev-script": "protractor config.js --params.Url=http://devel/ --browser.params.webmaster='' --browser.params.webmaspass=''"
},

Resources