Cypress: Uncaught CypressError: Cannot call "cy.get()" outside a running test - node.js

When running my cypress test it skips the test and rund th after hooks straight away. It then logs this error msg and finishes:
Uncaught CypressError: Cannot call "cy.get()" outside a running test.
This usually happens when you accidentally write commands outside an it(...) test.
If that is the case, just move these commands inside an it(...) test.
Check your test file for errors.
https://on.cypress.io/cannot-execute-commands-outside-test
This error originated from your test code, not from Cypress.
When Cypress detects uncaught errors originating from your test code it will automatically fail the current test.
Cypress could not associate this error to any specific test.
We dynamically generated a new test to display this failure.
Any ideas what could be causing this strange behaviour. It should run the test first then run the after hooks. I am using cypress-cucumber-preprocessor and running a feature file.
Below is my index.js from support folder (for hooks):
import '#applitools/eyes-cypress/commands';
import './commands';
const xhrData = [];
//Hooks
before(function () {
cy.fixture('./TestData').as('TestData');
// runs once before all tests in the block
cy.server({
// Here we hanDle all requests passing through Cypress' server
onResponse: (response) => {
if (Cypress.env('record')) {
const url = response.url;
const method = response.method;
const data = response.response.body;
// We push a new entry into the xhrData array
xhrData.push({ url, method, data });
}
}
});
// This tells Cypress to hook into any GET request
if (Cypress.env('record')) {
cy.route({
method: 'GET',
url: '*',
});
cy.route({
method: 'POST',
url: '*',
});
}
// Load stubbed data from local JSON file
if (!Cypress.env('record')) {
cy.fixture('fixture')
.then((data) => {
for (let i = 0, length = data.length; i < length; i++) {
cy.route(data[i].method, data[i].url, data[i].data);
}
});
}
});
beforeEach(function () {
cy.visit(Cypress.config().baseUrl);
// runs before each test in the block
cy.eyesOpen({
appName: 'CafeTownsend',
testName: 'Complete Happy Path',
browser: {
"viewportWidth": 1000,
"viewportHeight": 660
},
});
});
after(function () {
// runs once after all tests in the block
if (Cypress.env('record')) {
const path = './cypress/fixtures/fixture.json';
cy.writeFile(path, xhrData);
cy.log("Wrote "+ xhrData.length +" XHR responses to local file "+path);
}
});
afterEach(function () {
// runs after each test in the block
cy.eyesClose();
cy.reload();
});

I found the solution to this issue.
I was using page object model and in my constructors I did a cy.get to see that we could locate an anchor element.
I instantiate several pages in the step defs, and these seemed to be called before the test is run, hence the error.
For now I am putting all cy.gets outside of the constructor.
perhaps there is a bettwe way to solve this issue.

Related

Selenium Test Case not getting executed with Jest

I am working on setting up an automation test suite for an application using selenium and jest and it turns out that the console never reaches the inner body of the minimalist test case written below.
describe('When a user Opens Launchpad', () => {
test('It should be able to Navigate to Tasks Application without errors', async () => {
driver.get('http://localhost:4004/fiori.html').then(function () {
const temp = driver.findElement(By.xpath("li[#id='__tile11']"));
temp.then(function (element){
element.getAttribute("innerHTML");
expect(element.getText()).toBe("VT Dashboard");
})
});
}, 200000);
});
I looked online and tried multiple fixes like putting the driver.get() method above all these functions, making the test cases synchronous and using getText() instead of getAttribute() but none of them worked.
I either get an element not found error (The element actually exists when I check it on the chromium browser) or the test case executes successfully without reaching the expect statement in debug mode.
Bottomline is that driver.findElement() returns a promise instead of an element and would be great if I could get an element instead of promise.
Any help or correction here would be greatly appreciated.
If the function is async you should return the promise chain from that function or just use await keyword. So try following:
test('It should be able to Navigate to Tasks Application without errors', async () => {
await driver.get('http://localhost:4004/fiori.html');
const temp = await driver.findElement(By.xpath("li[#id='__tile11']"));
element.getAttribute("innerHTML");
expect(element.getText()).toBe("VT Dashboard");
}, 200000);
or
test('It should be able to Navigate to Tasks Application without errors', async () => {
return driver.get('http://localhost:4004/fiori.html').then(function () {
const temp = driver.findElement(By.xpath("li[#id='__tile11']"));
temp.then(function (element){
element.getAttribute("innerHTML");
expect(element.getText()).toBe("VT Dashboard");
})
});
}, 200000);

Why is the second Jest mock function never being called?

I am mocking navigator functions for simple clipboard functionality. Here is the relevant code:
// FUNCTION
/**
* Adds a click event to the button which will save a string to the navigator clipboard. Checks for
* clipboard permissions before copying.
*/
function loader(): void {
async function copyUrl(): Promise<void> {
const permission = await navigator.permissions.query({ name: "clipboard-write" });
if (permission.state == "granted" || permission.state == "prompt" ) {
await navigator.clipboard.writeText("the url");
} else {
console.error('Permission not supported');
}
}
const button = document.querySelector('button') as HTMLElement;
button.addEventListener('click', async () => {
await copyUrl();
});
}
// TEST
it('works', () => {
// mock navigator functions
Object.assign(navigator, {
permissions: {
query: jest.fn(async () => ({ state: "granted" }))
},
clipboard: {
writeText: jest.fn(async () => {})
}
});
// initialize DOM
document.body.innerHTML = '<button></button>';
loader(); // adds the event listener
// click the button!
const button = document.querySelector('button') as HTMLElement;
button.click();
expect(navigator.permissions.query).toHaveBeenCalledTimes(1);
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('the url');
});
The test fails on expect(navigator.clipboard.writeText).toHaveBeenCalledWith('the url') with:
Expected: "the url" Number of calls: 0
Defeats the purpose of permissions, yes, but for the sake of debugging:
Try adding a clipboard call before permissions call like so?
// FUNCTION
// ...
async function copyUrl(): Promise<void> {
// add this
await navigator.clipboard.writeText('the url');
// keep the rest still
const permission = await navigator.permissions.query({ name: "clipboard-write" });
// ...
}
This fails on the first assertion now, expect(navigator.permissions.query).toHaveBeenCalledTimes(1) with
Expected number of calls: 1 Received number of calls: 0
With the addition above, I also changed the assertions to be:
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('the url');
expect(navigator.clipboard.writeText).toHaveBeenCalledTimes(2);
expect(navigator.permissions.query).toHaveBeenCalledTimes(1);
... which failed on the second assertion because it expected 2 calls but only received 1.
I have been testing in a VSCode devcontainer and tried out the extension firsttris.vscode-jest-runner to debug the test. With breakpoints in the loader function, I'm able to see that every single line executes perfectly with my mockup but still fails at the end of debug.
I even changed the mock navigator.permissions.query function to return { state: 'denied' } instead. Both running and debugging, it did not satisfy the permission check and gave an error to the console as expected but the test still failed at expect(navigator.permissions.query).toHaveBeenCalledTimes(1) (with the added writeText call before it).
It seems to me that after the first call of a mock function, the others just don't work.
Am I missing something? Send help pls lol
EDITS
Using jest.spyOn as in this answer has the same issues.
Using an async test with an expect.assertions(n) assertion still produces the exact same issue.

cy.readFile results in timeout?

I am trying to read an JSON file that I have just written with another test in the same cypress project. However when it tries to read the file it times out after 4000 milliseconds.
Has anyone experienced this before? How could I solve it?
I have tried increasing the time out by giving it a settings object but that doesn't increase the time out time. I thought it might be a file permissions issue but that doesn't seem to be it either.
I am running on Mac but tried the same project on Windows with the same result.
before('grab generated user data', function (){
let data = cy.readFile("Generated User/Cypress test 131.json", {log:true, timeout: 180000});
}
I expect it to just give back the parsed JSON object. As it says in the Cypress docs. (https://docs.cypress.io/api/commands/readfile.html#Syntax)
1.Your file should be in the project directory where cypress.json file is present.
2.Your file name should be Cypresstest131.json or Cypress-test-131.json
before('grab generated user data', function (){
let data = cy.readFile("Cypresstest131.json", {log:true, timeout: 4000});
data.its('name').should('eq', 'Eliza')
})
or
before('grab generated user data', function (){
cy.readFile("Cypress-test-131.json", {log:true, timeout: 4000}).its('name').should('eq', 'Eliza')
})
Hope this help you
I ended up creating a data.json with cy.createFileSync(). When I want to read the file instead of using cypresses cy.readFile() function I created a cypress task that uses the fs library to read the file.
I am leaving you with the code snipped of the task I used to read the file.
const fs = require('fs');
const request = require('request');
module.exports = (on, config) => {
on('task', {
// Cypress task to get the last ID
getLastId: () => {
// Make a promise to tell Cypress to wait for this task to complete
return new Promise((resolve) => {
fs.readFile("data.json", 'utf8', (err, data) => {
if (data !== null && data !== undefined) {
data = JSON.parse(data);
if (data.hasOwnProperty('last_id')) {
resolve(data.last_id);
} else {
resolve("Missing last_id");
}
} else {
resolve(err);
}
});
});
}
Calling this function would be as simple as
let id = 0;
before('grab generated user data', function (){
cy.task('getLastId').then((newID)=>{
id = newID;
});
});

Resemblejs in jest hangs

I'm using ResembleJS for image comparison. I can get it to run when I run it in a standalone script. Here's the code:
var compareImages = require('resemblejs/compareImages');
var fs = require('fs');
var path = require('path');
// The parameters can be Node Buffers
// data is the same as usual with an additional getBuffer() function
async function getDiff() {
var img = path.join(__dirname, 'small.jpg');
const data = await compareImages(
fs.readFileSync(img),
fs.readFileSync(img)
);
console.log(data);
fs.writeFileSync('./output.png', data.getBuffer());
}
getDiff();
Everything works as expected.
But when I run the comparison inside of a test in with the jest framework, it hangs and eventually times out. At first I thought maybe it was just running really slow, so I set my max timeout in jest to be 1 minute. Still failed. So I set my test image to be 1 pixel so it's the simplest test. Still wouldn't finish.
Running from a docker container with Node 8.9.4 (which is what comes from the docker hub node:8). Running jest 22.0.4.
Anybody else have issues running these two together?
I know Resemblejs runs tests with Jest, so not sure what could be causing the issue.
could you please post the code for your tests ?
Are you sure you are returning something from your test block ? In order for an test not to hang you need to return a promise which will resolve before the timeout. Below two examples
test("test", () => {
// test is done when writeFile resolves
return new Promise((resolve, reject) => {
fs.writeFile("path", "encoding", (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
});
test("test", async function () {
// test is done after the assertion
const result = await fetch();
expect(result).toBe(); // test;
});
I had a similar problem with slow tests with Jest, React and Docker (but I'm not using Resemblejs).
I found the solution on Github:
And for me solution was simply add "roots": ["./src"] to jest.config.js

casperJS - grunt-casper: Running multiple Test-Suites in a loop

Preparation
Hi i am using CasperJS in combination with grunt-casper (github.com/iamchrismiller/grunt-casper) for running automated functional and regression tests in our GUI Development process for verification.
We use it like this, casper runner in gruntfile.js:
casper: {
componentTests: {
options: {
args: ['--ssl-protocol=any', '--ignore-ssl-errors=true', '--web-security=no'],
test: true,
includes: ['tests/testutils/testutils.js']
},
files: {
'tests/testruns/logfiles/<%= grunt.template.today("yyyy-mm-dd-hhMMss") %>/componenttests/concat-testresults.xml': [
'tests/functionaltests/componenttests/componentTestController.js']
}
},
so as it can be seen here we just normally run casper tests with SSL params and calling only ONE Controllerclass here instead of listing the single tests (this is one of the roots of my problem). grunt-casper delivers the object which is in charge for testing and inside every single Controllerclass the tests are included and concatenated....
...now the componentTestController.js looks like the following:
var config = require('../../../testconfiguration');
var urls = config.test_styleguide_components.urls;
var viewportSizes = config.test_styleguide_components.viewportSizes;
var testfiles = config.test_styleguide_components.testfiles;
var tempCaptureFolder = 'tests/testruns/temprun/';
var testutils = new testutils();
var x = require('casper').selectXPath;
casper.test.begin('COMPONENT TEST CONTROLLER', function(test) {
casper.start();
/* Run tests for all given URLs */
casper.each(urls, function(self, url, i) {
casper.thenOpen(url, function() {
/* Test different viewport resolutions for every URL */
casper.each(viewportSizes, function(self, actViewport, j) {
/* Reset the viewport */
casper.then(function() {
casper.viewport(actViewport[0], actViewport[1]);
});
/* Run the respective tests */
casper.then(function() {
/* Single tests for every resolution and link */
casper.each(testfiles, function(self, actTest, k) {
casper.then(function() {
require('.'+actTest);
});
});
});
});
});
});
casper.run(function() {
test.done();
});
});
Here you can see that we running a 3 level loop for testing
ALL URLs given in a JSON config file which are contained in an ARRAY of String ["url1.com","url2.com"....."urln.com"]
ALL VIEWPORT SIZES so that every URL is tested in our desired Viewport resolutions to test the correct Responsibility behaviour of the components
ALL TESTFILES, all testfiles only include a TEST STUB what means, no start, begin or something else, its all in a large Testsourrounding.
MAYBE this is already mocky and can be done in a bette way, so if this is the case i would glad if someone has proposals here, but don't forget that grunt-casper is involved as runner.
Question
So far, so good, the tool in general works fine and the construction we built works as we desired. But the problem is, because all testfiles are ran in a large single context, one failing component fails the whole suite.
In normal cases this is a behaviour i would support, but in our circumstances i do not see any proper solution than log the error / fail the single testcomponent and run on.
Example:
I run a test, which is setUp like described above and in this part:
/* Single tests for every resolution and link */
casper.each(testfiles, function(self, actTest, k) {
casper.then(function() {
require('.'+actTest);
});
});
we include 2 testfiles looking like the following:
Included testfile1.js
casper.then(function () {
casper.waitForSelector(x("//a[normalize-space(text())='Atoms']"),
function success() {
casper.test.assertExists(x("//a[normalize-space(text())='Atoms']"));
casper.click(x("//a[normalize-space(text())='Atoms']"));
},
function fail() {
casper.test.assertExists(x("//a[normalize-space(text())='Atoms']"));
});
});
Included testfile2.js
casper.then(function () {
casper.waitForSelector(x("//a[normalize-space(text())='Buttons']"),
function success() {
casper.test.assertExists(x("//a[normalize-space(text())='Buttons']"));
casper.click(x("//a[normalize-space(text())='Buttons']"));
},
function fail() {
testutils.createErrorScreenshot('#menu > li.active > ul > li:nth-child(7)', tempCaptureFolder, casper, 'BUTTONGROUPS#2-buttons-menu-does-not-exist.png');
casper.test.assertExists(x("//a[normalize-space(text())='Buttons']"));
});
});
So if the assert in testfile1.js fails, everthing failes. So how can i move on to testfile2.js, even if the first fails? Is this possible to configure? Can it be encapsulated somehow?
FYI, this did not work:
https://groups.google.com/d/msg/casperjs/3jlBIx96Tb8/RRPA9X8v6w4J
Almost similar problems
My problem is almost the same like this here:
https://stackoverflow.com/a/27755205/4353553
And this guy here has almost another approach i tried but got his problems too because multiple testsuites ran in a loop occuring problems:
groups.google.com/forum/#!topic/casperjs/VrtkdGQl3FA
MUCH THANKS IN ADVICE
Hopefully I understood what you ware asking - is there a way to suppress the failed assertion's exception throwing behavior?
The Tester's assert method actually allows for overriding the default behavior of throwing an exception on a failed assertion:
var message = "This test will always fail, but never throw an exception and fail the whole suite.";
test.assert(false, message, { doThrow: false });
Not all assert helpers have this option though and the only other solution I can think of is catching the exception:
var message = "This test will always fail, but never throw an exception and fail the whole suite.";
try {
test.assertEquals(true, false, message);
} catch (e) { /* Ignore thrown exception. */ }
Both of these approaches are far from ideal since the requirement in our cases is to not throw for all assertions.
Another short term solution that requires overriding the Tester instance's core assert method is (but is still quite hacky):
// Override the default assert method. Hopefully the test
// casper property doesn't change between running suites.
casper.test.assert =
casper.test.assertTrue = (function () {
// Save original assert.
var __assert = casper.test.assert;
return function (subject, message, context) {
casper.log('Custom assert called!', 'debug');
try {
return __assert.apply(casper.test, arguments);
}
catch (error) {
casper.test.processAssertionResult(error.result);
return false;
}
};
})();
That said, I'm currently looking for a non-intrusive solution to this "issue" (not being able to set a default value for doThrow) as well. The above is relative to Casper JS 1.1-beta3 which I'm currently using.

Resources