How to write custom messages on passed tests with jasmine and protractor? - testing

I'm looking a way to add custom messages on succeeded tests with protractor and jasmine.
There're many ways to customize messages on failure, like jasmine-custom-message node package or simply:
expect(column.get(0)).toEqual("7", "This is not something I've expected");
But I haven't found a way to add custom messages on success. I'm using protractor-jasmine2-html-reporter to generate my reports, but successful tests only display a "passed" or "0 failure" messages and I'd like to be more explicit about what am I testing and why the tests passed.

You want to write a custom matcher for Jasmine. You want to include them in the protractor.conf.js file so they are accessible over the entire project
https://jasmine.github.io/2.0/custom_matcher.html
Here is an example of comparing numbers with the message printing off if there is an error. The error if you run this will be Expected 7 to be 8 (Expected Error). Note, this is including it in the spec using the beforeEach.
var customMatchers = {
toBeEqualWithMessage: function(util, customEqualityTesters) {
return {
compare: function(actual, expected, message) {
var result = {};
result.pass = util.equals(actual, expected, customEqualityTesters);
if (!result.pass) {
result.message = "Expected " + actual + " to be " + expected + " (" + message + ")";
}
return result;
}
};
}
};
describe('Custom Matcher', function(){
beforeEach(function() { jasmine.addMatchers(customMatchers);});
it('should use a matcher', function(){
expect(7).toBeEqualWithMessage(7,"No error because they match");
expect(7).not.toBeEqualWithMessage(8,"No error because of the 'not'");
expect(7).toBeEqualWithMessage(8,"Expected Error");
});
});
FYI: The doc has a result.message for a passing case, but I don't know where that is used, maybe a verbose print out.

Related

How can i use soft assertion in Cypress

I have configured soft assert from npm (npm i soft-assert) and now my package.josn has "soft-assert": "^0.2.3"
i want to use function of Soft assert
softAssert(actual, expected, msg, ignoreKeys)
But don't know, what is the exact steps to use it
Example:
When i use soft assertion function in my code, getting following error.
If i use like this
cy.softAssert(10, 12, "expected actual mismatch and will execute next line") : not supported
or if i use different way like
softAssert(10, 12, "expected actual mismatch and will execute next line") : SoftAssert not defined
Can any one tell me how to use this 'softAssert' function in cypress code with some small example?
Now the problem I am facing
it('asserts and logs and fails', () => {
Cypress.softAssert(10, 12, "expected actual mismatch...");
cy.log("text")
Cypress.softAssertAll();
})
I need my code after soft assertion as cy.log("text") to be executed in the same 'it' block but the current test failing the whole 'it' block, without executing 'cy.log("text")' statement.
The soft assertion concept is pretty cool, and you can add it with minimal implementation to Cypress
const jsonAssertion = require("soft-assert")
it('asserts several times and only fails at the end', () => {
jsonAssertion.softAssert(10, 12, "expected actual mismatch");
// some more assertions, not causing a failure
jsonAssertion.softAssertAll(); // Now fail the test if above fails
})
To me, it would be nicer to see each soft assertion failure in the log, so it's possible to add custom commands to wrap the soft-assert functions
const jsonAssertion = require("soft-assert")
Cypress.Commands.add('softAssert', (actual, expected, message) => {
jsonAssertion.softAssert(actual, expected, message)
if (jsonAssertion.jsonDiffArray.length) {
jsonAssertion.jsonDiffArray.forEach(diff => {
const log = Cypress.log({
name: 'Soft assertion error',
displayName: 'softAssert',
message: diff.error.message
})
})
}
});
Cypress.Commands.add('softAssertAll', () => jsonAssertion.softAssertAll())
//-- all above can go into /cypress/support/index.js
//-- to save adding it to every test (runs once each test session)
it('asserts and logs but does not fail', () => {
cy.softAssert(10, 12, "expected actual mismatch...");
cy.log('text'); // this will run
})
it('asserts and logs and fails', () => {
cy.softAssert(10, 12, "expected actual mismatch...");
cy.log('text'); // this will run
cy.softAssertAll();
})

Intercept XMLHttpRequest from Greasemonkey script fails

I seek to manipulate the XMLHttpRequest done by a website using Greasemonkey (version 4.9 installed). Interception should be simple (How can I intercept XMLHttpRequests from a Greasemonkey script?) but does not work for me. Maybe things changed with newer versions of Greasemonkey?
I obviously tried the examples in the linked question, but they don't have any effect - nothing printed in the console although I have an console.log(...) in my customised open function.
Next, I gave unsafeWindow a try. It should not be needed. My userscript runs with #grant none and documentation (see here) says my script should run in the content scope.
With unsafeWindow I get an effect but it breaks XMLHttpRequest completely
// ==UserScript==
// #name Test
// #version 1
// #include *
// #run-at document-start
// #grant none
// ==/UserScript==
"use strict";
let realOpen = unsafeWindow.XMLHttpRequest.prototype.open
console.log("Real: " + realOpen)
unsafeWindow.XMLHttpRequest.prototype.open = function() {
console.log("Called for " + this + " with URL: " + arguments[0])
//call original
return realOpen.apply(this, arguments)
};
window.addEventListener ("load", function() {
console.log ("Page loaded");
});
console.log("Unsafe: ", unsafeWindow.XMLHttpRequest.prototype.open.toString())
console.log("Normal: ", XMLHttpRequest.prototype.open.toString())
This gives following output in console:
Real: function open() {
[native code]
}
Unsafe: function() {
console.log("Called for " + this + " with URL: " + arguments[0])
//call original
return realOpen.apply(this, arguments)
}
Normal: function open(method, url) {
// only include method and url parameters so the function length is set properly
if (arguments.length >= 2) {
let newUrl = new URL(arguments[1], document.location.href);
arguments[1] = newUrl.toString();
}
return origOpen.apply(this, arguments);
}
==> Page loaded
As mentioned, function of XMLHttpRequest is broken. When I use the Firefox developer console to have a further look I get this
>> window.XMLHttpRequest.prototype.open
Restricted { }
Any properties set on window (like window.foobar = "foobar") do not exist in console, but those set on unsafeWindow do. I assume this has to do with Greasemonkey's sandboxing.
Why are there two versions of XMLHttpRequest even when I use #grant none? Why is my custom function restricted? Can I avoid that? Why does it work without problems when I install event listener on window?
Next, I gave unsafeWindow a try. It should not be needed. My userscript runs with #grant none and documentation (see here) says my script should run in the content scope.
This is wrong for Greasemonkey 4 as stated in its announcement:
Due to the more limited abilities that the new extension system gives us, we are currently unable to make #grant none scripts work in the same way. Most importantly, they have a different connection to unsafeWindow. For the short term at least, it's a good idea to adopt cloneInto and exportFunction.
See also this other question Firefox doesn't respect Object.defineProperty() from a Greasemonkey script?
This change explain the observations, but no idea why adding listener to window work.

Possible to manipulate CasperJS assertions?

My CasperJS asserts seem to be overly strict. I have a function where I am trying to test the names of client logo images from an array, using Casperjs. However I do not seem to be able to use a variable from a forLoop in casperJS.
I understand there are probably hoisting issues that I am not accounting for, but this does not seem to be the primary problem. I have tried several things to resolve hoisting issues, such as immediately invoked functions, try catch blocks, and using ES6 term "Let" in my loop. None seem to work. Then I notice if I simply hard-code the string my variable should represent, and stick a console.log into my assert of a PASSING test, right before the return, the passing test fails.
Here is my failing code
var clients = 'https://www.google.com/';
var logoArray = ["images/logos/AC.png", "images/logos/Affiny.png", "images/logos/ffintus.png", "images/logos/agileAsset.png"]
function checkClientsArrayTest() {
casper.test.begin('The layout is as expected', 10, function suite(test) {
casper.start(clients, function () {
casper.then(function () {
for (var i = 0; i < logoArray.length; i++) {
try { throw i }
catch (ii) {
console.log(ii);
console.log(i);
test.assertEvalEquals(function () {
return document.querySelectorAll('div.client_logo a img')[ii].getAttribute('src')
.match(logoArray[ii]).toString();
}, logoArray[ii], 'Test searches for Client Logos in DOM.');
}
}
});
}).run(function () {
test.done();
});
});
}
If I change logoArray[ii] to a hardcoded string from the first index of the array, it passes. If I consolelog logoArray[ii], it seems to be what I expect. But if I pass a variable to the assert, or even stick a console.log inside of it, the test fails with the following
Running check for the layout of URL: https://www.google.com
0
0
FAIL Test searches for Client Logos in DOM.
type: assertEvalEquals
file: headlessTester.js
subject: null
fn: undefined
params: undefined
expected: "images/logos/AC.png"
Is this an issue of me getting hoisting wrong (shouldn't fail by sticking in a logger if this is the case afaik), or is this due to strictly structured asserts in CasperJS?

Chai-As-Promised is eating assertion errors

I'm using chai-as-promised + mocha for writing some selenium-webdriver tests. Since webdriver extensively uses promises, I imagined it would be better if I used chai-as-promised for those type of tests.
The problem is that when the tests fail, the error is not being caught properly by mocha, and it just fails without outputting anything.
Sample code:
it 'tests log', (next) ->
log = #client.findElement(By.css("..."))
Q.all([
expect(log.getText()).to.eventually.equal("My Text")
expect(log.findElement(By.css(".image")).getAttribute('src'))
.to.eventually.equal("/test.png")
]).should.notify(next)
According to documented behaviour, chai-as-promised should pass the errors along to mocha when the expectation fails. Right?
As a variation,
I've also tried these, but to no avail:
#2
# same, no error on failure
it 'tests log', (next) ->
log = #client.findElement(By.css("..."))
Q.all([
expect(log.getText()).to.eventually.equal("My Text")
expect(log.findElement(By.css(".image")).getAttribute('src'))
.to.eventually.equal("/test.png")
]).should.notify(next)
#3
# same, no error shown on failure
it 'tests log', (next) ->
log = #client.findElement(By.css("..."))
expect(log.getText()).to.eventually.equal("My Text")
.then ->
expect(log.findElement(By.css(".image")).getAttribute('src'))
.to.eventually.equal("/test.png").should.notify(next)
#4
## DOES NOT EVEN PASS
it 'tests log', (next) ->
log = #client.findElement(By.css("..."))
Q.all([
expect(log.getText()).to.eventually.equal("My Text")
expect(log.findElement(By.css(".image")).getAttribute('src'))
.to.eventually.equal("/test.png")
])
.then ->
next()
.fail (err) ->
console.log(err)
.done()
I think you're having two different issues:
First, you need to return a promise at the end of your tests (e.g. Q.all([...]); in your first test should be return Q.all([...]).
Second, I found that chai-as-promised doesn't seem to work unless used with mocha-as-promised.
Here's an example of mocha-as-promised with two assertions that will cause the test to fail.
/* jshint node:true */
/* global describe:false */
/* global it:false */
'use strict';
var Q = require('q');
require('mocha-as-promised')();
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
var expect = chai.expect;
describe('the test suite', function() {
it('uses promises properly', function() {
var defer = Q.defer();
setTimeout(function() {
defer.resolve(2);
}, 1000);
return Q.all([
expect(0).equals(0),
// the next line will fail
expect(1).equals(0),
expect(defer.promise).to.eventually.equal(2),
// the next line will fail
expect(defer.promise).to.eventually.equal(0)
]);
});
});

Automatically close PhantomJs after running script

I want to run PhantomJs scripts from my program, but since the scripts may not be written by me, I need to make sure PhantomJs exits after the execution are either completed or fails for any reason (e.g., invalid syntax, timeout, etc). So far, All I've read says you must always include the instruction phantom.exit() for PhantomJs to exit. Is there any way to automatically close PhantomJs after it executes a given script?
Thanks.
Create a file run-javascript.js:
var system = require('system');
try {
for (var i=1; i<system.args.length; i++) {
var scriptFileName = system.args[i];
console.log("Running " + scriptFileName + " ...");
require(scriptFileName);
}
}
catch(error) {
console.log(error);
console.log(error.stack);
}
finally {
phantom.exit();
}
Then to run your file myscript.js:
phantomjs run-javascript.js ./myscript.js
You have to include an explicit path for the myscript.js, i.e. ./myscript.js, otherwise phantomjs will look for the script as a module.
There are three execution scenarios that are handled here:
Successful execution, in which case phantom.exit() is called in the finally clause.
Error in the script being run, in which case the require function prints a stacktrace and returns (without throwing any error to the calling code).
Error running the script (e.g. it doesn't exist), in which case the catch clause prints out the stacktrace and phantom.exit() is called in the finally clause.