How to add wait for the test? - webdriver-io

I am using WebdriverIO for the following test
webdriverio
.remote(options)
.init()
.url('http://www.google.com')
.getTitle().then(function(title) {
console.log('Title was: ' + title);
})
.end();
However, my ISP provide a web virus checking page between google.com, so the test always return the virus checking page title. How can I make sure the result always return Google?

Using pauses in your tests is a bad practice. It's better to use explicit waits instead.
E.g. you can use waitUntil method, provided by Wdio API. So, you can create helper function to wait for expected URL.
Here is the example in ES6:
function waitForUrl(url, timeout) {
browser.waitUntil(() => browser.getUrl().includes(url)
}, timeout, `Expected url must be ${url}`)
}
You can simply pass function (or promise) as waitUntil condition along with timeout (in ms), error message and interval (also in ms, default value is 500ms). So, waitUntil will be waiting until that condition is fulfilled with a truthy value. Otherwise, error will be thrown.

You can use the pause(time) function to pause your test for a while till you are redirected to Google.
webdriverio
.remote(options)
.init()
.url('http://www.google.com')
.pause(5000)
.getTitle().then(function(title) {
console.log('Title was: ' + title);
})
.end();

Related

Cypress - log response data from an request after a click()

Although I know this may not be considered as a best practice, but what I want to achieve is to silently delete a record from a database after the same was created throughout UI. In htat way I want to keep our test environment clear as much as possible and reduce the noise of test data.
After my tests create a new record by clicking over the UI, I wait for POST request to finish and then I would like to extract the id from the response (so I can reuse it to silently delete that record by calling the cy.request('DELETE', '/id')).
Here's a sample test I have put on as a showcase. I'm wondering why nothing is logged in this example.
it('GET cypress and log', () => {
cy.server()
.route('**/repos/cypress-io/cypress*')
.as('getSiteInfo');
cy.visit('https://www.cypress.io/dashboard');
cy.get('img[alt="Cypress.io"]')
.click()
.wait('#getSiteInfo')
.then((response) => {
cy.log(response.body)
})
})
As far as I can see from here https://docs.cypress.io/api/commands/wait.html#Alias this should be fine.
your code contains two problems.
First:
The click triggers a new page to be loaded but cypress does not wait until the PageLoad event is raised (because you do not use visit). On my PC the Request takes about 5 seconds until it is triggered after the click. So you should use wait(..., { timeout: 10000 }).
Second:
wait() yields the XHR object, not the response. So your code within then is not correct. Also the body is passed as object. So you should use JSON.stringify() to see the result in the command log.
This code works:
describe("asda", () => {
it('GET cypress and log', () => {
cy.server()
.route('**/repos/cypress-io/cypress*')
.as('getSiteInfo');
cy.visit('https://www.cypress.io/dashboard');
cy
.get('img[alt="Cypress.io"]')
.click()
.wait('#getSiteInfo', { timeout: 20000 })
.then((xhr) => {
cy.log(JSON.stringify(xhr.response.body))
})
})
})
Instead of route and server method, try intercept directly

Is it possible to trigger programmatically a ember mirage request response

I use Ember mirage in my tests. I need to check the state of my tested component after a request has been send but before the respond has been received.
How it is possible to configure my test to avoid the mirage server responds automatically and trigger the response programmatically?
I used to do that with sinonjs but I do not find the way to manage this use case with Ember mirage. It is possible?
http://www.ember-cli-mirage.com/docs/v0.3.x/route-handlers/
You can add a handler like this inside your test:
server.get('/users/:id', function(db, request) {
console.log(request) // to debug request/response
return db.users.find(request.params.id);
});
If I understand your question correctly, you are trying to test a situation on the page (acceptance test) when data were sent to the server but the response still did not arrive.
It is possible to access server instance in your test, so it is not that complicated to create your own method that will pause/resume responding but the simpler option (that I use as well) is just to postpone response from mirage using timing option (http://www.ember-cli-mirage.com/docs/v0.3.x/configuration/#timing). Then, when you do your tests before andThen() you should be in a situation that you wish to test.
you can access the underlying pretender instance and the fact that mirage just passes the timing parameter straight through to the pretender request.
https://github.com/pretenderjs/pretender#timing-parameter
Unfortunately pretender doesn't have docs for requestReferences and requiresManualResolution(verb, path), but this helper function will process all outstanding manual requests
function resolveManualPretenderRequests(pretender) {
pretender.requestReferences.forEach((ref) => {
if (pretender.requiresManualResolution(ref.request.method, ref.request.url)) {
pretender.resolve(ref.request);
}
});
}
Then you can just use mirage to register a manual request handler
server.get('/models:id', { timing: true });
so in an example test, you can use the ember test helper waitFor() to do something like
test('button is disabled while loading', async function(assert) {
assert.expect(2);
// passing true to timing tells the underlying pretender handler wait for the request to be manually processed
server.get('/models/:id', { timing: true });
// await render will wait for promises to settle, but we actually don't want that
const renderPromise = render(hbs`<MyComponent />`);
// the waitFor() helper instead will allow us to just wait for our button to render
await waitFor('button');
const button = this.element.querySelector('button');
// since the request has not resolved yet, the button is disabled
assert.strictEqual(button.disabled, true);
// then we manually resolve the request
resolveManualPretenderRequests(server.pretender);
// now we can await the render so that we get our updated button state
await renderPromise;
// with the request resolved, now the button is no longer disabled
assert.strictEqual(button.disabled, false);
});

Selenium Node API web driver wait timeout handler

I am new to Selenium web drive. Trying to do some page automation and are using driver.wait functions to wait for a selector rendering first and then do some operations later.
Was wondering if Selenium has a way to pass in a timeout handler to manage timeout if the element is not showing up after x seconds.
Here's my code:
driver.wait(function () {
return driver.isElementPresent(webdriver.By.css('input[id="searchMap"]'));
}, 10000);
So after 10 secs if input[id="searchMap"] does not show up, Selenium script will end and Error is thrown.
I am looking for something like this:
driver.wait(function () {
return driver.isElementPresent(webdriver.By.css('input[id="searchMap"]'));
}, 10000, function fail(){
console.log("Time is up!");
});
Found a solution myself. Have to use catch for Selenium promise class.
http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/promise_exports_Promise.html
Here is my code:
driver.wait(function () {
return driver.isElementPresent(webdriver.By.css('div.info-page'));
}, 10000).catch(function(e){
console.log('Catching Error');
});

Qunit beforeEach, afterEach - async

Since start(), stop() will be removed in Qunit 2.0, what is the alternative for async setups and teardowns via the beforeEach, afterEach methods? For instance, if I want the beforeEach to wait for a promise to be finished?
QUnit basically wants people to stop using the global methods (not just start() and stop(), but also test(), expect(), etc). So, as of version 1.16.0, you should always use either the global namespace (QUnit) or the assert API argument passed into the test() functions. This includes the new async control:
QUnit.test( "testing async action", function( assert ) { // <-- note the `assert` argument here
var done = assert.async(); // tell QUnit we're doing async actions and
// hold onto the function it returns for later
setTimeout(function() { // do some async stuff
assert.ok( true, "This happened 100 ms later!" );
done(); // using the function returned from `assert.async()` we
// tell QUnit we're don with async actions
}, 100);
});
If you are familiar with the old start() and stop() way of doing things, you should see that this is extremely similar, but more compartmentalized and extensible.
Because the async() method call is on the assert argument into the test, it cannot be used in the beforeEach() function. If you have an example of how you were doing that before, please post it and we can try to figure out how to git it into the new way.
UPDATE
My mistake previously, the assert object is being passed into the beforeEach and afterEach callbacks on modules, so you should be able to do the same logic that you would do for a test:
QUnit.module('set of tests', {
beforeEach: function(assert) {
var done = assert.async();
doSomethingAsync(function() {
done(); // tell QUnit you're good to go.
});
}
});
(tested in QUnit 1.17.1)
Seeing that nobody has answered the beforeEach/afterEach part: a test suite is supposed to run as soon as the page loads. When that is not immediately possible, then resort to configuring QUnit:
QUnit.config.autostart = false;
and continue with setting up your test suite (initializing tests, feeding them to QUnit, asynchronously waiting for some components to load, be it AJAX or anything else), your site, and finally, when it's ready, just run:
QUnit.start();
QUnit's docsite has it covered.
Ember Qunit, has once exists beforeEach/setup, afterEach/teardown co-exist for a little while.
See PR: https://github.com/emberjs/ember-qunit/pull/125

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();
});