Testing javascript that updates DOM - javascript

I am new to web testing and would like to know how can I test javascript that reads and updates the DOM.
function otherFunction(string) {
// do some processing and return processed data
}
function domUpdater() {
var string = document.getElementById("input").value;
document.getElementById("output").innerHTML = otherFunction(string);
}
I can test easily the otherFunction which accepts and input and returns an output.
expect(otherFunction("input1")).to.be("expected1");
expect(otherFunction("input2")).to.be("expected2");
I am not clear on how can I test the domUpdater function which modifies the DOM?

I usually use jsdom, and in my case since I'm using mocha it would look like this (using jsdom-mocha):
var jsdom = require('mocha-jsdom')
var expect = require('chai').expect
describe('mocha tests', function () {
jsdom()
it('has document', function () {
var div = document.createElement('div')
expect(div.nodeName).eql('DIV')
})
})
However if you can afford it (the tests tend to take a bit longer to run) i would recommend looking into running your tests in a headless browser, using something like Puppeteer.
A quick google search yielded this for how to run jest with puppeteer:
First install jest-puppeteer
yarn add --dev jest-puppeteer
Specify preset in your Jest configuration:
{
"preset": "jest-puppeteer"
}
Write your test
describe('Google', () => {
beforeAll(async () => {
await page.goto('https://google.com');
});
it('should be titled "Google"', async () => {
await expect(page.title()).resolves.toMatch('Google');
});
});

Related

Externally determine which test cases fail - Javascript

I am working on an problem for which i need to detect which test cases fail for any javascript/node.js application, when that application's test suite is run. I need to determine this in a programmatic manner.
Mocha testsuite output result
Consider an example of test output above, for this example I would like to write an external javascript script that can tell me which particular test case failed.
Currently the only solution in my mind is; executing npm test in a javascript child process and read its output from the stdout stream, parse the output and extract necessary information, something like this.
const { spawn } = require('child_process');
const chalk = require('chalk');
const child = spawn('npm.cmd',['test']);
line = 0
child.stdout.on('data', (data) => {
console.log(`${chalk.bgBlue('line = ' + line)} , data = ${data}`);
line++;
});
However, this would be a very strict approach. I would like a more generic way of going about it, that can work for a variety of test modules(not just mocha).
Help would be appreciated !
You can get the state for every test after the execution into the code. So you can know if the test has been passed or not.
The code you need is quite simple. Something like this:
afterEach(function () {
const state = this.currentTest.state;
if (state !== "passed") {
//Do whatever you want with this value
}
});
For example, if you want to store into code, which test has been failed, then you can code this:
var testFailed = []
describe('test', function () {
afterEach(function () {
const state = this.currentTest.state;
if (state !== "passed") {
testFailed.push(this.currentTest.title)
}
});
after(function(){
console.log(testFailed)
})
it('test1', () => {
assert.equal(1, 1)
});
it('test2', () => {
assert.equal(1, 2)
});
})
And the output will be:
test
√ test1
1) test2
[ 'test2' ]
1 passing (15ms)
1 failing
Now you can play with this. You can use the variable to do your work, or even you can create a file or whatever you want to store the info.

How to avoid an infinite loop in JavaScript

I have a Selenium webdriverIO V5 framework. The issue I am facing here is, the below code works fine on Mac OS, but it does not work correctly on the Windows OS. In the Windows OS it gets stuck with an infinite loop issue.
The below code functionality is: Merge yaml files (which contains locators) and return the value of the locator by passing the key:
const glob = require('glob');
const yamlMerge = require('yaml-merge');
const sleep = require('system-sleep');
let xpath;
class Page {
getElements(elementId) {
function objectCollector() {
glob('tests/wdio/locators/*.yml', function (er, files) {
if (er) throw er;
xpath = yamlMerge.mergeFiles(files);
});
do {
sleep(10);
} while (xpath === undefined);
return xpath;
}
objectCollector();
return xpath[elementId];
}
}
module.exports = new Page();
Since you are waiting on the results of a callback, I would recommend returning a new Promise from your getElements function and resolve() the value you receive inside the callback. Then when you call getElements, you will need to resolve that Promise or use the await notation. The function will stop at that point and wait until the Promise resolves, but the event loop will still continue. See some documentation for more information.
I'll write an example below of what your code might look like using a Promise, but when you call getElements, you will need to put the keyword await before it. If you want to avoid that, you could resolve the Promise from objectCollector while you're in getElements and remove the async keyword from its definition, but you really should not get in the way of asynchronous JavaScript. Also, you can probably shorten the code a bit because objectCollector looks like an unnecessary function in this example:
const glob = require('glob')
const yamlMerge = require('yaml-merge')
const sleep = require('system-sleep')
let xpath
class Page {
function async getElements(elementId) {
function objectCollector() {
return new Promise((resolve,reject) => {
glob('tests/wdio/locators/*.yml', function (er, files) {
if (er) reject(er)
resolve(yamlMerge.mergeFiles(files))
})
})
}
let xpath = await objectCollector()
return xpath[elementId]
}
}
module.exports = new Page();

Jest mockImplementation on single function within module

Hi there I am just trying to use jest to jest my image min module, the issue I am having is when using imagemin it creates its own tmp folder within a child process which just screws with the path because I am using mock-fs. So all I want to do is have a single function within the module return a predetermined result which will then be passed to another function.
So far in my jest I have
it('Should compress jpg', () => {
expect.assertions(1);
let mock = jest.fn();
mock.mockReturnValueOnce(true);
utility.compress = mock;
let opts = {};
let dest = './tmp/dest/img';
let file = path.join(dest, 'jpeg_img.jpg');
return utility.imageCompress(['./dummy_data/img/*.jpg'], dest, opts)
.then(data => {
expect(data).toEqual([]);
expect(fs.existsSync(file)).toBe(true);
expect(fs.statSync('./dummy_data/img/jpeg_img.jpg').size)
.toBeLessThan(fs.statSync(file).size);
});
});
So the utility.imageCompress calls the compress function
I am exporting the function but I still get utility.compress.mockImplementation is not a function.
Any help would be great thanks

Protractor Cucumber BDD Tests Show Pass before Execution

I have a sample BDD test using Protractor with Cucumber. On executing the code, the console immediately shows the result as passed and the code actually begins executing only after that.
I wish execution status display to be in sync with actual execution.(e.g Console displays - 'Given I launch the protractor demo page' and the code underneath is executed, then console displays next step and so on) I know it has got something to do with Async coding and callbacks, not able to figure out the exact problem though.
Feature file:
Feature: Test
Scenario: Test Scenario
Given I launch the protractor demo page
When I enter two in the first field
And I enter three in the second field
And I click Go button
Then Result should be displayed as Five
Step File:
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
var expect = chai.expect;
module.exports = function () {
this.Given(/^I launch the protractor demo page$/, function (callback) {
browser.driver.manage().window().maximize();
browser.get('http://juliemr.github.io/protractor-demo/');
browser.getTitle().then(function(text){
console.log('title is - ' + text);
expect(text).to.equal('Super Calculator');
});
callback();
});
this.When(/^I enter two in the first field$/, function (callback) {
element(by.model('first')).sendKeys('2');
callback();
});
this.When(/^I enter three in the second field$/, function (callback) {
element(by.model('second')).sendKeys('3');
callback();
});
this.When(/^I click Go button$/, function (callback) {
element(by.id('gobutton')).click();
callback();
});
this.Then(/^Result should be displayed as Five$/, function (callback) {
element(by.repeater('result in memory')).all(by.tagName('td')).get(2).getText().then(function(text){
expect(text).to.equal('5');
});
callback();
});
};
You need to either return a promise or use the done callback in your step definitions. Otherwise cucumber doesn't know when your asynchronous
actions are complete.
I had the same question and above statement was the response from one of the core members of the protractor-cucumber github forum.
I prefer to return promises when I am performing some actions on the results with .then function and use .done callback function when I am not, Also you don't need callbacks now CucumberJS supports promises. So your step file should look like -
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
var expect = chai.expect;
module.exports = function () {
this.Given(/^I launch the protractor demo page$/, function () {
browser.driver.manage().window().maximize();
browser.get('http://juliemr.github.io/protractor-demo/');
return browser.getTitle().then(function(text){
console.log('title is - ' + text);
expect(text).to.equal('Super Calculator');
});
});
this.When(/^I enter two in the first field$/, function () {
return element(by.model('first')).sendKeys('2');
});
this.When(/^I enter three in the second field$/, function () {
return element(by.model('second')).sendKeys('3'); // you can use return also
});
this.When(/^I click Go button$/, function () {
return element(by.id('gobutton')).click();
});
this.Then(/^Result should be displayed as Five$/, function () {
return element(by.repeater('result in memory')).all(by.tagName('td')).get(2).getText().then(function(text){
expect(text).to.equal('5');
});
});
};
I would recommend you to read about Promises http://www.html5rocks.com/en/tutorials/es6/promises/ as it requires some understanding how they behave.They can be sometimes tricky, it took me a while to get an idea still I have lot to learn :)

Using asynchronous commands in nightwatch e2e tests

I have a following e2e scenario written using Nightwatch:
var Q = require('q');
module.exports = {
afterEach: function (browser, done) {
browser.end(function() {
done();
});
},
'should display same data on second page as on first page': function (browser) {
//Given
var firstPage = bowser.pages.first()
//When
Q.all([
firstPage.getTextPromise('#element1'),
firstPage.getTextPromise('#element2'),
firstPage.getTextPromise('#element3')]
).then( function(values) {
users.click('#linkToSecondPage');
//Then
var secondPage = browser.page.secondPage();
secondPage.expect.element('#dataElement1').text.to.equal(values[0]).before(5000);
secondPage.expect.element('#dataElemnet2').contains.text(values[1]);
secondPage.expect.element('#dataElement3').contains.text(values[2]);
});
} }
The getTextPromise command is defined by me in following way:
commands: [{
getTextPromise: function(selector) {
var self = this;
return Q.Promise(function (resolve, reject) {
self.getText(selector, function(result) {resolve(result.value); });
});
} }]
The rationale behind this scenarion is to remember some values on one page before clicking on link to second page
and then checking that on second page the same content is displayed (for example, you click on one item in a table
and go to page displaying details of this particular item).
Unfortunately, I observed that this test sometimes does not check things inside the then callback.
I think this is caused by the test finishing (calling done in afterEach()) before he callback returns.
I thought there was a done() callback passed to the test (much like in nightwatch async unit tests) that I could use but apparently there is not.
Is there a proper way to do this in Nightwatch? Perhaps I am using commands in wrong way?
Nightwatch will keep track of command run order itself if the command runs a method on 'this', and returns 'this'.
Try a command like this, adapted as a page command if you prefer:
exports.command = function() {
var self = this;
var globals = self.globals;
if (!globals.values) { globals.values = []; }
var link = 'some_xpath';
self.getText('selector', function(result) {
if(result.status !== -1){
self.globals.values.push = result.value;
}
});
return self;
};
Because the command returns this. It can be chained and you could be sure the commands run in order without manually writing promises.
example:
var firstPage = bowser.pages.first()
var secondPage = browser.page.secondPage();
firstPage.getTextPromise('#element1')
.getTextPromise('#element2')
.getTextPromise('#element3');
secondPage.expect.element('#dataElement1').text.to.equal(global.values[0]).before(5000)
.expect.element('#dataElemnet2').contains.text(global.values[1])
.expect.element('#dataElement3').contains.text(global.values[2]);
I haven't tested this out so it may need a slight tweak. Hopefully it gives a rough idea of how to chain your commands the nightwatch way. If you run into a problem let me know.

Categories

Resources