Missing functions in Karma tests - javascript

I'm using Jasmine, Karma, and PhantomJS to automate my tests, but I'm hitting a problem: Phantom doesn't seem to parse my JS correctly. For example, I'm using this mock:
var App = function() {
return {
pageController : {
currentPage : {
on : function() {},
toJSON : function() {},
get : function() {
return dark;
}
}
},
mainLayout : {
header : {
show : function() {},
$el : {}
}
}
};
};
console.log("in test", App());
...which logs out as:
PhantomJS 1.9 (Mac) LOG: [ 'in test',
{ pageController: {},
mainLayout: { header: [Object] } } ]
app.pageController has been emptied here, which causes my tests to fail. Why is this happening & how I can fix it?
The problem seems directly related to the function definitions. For example:
console.log("this is a function:", function() { return 'wat'; });
yields
PhantomJS 1.9 (Mac) LOG: [ 'this is a function:', null ]
The error also occurs in Chrome. It squashes created jasmine spies as well, so I'm guessing it's to do with Karma?

Karma's logging reports all functions as null. (Tests were failing for unrelated reasons).

Related

How to handle logging in cross-browser testing in Protractor?

I was building an automation framework with javascript(VanillaJS), jasmine, and protractor. I chose the log4js with log4js-protractor-appender for the logging. I try to save logs(by browser type) when I perform cross-browser testing. I wanted to run the specs on safari and chrome then expecting to have 2 separate log files for each browser.
Q: How to create two separate log files where one of them contains only log of chrome, the second file contains only logs of safari browser by using technologies mentioned before?
Here is the log4js code from the conf.js file
beforeLaunch : function(){
log4js.configure({
appenders: {
out: { type: 'console' },
result: { type: 'dateFile', filename: 'logs/result',"pattern":"-dd.log", alwaysIncludePattern:true},
error: { type: 'dateFile', filename: 'logs/error', "pattern":"-dd.log", alwaysIncludePattern:true},
default: { type: 'dateFile', filename: 'logs/default', "pattern":"-dd.log", alwaysIncludePattern:true}
},
categories: {
default: { appenders: ['out','default'], level: 'info' },
result: { appenders: ['result'], level: 'info' },
error: { appenders: ['error'], level: 'error' }
}
});
},
onPrepare : function() {
browser.logger = log4js.getLogger('protractorLog4js');
}
The expected result is to have 2 files: default_chrome.log & default_safari.log
// obtain browser name
browser.getBrowserName = function() {
return browser.getCapabilities().then((caps) => {
browser.browserName = caps.get('browserName');
}
)}
// resolve the promised so the browser name is obtained.
browser.getBrowserName();
log4js.configure({
appenders: {
out: { type: 'console' },
default: { type: 'dateFile', filename: 'logs/default_'+ browser.browserName, "pattern":".log", alwaysIncludePattern:true}
},
categories: {
default: { appenders: ['out','default'], level: 'info' }
}
});
I tried this option too:
var browName = () => {return browser.getCapabilities().then((caps) => {caps.get('browserName');});}
I can't provide a ready-to-use answer, because it'll require to have your setup locally, but I can give you directions to look in...
According to https://github.com/angular/protractor/blob/master/lib/config.ts, beforeLaunch is called once per execution (once for all browsers), whereas onPrepare is called for each browser instance and should be used for configuring your logger. So everything related to logger should go to onPrepare

Vue js filter not compatible on some mobile device

Am using vue js on my webview app only to filter user search for now. Everything is working very fine till i run my app on Samsung SM-G530H, i get an error saying Uncaught SyntaxError: Unexpected token (, i have checked everything correct and it work on other device except older device. Please how do make it compatible in all device?
new Vue({
el: '#SearchVueContenPage',
data() {
return {
q: '',
total_result: 0,
searchProduct: null,
loading: false,
sort_filter: ``,
URL: ajax_appserver("public", "_api/searchProduct.php")
}
},
computed: {
search() {
if (!this.searchProduct) {
return []
}
if (!this.q) {
this.total_result = 0;
return this.searchProduct.recent.slice(0,4);
}
var query = this.q.toLowerCase();
var searchResult = this.searchProduct.result.filter(row => row.product_name.toLowerCase().includes(query) || row.business_name.toLowerCase().includes(query));
this.total_result = searchResult.length;
return searchResult;
}
},
mounted() {
this.loading = true;
this.fetchData().then(() => {
this.loading = false
});
},
methods: {
sortStatus: function(status) {
this.sort_filter = status;
},
async fetchData() {
ajax_fetch(this.URL).then(json => {
this.searchProduct = json;
Vue.nextTick(function(){
//Store object in IndexDb
}.bind(this));
});
}
}
});
It seems that the error is happening because you are trying to run code that uses "Method definitions" syntax.
Method definitions on MDN
The reason you are getting the error is that "Method definitions" is a relatively new feature/syntax in JS and not supported by all browsers.
The solution for that will be to precompile the code to ES5 using babel.
If you are using VUE-CLI you already have webpack and you just need to configure it to output ES5 code.

Nightwatch cannot take screenshot return is not a function

I'm using nightwatch-cucumber module, which works pretty great,
but I can't save any screenshot in my testing step.
nightwatch.config.js
...
test_settings: {
default: {
screenshots : {
enabled : true,
on_failure : true,
path: 'screenshots/'
},
...
step.js
...
return pageObj
.submit()
.waitForElementVisible('#status')
.getText('#status')
.saveScreenshot('./screenshots')
.expect.element('#status').text.to.contain(status);
...
console error
TypeError: pageObj.submit(...).waitForElementVisible(...).getText(...).saveScreenshot is not a function
any suggestion?
Use this one in the command section. In page object file.
const commands = {
saveScreenshot(filePath) {
this.api.saveScreenshot(filePath);
return this;
}
module.exports = {
url: 'url',
commands: [commands],
elements: {
.......
}
};
}

How to make a list of failed specs using jasmine custom reporter to post to slack?

I am trying to work on a custom jasmine reporter and get a list of all the failed specs in the specDone function:
specDone: function(result) {
if(result.status == 'failed') {
failedExpectations.push(result.fullName);
console.log(failedExpectations);
}
}
where failedExpectations will store an entire list of the failed specs and i need to access this in the afterLaunch function in the protractor config file. But due to the fact that the config file loads everytime a new spec runs it basically gets overwritten and scoping is such that I cannot access it in the afterLaunch function, that is where I am making the call to the slack api. Is there a way to achieve this?
This is what i have it based on : http://jasmine.github.io/2.1/custom_reporter.html
I think the best way is to post the results asynchronously after each spec (*or every "it" and "describe") using #slack/web-api. This way you don't have to worry about overwriting. Basically you "collect" all the results during the test run and send it before the next suite starts.
Keep in mind all of this should be done as a class.
First you prepare your you '#slack/web-api', so install it (https://www.npmjs.com/package/#slack/web-api).
npm i -D '#slack/web-api'
Then import it in your reporter:
import { WebClient } from '#slack/web-api';
And initialize it with your token. (https://slack.com/intl/en-pl/help/articles/215770388-Create-and-regenerate-API-tokens):
this.channel = yourSlackChannel;
this.slackApp = new WebClient(yourAuthToken);
Don't forget to invite your slack app to the channel.
Then prepare your result "interface" according to your needs and possibilities. For example:
this.results = {
title: '',
status: '',
color: '',
successTests: [],
fails: [],
};
Then prepare a method / function for posting your results:
postResultOnSlack = (res) => {
try {
this.slackApp.chat.postMessage({
text: `Suit name: ${res.title}`,
icon_emoji: ':clipboard:',
attachments: [
{
color: res.color,
fields: [
{
title: 'Successful tests:',
value: ` ${res.successTests}`,
short: false
},
{
title: 'Failed tests:',
value: ` ${res.fails}`,
short: false
},
]
}
],
channel: this.channel
});
console.log('Message posted!');
} catch (error) {
console.log(error);
}
When you got all of this ready it's time to "collect" your results.
So on every 'suitStart' remember to "clear" the results:
suiteStarted(result) {
this.results.title = result.fullName;
this.results.status = '';
this.results.color = '';
this.results.successTests = [];
this.results.fails = [];
}
Then collect success and failed tests:
onSpecDone(result) {
this.results.status = result.status
// here you can push result messages or whole stack or do both:
this.results.successTests.push(`${test.passedExpectations}`);
for(var i = 0; i < result.failedExpectations.length; i++) {
this.results.fails.push(test.failedExpectations[i].message);
}
// I'm not sure what is the type of status but I guess it's like this:
result.status==1 ? this.results.color = #DC143C : this.results.color = #048a04;
}
And finally send them:
suiteDone() {
this.postResultOnSlack(this.results);
}
NOTE: It is just a draft based on reporter of mine. I just wanted to show you the flow. I was looking at Jasmine custom reporter but this was based on WDIO custom reporter based on 'spec reporter'. They are all very similar but you probably have to adjust it. The main point is to collect the results during the test and send them after each part of test run.
*You can look up this explanation: https://webdriver.io/docs/customreporter.html
I highly recommend this framework, you can use it with Jasmine on top.

JsTestDriver assert when using requirejs in intellij

I was trying to write some javascript unit tests, using requirejs and jsTestDriver intellij plugin. When I run them in the IDE I have no error even when there are some. I only see them when opening my browser console.
Did someone manage to make IDE plugin displays failures into a require function ?
My code below and some screen shots illustrating my problem.
TestCase("Collections", {
"test User Collection": function () {
require(['lib/underscore', 'lib/backbone', 'app/user', 'app/collections'],
function (_, Backbone, user, appCollections) {
assertNotUndefined('Users must be defined', appCollections.users);
assertTypeOf('Users must be backbone collection', typeof Backbone.Collection, appCollections.users);
assertTypeOf("Users' model must be a user", typeof Backbone.Model, appCollections.users.model);
});
}
});
I haven't tested this, but it might get you started:
var CollectionsTest = AsyncTestCase('Collections');
CollectionsTest.prototype.testIt = function(queue) {
queue.call('Step 1', function(callbacks) {
function test1(_, Backbone, user, appCollections) {
assertNotUndefined('Users must be defined', appCollections.users);
assertTypeOf('Users must be backbone collection', typeof Backbone.Collection, appCollections.users);
assertTypeOf("Users' model must be a user", typeof Backbone.Model, appCollections.users.model);
}
var onModulesLoaded = callbacks.add(test1);
require(['lib/underscore', 'lib/backbone', 'app/user', 'app/collections'], onModulesLoaded);
});
};

Categories