Protractor with mocha and chai - jasmine

I started using Protractor and the first thing I've tried to do is to use Mocha and Chai instead of Jasmine. Although now I'm not sure if that was a good idea.
first I needed to make Chai accessible from all the spec files, without having to import everytime, I found it's possible to do in protractor.conf file:
onPrepare: ->
global.chai = require 'chai'
chai.use require 'chai-string'
chai.use require 'chai-as-promised'
global.expect = chai.expect
now in a spec like this:
it "when clicked should sort ",->
headerColumns.get(0).click()
firstCellText = $$(".first-cell").getText()
secondCellText = $$(".second-cell").getText()
# this won't work
expect(firstCellText).eventually.be.above(secondCellText)
to make it work I could do:
# now this works
$$(".second-cell").getText().then (secondCellText)->
expect(firstCellText).eventually.be.above(secondCellText)
but that's ugly, and I don't want to wrap stuff inside of .then all the time. I'm thinking there should be a better way(?)

I was having the same problem. The issue for me was to add a longer timeout to mocha through the Protractor config.js.
This works because Protractor tests take considerably longer relative to other modules like supertest since an actual browser is being interacted with.
I added
mochaOpts: {
timeout: 5000
}
to my protractor config and the tests passed.

Either you need to mention timeout for the whole test suite using "this.timeout(1000);" just below the describe block, or you can change it for individual test cases by explicitly defining timeout for each "it" block.
example for describe block:
describe("test-suite",function () {
this.timeout(5000);
it("test-case",function () {
//test case code goes here
});
});
example for it block:
it("test-case",function () {
this.timeout("20000");
});

I found this question while I was trying to do the same thing in TypeScript, but the approach in the protractor.conf.js is identical.
Making chai available globally
It appears to achieve this you're right that it needs to be done in the on prepare. a fairly terse example is below. As I understand it this is needed because chai is of course not apart of mocha but some additional candy that we can use with mocha. Unlike jasmine where everything is bundled into the framework.
protractor.conf.js fragment
onPrepare: function() {
var chai = require('chai'); // chai
var chaiAsPromised = require("chai-as-promised"); // deal with promises from protractor
chai.use(chaiAsPromised); // add promise candy to the candy of chai
global.chai = chai; // expose chai globally
}
example spec
Once you've got chai and chai-as-promised setup globally you need to add a "little" boiler plate to your spec to expose expect which comes from chai.
example.e2e-spec.ts fragment
const expect = global['chai'].expect; // obviously TypeScript
it('will display its title', () => {
pageObject.navigateTo();
const title = element(by.css('app-root h1')).getText();
expect(title).to.eventually.contain('An awesome title');
});
Avoiding then
I can't tell what your $$ references are, but if you're using the protractor components browser and by etc. then things clean up a little bit.
The call const title = element(by.css('app-root h1')).getText(); seems to return a promise which jasmine seems to deal with out of the box while mocha+chai doesn't. That's where chai-as-promised comes in.
using our additional syntax candy expect(title).to.eventually.contain('An awesome title'); resolves the promise quite neatly and we've avoided all those then calls, but we do need the eventually.
I've provided you a link to a working TypeScript example that might help demonstrate.

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:

How to find Docs for Jest, Enzyme, Create-React-App, Shallow()?

Im using Create React App and have set up my test files like this:
import React from 'react';
import { shallow, configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Then I set up wrapper using shallow() like this:
let wrapper;
beforeEach(() => {
const defaultProps = {
color: 'orange',
value: 17,
title: 'live services',
link: 'htttp://google.com'
};
wrapper = shallow(<Callout {...defaultProps} />);
});
Im using assertions that I have been using for a while such as
expect(wrapper.find('h5').html()).toContain('some title');
expect(wrapper.containsMatchingElement(<Foo />)).toBe(true);
These assertions work but i want to find more.
I have no idea where to find the docs for the assertions that are available to me.
The assertions I have working so far look a bit like Jasmine assertions in that they are using camel case but the methods are still named differently.
https://jasmine.github.io/
I thought I was using jest and enzyme but the assertions are completely different to those in the Enzyme docs
https://airbnb.io/enzyme/
For example
expect(wrapper.find(Foo)).to.have.lengthOf(3);
Does not work. These methods of find() are not available to my current set up.
In the Jest Docs I can only find assertions for testing javaScript functions and can't find any methods for traversing and testing Virtual DOM or shadow DOM elements like the ones I have been using( see above)
https://jestjs.io/docs/en/jest-object
How do I see what assertions are available to shallow() and shallow.find() with my current setup?
You can find the Jest assertion methods here Jest assertion methods
You could also look at this library package https://www.npmjs.com/package/jest-enzyme

mock StripeCheckout in Jasmine test

I am writing Jasmine tests for my Javascript application. A major time-sink has been testing my code which depends on StripeCheckout. Stripe does not want you to use it offline. I realized I should mock the service, but that has not been easy in Jasmine.
How can I mock "custom" (instead of "simple") usage of StripeCheckout?
I tried to use spies, like so,
var StripeCheckout = jasmine.createSpyObj('StripeCheckout', ['configure']);
But I think the created object needs to attach to the global object (window).
So, I can add an object to the global
object. This worked,
but it feels lame.
Another option could be to tell
Karma to load the
page over the network. This worked for me, but it seems lame to make
a network request for tests.
I'm not sure if you have figured this out yet but an easy way to do this would be to just create a simple mocked implementation for StripeCheckout. Something like this should work.
beforeEach(function() {
module(function($provide) {
$provide.factory('StripeCheckout', function() {
//your mocked custom implementation goes here
configure: function() {
//do something
}
}
}
inject(function($injector) {
StripeCheckoutMock = $injector.get('StripeCheckout');
}
)
This way you are not making a request in order to run your tests. The test will just use the mocked service that you have set up.

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