Cypress reuse test cases in multiple test suites - testing

I am new to Cypress and trying out one POC.
The application I am working on requires me to test the same component in different test suites. Is there any why in which I can avoid rewriting the same chunk of code, like using function?
export function testWelcomeBanner() {
...
welcomeBanner.should('have.text', 'welcome');
...
}
I did try some ways, like trying to call this function from it block in test suites etc. but received errors. Any help appreciated.

You can use custom commands to reuse your scripts. You can read more about custom commands from the cypress docs.
You can write your reusable functions under cypress/support/command.js
Cypress.Commands.add('welcomeBanner', (text) => {
cy.get('locator').should('have.text', 'text');
})
You can use the above command in any of your tests like
cy.welcomeBanner('Welcome Text')

Cypress recommends using functions just as you would with plain old JavaScript.
...writing Cypress tests is JavaScript, and it's often more efficient to write a function for repeatable behavior.
Source
Put reusable functions into a separate file.
utils.js:
/// <reference types="cypress" />
export function testWelcomeBanner() {
// Add more logic as needed here. You can also return
// the result of your `cy.` call.
cy.get("div.welcomeBanner")
.should("have.text", "welcome");
}
Then import those functions in your Cypress tests.
myTest.spec.js:
/// <reference types="cypress" />
import { testWelcomeBanner } from "../utils.js"; // Adjust the path for your environment
describe("testing", () => {
it("can do something", () => {
...
testWelcomeBanner();
...
});
});

Related

An updated approach to testing vuex actions

In the "Testing Actions" documentation, there is a recommendation to use inject-loader in order to mock entire module imports, and their respective dependencies, when unit testing.
For example, you can mock the ../api/shop import found inside the ./actions file with the following:
const actionsInjector = require('inject-loader!./actions')
// create the module with our mocks
const actions = actionsInjector({
'../api/shop': {
getProducts (cb) {
setTimeout(() => {
cb([ /* mocked response */ ])
}, 100)
}
}
})
Unfortunately, that package does not support Webpack 5.
Is there an updated approach, or alternative package, that is recommended?
Thanks #Estus Flask.
The clarification/mixup was that, whilst I was using vi.mock, and it's auto-mocking algorithm :
"...will mock the module itself by invoking it and mocking every
export."
i.e. it still runs the import statements. To prevent this, a factory must be provided (see documentation), e.g.:
vi.mock('module', <factory-here>)
Which then replaces the entire file import.

Invalid first argument. It must be a callback function

I am new to jest with selenium automation test. I am trying to add a beforeAll() and afterAll() functions to open and close the browsers once and run all the tests across multiple files, instead of calling it individually in all the files and opening multiple browsers and loading the website everytime.
Here is my test:
enter image description here
Output
This is beforeAll() and afterAll() methods sitting in a separate file
Actual Test
beforeAll is different from it or describe. The first argument can only be empty or with done if you using callback:
// works
beforeEach((done) => {
...
done()
});
// works
beforeEach(() => {
return asyncSomething()
});
// Doesn't work.
beforeEach(("Don't add string here") => {..});

Meteorjs test Meteor methods

I have the following simple Meteor Method that I want to test.
It inserts a given Object into my collection
Meteor.methods({
insertHelper(profile){
HelperCollection.insert(profile);
return true;
},
}
For Testing i use "dispatch:mocha-phantomjs"
My Test so far is the following:
describe('methods', () => {
it('can delete owned task', () => {
Meteor.call('insertHelper',{a: 1});
});
});
When running my tests I get the message " Error: Method 'insertHelper' not found [404]"
So how can I access my Meteor methods from my Test suite?
As discussed in the comments, we have to include the files where the Meteor methods are defined in order to test them :
import '/path/to/method/file.js';
or with require :
require('/path/to/methos/file.js');
EDIT
Meteor advises to use import instead of using require, if you can.

XMLHttpRequest is not defined when testing react-native app with jest

i am trying to test a apiwrapper in a react-native based app using jest (integration testing).
When i run it in the iOs simulator everything runs fine however it wont run my jest tests correctly - i always get:
ReferenceError: XMLHttpRequest is not defined
when i try to run tests using my api wrapper, eg.:
it('Login successful with correct data', () => {
let api = Api.getInstance();
return api.login("test", "testpass")
.then(result => expect(result).toEqual('login_successful'));
});
the api class i am trying to test here does use the fetch api (not vanilla xhr). I assume its something related to jest trying to mock something but have not found a way to make it work yet.
Thanks in advance.
In my case, I'm not testing the search code but only importing it somewhere in my code path, so I decided to just mock it at the global level in a setup.js file (loaded using --require at test run). The following works for me:
// needed in react-instantsearch
class XMLHttpRequest {}
global.XMLHttpRequest = XMLHttpRequest;
I had a similar problem with lokka using XMLHttpRequest. I made a mock for lokka, which my api wrapper class depends on. You could try mocking your api wrapper.
This is what my lokka mock looks like for now. I'll add more to it when I start testing error handling.
export default class {
query() {
return new Promise(resolve => {
resolve(200);
});
}
}
You might be able to mock your api wrapper with something similar:
export default class Api {
getInstance() {
\\ However you implemented getInstance
}
login(user, password) {
return new Promise(resolve => {
resolve('login_successful');
});
}
}

How to set jasmine for karma e2e for testing angular app?

I try to create e2e tests with karma and jasmine with yeoman. In my karma-e2e.conf.js I add jasmine:
files = [
JASMINE,
JASMINE_ADAPTER,
ANGULAR_SCENARIO,
ANGULAR_SCENARIO_ADAPTER,
'test/e2e/**/*.js'
];
A need async testing so I need to use runs, waits, waitsFor (https://github.com/pivotal/jasmine/wiki/Asynchronous-specs)
But if I try to use it:
it('test', function () {
runs(function () {
...
});
});
Scenatio test runner returns this:
TypeError: Cannot call method 'runs' of null
at runs (http://localhost:8080/adapter/lib/jasmine.js:562:32)
at Object.<anonymous> (http://localhost:8080/base/test/e2e/eduUser.js:42:3)
at Object.angular.scenario.SpecRunner.run (http://localhost:8080/adapter/lib/angular-scenario.js:27057:15)
at Object.run (http://localhost:8080/adapter/lib/angular-scenario.js:10169:18)
I don't know where the problem is. Can you help me please?
Angular e2e tests with Karma don't and can't use the JASMINE adapter. Instead you have the ANGULAR_SCENARIO_ADAPTER which has a similar feel to writing Jasmine tests.
All commands in the adapter's API are asynchronous anyway. For example element('#nav-items').count() doesn't return a number, it returns a Future object. Future objects are placed in a queue and executed asynchronously as the runner progresses. To quote the API docs:
expect(future).{matcher}:
[...] All API statements return a future object, which get a value assigned after they are executed.
If you need to run your own asynchronous test code, you can extend the adapter's DSL, this is easier than it might sound. The idea is that you return your own Future which can be evaluated by a matcher such as toBe(). There are some examples on how to do this in the e2e-tests.js Gist from Vojta. Just remember to call done(null, myRetrunValue); when your test code is successful (myRetrunValue is the value evaluated by your matcher). Or done('Your own error message'); if you want the test to fail.
UPDATE: In response to question below. To simulate a login, first add a function called login to the dsl:
angular.scenario.dsl('login', function() {
return function(selector) {
// #param {DOMWindow} appWindow The window object of the iframe (the application)
// #param {jQuery} $document jQuery wrapped document of the application
// #param {function(error, value)} done Callback that should be called when done
// (will basically call the next item in the queuue)
return this.addFutureAction('Logging in', function(appWindow, $document, done) {
// You can do normal jQuery/jqLite stuff here on $document, just call done() when your asynchronous tasks have completed
// Create some kind of listener to handle when your login is complete
$document.one('loginComplete', function(e){
done(null, true);
}).one('loginError', function(e){
done('Login error', false);
});
// Simulate the button click
var loginButton = $document.find(selector || 'button.login');
loginButton.click();
})
};
});
And then call:
beforeEach( function()
{
expect( login('button.login') ).toBeTruthy();
});