Programming language used is javascript (promises flow disabled) : using async await to disable the asynchronous nature of javascript
My every test case in test suite has structure like above. Now, How can i want every test case belonging to test suite to be run in a sequence following the trend like
Opening of browser instance for a first test case & running the whole test case which is happening
then closing the above instance of first test case irrespective of the failure/success run.
Now opening the new browser instance for 2nd test case-->>running whole test case--->>closing the browser instance of this particular test case--->>
Now opening the new browser instance for 3rd test case-->>running whole test case--->>closing the browser instance of this particular test case--->>
Is this advisable to run the test suite in this way? If yes, then how should i manage with the commands like browser.close() or whatever your approach is. I have tried this but getting such errors like
AfterAll Failed: invalid session id
Every test case structure
describe("Login Suite", () => {
beforeEach(async function () {
//browser instance initialization & application navigation is happening here
})
it('Test case name', async function () {
try {
// Include test steps
} catch (e) {
browser.logger.info("Test SWM-2019065 failed with exception: " + e)
expect(true).toBe(false, e)
}
})
afterEach(async function () {
//await browser.restart();
or
//await browser.close();
})
})
Related
I'm trying to take a simple screenshot using Cypress, however, it only works in the Cypress GUI (cypress open).
Whenever I run cypress run, it shows that the test succeeded but there's not screenshot saved.
This my code:
describe('Snapshot', () =>
it.only('Take snapshot', async () => {
cy.visit("http://www.google.com");
cy.screenshot();
});
});
Actually, even in the GUI you may get inconsistent behaviour with the code you've provided: you should try to refactor your tests to avoid the use of async.
Cypress already does a lot of async stuff itself. See this answer for more information about how cypress uses promises, and avoiding async, as well as a few things you could try if you really want to use async.
Your code will successfully create screenshots under cypress run if you remove the async keyword like this:
describe('Snapshot', () => {
it.only('Take snapshot', () => {
cy.visit("http://www.google.com");
cy.screenshot();
});
});
Note: I also added the missing opening brace { at the end of the first line. Since you say this code ran for you in the GUI, I'm assuming the brace was not the issue but was simply lost while posting.
I have an application that I created using Ext JS and I am writing tests for it using Selenium WebDriver (the Node package - version 4.0.0-alpha.1) and Jest. In one of my test scripts, I want to wait for a function to be called before continuing with the remaining test logic but I am not sure how to implement this. To help demonstrate what I am trying to accomplish, I created a sample app using Sencha Fiddle. All of the code for that app as well as a running version of the app can be found here: https://fiddle.sencha.com/#view/editor&fiddle/2o6m. If you look in the app folder of the fiddle, you'll see that there is a Test component with a simple controller. There is an onAdd function in the controller and that is the function I want to wait for before continuing since in my actual application there is code in that function that the rest of the tests are dependent on. I can access that function in dev tools by running the following line of code: Ext.ComponentQuery.query('test')[0].getController().onAdd (note that the activeElement needs to be set to the preview iFrame (document.getElementsByName('fiddle-run-iframe')[0]) in the fiddle for this to work). This means I can access the function in driver.executeScript the same way, but once I have the function, I am not sure how to wait for it to be called before continuing. I was trying to use the mock/spy feature in Jest, but this is not working because jest is not defined inside driver.executeScript so I can't call jest.fn or jest.spyOn. I created a sample test script that works with the sample app to demonstrate what I am trying to do, but right now it fails with an error since, as I said, jest is not defined inside driver.executeScript. Here is the code for the sample test script:
const {Builder, By, Key, until} = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
const driver = global.driver = new Builder()
.forBrowser('chrome')
.setChromeOptions(new chrome.Options())
.build();
jest.setTimeout(10000);
beforeAll(async () => {
await driver.manage().window().maximize();
await driver.get('https://fiddle.sencha.com/#view/editor&fiddle/2o6m');
});
afterAll(async () => {
await driver.quit();
});
describe('check title', () => {
it('should be SAMPLE STORE LOAD', async () => {
expect(await driver.wait(until.elementLocated(By.css('.fiddle-title'))).getText()).toBe('SAMPLE STORE LOAD');
});
});
describe('check store add', () => {
it('should call add function', async () => {
let spy;
await driver.switchTo().frame(await driver.findElement(By.name('fiddle-run-iframe')));
await driver.wait(until.elementIsNotVisible(await driver.wait(until.elementLocated(By.xpath('//div[starts-with(#id, "loadmask")]')))));
await driver.executeScript(() => {
const test = document.getElementsByName('fiddle-run-iframe')[0].contentWindow.Ext.ComponentQuery.query('test')[0];
spy = jest.spyOn(test.getController(), 'onAdd'); //This throws an error since jest is not defined inside driver.executeScript
});
expect(spy).toHaveBeenCalled(); //wait for onAdd function to be called before continuing
});
//additional tests occur here after wait...
});
You can ignore all the logic related to switching to the iFrame because that is only necessary for the fiddle since it runs the preview of the app in an iFrame. My actual app does not exist inside an iFrame. Nonetheless, I think this script effectively demonstrates what I am trying to accomplish which is to wait until the onAdd function is called before continuing with my tests. I am not sure if I need to use Selenium or Jest, some combination of the two, or a different testing tool entirely to do this. I am relatively new to writing tests and this is my first time posting on Stack Overflow so I apologize if anything I said is unclear. I would be happy to clarify anything if you have any questions and grateful for any advice you have to offer!
From my point of view, combining 2 different frameworks (approaches to testing) in a single test might not be the best idea. Here are some thoughts on how I would deal with a similar case. Very little theory:
Selenium - is great in simulation end-user behavior with a browser. Basically, it can simulate actions (clicks, text inputs, etc.) and can get information from a browser window (presence of elements, texts, styles, etc.)
Jest - is a unit test framework to jest javascript code.
executeScript is a method of Selenium, it executes any javascript code in a browser. Browser does not know anything about jest - so it's expected that you faced an error you described. Your project knows about jest, as it's specifically imported in a project.
Back to the question "How to check in Selenium that a js function has been called?"
The most typical solution - is to wait until something has changed on a browser screen. Typical cases:
some element appears
some element disappears
some element's style changed
wait for condition in js example
(a bit of a hack) Another possible solution is to add a some flag in the js code of an app that will be false before function is called and will be set to true after function is called. Then you can access this flag's value in the executeScript.
some possible implementations here
I'm writing a script in Nightwatch that tests a specific element on a page. It's possible that the script could be testing a URL in which the element is not present on the page, in which case I want the script to end the test without any failures being logged.
I cannot seem to find a way to abort the test early without invoking a failure, however. Is there any way to have a Nightwatch test abort on a pass?
Here's a part of the code I'm working with for reference:
//End test if pagination is not present
'Pagination Present' : function (browser) {
browser
.execute(function() {
return document.querySelectorAll("ul[class='pagination']").length;
},
function(count){
if (count.value == 0) {
browser.assert.equal(count.value, 0, "There is no pagination on this page.");
browser.end();
}
})
},
Invoking browser.end(); closes the browser, but it reopens immediately after and the tests continue. Every single case fails, since the pagination does not exist on the given page. I'd like to end the test immediately after browser.assert.equal passes. Is there any way to do so?
You can use try/catch.
I had the same issue with some tests and i've got it to skip that assertion like this: you try to check something, but if you don't find the element, instead of failing the test, i just display a message in the console and exit the whole test:
'Test product\'s UPSs' : function (browser) {
try {
browser.assert.elementPresent('#someElement');
}
catch(err) {
console.log('this product has no Special features! Skipping');
process.exit();
}
}
In case you have further tests that you know they wouldn't fail and you'd like to continue with them, just leave out the process.exit() function. While it might not be the safest way to do it, at least it gets the job done.
I have written one scenario to test the application using protractor. My application starts with login page which is non-angular page then, after logging in moves on to the angular page.
Below is the javascript code snippet that i used to run:
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
var expect = chai.expect;
var myStepDefinitionsWrapper = function () {
this.Given(/^that I login with valid user credentials$/, function (callback) {
console.log("I'm in before URL");
browser.driver.get('http://localhost:8000/#');
console.log("I'm in after URL");
browser.driver.wait(function() {
console.log("I'm in Wait");
return browser.driver.isElementPresent(by.xpath("//input[contains(#placeholder,'Username')]"));
},10000);
browser.driver.findElement(by.xpath("//input[contains(#placeholder,'Username')]")).then(function(username) {
console.log("I'm in Username");
username.sendKeys("welby");
});
browser.driver.findElement(by.xpath("//input[contains(#type,'password')]")).then(function(password) {
console.log("I'm in Password");
password.sendKeys("asdf");
});
browser.driver.findElement(by.xpath("//button[#type='submit']")).click();
console.log("I'm after click");
callback();
});
this.When(/^I click perform button in Tasks window$/, function (callback) {
browser.waitForAngular();
element(by.xpath("//*[text()[contains(.,'Smith, Sally')]]/following::td[2]/button[text()='Perform']")).click();
console.log("Clicked Perform");
callback();
});
}
Output:
"C:\Program Files (x86)\JetBrains\WebStorm 10.0.4\bin\runnerw.exe" "C:\Program Files (x86)\nodejs\node.exe" node_modules\protractor\lib\cli.js E2E\protractor-conf.js Using the selenium server at http://127.0.0.1:4444/wd/hub [launcher] Running 1 instances of WebDriver
- I'm in before URL
- I'm in after URL
- I'm after click
- Clicked Perform
1 scenario (1 passed) 3 steps (3 passed)
[launcher] 0 instance(s) of WebDriver still running [launcher] chrome #1 passed
Process finished with exit code 0
Judging by the style of the code in your question you appear to be using Cucumber.js for your test runner. In this case then, you should be able to omit the callback parameter to your step definitions and simply return a promise:
this.Given(/^that I login with valid user credentials$/, function () {
// The rest of the code remains the same.
return browser.driver.findElement(by.xpath("//button[#type='submit']")).click();
});
And:
this.When(/^I click perform button in Tasks window$/, function () {
browser.waitForAngular();
return element(by.xpath("//*[text()[contains(.,'Smith, Sally')]]/following::td[2]/button[text()='Perform']")).click();
});
The capability of Cucumber.js to use promises is documented here.
Protractor is built on Selenium. I strongly suggest reading the entire "Understanding the API" section of the Selenium documentation so that you understand how the JavaScript version of Selenium uses and sequences promises.
The reason your code is not working right now is that by calling callback() like you do you are telling Cucumber.js that your step is finished before Protractor (and Selenium) has actually performed the actions you want. When you return a promise, Cucumber.js waits until the promise is resolved or fails before moving on.
I am trying to write unit test for async db calls. I'm using NodeJS with ORMnomnom package installed as orm db access and nodeunit for unit testing.
But it hang for this simple test:
Here is code test\test1.js
modelsdb = require('../model/model_db')
exports['test db'] = function (test) {
test.expect(1);
console.log('test db');
modelsdb.MyTable.objects.all( function (err, data) {
test.ok(true, "this assertion should pass");
test.done();
console.log('test must finish here!');
});
}
exports.testSomething = function(test){
console.log('testSomething');
test.expect(1);
test.ok(true, "this assertion should pass");
test.done();
};
When I run this test all assertions passed, I see my messages in console: 'test db' 'test must finish here!' 'testSomething' (means that test.done() reached inside callback function) but test doesn't finish. I need to stop it manually, get: 'Process finished with exit code 1'. If I change to test.ok(false,""), so I get AssertionError but test doesn't finish either. If I remove 'test db' and left only testSomething function - test finished as expected, all assertion passed.
I also try testpilot package which is based on nodeunit.
It gives
test1
FAIL : test db
an error occurred during test:
Error: timed out waiting for test
Any suggestions?
Thanks.
Add a tearDown method to your exports to close mongoose's connection pool. As long as it's still open the test won't exit.
You don't show how you're opening your mongoose connection, but something like this:
exports.tearDown = function (callback) {
mongoose.disconnect(callback);
};
I'm having a similar issue with nodeunit and q/mongoose - There is a bug that has been opened for it. I've tried to do the terrible process.exit(0) after calling test.done(), but any logging that is pending may not be flushed, so it isn't ideal. Ended up having to call process.exit(0) in a timeout block.