istanbul-middleware
istanbul-middleware copied to clipboard
Should include example for use with Selenium
I think this example is very good:
https://github.com/gotwarlost/istanbul/issues/132
specifically this line is very important to know:
driver.executeScript("return window.__coverage__;")
Perhaps include something like this in the readme?
// server
var im = require('istanbul-middleware');
var express = require('express');
var app = express();
app.use('/coverage', im.createHandler());
app.listen(8888);
// test suite
// Add the following logic to every test suite which uses selenium-webdriver:
after(async function (done) {
// http POST coverage info
await driver.switchTo().defaultContent();
let obj = await driver.executeScript("return window.__coverage__;")
var str = JSON.stringify(obj);
var options = {
port: 8888,
host: "localhost",
path: "/coverage/client",
method: "POST",
headers: {
"Content-Type": "application/json",
}
};
var req = http.request(options, function (res) {
console.log("\nFinished sending coverage data.");
done();
});
req.write(str);
req.end();
})
test.after(function () {
// at the end of the *whole* test run, download all coverage data and place it somewhere
console.log("Closing browser.");
driver.quit();
})
Hello ORESoftware,
I am taking help of your above mentioned code to get Client Side JS coverage.I am using Istanbul for it.
But when I try to execute this line : 'driver.executeScript("return window.coverage;")', I get following error :
_ReferenceError: window is not defined
at /Users/kapaga/Desktop/Node/webdriver.js:23:19
at ManagedPromise.invokeCallback_ (/Users/kapaga/Desktop/Node/node_modules/selenium-webdriver/lib/promise.js:1384:14)
at TaskQueue.execute_ (/Users/kapaga/Desktop/Node/node_modules/selenium-webdriver/lib/promise.js:3092:14)
at TaskQueue.executeNext_ (/Users/kapaga/Desktop/Node/node_modules/selenium-webdriver/lib/promise.js:3075:27)
at asyncRun (/Users/kapaga/Desktop/Node/node_modules/selenium-webdriver/lib/promise.js:2935:27)
at /Users/kapaga/Desktop/Node/node_modules/selenium-webdriver/lib/promise.js:676:7
at process._tickCallback (internal/process/next_tick.js:109:7)_
It seems Node doesn't support 'window' instead there is something called 'global' for Node.But when I try to use 'global', I get following error :
_WebDriverError: unknown error: global is not defined
(Session info: chrome=59.0.3071.86)
(Driver info: chromedriver=2.28.455517 (2c6d2707d8ea850c862f04ac066724273981e88f),platform=Mac OS X 10.12.4 x86_64)
at WebDriverError (/Users/kapaga/Desktop/Node/node_modules/selenium-webdriver/lib/error.js:27:5)
at Object.checkLegacyResponse (/Users/kapaga/Desktop/Node/node_modules/selenium-webdriver/lib/error.js:517:15)
at parseHttpResponse (/Users/kapaga/Desktop/Node/node_modules/selenium-webdriver/lib/http.js:509:13)
at doSend.then.response (/Users/kapaga/Desktop/Node/node_modules/selenium-webdriver/lib/http.js:441:30)
at process._tickCallback (internal/process/next_tick.js:109:7)
From: Task: WebDriver.executeScript()
at thenableWebDriverProxy.schedule (/Users/kapaga/Desktop/Node/node_modules/selenium-webdriver/lib/webdriver.js:816:17)
at thenableWebDriverProxy.executeScript (/Users/kapaga/Desktop/Node/node_modules/selenium-webdriver/lib/webdriver.js:887:16)
at Object.<anonymous> (/Users/kapaga/Desktop/Node/webdriver.js:20:13)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:393:7)_
Can you please help me out here? I am new to Javascriot world ( & to be precise to the Coding world, as I am a QA) so it's highely likely that I might be missing out something very silly here.
Thanks
I can try to help...first this article might help: https://medium.com/@the1mills/front-end-javascript-test-coverage-with-istanbul-selenium-4b2be44e3e98
You want to use window not global, because that script is executing in the browser.
Looks like I am using a different webdriver package. I am using this:
npm install --save-dev webdriver-manager
So try using that installation.
then in a bash script, I do this:
# start-selenium.sh
cd $(dirname "$0")
./node_modules/.bin/webdriver-manager update
./node_modules/.bin/webdriver-manager start
try using that, and let me know if it works. If not, we try more things.
Make sure to make the script executable, with
chmod u+x ./start-selenium.sh
then you can execute the script like so
./start-selenium.sh
Hey @ORESoftware @gotwarlost,
After I include 'webdriver-manager' , I get following error :
var browser = new driver.Builder().usingServer().withCapabilities({'browserName': 'chrome' }).build();
^
TypeError: driver.Builder is not a constructor
at Object.<anonymous> (/Users/kapaga/Desktop/Node/webdriver.js:4:15)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:393:7)
at startup (bootstrap_node.js:150:9)
at bootstrap_node.js:508:3
Any leads here?
Also when I try to follow https://medium.com/@the1mills/front-end-javascript-test-coverage-with-istanbul-selenium-4b2be44e3e98 , I get following error while running my test :
return async cb => {
^^
SyntaxError: Unexpected identifier
at createScript (vm.js:56:10)
at Object.runInThisContext (vm.js:97:10)
at Module._compile (module.js:542:28)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (/Users/kapaga/Desktop/Node/webdriver-gotwarlost.js:7:24)
Actually my Node is not able to recognize following keywords : await async after let cb req
What all libraries do i need to install for above keywords to work ? I did npm install for above mentioned libraries & used in my scripts like (var async = require('asyncawait/async'); var await = require('asyncawait/await');var let = require('let');) but node still doesn't recognize them. Please help.
Hey @ORESoftware @gotwarlost ,
I managed to tweak the scripts so that I can avoid keywords like await,after,let etc.Following is my code now :
My Server :
const cov = require('istanbul-middleware');
const isCollectCoverage = process.env.CDT_COLLECT_COVERAGE === 'yes';
const express = require('express');
const app = express();
const path = require('path');
if (isCollectCoverage) {
app.use(express.static(path.join(__dirname, 'public-coverage')));
}
else {
app.use(express.static(path.join(__dirname, 'public')));
}
// ....
if (isCollectCoverage) {
app.use('/coverage', cov.createHandler()); // mount istanbul middleware here
}
app.listen(3000);
POST script to server :
var http = require('http');
var CircularJSON = require('circular-json');
exports.loadCoverage = function (driver) {
//return async cb => {
driver.switchTo().defaultContent();
obj = driver.executeScript('return window.__coverage__;');
str = CircularJSON.stringify(obj);
options = {
port: 3000,
host: "localhost",
path: '/coverage/client',
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
};
req = http.request(options, res => {
console.log(' => Response status => ', res.statusCode);
console.log(' => Finished sending coverage data.');
data = '';
// you must listen to data event, so that the end event will fire...
res.on('data', d => {
data += d;
});
res.once('end', function () {
console.log('\nFinished sending coverage data => response => ', data);
// cb(); // fire the final callback
});
});
req.write(str);
req.end();
};
My Test :
var driver = require('selenium-webdriver');
var browser = new driver.Builder().usingServer().withCapabilities({'browserName': 'chrome' }).build();
browser.get('file:///Users/kapaga/Desktop/sample.html');
const {loadCoverage} = require('./coverage_helpers');
//after.cb('send coverage data', loadCoverage(browser));
loadCoverage(browser);
I have instrumented my code as per the command mentioned in the article & injecting it in sample.html.
When I try to run my test , my page is loaded but no coverage data is reported :
=> Response status => 404
=> Finished sending coverage data.
Finished sending coverage data => response => <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot POST /coverage/client</pre>
</body>
</html>
What could be the possible reason for this output ? Variable 'window__coverage__' is properly getting populated in the browser & it is getting returned to the object in the script.
Use NVM to upgrade to a newer version of Node.js https://github.com/creationix/nvm
You should use version 8 if possible.
Try using the original code, and then let me know if you still have problems. Make sure you are running all the Selenium code on the backend in Node.js.
e.g.:
browser.get('file:///Users/kapaga/Desktop/sample.html');
the above line should be running in Node.js.
I am running Node Version 8.1.2 (ran latest Node.js JAR file.Shall I update using NVM ? Will it make any difference?) & I am running 'browser.get('file:///Users/kapaga/Desktop/sample.html');' in Node.js only.
Reinstalled latest version of Node (8.1.2) using NVM & used original code but still node is not able to identify the keywords like cb,after,let etc (as mentioned in my previous comment). Can there be any ES compatibility issue here? Can you use the code which I have pasted above to run a sample test on you local so that if it runs on your local then I can try to replicate your different Library versions on my local?
are you sure you are using node version 8?
what happens when you run
node -v
at the command line?
make sure you do
nvm install 8
nvm use 8
and to make 8 your default version, there's a special nvm command for that
When I do node -v
i get v8.1.2
. I have done 'nvm use 8.1.2' also.Still no change in the problem.
Is it your IDE that cannot identify the keywords or the actually node.js runtime? what is the error that you get?
I get following error :
after.cb('send coverage data', loadCoverage(browser));
^
ReferenceError: after is not defined
at Object.<anonymous> (/Users/kapaga/Desktop/Node/webdriver-gotwarlost.js:8:1)
at Module._compile (module.js:569:30)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Function.Module.runMain (module.js:605:10)
at startup (bootstrap_node.js:158:16)
at bootstrap_node.js:575:3
It's Node.js runtime which cannot identify the keywords.
You are getting closer.
Ok, so after
is a global variable that does not have to with Node or JavaScript, but it is from a test harness library like Jasmine or Mocha. In my case, after.cb is from the Suman library, which is similar to Mocha, etc.
There are a lot of moving pieces here.
First install Mocha:
npm install -g mocha
Create this simple file:
// bar.js
describe('foo', function(){
before('get home',function(){
return browser.get(xxx); // fix this with the right url, this returns a promise
});
it('simple test', function(){
// make some call to selenium to do some actions in your front-end code
});
after('load coverage', function(){
return driver.switchTo().defaultContent().then(function(){
return driver.executeScript('return window.__coverage__;');
}).then(function(obj){
// must return a promise
return postTheDataToYourServerRunningIstanbulMiddleWare(obj);
});
});
});
then run:
mocha bar.js
mocha will load the global variables into the environment. You probably will have a few more problems but we can work through them.
The before/after/it hooks in Mocha (and all similar libraries) will handle promises returned from the callback.
At the end I would like to ask you to choose to use Suman instead of Mocha :)
Note that the after hook above could be re-written as:
after('load coverage', async function(){
await driver.switchTo().defaultContent().then(function(){
let obj = await driver.executeScript('return window.__coverage__;');
return postTheDataToYourServerRunningIstanbulMiddleWare(obj);
});
async/await is a native wrapper around promises + generators.
note that for this to work, either way,
postTheDataToYourServerRunningIstanbulMiddleWare(obj);
must return a promise.
Sure.Let me try it.
Finally I am able to see coverage report using following code :
var http = require('http');
var CircularJSON = require('circular-json');
var driver = require('selenium-webdriver');
var browser = new driver.Builder().usingServer().withCapabilities({'browserName': 'chrome' }).build();
describe('selenium test', function(){
this.timeout(15000);
before('Launching Browser',function(){
return browser.get('file:///Users/kapaga/Desktop/sample.html');
it("Posting Data to Istanbul Middleware",function (done) {
browser.switchTo().defaultContent();
browser.executeScript("return window.__coverage__;").then(function (obj) {
var str = CircularJSON.stringify(obj);
var options = {
port: 3000,
host: "localhost",
path: "/coverage/client",
method: "POST",
headers: {
"Content-Type": "application/json",
}
};
var req = http.request(options, function (res) {
console.log("\nFinished sending coverage data.");
done();
});
req.write(str);
req.end();
});
});
after(function () {
// at the end of the *whole* test run, download all coverage data and place it somewhere
console.log("Closing browser.");
browser.quit();
});
});
Thanks a ton for your help & guidance. :) :) 👍
But when I try to use code mentioned here : https://medium.com/@the1mills/front-end-javascript-test-coverage-with-istanbul-selenium-4b2be44e3e98 , I get following error :
after.cb('send coverage data', loadCoverage(browser));
^
TypeError: after.cb is not a function
at Object.<anonymous> (/Users/kapaga/Desktop/Node/test/webdriver-gotwarlost.js:10:7)
at Module._compile (module.js:569:30)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Module.require (module.js:513:17)
at require (internal/module.js:11:18)
at /Users/kapaga/.nvm/versions/node/v8.1.2/lib/node_modules/mocha/lib/mocha.js:230:27
at Array.forEach (native)
at Mocha.loadFiles (/Users/kapaga/.nvm/versions/node/v8.1.2/lib/node_modules/mocha/lib/mocha.js:227:14)
at Mocha.run (/Users/kapaga/.nvm/versions/node/v8.1.2/lib/node_modules/mocha/lib/mocha.js:495:10)
at Object.<anonymous> (/Users/kapaga/.nvm/versions/node/v8.1.2/lib/node_modules/mocha/bin/_mocha:469:18)
at Module._compile (module.js:569:30)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Function.Module.runMain (module.js:605:10)
at startup (bootstrap_node.js:158:16)
at bootstrap_node.js:575:3
Any lead here?
after.cb
is from the Suman library. Mocha does not have that style. Just use Mocha, if it is working for you.
Sure. Thanks a lot. :)
Np at all...if you think I know a thing or two, definitely star this repo
https://github.com/sumanjs/suman
when I release that project it's gonna be so huge
by the way, in your code above, you want to do:
return browser.quit();
this returns the promise to the caller, so the caller can wait for the promise to resolve before shutting down the process.