Casperjs doesn't execute javascript code - phantomjs

I have a page, and I'm referencing a bunch of scripts with regular script tag in the page's header: jQuery, etc, and my compiled script called index.js. Well the latter is big one, around 1.2M (don't ask why).
My index.html seems like this:
<html>
<head>
<title>Cool</title>
<script src='jQuery.js'></script>
<!-- more scripts -->
<script src='index.js'></script>
<!-- more stuff -->
The problem is if I use PhantomJS engine, my script doesn't get executed on any platforms. If I use SlimerJS/XUL then it gets executed on Windows, but doesn't get on OSX. I'm verifying it with a regular waitFor, evaluating a global variable's value, nothing extraordinary:
casper.test.begin('index.js executes', 1, function (test) {
casper.start(host);
casper.waitFor(
function () {
return casper.evaluate(function () {
return !!window.ENV;
});
},
function () {
test.pass('index.js run');
},
function () {
test.fail('index.js did not run');
});
casper.run(function () {
test.done();
});
});
On the other hand jQuery gets initialized in either environments, I can run jQuery code in evaluate context well, so this will pass:
casper.test.begin('jQuery works', 1, function suite(test) {
casper.start(host);
casper.waitFor(
function () {
return casper.evaluate(function () {
try {
return !!$('html').length;
}
catch (e) {
return false;
}
});
},
function () {
test.pass('jQuery works');
},
function () {
test.fail('jQuery did not init');
});
casper.run(function () {
test.done();
});
});
If I log out page events I can see that index.js loads with HTTP result of 200, it just doesn't get executed.
Did someone experienced this before? Does PhantomJS or SlimeJS have some platform specific limitations of script size/complexity?

Related

How to run method inside a response function using Vue.js

I'm trying to run a method when I get success response from API, but the method dont run. I made a quick example here to show.
The test() function should be executed after i get the response, since its calling another API endpoint. Here is the vue.js code.
var app = new Vue({
el: "#contents",
data: {
id: null,
details: [],
},
methods: {
fetchProductDetails: function(){
let vue = this;
axios.post("/api/get-details", {
id : id
})
.then(function (response) {
vue.details = response.data;
this.test();
})
.catch(function (error) {});
},
test: function () {
console.log(app.details);
}
},
mounted: function(){
this.fetchProductDetails();
},
});
You should run vue.test() instead of this.test(), just like you use vue.details = response.data instead of this.details = response.data.
When using an unnamed function in .then(), this no longer refers to your vue application, but to the unnamed function. You could use ES6 arrow function syntax in order to avoid having to set this to a specific variable, as arrow functions use their parent's scope for this instead of setting this to refer to themselves:
axios.post("/api/get-details", { id: this.id })
.then(response => {
this.details = response.data;
this.test();
})
.catch(error => { console.log(error)});
Arrow functions (and ES6 in general) are not supported by IE11 however. so you'd need to use Babel to compile it back to something ES5 JavaScript if you need to support older browsers.

How do I take a screenshot when a test in internjs fails?

I am having issues figuring out how to take a screenshot ONLY when a test fails in InternJs. I have this simple test in my registerSuite;
'verify google homepage': function () {
var url = 'https://www.google.com/';
return this.remote
.get(url)
.getCurrentUrl()
.then(function (data) {
assert.strictEqual(data, url, 'Incorrect URL');
})
.findByName('q')
.click()
}
I can simply create a screenshot using the following code;
.takeScreenshot
.then(function (data) {
fs.writeFileSync('/path/to/some/file', data, 'base64');
)}
I want to only take a screenshot, if the above test fails the assertion or is unable to find the locator.
I looked into the afterEach method, but I can't figure out how to get the status of the last test to apply a conditional.
So my question is, has anyone setup their internjs test to only take screenshots on failures and how was it accomplished?
It is not currently possible to interact with the currently executing test from beforeEach or afterEach methods; this capability is coming in the next version of Intern.
Selenium server, by default, provides a screenshot on every Selenium command failure, which is a Buffer object on the error.detail.screen property. If a Selenium command fails, just use this property which already has the screenshot waiting for you.
For assertion failures, you can create a simple promise helper to take a screenshot for you:
function screenshotOnError(callback) {
return function () {
try {
return callback.apply(this, arguments);
}
catch (error) {
return this.remote.takeScreenshot().then(function (buffer) {
fs.writeFileSync('/path/to/some/file', buffer);
throw error;
});
}
};
}
// ...
'verify google homepage': function () {
return this.remote.get(url).getCurrentUrl().then(screenshotOnError(function (actualUrl) {
assert.strictEqual(actualUrl, url);
}));
}
If it’s too inconvenient to wrap all your callbacks manually like this, you can also create and use a custom interface for registering your tests that wraps the test functions automatically for you in a similar manner. I’ll leave that as an exercise for the reader.
You can use catch method at the end of your chain and use error.detail.screen as suggested by C Snover.
'verify google homepage': function () {
return this.remote
.get(require.toUrl('./fixture.html'))
.findById('operation')
.click()
.type('hello, world')
.end()
.findById('submit')
.click()
.end()
.catch(function(error){
fs.writeFileSync('/tmp/screenshot.png', error.detail.screen);
})
}
I've been playing with this today and have managed to get it for an entire suite rather than needing to add the code to every single test which seems quite needless.
var counter = -1,
suite = {
beforeEach: function () {
counter++;
},
afterEach: function () {
var currentTest = this.tests[counter];
if (!currentTest.error) {
return;
}
this.remote
.takeScreenshot().then(function (buffer) {
if (!fs.existsSync(path)) {
fs.mkdirSync(path);
}
fs.writeFileSync('/tmp/' + currentTest.name + '.png', buffer);
});
}
};
The annoying thing you will need to do is do this for every test suite rather than "globally" but is much better than doing it for every test.
Building on the answer by Hugo Oshiro,
// tests/support/CleanScreenshots.js
define([
'intern/dojo/node!path',
'intern/dojo/node!del',
], function(path, del) {
return new Promise((resolve, reject) => {
let directory = 'tests/screenshots';
del(path.join(directory, '**/*'))
.then(resolve)
.catch(reject);
});
});
Then in your intern config:
/* global define */
define([
'tests/support/CleanScreenshots'
], function (CleanScreenshots) {
return {
...
setup: function () {
return CleanScreenshots();
},
...
};
});
According to this issue, starting with the Intern 3.0 you can do a custom reporter that take an Screenshots when test fail. So you can centralize it in a simple way, just referencing the custom reporter in your config.js. In my case, what can I just add a reporter array in the config.js with the path to my custom array:
reporters: [
{ id: 'tests/support/ScreenShot' }
],
than I made an custom reporter overriding testFail:
'use strict';
define([
'intern/dojo/node!fs',
], function(fs) {
function ScreenShot(config) {
config = config || {};
}
ScreenShot.prototype.testFail = function(test) {
test.remote.takeScreenshot().then(function(buffer) {
try {
fs.writeFileSync('./screenshots/' + test.parent.name.replace(/ /g, '') + '-' +
test.name.replace(/ /g, '') + '.png', buffer);
} catch (err) {
console.log('Failed to take a screenshot: ' + err);
}
});
};
return ScreenShot;
});
Pay attention to the relative paths both to reference the custom reporter and the place for screenshots. They all seems to be taken considering where you run intern-runner, not the place the source files are located.
For more info about custom reporters go to this page.

Using a json file to store configurations for a dojo application

I am writing a fontend web app using dojo that does a lot of calls to rest endpoints using xhr. I would like to have a place to store configurations for things like endpoint locations and html tag references. I thought I would use an xhr call to a json file to do this, but I am having trouble getting my functions to trigger in the right order/at all. Below is my main js file which has an init() function that I am passing as the callback to my conf initializer ("ebs/conf") module, also below. I have used the Chrome debugger to set breakpoints within my conf.get() method, and it looks as though it never gets called.
Can someone give me some advice please?
Main JS File:
// module requirements
require([ "dojo/dom", "dojo/on", "ebs/prices", "ebs/cart", "ebs/conf",
"dojo/ready" ], function(dom, on, prices, cart, conf, ready) {
ready(function() {
conf.get("/js/config.json", init());
function init(config) {
on(dom.byId("height"), "keyup", function(event) {
prices.calculate(config);
});
on(dom.byId("width"), "keyup", function(event) {
prices.calculate(config);
});
on(dom.byId("qty"), "keyup", function(event) {
prices.calculate(config);
});
on(dom.byId("grills"), "change", function(event) {
prices.calculate(config);
});
cart.putSampleCart();
cart.load(config);
}
});
});
And here is my 'conf' module ("ebs/conf"):
define(["dojo/json", "dojo/request/xhr"], function(json, xhr) {
return {
get : function(file, callback) {
// Create config object from json config file
var config = null;
xhr(file, {
handleAs : "json"
}).then(function(config) {
callback(config);
}, function(error) {
console.error(error);
return error;
});
}
}
});
Your are not passing the function as the callback. You are executing it and passing the result as the second argument.
conf.get("/js/config.json", init());
should be
conf.get("/js/config.json", init);

Sinon JS "Attempted to wrap ajax which is already wrapped"

I got the above error message when I ran my test. Below is my code (I'm using Backbone JS and Jasmine for testing). Does anyone know why this happens?
$(function() {
describe("Category", function() {
beforeEach(function() {
category = new Category;
sinon.spy(jQuery, "ajax");
}
it("should fetch notes", function() {
category.set({code: 123});
category.fetchNotes();
expect(category.trigger).toHaveBeenCalled();
}
})
}
You have to remove the spy after every test. Take a look at the example from the sinon docs:
{
setUp: function () {
sinon.spy(jQuery, "ajax");
},
tearDown: function () {
jQuery.ajax.restore(); // Unwraps the spy
},
"test should inspect jQuery.getJSON's usage of jQuery.ajax": function () {
jQuery.getJSON("/some/resource");
assert(jQuery.ajax.calledOnce);
assertEquals("/some/resource", jQuery.ajax.getCall(0).args[0].url);
assertEquals("json", jQuery.ajax.getCall(0).args[0].dataType);
}
}
So in your jasmine test should look like this:
$(function() {
describe("Category", function() {
beforeEach(function() {
category = new Category;
sinon.spy(jQuery, "ajax");
}
afterEach(function () {
jQuery.ajax.restore();
});
it("should fetch notes", function() {
category.set({code: 123});
category.fetchNotes();
expect(category.trigger).toHaveBeenCalled();
}
})
}
What you need in the very beginning is:
before ->
sandbox = sinon.sandbox.create()
afterEach ->
sandbox.restore()
Then call something like:
windowSpy = sandbox.spy windowService, 'scroll'
Please notice that I use coffee script.

How to structure multiple pages with RequireJS

How to structure multiple pages with RequireJS? Is, like the following sample, declaring every class in app.js is the right thing to do? Has every html file to declare the <script data-main="src/main" src="src/require.js"></script>?
What I want to avoid is loading all the script when a user reach the first page of a site.
main.js defining all external dependencies:
require(
{
baseUrl:'/src'
},
[
"require",
"order!http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js",
"order!http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js",
"order!http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.6/underscore-min.js",
"order!http://ajax.cdnjs.com/ajax/libs/backbone.js/0.3.3/backbone-min.js"
],
function (require) {
require(["app"], function (app) {
app.start();
});
}
);
app.js file defining every component:
define([ "product/ProductSearchView",
"product/ProductCollection"
], function (ProductSearchView,
ProductCollection) {
return {
start: function() {
var products = new ProductCollection();
var searchView = new ProductSearchView({ collection: products });
products.fetch();
return {};
}
}
});
You can require files within your existing module. So say when someone clicks a link you could trigger a function that does the following:
// If you have a require in your other module
// The other module will execute its own logic
require(["module/one"], function(One) {
$("a").click(function() {
require(["new/module"]);
});
});
// If you have a define in your other module
// You will need to add the variable to the require
// so you can access its methods and properties
require(["module/one"], function(One) {
$("a").click(function() {
require(["new/module"], function(NewModule) {
NewModule.doSomething();
});
});
});
This is a complete example of how this all works; require.js and order.js are in the same directory as the app's JS files.
<html>
<head>
<script data-main="js/test" src="js/require.js"></script>
</head>
<body>
<button>Clickme</button>
</body>
</html>
test.js (in js folder)
require(
{
baseUrl:'/js'
},
[
"order!//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js",
"order!//ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js"
],
function () {
require(["app"], function (app) {
app.start();
});
}
);
app.js (in js folder) with a on-demand load of Employee.js:
define([], function () {
return {
start: function() {
$('button').button();
$('button').click(function() {
require(['Employee'], function(Employee) {
var john = new Employee('John', 'Smith');
console.log(john);
john.wep();
});
});
return {};
}
}
});
Employee.js (in js folder):
define('Employee', function () {
return function Employee(first, last) {
this.first = first;
this.last = last;
this.wep = function() {
console.log('wee');
}
};
});