Using ajax-post within mocha test reporter fails - javascript

i'm tyring to send my mocha test results with jquery post to my API. So I wrote a custom reporter:
var mocha = require('mocha');
var $ = require('jquery');
module.exports = Reporter
function Reporter(runner) {
mocha.reporters.Base.call(this, runner);
var passes = 0;
var failures = 0;
runner.on('pass', function (test) {
passes++;
});
runner.on('fail', function (test, err) {
failures++;
});
runner.on('end', function () {
data = {
date: formatDate(new Date()),
passed: passes,
failed: failures
}
$.ajax({
url: "https://localhost:8080/test/results",
method: "POST",
data: data,
dataType: "json",
success: function () {
console.log("sent");
},
error: function () {
console.log("failed");
}
});
});
}
I used npm i jquery and it added "jquery": "^3.4.1" into my package.json
But when I execute mocha tests, it throws an exception, that $.ajax is not a function. My research didn't find any helpful results. (And I don't use the slim-version of jquery)
Any idea what I did wrong? Or may I not use $.ajax for this?

Initializing jQuery in Node vs in Browser
The problem seems to be with initializing jQuery in Node, which is different than initializing in browser.
Documentation of jQuery npm package, which you can find here, says as follows:
For jQuery to work in Node, a window with a document is required.
Since no such window exists natively in Node, one can be mocked by
tools such as jsdom. This can be useful for testing purposes.
Instead of simply using below line:
var $ = require('jquery'); // Would work in browser
You should first mock DOM and after that initialize jQuery:
require("jsdom").env("", function(err, window) {
if (err) {
console.error(err);
return;
}
var $ = require("jquery")(window);
});

Related

Object is not defined when stubbing with Jasmine

I am very new to Jasmine. I am intending to use it for with vanilla javascript project. The initial configuration was a breeze but I am receiving object not defined error while using spyOn.
I have downloaded the version 3.4.0 Jasmine Release Page and added the files 'as is' to my project. I then have changed jasmine.json file accordingly and see the all the example tests passing. However when try spyOn on a private object, I am getting undefined error,
if (typeof (DCA) == 'undefined') {
DCA = {
__namespace: true
};
}
DCA.Audit = {
//this function needs to be tested
callAuditLogAction: function (parameters) {
//Get an error saying D365 is not defined
D365.API.ExecuteAction("bu_AuditReadAccess", parameters,
function (result) { },
function (error) {
if (error != undefined && error.message != undefined) {
D365.Utility.alertDialog('An error occurred while trying to execute the Action. The response from server is:\n' + error.message);
}
}
);
}
}
and my spec class
describe('Audit', function(){
var audit;
beforeEach(function(){
audit = DCA.Audit;
})
describe('When calling Audit log function', function(){
beforeEach(function(){
})
it('Should call Execute Action', function(){
var D365 = {
API : {
ExecuteAction : function(){
console.log('called');
}
}
}
// expectation is console log with say hello
spyOn(D365.API, 'ExecuteAction').and.callFake(() => console.log('hello'));
var params = audit.constructActionParameters("logicalName", "someId", 'someId');
audit.callAuditLogAction(params);
})
})
})
As you can see my spec class does not know about actual D365 object. I was hoping to stub the D365 object without having to inject it. Do I need to stub out whole 365 library and link it to my test runner html?
I got it working after some pondering. So the library containing D365 should still need to be added to my test runner html file. after that I can fake the method call like below,
it('Should call Execute Action', function(){
spyOn(D365.API, 'ExecuteAction').and.callFake(() => console.log('hello'));
var params = audit.constructActionParameters("logicalName", "someId", 'someId');
audit.callAuditLogAction(params);
})
it is now working.

Node.js - Get used memory of executed app (even after it has been killed)

How can I take memory usage of ChildProcess even after it was killed (in exec callback)?
I tried using the pidusage module, but it only works when the process is opened.
What I actually tried:
var proc = exec(execComm,(error, stdout, stderr) => {
if (error) {
callback({status: -1, reason:stderr });
}
var pidusage = require("pidusage");
pidusage(proc.pid,function(err,stat){
console.log(err,stat);
});
callback({ status:0, file: out });
});
But why does pidusage send [Error: No maching pid found]?
Is it because this module can't get info of the already closed one?
And how to get that info in the exec callback?
You could bind a helper to the exit signal of your app and read out memory usage then but since the gc will likely run on unpredictable times I'm not sure what use you get out of that.
const ExitHandler = () => { /* your code */ };
process.on( 'exit', ExitHandler.bind( null, { withoutSpace: false } ) ); // on closing
process.on( 'SIGINT', ExitHandler.bind( null, { withoutSpace: true } ) ); // on [ctrl] + [c]
process.on( 'uncaughtException', ExitHandler.bind( null, { withoutSpace: false } ) ); // on uncaught exceptions
I belive you could use something like node-heapdump to create heapdumps in your child-processes that you could inspect after the fact.
That way you could also have multiple dumps so you could inspect the memory usage over time.

load data from module before test executes

(I asked this question recently and accepted an answer but it's still not what I need.) I really need to create dynamic tests from data loaded from a module. Each item from the array will have it's own describe statement with certain protractor actions. My previous post has an answer that says to use an it statement, but I can't do that because there's too much going on.
My main problem is that the data doesn't get loaded in time for the describe. I had another suggestion to use VCR.js or something similar but I don't think those will work because I'm using a module. Is there a way I can save the data to a separate file and load it in? Would that be a good way to go?
var data = require('get-data'); //custom module here
describe('Test', function() {
var itemsArr;
beforeAll(function(done) {
data.get(function(err, result) {
itemsArr = result; //load data from module
done();
});
})
//error: Cannot read property 'forEach' of undefined
describe('check each item', function() {
itemsArr.forEach(function(item) {
checkItem(item);
});
});
function checkItem (item) {
var itemName = item.name;
describe(itemName, function() {
console.log('describe');
it('should work', function() {
console.log('it');
expect(true).toBeTruthy();
});
});
}
});
UPDATE:
I used Eugene's answer and came up with this. I can't test each individual study how I want because the it statement doesn't fire. Is this problem even solvable??
describe('check each item', function () {
it('should load data', function (done) {
browser.wait(itemsPromise, 5000);
itemsPromise.then(function(itemsArr) {
expect(itemsArr).toBeTruthy();
studyArr = itemsArr.filter(function (item) {
return item.enabled && _.contains(item.tags, 'study');
});
studyCount = studyArr.length;
expect(studies.count()).toEqual(studyCount);
checkItems(studyArr);
done();
});
});
function checkItems (itemsArr) {
itemsArr.forEach(function (item) {
describe(item.id, function () {
console.log('checkItems', item.id);
// doesn't work
it('should work', function (done) {
expect(false).toBeTruthy();
done();
});
});
});
}
});
You're trying to do something that Jasmine does not allow: generating tests after the test suite has started. See this comment on an issue of Jasmine:
Jasmine doesn't support adding specs once the suite has started running. Usually, when I've needed to do this, I've been able to know the list of options ahead of time and just loop through them to make the it calls. [...]
("adding specs" === "adding tests")
The point is that you can generate tests dynamically but only before the test suite has started executing tests. One corollary of this is that the test generation cannot be asynchronous.
Your second attempt does not work because it is trying to add tests to a suite that is already running.
Your first attempt is closer to what you need but it does not work either because describe calls its callback immediately, so beforeAll has not run by the time your describe tries to generate the tests.
Solutions
It all boils down to computing the value of itemsArr before the test suite start executing tests.
You could create a .getSync method that would return results synchronously. Your code would then be something like:
var data = require('get-data'); //custom module here
var itemsArr = data.getSync();
describe('Test', function() {
describe('check each item', function() {
itemsArr.forEach(function(item) {
checkItem(item);
});
});
[...]
If writing .getSync function is not possible, you could have an external process be responsible for producing a JSON output that you could then deserialize into itemsArr. You'd execute this external process with one of the ...Sync functions of child_process.
Here's an example of how the 2nd option could work. I've created a get-data.js file with the following code which uses setTimeout to simulate an asynchronous operation:
var Promise = require("bluebird"); // Bluebird is a promise library.
var get = exports.get = function () {
return new Promise(function (resolve, reject) {
var itemsArr = [
{
name: "one",
param: "2"
},
{
name: "two",
param: "2"
}
];
setTimeout(function () {
resolve(itemsArr);
}, 1000);
});
};
// This is what we run when were are running this module as a "script" instead
// of a "module".
function main() {
get().then(function (itemsArr) {
console.log(JSON.stringify(itemsArr));
});
};
// Check whether we are a script or a module...
if (require.main === module) {
main();
}
Then, inside the spec file:
var child_process = require('child_process');
var itemsArr = JSON.parse(child_process.execFileSync(
"/usr/bin/node", ["get-data.js"]));
describe('Test', function() {
itemsArr.forEach(function(item) {
checkItem(item);
});
function checkItem (item) {
var itemName = item.name;
describe(itemName, function() {
console.log('describe');
it('should work', function() {
console.log('it');
expect(true).toBeTruthy();
});
});
}
});
I've tested the code above using jasmine-node. And the following file structure:
.
├── data.js
├── get-data.js
└── test
└── foo.spec.js
./node_modules has bluebird and jasmine-node in it. This is what I get:
$ ./node_modules/.bin/jasmine-node --verbose test
describe
describe
it
it
Test - 5 ms
one - 4 ms
should work - 4 ms
two - 1 ms
should work - 1 ms
Finished in 0.007 seconds
2 tests, 2 assertions, 0 failures, 0 skipped
Try to use a promise, something like:
var deferred = protractor.promise.defer();
var itemsPromise = deferred.promise;
beforeAll(function() {
data.get(function(err, result) {
deferred.fulfill(result);
});
})
And then:
describe('check each item', function() {
itemsPromise.then(function(itemsArr) {
itemsArr.forEach(function(item) {
checkItem(item);
});
});
});
Another solution I can think of is to use browser.wait to wait until itemsArr becomes not empty.
Is your get-data module doing some browser things with protractor? If so, you will need to set/get itemsArr within the context of the controlFlow. Otherwise it will read all the code in the get-data module, but defer its execution and not wait for it to finish before moving right along to those expect statements.
var data = require('get-data'); //custom module here
var itemsArr;
describe('Test', function() {
beforeAll(function() {
// hook into the controlFlow and set the value of the variable
browser.controlFlow().execute(function() {
data.get(function(err, result) {
itemsArr = result; //load data from module
});
});
});
//error: Cannot read property 'forEach' of undefined
describe('check each item', function() {
// hook into the controlFlow and get the value of the variable (at that point in time)
browser.controlFlow().execute(function() {
itemsArr.forEach(function(item) {
checkItem(item);
});
});
});
function checkItem (item) {
var itemName = item.name;
describe(itemName, function() {
console.log('describe');
it('should work', function() {
console.log('it');
expect(true).toBeTruthy();
});
});
}
});

protractor-http-mock cant find element

I am trying to mock a http request of our angular app with protractor and
protractor-http-mock. My protractor spec file looks like this:
beforeEach(function () {
mock(['bank']);
browser.get(this.createUrl());
});
afterEach(function(){
mock.teardown();
});
My bank.js file looks like this:
module.exports = {
request: {
path: '/api/v0/bank/demo',
method: 'GET'
},
response: {
... my json object
}
};
When I run protractor it says:
Failed: No element found using locator: by.model("bank.model.bic")
but without mocking everything runs successfull.

How to monitor HTTP calls using browsermob-proxy and nightwatch.js?

I am writing testcases using Nightwatch.js framework for SPA application. A requirement came in here we have to monitor HTTP calls and get the performance results for the site. As this could be easily achieved using JMeter.
Using automation testing tool, we can do it by using browsermob-proxy and selenium.
Is it possible to do the same using Nightwatch.js and browsermob-proxy?
Also what are the steps to do to the same.
For using Nightwatchjs and browsermob-proxy together, check out this repo, which includes info on the NodeJS bindings for browsermob-proxy and programmatically generating HAR (HTTP Archive) files.
If you're content with just using Nightwatchjs, this repo has code in the tests directory for the following:
Custom command to get the requests made so far
Custom assertion for checking if a request, given a filter and query string params, exists.
You might have to brush up on how to add custom commands and assertions to your Nightwatch project, but after that you should be set to go!
You can use browsermob-proxy-api
just simply download browsermob-proxy server then
install by npm command: npm install browsermob-proxy-api --save-dev
configure you night watch like this in desiredCapabilites:
'test_settings': {
'default': {
'launch_url': 'http://localhost:3000',
'screenshots': {
'enabled': true, // if you want to keep screenshots
'path': './screenshots' // save screenshots here
},
'globals': {
'waitForConditionTimeout': 30000 // sometimes internet is slow so wait.
},
'desiredCapabilities': { // use Chrome as the default browser for tests
'browserName': 'chrome',
'proxy': {
'proxyType': 'manual',
'httpProxy': 'localhost:10800'
},
'acceptSslCerts': true,
'javascriptEnabled': true, // turn off to test progressive enhancement
}
},
then download index.js from here:
https://github.com/jmangs/node-browsermob-proxy-api
and add code from example to your step_definitions if you use gherkin or describe step
Bit late into dance. I managed to integrate browsermob to nightwatch. Here are the detailed steps
Download browsermob proxy https://bmp.lightbody.net/
Open your cmd and go to bin folder and then start browsermob using "browsermob-proxy".
I am assuming you have basic nightwatch setup. You also need mobproxy. Install it from "npm i browsermob-proxy-api"
Create a global hook in nightwatch. Say 'globalmodule.js' and give this file path in globals_path in nightwatch.json
In globalmodule, create global hooks as described in http://nightwatchjs.org/guide#external-globals
In beforeEach hook, add below code: //if you are not under corporate proxy and you dont need to chain to upstream proxy
var MobProxy = require('browsermob-proxy-api');
var proxyObj = new MobProxy({'host': 'localhost', 'port': '8080'});
//assuming you started browsermob in 8080 port. That is in step 2.
//if you are working under corporate proxy, you might have to chain your request. This needs editing in browsermob-proxy-api package. Follow steps given at end of this section.
Start proxy on new port
proxyObj.startPort(port, function (err, data) {
if (err) {
console.log(err);
} else {
console.log('New port started')
}
})
Once we have new port, we have to start our chrome browser in above port so that all browser request are proxied through browsermob.
proxyObj.startPort(port, function (err, data) {
if (err) {
console.log(err);
} else {
console.log('New port started')
var dataInJson = JSON.parse(data);
//Step 8:
this.test_settings.desiredCapabilities = {
"browserName": "chrome",
"proxyObj": proxyObj, //for future use
"proxyport": dataInJson.port, //for future use
"proxy": {
"proxyType": "manual",
"httpProxy": "127.0.0.1:" + dataInJson.port,
"sslProxy": "127.0.0.1:" + dataInJson.port //important is you have https site
},
"javascriptEnabled": true,
"acceptSslCerts": true,
"loggingPrefs": {
"browser": "ALL"
}
}
}
})
Try to run with above setting, you can check if cmd [created in step2 to confirm request are going via above port. There will be some activiy]
For creating HAR and getting created HAR, browsermob-proxy-api gives excellent api.
add createHAR.js in any path and mention that path in nightwatch.json[custom_commands section]
exports.command = function (callback) {
var self = this;
if (!self.options.desiredCapabilities.proxyObj) {
console.error('No proxy setup - did you call setupProxy() ?');
}
this.options.desiredCapabilities.proxyObj.createHAR(this.options.desiredCapabilities.proxyport, {
'captureHeaders': 'true',
'captureContent': 'true',
'captureBinaryContent': 'true',
'initialPageRef': 'homepage'
}, function (err, result){
if(err){
console.log(err)
}else{
console.log(result)
if (typeof callback === "function") {
console.log(this.options.desiredCapabilities.proxyObj);
console.log(this.options.desiredCapabilities.proxyport);
// console.log(result);
callback.call(self, result);
}
}
});
return this;
};
then to getHAR, add getHAR.js, add below code.
var parsedData;
exports.command = function(callback) {
var self = this;
if (!self.options.desiredCapabilities.proxy) {
console.error('No proxy setup - did you call setupProxy() ?');
}
self.options.desiredCapabilities.proxyObj.getHAR(self.options.desiredCapabilities.proxyport, function (err, data) {
console.log(self.options.desiredCapabilities.proxyObj);
console.log(self.options.desiredCapabilities.proxyport);
//console.log(result);
if(err){
console.log(err)
}else{
parsedData = JSON.parse(data)
console.log(parsedData.log.entries)
}
if (typeof callback === "function") {
console.log(self.options.desiredCapabilities.proxyObj);
console.log(self.options.desiredCapabilities.proxyport);
callback.call(self, parsedData);
}
});
return this;
};
At start of test, createHAR will not have proxyObj, So this step should be executed sync. Wrap that step with browser.perform()
browser.perform(function(){
browser.createHAR()
})
////some navigation
browser.perform(function(){
browser.getHAR()
})
Note: If you are working behind corporate proxy, You might have to use chain proxy piece which browsermob offers.
According to browsermob proxy documentation, get down to api section, -> /proxy can have request parameters "proxyUsername" and "proxyPassword"
In node_modules->browsermob-proxy-api->index.js
add below line after line 22:
this.proxyUsername = cfg.proxyUsername || '';
this.proxyPassword = cfg.proxyPassword || '';
this.queryString = cfg.queryString || 'httpProxy=yourupstreamProxy:8080'; //you will get this from pac file
then at line 177, where package is making request '/proxy' to browser.
replace
path: url
to
path: url + '?proxyUsername=' +this.proxyUsername + '&proxyPassword=' + this.proxyPassword + '&' + this.queryString

Categories

Resources