Possible to manipulate CasperJS assertions? - testing

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?

Related

Can we overwrite 'expect' method of testcafe's TestController

I am looking for a way to overwrite expect method for TestController. My idea is existing tests whoever used t.expect method, I want to perform additional steps in those cases.
I came up with below sample code but testcafe runtime fails with below error
TypeError: Cannot read property '_expect$' of undefined
sample code attempting to override:
import { Selector } from "testcafe";
fixture`Getting Started`.page`http://devexpress.github.io/testcafe/example`;
test("My first test", async (t) => {
t = modify(t);
await t.typeText("#developer-name", "John Smith").click("#submit-button");
// Use the assertion to check if the actual header text is equal to the expected one
await t
.expect(Selector("#article-header").innerText)
.eql("Thank you, John Smith!");
});
function modify(t) {
let prevExpect = t.expect;
t.expect = (param) => {
console.log("modified expecte has been used");
return prevExpect(param);
};
return t;
}
Also, when using t.click(Selector(...).expect(...), It doesn't use my overwritten expect. How to make it work in the call chain as well?
Technically, it's possible to overwrite the expect method, but please note that this approach may lead to incorrect work and unexpected errors.
You need to modify your modify function as follows:
function modify (t) {
let prevExpect = t.expect;
t.expect = (param) => {
console.log("modified expect has been used");
return prevExpect.call(t, param);
};
return t;
}
As for the t.click(Selector(...).expect(...) issue, you call the expect method of Selector, but Selector does not have the expect method.
You need to add ) after Selector:
await t.click(Selector(...)).expect(...)

Why jest expects an anonymous function to catch an error?

I have not comprehended what's the reason behind the fact that expects a curried function when I want to test the output of the error message. If it was going to be a return value a direct call to the function leads to the value to be tested correctly in .toBe
function calculateMedian({numbers}) {
if (Array.isArray(numbers) && numbers.length === 0) {
throw new Error('Cannot calcuate median without any numbers');
}
}
However, if i were to test the following snipped without the anonymous function the test will simply fail. What is the reason behind it?
Passing Test
it('should throw an error when given an empty array', () => {
expect(() =>
calculateMedian({
numbers: [],
}),
).toThrow('Cannot calcuate median without any numbers');
});
Failing Test
it('should throw an error when given an empty array', () => {
expect(calculateMedian({numbers: []})
).toThrow('Cannot calcuate median without any numbers');
});
expect and toThrow are just function calls. So, for the assertion on exception to work, the thing you pass as expect argument needs to allow for execution controlled by the testing framework.
The flow is similar to:
expect() saves the lambda as variable
toThrow() executes the saved variable in a try/catch block and tests the caught exception.
The way you would do it without the toThrow method would be similar to:
try {
calculateMedian({numbers: []};
fail();
} catch (err) {
expect(err.message).toBe('Cannot calcuate median without any numbers')
}
If, instead of passing a lambda/function you simply invoke the function, the error will be thrown before program control gets to the toThrow method. The test will fail because of the thrown error.

How to override dojo's domReady

I want to override dijit._CssStateMixin's domReady() method.
Is there any way to override that instead of changing the listener mechanism in Dojo.
I tried overriding _cssMouseEvent() method in simple javascript, but it still does invoke dijit's _cssMouseEvent() from domReady().
I have tried following approach:
dojoConfig = {
map: {
'dijit/_CssStateMixin': {
'dojo/domReady': 'app/noop'
}
}
};
I have added 'app' folder and then 'noop.js' inside that.
noop.js has nothing in it:
define([], function () {
return function () {};
});
Even after this I can see that dijit.js's _CssStateMaxin domReady() getting called from listener.apply (code snippet pasted below)
var addStopImmediate = function(listener){
return function(event){
if(!event.immediatelyStopped){// check to make sure it hasn't been stopped immediately
event.stopImmediatePropagation = stopImmediatePropagation;
return listener.apply(this, arguments);
}
};
}
If your ultimate goal is to prevent the domReady callback in dijit/_CssStateMixin from running, your simplest bet is likely to re-map dojo/domReady to a different module that doesn't call the callback at all, when loaded via dijit/_CssStateMixin.
NOTE: Stripping out these handlers might have adverse visual effects on Dijit widgets which inherit _CssStateMixin, since it may hinder the application of Dijit CSS classes related to hover and focus. But if your concern is that _CssStateMixin is hampering performance, it may at least be worth a try to confirm or deny your suspicion.
First we have to create a simple module that returns a function that does nothing, which we will later substitute for dojo/domReady when loaded by dijit/_CssStateMixin, so that it can still call domReady but it won't execute the callback it passes.
For simplicity's sake I'll assume you already have a custom package that you can easily add a module to; for this example I'll assume it's called app. Let's create app/noop:
define([], function () {
return function () {};
});
Now let's configure the loader to map app/noop in place of dojo/domReady specifically when loaded by dijit/_CssStateMixin:
var dojoConfig = {
...,
map: {
'dijit/_CssStateMixin': {
'dojo/domReady': 'app/noop'
}
},
...
};
Now the offending domReady callback should no longer be run.
If you're curious about map, you can read more about it in this SitePen FAQ.

CameraCaptureUI.captureFileAsync fails to return IAsyncOperation object

For some reason, my code is unable to retrieve the IAsyncOperation object that is returned upon calling captureFileAsync method of the Windows.Media.Capture.CameraCaptureUI() method. The IAsyncOperation object is returned according to this documentation. In that documentation link, it states:
Return value
Type: IAsyncOperation<StorageFile>
When this operationcompletes, a StorageFile object is returned.
So here is my code:
var dialog = new Windows.Media.Capture.CameraCaptureUI();
var aspectRatio = { width: 4, height: 3 };
dialog.photoSettings.croppedAspectRatio = aspectRatio;
appSession.InAsyncMode = dialog.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo).done(function (file) {
if (file) {
self.addPage(URL.createObjectURL(file));
} else {
WinJS.log && WinJS.log("No photo captured.", "sample", "status");
}
}, function (err) {
// None taken
});
When I inspect the value of appSession.InAysncMode, I see that the function returns undefined. I suspect it returns undefined because the operation is not complete (i.e. the user has not yet created the photo, and it has not been saved to disc), but I need it in order to cancel out of the camera capture mode programmatically. Does anybody know why it would return undefined instead of the documented IAsyncOperation object?
Thanks!
For reference, here's the answer I posted on the MSDN forum.
To answer your ending question, you can cancel the capture UI by canceling the promise from dialog.captureFileAsync.
Your InAsyncMode flag is undefined because you're assigning to it the return value from captureFileAsync.done() which is, by definition, undefined. It has nothing to do with the API's success.
In the docs, when you see IAsyncOperation, what you get in JavaScript is a promise that will deliver as a result to the completed handler if it succeed. You never see IAsyncOperation or related interfaces in JavaScript directly. The documentation for WinRT is written to be language-neutral, so it's important to understand how those things show up in JS (as promises). In C# you don't see it either, as you just use the await keyword. It's mostly in C++ that you actually encounter the interface.
Anyway, you I believe you want is something along the lines of the code below, where you could eliminate IsAsyncMode in favor of just checking for a non-null promise:
appSession.capturePromise = dialog.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo);
appSession.IsAsyncMode = (appSession.capturePromise != null);
//This will close the capture UI after 5 seconds--replace with whatever logic you need
setTimeout(function () { appSession.capturePromise.cancel(); }, 5000);
appSession.capturePromise.done(function (file) {
if (file) {
} else {
}
}, function (err) {
appSession.IsAsyncMode = false;
appSession.capturePromise = null;
});

Dojo 1.7 how to use dojo components outside of require()

I have created Dojo widget like below using AMD loader in Dojo 1.7.2
var myCpane;
require([
"dijit/layout/ContentPane"
], function(ContentPane) {
myCpane = new ContentPane();
});
myCpane.startup(); // It gives 'myCpane' as undefined
In the above example, in the last statment, the variable 'myCpane' is coming as 'undefined', if I use the 'myCpane.startup()' inside the 'require()' callback function then, it will work fine.
But I want to use that 'myCpane' variable on outside of the 'require' function (for many reasons). I know the 'require()' callback function execution delayed due to the component loading process by Dojo.
My question is,
How to block the 'require()' function until it completes to execute it's callback function.
So the variable 'myCpane' will not be 'undefined' when the control come out from the 'require()' function
===========================================================
To overcome this issue, I have written a small function to load the modules and wait until the module load complete
LoadModule: function(modulePath) { // modulePath = "dijit/layout/ContentPane"
var moduleObject = undefined;
require({async: false}, [modulePath], function(getModuleObject) {
moduleObject = getModuleObject;
});
// Wait until the module loads completes
while(moduleObject === undefined);
// Return the loaded module.
return moduleObject;
}
The output of the function is always executing the while loop, the control never comes inside of 'require()'s callback function to set the value to the variable "moduleObject".
When the 'require()' function will call it's callback function? I have verified using the browser debugger window the file 'ContentPane.js' is loaded properly, but the callback function is not called, If I comment the while loop then, the callback is called properly.
When the control will come inside of the callback function in my case ?
I'm not sure what are you about to achieve, but it looks for me like a programming anti-pattern. Anyway you can achieve this via dojo/_base/Deferred:
require(["dojo/_base/Deferred"], function(Deferred) {
var deferred = new Deferred();
require(["dijit/layout/ContentPane"], function(ContentPane) {
var myCpane = new ContentPane();
deferred.resolve(myCpane); //resolve, i.e. call `then` callback
});
deferred.then(function(myCpane) {
console.log(myCpane);
myCpane.startup();
});
});​
Mess with it at jsFiddle: http://jsfiddle.net/phusick/HYQEd/
I would also suggest you consider one of these two strategies to achieve the same:
Give the ContentPane an id and obtain its reference via dijit's registry.byId().
Create ContentPane instance in a separate module and expose it as a return value of that module:
// file: myCpane.js
define(["dijit/layout/ContentPane"], function(ContentPane) {
var myCpane = new ContentPane();
return myCpane;
});
// file: main.js
require(["./myCpane"], function(myCpane) {
myCpane.startup();
});
I think this goes more to scope issue then amd loader question; consider
var x;
function foo() {
x = { bar : 1 };
}
// you wouldn't expect to have reference to x variable here
if(typeof x.bar == "undefined") console.log(x);
// foo() is called at a random time - or in dojo loader case, when modules are present
foo();
console.log(x.bar); // oohh now its there ^^
x in this case translates to your myCpane, which is declared as variable (var $$) inside a function, the function that is callback for when loader is done requireing modules.
The Deferred is a nice handler for this as stated below. A slight overhead though, if youre allready in a detached (async) function flow. For full control, look into require() you could do this as well:
var myCpane;
require({ async: false }, [
"dijit/layout/ContentPane"
], function(ContentPane) {
myCpane = new ContentPane();
});
// require does not return until module loading is done and callback executed
myCpane.startup();