Qunit user actions testing - qunit

I am trying to setup Qunit to test user actions like this:
QUnit.test( "Ran user search", function( assert ) {
assert.greaterThan($('#user-list .list li').length, 0, 'Number of results returned');
//setup user settings tests
var testUser = $('#user-list .list li').first();
testUser.find('.show-hide-more').trigger('click');
var testSettingsPanel = testUser.find('.show-more').first();
assert.equal(testSettingsPanel.css('display'), 'block', 'Settings panel should be openable');
});
The final assert fails because the display style is still none and not block. The click event should be changing it from none to block, and when I run the steps one by one in the console this is what happens, so my guess is there is a race condition happening in here. Anyone see what I need to change?
Edit
Adding this after the trigger:
console.log(testSettingsPanel.css('display'));
Gives me 'none', so there definitely seems to be a race condition or something going on. How can I overcome this?

Worked the issue out. Turns out what I thought was a simple toggle click was actually an ajax call, which I didn't recognise because I'm not yet familiar with the library.
This works fine:
var done = assert.async();
setTimeout(function() {
assert.equal(testSettingsPanel.css('display'), 'block', 'Settings panel should be openable');
done();
}, 1000);

Related

Hide Testcafe Overlay

I'm trying to use testcafe to fill forms on a page.
When the form is filled, I'd like to be able to stop the test with the window still open so a human can review the form before clicking submit.
I can pause the test with t.debug() but this locks the page and shows the testcafe controls overlay at the bottom.
Is there a way I can remove this overlay and unlock the page?
I've tried using client functions to hide the element with javascript as follows:
test('test_1', async (t) => {
const hideOverlay = ClientFunction(function() {
const target = document.querySelector('#root-hammerhead-shadow-ui > div > div');
target.style.display = 'none';
return true;
})
await t.wait(5000);
setTimeout(async function() {
const res = await hideOverlay();
console.log('-------->', { res });
}, 6000);
await t.debug();
});
Since no code will be executed after debug is invoked, I thought I could use a settimeout to queue the call to the function that hides the overlay, so that it is queued and only executes after debug is called and the overlay is visible.
Didn't work though :( code didn't execute, got an unhandled promise rejection.
Could really use some help here, thanks :)
Yes, you can unlock the page by clicking the 'Unlock page' button in the footer as #VysakhMohan mentioned in the comment.
Please refer to the client-side debugging documentation for more details.

How to use Jest to test React rendered async data?

I am using React for render and Jest/Jasmine for test. I have test written using old Jest/Jasmine waitsFor and runs but these are gone now in Jasmine 2 and I am not sure how to replace with new done asyncs.
In my code React renders a small page about a user. That page has an AJAX call to fetch user posts. I want to test that user posts have come back nice, and waitsFor was very, very good at this: wait until user has some post, then continue.
I looked online at lots of people talking about using AJAX calls inside Jest test which is not what I want. My Jest test has no idea about AJAX call being made, so I need a way to wait until results come back.
Here is my current code with waitsFor and runs:
it('loads user post', () => {
var page = TestUtils.renderIntoDocument(
<UserPage params={{user: 'fizzbuzz', 'pass': 'xxx'}} />
);
waitsFor(() => {
return page.state.posts.length > 0;
}, "post loaded", 10000);
runs(() => {
var posts = TestUtils.scryRenderedDOMComponentsWithClass(page, 'post');
expect(posts.length).toEqual(10);
});
});
How can I delete the waitsFor and runs and replace with Jasmine 2.0 code that works? All Jest test knows is that page.state.posts.length must be greater than 0 before expecting anything.
You should refactor this test into two unit tests that will provide a more rigorous testing of your code. It would make the tests more independent of one another and help identify errors in a more refined scope. These won't be exact as I do not know what your code is like, but here's something along the lines I would expect to see: -
it('generates the expected properties for a page', function () {
var page = TestUtils.renderIntoDocument(
<UserPage params={{user: 'fizzbuzz', 'pass': 'xxx'}} />
);
expect(page.someProperty).toBeDefined();
expect(page.user).toEqual('fizzbuzz');
});
it('generates the correct number of posts from a given page object', function () {
var fakePage = {
// put your fake mock data here that TestUtils expects
};
var posts = TestUtils.scryRenderedDOMComponentsWithClass(fakePage, 'post');
expect(posts.length).toEqual(10);
});
I am not too sure what is happening in your renderIntoDocument function so the top test may be a little broken... It looks like there is either too much going on inside the function, or you need to test the calls that function is making instead. If you elaborate on what it does I'll edit the answer.

CasperJS form fill sometimes stays on the current page

I have a simple casperjs test to submit a search form on my homepage. Then I assert that the title on the landing page is correct.
Works fine on my computer (OSX 10.9.2) but on my colleague's laptops (a Win 7 and Win 8), the test fails randomly because casper "thinks" it is still on the search page.
casper.test.begin('Search', function(test) {
casper.start("http://localhost:8080/site", function() {
this.fill(searchForm, { query: goodQuery }, true);
});
casper.then(function() {
// sometimes fails, says it's "My Project" main title
test.assertTitle('Search Result', 'Search result title is ok');
});
}
Introducing a casper.waitFor(3000) before checking the page title does not change the outcome. I've also tried to replace the then step by a waitForUrl, but it fails after 5 secs, saying it is still on the current page.
Plenty of other tests work fine on all computers but it's the only one with form submition.
Any hints on how to solve or properly work around this? I'd rather not simulate a click on the submit button (more coupling to the form internals) if possible (but it would be okay I guess).
Thanks
$ casperjs --version
1.1.0-beta3
$ phantomjs --version
1.9.7
EDIT: submitting the form and waitForUrldid not help. I found out that the test actually runs fine on its own, even on the Windows 7 machine. But when I run two tests:
01 search.js (the one described above)
02 menu.js (a simple one, merely containing assertExists)
'search.js' fails most of the time... and sometimes 'menu.js' fails instead! I suspect some mishandled concurrent access, although it consistently works on OSX. I must be doing something wrong. Both tests have the same structure:
casper.test.begin('Some test', function(test) {
casper.start(someUrl, function() {
// some test
});
casper.run(function() {
test.done();
});
});
Any clue?
Try :
casper.test.begin('Search', function(test) {
casper.start("http://localhost:8080/site", function() {
this.fill(searchForm, {
query: goodQuery
},false);
this.click("your selector for submit button");
});
casper.then(function() {//you should use waitForUrl/Selector/Text() instead
// sometimes fails, says it's "My Project" main title
test.assertTitle('Search Result', 'Search result title is ok');
});
casper.run(function() {
this.test.comment('------ Tests over ----\n');
test.done();
});
});
It's better to submit the form by clicking. Sometimes (often) it doesn't pass putting the fill arg at true. Just put the correct selector for the submit button.
You should wait for an item to appear on the following page. I would change your code to the following:
casper.test.begin('Search', function(test) {
casper.start("http://localhost:8080/site", function() {
this.fill(searchForm, { query: goodQuery }, true);
});
casper.waitForSelector('#someSelectorOnNextPage', function() {
test.assertTitle('Search Result', 'Search result title is ok');
});
}
I also experience same issue. Suprisingly adding empty then() handler fixes that in v1.1.0-beta3. I don't think this is expected behavior though:
casper.test.begin('Search', function(test) {
casper.start("http://localhost:8080/site", function() {
this.fill(searchForm, { query: goodQuery }, true);
});
// Do nothing here, just call it as a placeholder
// Here http://localhost:8080/site sends us to the next endpoint
casper.then(function() {});
// Now this is the final page we actually want to assert
casper.then(function() {
test.assertTitle('Search Result', 'Search result title is ok');
});
}
EDIT:
Although question author says casper.waitForUrl() didn't work for them, it did work for me as an alternative solution.
What does look strange is that in verbose mode whatever returns a 301 status code along with Location Header is recognized as HTTP 200 response by Casper.
EDIT 2:
Well obviously it doesn't happen every time, but what I noticed is that Casper sometimes doubles the previous response (that's why I thought it recognizes some specific HTTP codes as 200 mistakenly and that's why author's code functioned as if it stayed on same page after form submission) and sometimes not.
waitForUrl() fixes that obviously but there is still some underneath issue in Casper which scares me a bit and I hope I will find some time to report it with all the dumps to Casper issue tracker.

Protractor : How to wait for page complete after click a button?

In a test spec, I need to click a button on a web page, and wait for the new page completely loaded.
emailEl.sendKeys('jack');
passwordEl.sendKeys('123pwd');
btnLoginEl.click();
// ...Here need to wait for page complete... How?
ptor.waitForAngular();
expect(ptor.getCurrentUrl()).toEqual(url + 'abc#/efg');
Depending on what you want to do, you can try:
browser.waitForAngular();
or
btnLoginEl.click().then(function() {
// do some stuff
});
to solve the promise. It would be better if you can do that in the beforeEach.
NB: I noticed that the expect() waits for the promise inside (i.e. getCurrentUrl) to be solved before comparing.
I just had a look at the source - Protractor is waiting for Angular only in a few cases (like when element.all is invoked, or setting / getting location).
So Protractor won't wait for Angular to stabilise after every command.
Also, it looks like sometimes in my tests I had a race between Angular digest cycle and click event, so sometimes I have to do:
elm.click();
browser.driver.sleep(1000);
browser.waitForAngular();
using sleep to wait for execution to enter AngularJS context (triggered by click event).
You don't need to wait. Protractor automatically waits for angular to be ready and then it executes the next step in the control flow.
With Protractor, you can use the following approach
var EC = protractor.ExpectedConditions;
// Wait for new page url to contain newPageName
browser.wait(EC.urlContains('newPageName'), 10000);
So your code will look something like,
emailEl.sendKeys('jack');
passwordEl.sendKeys('123pwd');
btnLoginEl.click();
var EC = protractor.ExpectedConditions;
// Wait for new page url to contain efg
ptor.wait(EC.urlContains('efg'), 10000);
expect(ptor.getCurrentUrl()).toEqual(url + 'abc#/efg');
Note: This may not mean that new page has finished loading and DOM is ready. The subsequent 'expect()' statement will ensure Protractor waits for DOM to be available for test.
Reference: Protractor ExpectedConditions
In this case, you can used:
Page Object:
waitForURLContain(urlExpected: string, timeout: number) {
try {
const condition = browser.ExpectedConditions;
browser.wait(condition.urlContains(urlExpected), timeout);
} catch (e) {
console.error('URL not contain text.', e);
};
}
Page Test:
page.waitForURLContain('abc#/efg', 30000);
I typically just add something to the control flow, i.e.:
it('should navigate to the logfile page when attempting ' +
'to access the user login page, after logging in', function() {
userLoginPage.login(true);
userLoginPage.get();
logfilePage.expectLogfilePage();
});
logfilePage:
function login() {
element(by.buttonText('Login')).click();
// Adding this to the control flow will ensure the resulting page is loaded before moving on
browser.getLocationAbsUrl();
}
Use this I think it's better
*isAngularSite(false);*
browser.get(crmUrl);
login.username.sendKeys(username);
login.password.sendKeys(password);
login.submit.click();
*isAngularSite(true);*
For you to use this setting of isAngularSite should put this in your protractor.conf.js here:
global.isAngularSite = function(flag) {
browser.ignoreSynchronization = !flag;
};
to wait until the click itself is complete (ie to resolve the Promise), use await keyword
it('test case 1', async () => {
await login.submit.click();
})
This will stop the command queue until the click (sendKeys, sleep or any other command) is finished
If you're lucky and you're on angular page that is built well and doesn't have micro and macro tasks pending then Protractor should wait by itself until the page is ready. But sometimes you need to handle waiting yourself, for example when logging in through a page that is not Angular (read how to find out if page has pending tasks and how to work with non angular pages)
In the case you're handling the waiting manually, browser.wait is the way to go. Just pass a function to it that would have a condition which to wait for. For example wait until there is no loading animation on the page
let $animation = $$('.loading');
await browser.wait(
async () => (await animation.count()) === 0, // function; if returns true it stops waiting; can wait for anything in the world if you get creative with it
5000, // timeout
`message on timeout`
);
Make sure to use await
you can do something like this
emailEl.sendKeys('jack');
passwordEl.sendKeys('123pwd');
btnLoginEl.click().then(function(){
browser.wait(5000);
});
browser.waitForAngular();
btnLoginEl.click().then(function() { Do Something });
to solve the promise.

How to notify the FormWizard plugin about skipped steps (not shown) to avoid losing data?

I have the formwizard plugin integrated with an 8-step form; The problem is, whenever I'm trying to edit information and then jump to an specific step in the form so basically jumping ignoring previous steps, all steps that were not shown (cuz I jumped them) are not sent!!! :( so losing all data already populated into those fields.
For example,
$("#demoForm").formwizard("show","Step4");
This will trigger Step4, but if I am at Step1 and havent seen Step2 and Step3, and jump right into Step4.. then the plugin ignores those Step2 and 3 so when my processing script will process empty data. I would like to know how to notify the plugin that there are steps that were now shown in order to submit those values.
Note: I'm not using Ajax for this.
This is where the settings are:
$("#demoForm").formwizard({
formPluginEnabled: false,
validationEnabled : true,
disableUIStyles : true,
textNext: "Siguiente",
textBack: "Anterior",
textSubmit: "Guardar",
focusFirstInput : true
},
{
messages: { email: "Invalid email"}
},
{
// form plugin settings
}
);
Jumping to an specific step like this...
$('#gotostep').change(function(){
if($(this).val() != '')
{
$("#demoForm").formwizard("show",$(this).val());
return false;
}
});
..same thing happens if I try to force a submit changes on any steps using: $("#demoForm").submit(); :/
Thanks in advanced!
Frank
I guess it should suffice to enable all disabled input elements in the form when the form is submitted? Do this e.g. by hooking up a callback to the forms submit event like this:
$(function(){
var form = $("#demoForm");
form.submit(function(){
form.find(":input:disabled").removeAttr("disabled");
})})
Hope this helps.

Resources