is there an equivalent to cypress the dependsonmethods in testNG selenium? - cypress

Is there as simple as dependsonmethods used in test annotations in testNG equivalent in cypress?
example if in selenium test annotations it looks like this?
#Test()
public void tc1(){
}
#Test(dependsOnMethods= {"tc1"})
public void tc2(){
}
#Test(dependsOnMethods= {"tc1"})
public void tc3(){
}
if I am not mistaken this is somewhat like a parent function with 2 child functions that when the parent conditions inside is error then the two child functions will be skip.
in cypress I know there is callbacks and promise but depending on the kind of assertion you want it becomes more complex to me. I am new to cypress
please let me know if not too much to ask, can you at least provide an example
thanks

Cypress doesn't have dependsOnMethods like TestNG runner provides as both of them are different. But whatever you want to achieve, you can achieve through hooks provided by Mocha, as Cypress has Mocha as a test framework in itself.
Note: This is what all you can do with hooks and your problem should be solved with below code. If you have any specific requirement, please mention it.
describe('test suite', () => {
before(() => {})
beforeEach(() => { // put tc1() functionality
})
it('tc2 functionality', () => {
// now tc2() depends on beforeEach block where tc1 functionality is done
})
it('tc3 functionality', () => {
// now tc3() depends on beforeEach block where tc1 functionality is done
})
})

Related

How to programmatically stop a Cypress test

I have a Cypress test that has only one testing case (using v10.9 with the test GUI):
describe("Basic test", () => {
it.only("First test", () => {
cy.visit("http://localhost:9999");
cy.pause();
//if(cy.get("#importantBox").contains(...) {
//}
//else
{
Cypress.runner.stop();
console.log("Stopping...");
}
console.log("Visiting...");
cy.visit("http://localhost:9999/page1");
If a certain element doesn't exist in the page, I don't want the test to continue, so I try to stop it.
Unfortunately, I can see this in the console:
Stopping...
Visiting...
And the test keeps going without the necessary data...
So, can I somehow stop it without using huge if statements?
Stopping the test is relatively easy, the harder part is the condition check.
Cypress runner is built on the Mocha framework, which has a .skip() method. If you issue it in your else clause and inside the Cypress queue, the test will stop.
Two ways to access skip():
Using a function() callback gives access to this which is the Mocha context
it('stops on skip', function() {
...
cy.then(() => this.skip()) // stop here
})
Use cy.state() internal command (may be removed at some point)
it('stops on skip', () => {
...
cy.then(() => cy.state('test').skip()) // stop here
})
You should be aware that all Cypress commands and queries run on an internal queue which is asynchronous to javascript code in the test like console.log("Visiting..."), so you won't get any useful indication from that line.
To use synchronous javascript on the queue, wrap it in a cy.then() command as shown above with the skip() method, so to console log do
cy.then(() => console.log("Visiting..."))

In Mocha, why do I want to use only()/skip()?

What is the point of only() and skip()? If I only want to have a single it/describe get executed, why should I keep the other things in the file? If I want to skip something, why shouldn't I just remove that code? When does one want to use those methods?
About only. Imagine that you have 2000 unit tests in some npm module. And you need write 3 more tests for new feature. So you create something.test.js file and write test cases with describe.only()
const assert = require('assert')
describe.only('sample class', () => {
it('constructor works', () => {
assert.deepEqual(true, true)
})
it('1st method works', () => {
assert.deepEqual(true, true)
})
it('2nd method works', () => {
assert.deepEqual(true, true)
})
})
Now if you launch test locally via npm test, you run only your 3 tests, not whole bunch of 2003 tests. Tests are written much faster with only
About skip. Imagine that you need to implement urgent feature in 20mins, you don't have enough time to write tests, but you have time to document your code. As we know unit tests are the best documentation, so you just write test cases how code should works with describe.skip()
describe.skip('urgent feature', () => {
it('should catch thrown error', () => {})
})
Now everyone in your team know about your new functionality and maybe someone write tests for you. Now the knowledge of how your new feature works is not only in your head, the whole team knows about it. It's good for the project and business.
more reasons to use skip

Post result to external api after each test case

I'm setting up a CI-chain and decided to use Cypress for the UI testing. I need to get the result for each individual testcase in my suite. Preferably from within Node in for example a afterEach statement.
Has anyone done this before? Is there any built-in support for this?
I do not want to parse the end result for testcases preferably.
It was possible by using Mocha's this.currentState in conjunction with Cypress plugins.
This is how I solved it:
cypress/plugins/index.js
on("task", {
testFinished(event) {
console.log(event.title, event.result);
return null;
}
});
in my testsuite
afterEach(function() {
cy.task("testFinished", { title: this.currentTest.title, result: this.currentTest.state });
});
The console.log in plugins can now easily be switched for a POST request to wherever you want to store the results.

Conditionally ignore individual tests with Karma / Jasmine

I have some tests that fail in PhantomJS but not other browsers.
I'd like these tests to be ignored when run with PhantomJS in my watch task (so new browser windows don't take focus and perf is a bit faster), but in my standard test task and my CI pipeline, I want all the tests to run in Chrome, Firefox, etc...
I've considered a file-naming convention like foo.spec.dont-use-phantom.js and excluding those in my Karma config, but this means that I will have to separate out the individual tests that are failing into their own files, separating them from their logical describe blocks and having more files with weird naming conventions would generally suck.
In short:
Is there a way I can extend Jasmine and/or Karma and somehow annotate individual tests to only run with certain configurations?
Jasmine supports a pending() function.
If you call pending() anywhere in the spec body, no matter the expectations, the spec will be marked pending.
You can call pending() directly in test, or in some other function called from test.
function skipIfCondition() {
pending();
}
function someSkipCheck() {
return true;
}
describe("test", function() {
it("call pending directly by condition", function() {
if (someSkipCheck()) {
pending();
}
expect(1).toBe(2);
});
it("call conditionally skip function", function() {
skipIfCondition();
expect(1).toBe(3);
});
it("is executed", function() {
expect(1).toBe(1);
});
});
working example here: http://plnkr.co/edit/JZtAKALK9wi5PdIkbw8r?p=preview
I think it is purest solution. In test results you can see count of finished and skipped tests.
The most simple solution that I see is to override global functions describe and it to make them accept third optional argument, which has to be a boolean or a function returning a boolean - to tell whether or not current suite/spec should be executed. When overriding we should check if this third optional arguments resolves to true, and if it does, then we call xdescribe/xit (or ddescribe/iit depending on Jasmine version), which are Jasmine's methods to skip suite/spec, istead of original describe/it. This block has to be executed before the tests, but after Jasmine is included to the page. In Karma just move this code to a file and include it before test files in karma.conf.js. Here is the code:
(function (global) {
// save references to original methods
var _super = {
describe: global.describe,
it: global.it
};
// override, take third optional "disable"
global.describe = function (name, fn, disable) {
var disabled = disable;
if (typeof disable === 'function') {
disabled = disable();
}
// if should be disabled - call "xdescribe" (or "ddescribe")
if (disable) {
return global.xdescribe.apply(this, arguments);
}
// otherwise call original "describe"
return _super.describe.apply(this, arguments);
};
// override, take third optional "disable"
global.it = function (name, fn, disable) {
var disabled = disable;
if (typeof disable === 'function') {
disabled = disable();
}
// if should be disabled - call "xit" (or "iit")
if (disable) {
return global.xit.apply(this, arguments);
}
// otherwise call original "it"
return _super.it.apply(this, arguments);
};
}(window));
And usage example:
describe('foo', function () {
it('should foo 1 ', function () {
expect(true).toBe(true);
});
it('should foo 2', function () {
expect(true).toBe(true);
});
}, true); // disable suite
describe('bar', function () {
it('should bar 1 ', function () {
expect(true).toBe(true);
});
it('should bar 2', function () {
expect(true).toBe(true);
}, function () {
return true; // disable spec
});
});
See a working example here
I've also stumbled upon this issue where the idea was to add a chain method .when() for describe and it, which will do pretty much the same I've described above. It may look nicer but is a bit harder to implement.
describe('foo', function () {
it('bar', function () {
// ...
}).when(anything);
}).when(something);
If you are really interested in this second approach, I'll be happy to play with it a little bit more and try to implement chain .when().
Update:
Jasmine uses third argument as a timeout option (see docs), so my code sample is replacing this feature, which is not ok. I like #milanlempera and #MarcoCI answers better, mine seems kinda hacky and not intuitive. I'll try to update my solution anyways soon not to break compatibilty with Jasmine default features.
I can share my experience with this.
In our environment we have several tests running with different browsers and different technologies.
In order to run always the same suites on all the platforms and browsers we have a helper file loaded in karma (helper.js) with some feature detection functions loaded globally.
I.e.
function isFullScreenSupported(){
// run some feature detection code here
}
You can use also Modernizr for this as well.
In our tests then we wrap things in if/else blocks like the following:
it('should work with fullscreen', function(){
if(isFullScreenSupported()){
// run the test
}
// don't do anything otherwise
});
or for an async test
it('should work with fullscreen', function(done){
if(isFullScreenSupported()){
// run the test
...
done();
} else {
done();
}
});
While it's a bit verbose it will save you time for the kind of scenario you're facing.
In some cases you can use user agent sniffing to detect a particular browser type or version - I know it is bad practice but sometimes there's effectively no other way.
Try this. I am using this solution in my projects.
it('should do something', function () {
if (!/PhantomJS/.test(window.navigator.userAgent)) {
expect(true).to.be.true;
}
});
This will not run this particular test in PhantomJS, but will run it in other browsers.
Just rename the tests that you want to disable from it(...) to xit(...)
function xit: A temporarily disabled it. The spec will report as
pending and will not be executed.

Is there a way to add a Jasmine matcher to the whole environment

There are plenty of documents that show how to add a matcher to a Jasmine spec (here, for example).
Has anyone found a way to add matchers to the whole environment; I'm wanting to create a set of useful matchers to be called by any and all tests, without copypasta all over my specs.
Currently working to reverse engineer the source, but would prefer a tried and true method, if one exists.
Sure, you just call beforeEach() without any spec scoping at all, and add matchers there.
This would globally add a toBeOfType matcher.
beforeEach(function() {
var matchers = {
toBeOfType: function(typeString) {
return typeof this.actual == typeString;
}
};
this.addMatchers(matchers);
});
describe('Thing', function() {
// matchers available here.
});
I've made a file named spec_helper.js full of things like custom matchers that I just need to load onto the page before I run the rest of the spec suite.
Here's one for jasmine 2.0+:
beforeEach(function(){
jasmine.addMatchers({
toEqualData: function() {
return {
compare: function(actual, expected) {
return { pass: angular.equals(actual, expected) };
}
};
}
});
});
Note that this uses angular's angular.equals.
Edit: I didn't know it was an internal implementation that may be subjected to change. Use at your own risk.
jasmine.Expectation.addCoreMatchers(matchers)
Based on previous answers, I created the following setup for angular-cli. I also need an external module in my matcher (in this case moment.js)
Note In this example I added an equalityTester, but it should work with a customer matcher
Create a file src/spec_helper.ts with the following contents:
// Import module
import { Moment } from 'moment';
export function initSpecHelper() {
beforeEach(() => {
// Add your matcher
jasmine.addCustomEqualityTester((a: Moment, b: Moment) => {
if (typeof a.isSame === 'function') {
return a.isSame(b);
}
});
});
}
Then, in src/test.ts import the initSpecHelper() function add execute it. I placed it before Angular's TestBed init, wich seems to work just fine.
import { initSpecHelper } from './spec_helper';
//...
// Prevent Karma from running prematurely.
__karma__.loaded = function () {};
// Init our own spec helper
initSpecHelper();
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
//...

Resources