Calling 'it' method after condition is met in Jasmine - jasmine

I recently started doing automation tests for iOS using Appium and Jasmine.
it('should add product to cart', () => {
driver.pause(1000);
$("~ProductDetailCTAView.addToCartButton").click();
driver.pause(3000);
});
it('should see elements when clicked on the cart button', () => {
$("~UIBarButtonItem.shopBarButton").click();
$("~CartController.CartCell.0");
driver.pause(3000);
});
What I want to do is, call these methods if addToCartButton is enabled. I tried putting them in an if condition but it says I can't put 'it' methods inside if-else conditions. I looked for asynchronous testing in Jasmine on internet but got confused.

You really can't put an 'IF' on Jasmine unit testing 'it' ,
If you need to test different paths of your code, you should write an entire 'it' to it.

Related

Cypress: How to capture text from a selector on one page to use as text on another page

New cypress user here, I am aware that cypress does not handle variables like how testcafe and others do due to the asyn nature of it. Using the example given and what I could find I have this as an example:
cy.get('selector').invoke('text').as('text_needed')
cy.get('#text_needed')
const txtneeded = this.text_needed
cy.log(txtneeded)
This looks at a given selector, takes what it finds and uses it as text and set it as a variable usable at any time in the test and outputs it to the log. The plan is to use that text in a search filter in another page to find the item it references.
The problem is that it fails with Cannot read properties of undefined (reading 'text_needed')
Is this because the content of the selector is not assigned to text properly, the outer html is <a data-v-78d50a00="" data-v-3d3629a7="" href="#">PO90944</a> The PO90944 is what I want to capture.
Your help would be appreciated!
You cannot save an alias and access it via this.* in the same execution context (callback) because it's a synchronous operation and your alias is not yet resolved at this time.
This is a correct way to go:
cy.get('selector').invoke('text').as('text_needed')
cy.get('#text_needed').then(txtneeded => {
cy.log(txtneeded)
})
First, make sure to define it as traditional function, not as an arrow function as this context doesn't work as you'd expect there, more info here.
Next, typically in a single test you should use .then() callback to perform additional actions on elements, and use aliases when you need to share context between hooks or different tests, so please consider the following:
// using aliases together with this within the single test won't work
cy.get(<selector>).invoke('text').as('text_needed')
cy.get('#text_needed').should('contain', 'PO90944') // works fine
cy.log(this.text_needed) // undefined
// this will work as expected
cy.get(<selector>).invoke('text').then(($el) => {
cy.wrap($el).should('contain', 'PO90944'); // works fine
cy.log($el) // works fine
});
Setting alias in beforeEach hook for example, would let you access this.text_needed in your tests without problems.
Everything nicely explained here.
Edit based on comments:
it('Some test', function() {
cy.visit('www.example.com');
cy.get('h1').invoke('text').as('someVar');
});
it('Some other test', function() {
cy.visit('www.example.com');
cy.log('I expect "Example Domain" here: ' + this.someVar);
});
And here's the output from cypress runner:

What is the definition of "each test" when Cypress docs say "between each test"?

The Cypress docs Best Practices section, under the heading "Is resetting the state necessary?" says the following:
Remember, Cypress already automatically clears localStorage, cookies, sessions, etc before each test.
Does "each test" mean "each it() block"?
Given the following code, and it's comments, is the second it() block technically cookie-less, and session-less, and passing just because we're lucky that the page hasn't changed?
describe('When logged in', () => {
before(() => {
cy.customLoginAndSetSomeCookies()
cy.visit('/page-for-logged-in-folks-only')
})
it('I can see some stuff!', () => {
// `before` ran and set up cookies for us.
// `visit` set the page for us.
// So this passes just fine.
cy.get('#welcome').should('contain', 'You can see me!')
})
it('Is this a new test? Am I logged out?', () => {
// Am I technically cookie-less here, but since
// I'm still on this page I can still see this?
// (Passes, but only because no page transition?)
cy.get('#welcome').should('contain', 'You can see me!')
})
})
If I'm correct, then while these may pass fine, the problem comes if we try to do some "logged in" stuff in the second it() block. So the better pattern would probably be to combine these into a larger single block, or use beforeEach instead of before... BUT, I'm not confident in that answer, because I'm not sure the definition of "each test".
I found your answer, from their pricing page :)
What counts as a test recording?
We consider each time the it() function is called to be a single test. Only test runs configured to record to the Dashboard Service when running Cypress headlessly count toward your plan limit.

Can I have multiple 'it' in one 'describe' and use a beforeEach

So, I have a beforeEach to load up my site. I am mainly writing my test in one describe function with one it function.
my beforeEach is in the index.js>Support>Cypress folder
beforeEach(() => {
cy.visit('http://localhost:3000/');
});
Current Code Example:
describe('this is a test',function(){
it('will be a test example',function(){
cy.contains('test').click
cy.contains('another test').click()
})
})
A co worker pointed out that I should try to break them up to be more clear on what each test is doing so long as each part can run independently. I have several tests that can run independent, however, the beforeEach kicks in for each it('test_name',function() I write.
For example: I write a test to open a card, click on a state, add data about that state, then close. If I break each part into it's own it then it will have the beforeEach start back on the "home" page of my site.
Example of desired code:
describe('this is a test',function(){
it('will be a test example',function(){
cy.contains('test').click
})
it('will test another test',function(){
cy.contains('another test').click()
})
})
Is there a way for those several it functions to continue on the previous test rather than having the beforeEach effect it?
Thank you in advance.
You can use beforeEach() and before(). The behaviour of both is slightly different.
before() only applies once per describe()
beforeEach()applies for every it() in the describe()
Thus what you have to do:
Put all steps you want to only perform once per describe()in a before(). If there are still steps left which you want to perform every it(), put those in a beforeEach().
Note that you can use both before() and beforeEach() together.

Custom matcher not asserting in Astrolabe/Protractor + Jasmine test

I'm writing some page-object driven tests using Protractor and Astrolabe.
Jasmine is being used to implement describe/it style specs.
Adding custom matchers won't work using this.addMatchers (TypeError: Object #<Object> has no method 'toContainLowered'), so I used this guide to implement them.
It seems to be working, until I look closely at the output of my test run:
$> grunt test:func
Running "test:func" (test) task
Running "shell:protractor" (shell) task
Using the selenium server at http://localhost:4444/wd/hub
..
Finished in 6.727 seconds
2 tests, 1 assertion, 0 failures
Here is my code:
var loginPage = require('./../pages/loginPage');
describe('Login page', function () {
var ptor = loginPage.driver;
beforeEach(function () {
jasmine.Matchers.prototype.toContainLowered = function (expected) {
return this.actual.toLowerCase().indexOf(expected) > -1;
};
loginPage.go();
ptor.waitForAngular();
});
it('should display login page', function () {
expect(loginPage.currentUrl).toEqual(ptor.baseUrl);
});
it('should display an error when the username or password is incorrect', function() {
loginPage.login('bad', 'credentials');
ptor.waitForAngular();
expect(loginPage.lblError.getText()).toContainLowered('invalid username and/or password');
// expect(loginPage.lblError.getText()).toContain('Invalid Username and/or Password');
});
});
If I uncomment the last line and remove the toContainLowered matcher, I get the proper output:
2 tests, 2 assertions, 0 failures
I'm having a really difficult time debugging this promise-based code, and any efforts to put a console.log(this.actual.toLowerCase().indexOf(expected) > -1); will print false, which is confusing.
I even tried replacing the entire function definition with just return false;. Which still does not do anything. Finally, I tried passing no argument to the matcher, which should have thrown an Invalid Argument Error or something.
How do I define my own matchers in Jasmine when using Protractor/Astrolabe tests?
I've had similar problems with matchers, in particular with the .not matchers, which all seem to not work. I hypothesise that protractor is extending the Jasmine matchers to deal with the promises, and that that extension hasn't been applied to the .not, or to the custom matchers.
In my case, I wanted a .not.toMatch, and so I just wrote a convoluted regex that gave me what I wanted, with the not embedded in the regex.
I note that your matcher is called "toContainLowered", so perhaps you're looking for lowercase, and therefore you could instead do this with a regex by using .toMatch?
The issue I raised on this on the protractor github is here: https://github.com/angular/protractor/issues/266
I also see, in this code file: https://github.com/angular/protractor/blob/master/jasminewd/spec/adapterSpec.js, that the last commit is marked as "patched matcher should understand not". That might either fix the custom matchers for you, or provide an indication of what needs to be done to fix that custom matcher.
EDIT: now looking further into that issue thread, I see you've already been there. Which makes my answer somewhat superfluous. :-)

Declare "pending" specs/tests in jasmine or mocha

I would like to describe specifications that should be in the code, but implementation of them would be added later. In test results I would like to see them neither passed nor failed, but "are waiting" for implementation instead.
I'm interested if it is possible to do out of the box in mocha or jasmine.
Thanks
You can declare disabled functions in both mocha and jasmine using xit (instead of it), and xdescribe (instead of describe).
If you want the tests to appear as pending, in mocha you can just leave the second parameter blank in the call to the it() function. For example:
describe('Something', function () {
it('Should be pending')
xit('Should be disabled, i.e not appear on the list')
});
Update: The behaviour for xit/xdescribe is might change in Mocha if this merge happens: https://github.com/visionmedia/mocha/pull/510
Starting with Jasmine 2.0, writing xit() instead of it() for a spec marks it as pending (as already said in a comment of the accepted answer).
Aditionally, there is a pending() function you can call anywhere inside a spec to mark it as pending:
it("can be declared by calling 'pending' in the spec body", function() {
expect(true).toBe(false);
pending();
});
See also the documentation on pending specs in Jasmine 2.0.
In mocha, you can also use skip:
describe('my module', function() {
it.skip('works', function() {
// nothing yet
});
});
You can also do describe.skip to skip whole sections.

Resources