casperJS Can't find variable : $ - module

I'm trying to call a function defined in another module using this.evaluate().
The code snippet(calling the function) is:
this.waitFor(function check() {
var re = this.evaluate(universe.answer(couponElement, url));
if (re != 'no' & re!='yes' & re!=null) {
couponObj.push(re);
and the module in which the function is defined is like this:
var require = patchRequire(require);
var utils = require('utils');
exports.answer = function(couponElement, url) {
var lblInvalidCoupon = 'lblInvalidCoupon';
var tolTipCouponinner='tolTipCouponinner';
var txtFCCoupondisocunt = 'txtFCCoupondisocunt';
var btnRemoveFCCoupon = 'btnRemoveFCCoupon';
var check = $('#txtCouponCode').css('backgroundImage');
if (check.indexOf('ajax-loader.gif')>-1){
return 'no';
} else {
if (document.getElementById(lblInvalidCoupon)!=null){
Basically, I want to call the function using this.evaluate but unable to do so.

First, try with the simplest evaluate: remote.message event to capture console.log from page.
casper.on("remote.message", function(msg) {
console.log("[page] " + msg);
});
this.evaluate(function () {
console.log("Hi phantomworld! I am hello-ing from remote page!");
});
Next, check if jQuery is present:
this.evaluate(function () {
console.log(typeof jQuery);
});
If it says, [page] function, jQuery is present in the page. You need to dig more...
If not, inject it:
var casper = require('casper').create({
clientScripts: [
'includes/jquery.js'
]
});

You didn't actually pass the answer function to casper.evaluate, but you called it instead. The problem is that in this way answer was not executed in page context and because of this $ is not defined. casper.evaluate which executes a function in page context is sandboxed. It cannot use variables which are defined outside. The passed function must be self contained.
To fix this the arguments which are consumed by answer can be passed as additional parameters to casper.evaluate.
Change the line
var re = this.evaluate(universe.answer(couponElement, url));
to
var re = this.evaluate(universe.answer, couponElement, url);
If JQuery is not present in the page you need to follow sudipto's answer.

Related

CucumberJS tests passing even though it's not possible

I'm trying to convert some old ruby tests (which used cucumber, phantomjs and capybara) into JavaScript (using cucumber, phantomjs and selenium) as my project is 100% node based and I want to remove the Ruby dependency.
When I run the tests, they all pass. The problem is, I've not created the conditions for the test to pass yet so a pass is impossible. I'm not sure where I'm going wrong.
Here is my world.js file:
var {defineSupportCode} = require('cucumber');
var seleniumWebdriver = require('selenium-webdriver'),
By = seleniumWebdriver.By,
until = seleniumWebdriver.until;
function CustomWorld() {
this.driver = new seleniumWebdriver.Builder()
.withCapabilities(seleniumWebdriver.Capabilities.phantomjs())
.build()
// Returns a promise that resolves to the element
this.waitForElement = function(locator) {
var condition = seleniumWebdriver.until.elementLocated(locator);
return this.driver.wait(condition)
}
}
defineSupportCode(function({setWorldConstructor}) {
setWorldConstructor(CustomWorld)
});
And here is my step definitions file:
require('dotenv').config();
var chalk = require('chalk');
var {defineSupportCode} = require('cucumber');
var seleniumWebdriver = require('selenium-webdriver'),
By = seleniumWebdriver.By,
until = seleniumWebdriver.until;
defineSupportCode(function({ Given, When, Then }) {
Given(/^I show my environment$/, function (next) {
console.log(chalk.green("Running against:" + process.env.TARGET_URI))
next()
})
When(/^I visit "(.*?)"$/, function (url) {
return this.driver.get(url);
})
Then(/^I should be on "([^"]*)"$/, function(page_name) {
this.driver.get(process.env.TARGET_URI+'/'+page_name)
.then(function() {
return this.driver.getCurrentUrl();
})
})
Then(/^I should see "([^"]*)"$/, function (text) {
var xpath = "//*[contains(text(),'" + text + "')]";
var condition = seleniumWebdriver.until.elementLocated({xpath: xpath});
return this.driver.wait(condition, 5000);
});
})
The only possible tests that could be passing there are: When(/^I visit "(.*?)"$/... and Given(/^I show my environment$/...
For reference, here is my .feature file too:
Feature: Test the global header works as expected
Scenario: Header components should exist
Given I visit "/hello"
Then I expect to see a ".c-logo-bar" element
And I expect to see a ".c-search-bar" element
And I expect to see a ".c-main-nav-bar" element
Any ideas where I'm going wrong?

Odoo UI widget - how to get settings from database?

I'm writing an Odoo v9 widget, which renders a URL, based on concatenation of a setting in the database, and the actual form fields.
The setting in the database I figure should live in ir_config_parameter. I'm inserting a default value with my module.
What's the best way to get this value when rendering the widget? Doing an async ajax call using
new Model("ir.config_parameter")
seems a little heavy handed. Is there a better way to be doing this?
Thanks.
Widget code:
var UrlWidget2 = form_common.FormWidget.extend({
start: function() {
this._super();
this.field_manager.on("field_changed:ref", this, this.display_result);
this.display_result();
},
display_result: function() {
var ref = this.field_manager.get_field_value("ref");
if (!ref) return;
var baseUrl = 'https://example.com'; //this is the value I want to get from the setting in the database.
var url = baseUrl + '/foo/' + ref;
this.$el.html('View Externally<br /><br/>');
}
});
You can use RPC for this. This is example which work for me:
var Model = require('web.DataModel');
var UrlWidget2 = form_common.FormWidget.extend({
// just example how to get parameter from backend
display_result: function() {
var parameter = new Model('ir.config_parameter');
// get fields value, key
parameter.query(['value', 'key'])
// criteria of search - record with id = 1
.filter([['id', '=', 1]])
// only one record
.limit(1)
.all()
.then(function (parameter) {
// here data from server
console.log(parameter);
});
// ...
}
});
Hope this helps you.

How to spyOn a service function within the link of a directive?

I have a directive that uses a service function like so:
angular.module('testModule',
['serviceBeingUsed'])
.directive('testDirective', function(serviceBeingUsed) {
return {
restrict: 'AE',
templateUrl: 'testTemplate.tpl.html',
scope: {
boundVar1: "="
},
link: function(scope) {
scope.getRequiredData = function(data){
//gether data using service
serviceBeingUsed.fetchRequiredData(data).then(
function(result){
scope.requiredData = result;
}
);
};
}
};
});
In the above directive I inject the service I wish to use and this service function gets used within the scope function "getRequiredData()" which is inside the "link" of this directive.
I have my test suite set up like so:
describe('test suite', function () {
var scope,
$rootScope,
$compile,
$q,
element,
isoScope,
serviceBeingUsed;
beforeEach(module('testModule'));
beforeEach( inject( function(_$rootScope_,
_$q_,
_$compile_,
_serviceBeingUsed_) {
$rootScope = _$rootScope_;
$compile = _$compile_;
serviceBeingUsed = _serviceBeingUsed_;
$q = _$q_;
//This is where we create the directive and it's options.
element = angular.element('<test-directive bound-var1="blabla"></test-directive>');
//We create a new scope from the rootScope.
scope = $rootScope.$new();
//Now we compile the HTML with the rootscope
$compile(element)(scope);
//digest the changes
scope.$digest();
//We retrieve the isolated scope scope of the directive
isoScope = element.isolateScope();
}));
Now I have a test which runs and passes wherby I can spyOn the isolated scope function "getRequiredData()", this test looks like so:
it('getRequiredData runs', inject(function () {
spyOn(isoScope,"getRequiredData");
isoScope.getRequiredData();
expect(isoScope.getRequiredData).toHaveBeenCalled();
}));
This proves that the link functions CAN be tested however when trying to test if the service function is called the test fails and I have no idea why, the test for the service looks like this:
it('serviceFunction runs', inject(function () {
spyOn(serviceBeingUsed, "serviceFunction").and.callFake(function() {
var deferred = $q.defer();
var data = "returnedDataDummy";
deferred.resolve(data);
return deferred.promise;
});
isoScope.getRequiredData();
expect(serviceBeingUsed.serviceFunction).toHaveBeenCalled();
}));
How can I successfully test if the service function has been called here?
In writing this example I have solved my issue. In my actual code, inside the test "serviceFunction runs" I had also included a spyOn(isoScope,"getRequiredData)"
This has the effect of blocking the inner functionality of the function
getRequiredData()
which meant the the service function inside getRequiredData could never run.
To resolve this issue I needed to edit the spy for the outer function
from:
spyOn(isoScope,"getRequiredData");
to:
spyOn(isoScope,"getRequiredData").and.callThrough();
this simple change means that the function being spied on will also run its inner code and not just register that it has been called.
However one important lesson that I have learned is to not do too much inside each test and to separate the tests as much as possible.
So just to clarify, my original test which failed looked like this:
it('getRequiredData runs', inject(function () {
spyOn(serviceBeingUsed, "serviceFunction").and.callFake(function() {
var deferred = $q.defer();
var data = "returnedDataDummy";
deferred.resolve(data);
return deferred.promise;
});
spyOn(isoScope,"getRequiredData");
isoScope.getRequiredData();
expect(serviceBeingUsed.fetchRequiredData).toHaveBeenCalled();
expect(isoScope.getRequiredData).toHaveBeenCalled();
}));
the fix for this test which passes:
it('getRequiredData runs', inject(function () {
spyOn(serviceBeingUsed, "serviceFunction").and.callFake(function() {
var deferred = $q.defer();
var data = "returnedDataDummy";
deferred.resolve(data);
return deferred.promise;
});
spyOn(isoScope,"getRequiredData").and.callThrough();
isoScope.getRequiredData();
expect(serviceBeingUsed.fetchRequiredData).toHaveBeenCalled();
expect(isoScope.getRequiredData).toHaveBeenCalled();
}));

Returning value from file read with WinJS for use in page

I currently have an issue with a file read in a Windows 8/WinRT application. I have a simple navigation style app, several pages have access to the same data and I have a data.js file that defines a namespace (Data) with a number of members. One part of the application saves items to a txt file stored in the applications local data folder. But on some of the other pages I need to read this in or check for the existence of an item within the list of previously saved items. To do this I added another method into the data.js file. The trouble is, when I call this method to check for the existence of an item, it doesn't return the value straight away due to the async nature, but the rest of code in the page specific js file still seems to execute before it jumps back into the parsing. This means that the logic to check for an item doesn't seem to work. I have a feeling it's down to my use of either .done or .then but my code is as follows:
DATA.JS
var doesItemExist= function(item_id){
var appFolder = Windows.Storage.ApplicationData.current.localFolder;
//note I've tried this with and without the first "return" statement
return appFolder.getFileAsync(dataFile).then(function (file) {
Windows.Storage.FileIO.readTextAsync(file).done(function (text) {
try {
var json = JSON.parse(text);
if (json) {
for (var i = 0; i < json.items.length; i++) {
var temp_item = json.items[i];
if (temp_item.id === item_id) {
return true;
break;
}
}
} else {
return false;
}
} catch (e) {
return false;
console.log(e);
}
}, function (e) { return false;console.log(e); });
}, function (e) { // error handling
return false;
console.log(e);
});
}
WinJS.Namespace.define("Data", {
doesItemExist: doesItemExist
}); //all of the above is wrapped in a self executing function
Then on Page.js I have the following:
var add = document.getElementById('add');
if (Data.doesItemExist(selected_item.id)) {
add.style.display = 'block';
} else {
add.style.display = 'none';
}
All the variables here are assigned and debugging doesn't produce any errors, control just appears to go back to the if/else statement after it hits the getFileAsync but before it even goes through the for loop. But subsequently it does go in to the for loop but after the if statement has finished. I'm guessing this is down to the async nature of it all, but I'm not sure how to get around it. Any ideas?
thanks
A Promise should work here.
I created a new Navigation app, and added a Data.js file containing the following code:
(function () {
var appData = Windows.Storage.ApplicationData;
function doesItemExist(item_id) {
return new WinJS.Promise(
function (completed, error, progress) {
var exists = false;
appData.current.localFolder.createFileAsync("data.txt", Windows.Storage.CreationCollisionOption.openIfExists).then(
function (file) {
Windows.Storage.FileIO.readTextAsync(file).then(
function (fileContents) {
if (fileContents) {
if (fileContents = "foo!") {
completed(true);
}
else {
completed(false);
}
}
else {
completed(false);
}
}
);
},
function (e) {
error(e);
}
);
}
);
}
WinJS.Namespace.define("Data", {
doesItemExist: doesItemExist
});
})();
Note that I've simplified the code for retrieving and parsing the file, since that's not really relevant to the problem. The important part is that once you've determined whether the item exists, you call completed(exists) which triggers the .then or .done of the Promise you're returning. Note that you'd call error(e) if an exception occurs, as I'm doing if there's an exception from the call to createFileAsync (I use this call rather than getFileAsync when I want to be able to either create a file if it does not exist, or return the existing file if it does, using the openIfExists option).
Then, in Home.js, I added the following code to the ready handler:
var itemExists;
var itemExistsPromise = Data.doesItemExist(42);
itemExistsPromise = itemExistsPromise.then(function (exists) {
itemExists = exists;
var content = document.getElementById("content");
content.innerText = "ItemExists is " + itemExists;
});
itemExistsPromise.done(function () {
var a = 42;
});
var b = 0;
The code above sets the variable itemExistsPromise to the returned promise from the function in Data.js, and then uses an anonymous function in the .then function of the Promise to set the variable itemExists to the Boolean value returned from the doesItemExist Promise, and grabs the <p> tag from Home.html (I added an id so I could get to it from code) and sets its text to indicate whether the item exists or not). Because I'm calling .then rather than .done, the call returns another promise, which is passed into the itemExistsPromise variable.
Next, I call itemExistsPromise.done to do any work that has to wait until after the work performed in the .then above it.
If you set a breakpoint on the lines "var a = 42" and "var b = 0" (only included for the purpose of setting breakpoints) as well as on the line "itemExists = exists", you should find that this gives you the control you need over when the various parts are executed.
Hope that helps!

Can I use Ext's loader to load non-ext scripts/object dynamically?

In my ExtJS 4.0.7 app I have some 3rd party javascripts that I need to dynamically load to render certain panel contents (some fancy charting/visualization widgets).
I run in to the age-old problem that the script doesn't finish loading before I try to use it. I thought ExtJS might have an elegant solution for this (much like the class loader: Ext.Loader).
I've looked at both Ext.Loader and Ext.ComponentLoader, but neither seem to provide what I'm looking for. Do I have to just "roll my own" and setup a timer to wait for a marker variable to exist?
Here's an example of how it's done in ExtJS 4.1.x:
Ext.Loader.loadScript({
url: '...', // URL of script
scope: this, // scope of callbacks
onLoad: function() { // callback fn when script is loaded
// ...
},
onError: function() { // callback fn if load fails
// ...
}
});
I've looked at both Ext.Loader and Ext.ComponentLoader, but neither
seem to provide what I'm looking for
Really looks like it's true. The only thing that can help you here, I think, is Loader's injectScriptElement method (which, however, is private):
var onError = function() {
// run this code on error
};
var onLoad = function() {
// run this code when script is loaded
};
Ext.Loader.injectScriptElement('/path/to/file.js', onLoad, onError);
Seems like this method would do what you want (here is example). But the only problem is that , ... you know, the method is marked as private.
This is exactly what newest Ext.Loader.loadScript from Ext.4-1 can be used for.
See http://docs.sencha.com/ext-js/4-1/#!/api/Ext.Loader-method-loadScript
For all you googlers out there, I ended up rolling my own by borrowing some Ext code:
var injectScriptElement = function(id, url, onLoad, onError, scope) {
var script = document.createElement('script'),
documentHead = typeof document !== 'undefined' && (document.head || document.getElementsByTagName('head')[0]),
cleanupScriptElement = function(script) {
script.id = id;
script.onload = null;
script.onreadystatechange = null;
script.onerror = null;
return this;
},
onLoadFn = function() {
cleanupScriptElement(script);
onLoad.call(scope);
},
onErrorFn = function() {
cleanupScriptElement(script);
onError.call(scope);
};
// if the script is already loaded, don't load it again
if (document.getElementById(id) !== null) {
onLoadFn();
return;
}
script.type = 'text/javascript';
script.src = url;
script.onload = onLoadFn;
script.onerror = onErrorFn;
script.onreadystatechange = function() {
if (this.readyState === 'loaded' || this.readyState === 'complete') {
onLoadFn();
}
};
documentHead.appendChild(script);
return script;
}
var error = function() {
console.log('error occurred');
}
var init = function() {
console.log('should not get run till the script is fully loaded');
}
injectScriptElement('myScriptElem', 'http://www.example.com/script.js', init, error, this);
From looking at the source it seems to me that you could do it in a bit of a hackish way. Try using Ext.Loader.setPath() to map a bogus namespace to your third party javascript files, and then use Ext.Loader.require() to try to load them. It doesn't look like ExtJS actually checks if required class is defined in the file included.