jsdom not triggering internal <script> - javascript

I am trying to sample a page that has a script on it that changes the CSS of certain elements such that an attribute toggles between "active" and "inactive" based on the width of the window.
I have written nodeJS code that gathers and analyzes the page, but I cannot seem to trigger, or detect the triggering of the script. I suspect it has to do with defaultDocumentFeatures, but I could be wrong.
The script opens the page in JSDOM with a default width, then changes it to a specified block of other widths. This should result in changes in the output, but it does not. I am getting the same results for all situations. I suspect that the script on the page simply isn't running, but need help to make it do so
Here is my code (expurgated for public viewing.)
var express = require('express');
var router = express.Router();
var jsdom=require('jsdom');
router.get('/getSamplePage', function(req, res) {
getaEpicPage(req, res, function(contents){
console.log("got an sample page"+contents+"000000000");
//contents gets replaced by the actual results that will be processed upstream
res.send({'msg':'', 'contents':contents});
});
});
var getaSamplePage=function (req, res, callback) {
jsdom.defaultDocumentFeatures={
FetchExternalResources : ['script', 'css'],
ProcessExternalResources : ['script', 'css'],
MutationEvents : '2.0',
QuerySelector : false
};
var elementLocations=[
'sample_01',
'sample_02',
'sample_03'];
var contents=[{label:'DIV ID', value:'Is Populated', width: "Screen Width", position:"element size"}];
var windowWidths=[
479,
481,
781,
783,
1023,
1025,
]
for (var i in windowWidths){
jsdom.env({
url:'http://sourcefilelocation/',
scripts: ['http://code.jquery.com/jquery.js'],
created: function(errors, tstWindow) {
tstWindow.tstWindowWidth=windowWidths.pop();
tstWindow.addEventListener('resize', function() {
//verify that resize is triggered
console.log('Resize event completed');
});
tstWindow.constructor.prototype.resize = function (width){
//defining a "resize" event, since that may be what triggers things
console.log("resize has been attempted");
tstWindow.originalWidth=tstWindow.innerWidth;
tstWindow.outerWidth=tstWindow.innerWidth=width;
}
tstWindow.readyState="complete";
},
done: function(errors, tstWindow) {
setTimeout(function () {
//setting a timeout to ensure that any elements have finished I have put this as high as ten seconds.
console.log("ready state "+tstWindow.readyState);
tstWindow.resize(tstWindow.tstWindowWidth)
$=tstWindow.$;
for (var sampleLocation in sampleLocations) {
var sampleID=sampleLocations[sampleLocation];
$('div > [sampleAttribute='+sampleID+']').each(function(){
//If the script I am trying to watch work triggers, it should change the "content" attribute
var elementActive=$(this).css('content');
var position=$(this).attr('sample-position');
console.log("element css>>>>>> "+tstWindow.innerWidth+" "+sampleID+" "+position+" "+elementActive);
if (elementActive=='"active"'){
contents.push({label:sampleID, value: elementActive, width: tstWindow.originalWidth+"/"+tstWindow.innerWidth, position:position});
}
});
};
}, 50);
}
});
};
setTimeout(function () { callback(contents);}, 100);
};
module.exports = router;
Per suggestion I added this to my jsDom config object, just after the url:
FetchExternalResources : ['script', 'css'],
ProcessExternalResources : ['script', 'css'],
MutationEvents : '2.0',
QuerySelector : false,
But it has made no apparent difference.

As per the jsdom Readme when you're using jsdom.env the default feature set does not include processing scripts.
You have to pass the FetchExternalResources and ProcessExternalResources to jsdom.env specifically.
jsdom.env({
html: input,
url: url,
features: {
FetchExternalResources: ["script", "img", "css", "frame", "iframe", "link"],
ProcessExternalResources: ["script"]
},
created: function (err, window) {
console.log('Created');
},
loaded: function (err, window) {
console.log('Loaded');
}
});
jsdom.env doesn't use the jsdom.defaultDocumentFeatures object.

Related

How to create a custom Inject Node in NodeRED?

I want to start my node with a button click, so that I do not have to put the inject node in front. How would that be possible to register a button click in the javascript file?
I have tried to put node.on("input", async function(msg){/*some code*/}) inside the javascript file, where I register my node. I was able to add this button through this:
//HTML file script
<script type="text/javascript">
RED.nodes.registerType('light', {
category: "input",
color: "#f3c12b",
defaults: {
name: {value: ""},
plus: {value: ""},
topic: {value: this.name},
payload: {value: ""}
},
inputs: 0,
outputs: 1,
label: function(){
return "Licht '"+this.name+"'" || "Licht";
},
button: {
enabled: function(){
return true;
},
onclick: function(){
//I´ve put the code here, but then I have to reconfigure my functions
}
}
});
</script>
//Javascript file --> register function
//Not getting any response
node.on("input", async function(msg) {
msg = {};
msg.topic = this.topic;
msg.payload = "This is a new message!";
node.send(msg);
});
I was expecting, that when I click this the node is sending a message, but the node is not responding anything.
The best bet here is to look at the inject node source code.
inject.html
inject.js
In the case of the inject node, the onclick function of the button parameter in the HTML file actually does a POST call to /inject/{id} on the server.
onclick: function() {
...
var node = this;
$.ajax({
url: "inject/"+this.id,
type:"POST",
success: function(resp) { ... }
});
}
The inject JS file, which runs on the server, hosts an http endpoint at /inject/:id that when it's called gets the node by id and called node.receive() which acts as the trigger for it's input.
module.exports = function(RED) {
...
RED.httpAdmin.post("/inject/:id", RED.auth.needsPermission("inject.write"), function(req,res) {
var node = RED.nodes.getNode(req.params.id);
...
node.receive();
...
});
}

Show / hide preloader on page load in Framework7

I want to show a preloader over all the contents when a page is loading and hide it when the page load is finished and show the content (I'm not talking about internal links- like when you type an address in the browser and waiting for the page to load.)
Like this demo: https://demo.app-framework.com/
I’ve tried this:
var app = new Framework7({
// App root element
root: '#app',
// App Name
name: 'My App',
// App id
id: 'com.myapp.test',
on: {
init: function () {
console.log('App initialized');
},
pageInit: function () {
console.log('Page initialized');
app.preloader.hide();
},
}
// ... other parameters
});
var mainView = app.views.create('.view-main');
app.preloader.show();
But it doesn't work it shows the loader like other elements and doesn't hide it, I'm not sure if its something possible. I would appreciate if someone can point me in the right direction.
That's because in the pageInit event you are referring to a variable which is not initialised by the time you are calling (var app), please find the code snippet usefull.
var app = new Framework7({
// App root element
root: '#app',
// App Name
name: 'My App',
// App id
id: 'com.myapp.test',
on: {
init: function () {
console.log('App initialized');
},
pageInit: function () {
console.log('Page initialized');
//app.preloader.hide(); //app is not yet initialized this will return an undefined error.
},
}
// ... other parameters
});
var mainView = app.views.create('.view-main');
app.preloader.show(); //var app is initialized by now
app.on('pageInit', function (page) {
console.log('Page is now initialized');
app.preloader.hide();
});
The docs on Page has a section on Page Events. https://framework7.io/docs/page.html#page-name
Use app.preloader.show(); on an early event, and use app.preloader.hide(); when you want it removed.
pageBeforeIn: function (e, page) {
app.preloader.show();
},
pageAfterIn: function (e, page) {
app.preloader.hide();
},

How to override testClass methods with Siesta?

I'm using Bryntum Siesta for UI testing an ExtJS app. I've created a TestClass and aim to use its methods for different views. Whole actions of test are same only some specific things are changing such as package, view, grid names. Here is some snippets from Test Suite:
Main Test Class
var isDisplaying = 'Grid is displaying now.';
var collapseDesc = 'Collapse Navbar';
Class('Siesta.Test.ListScreen', {
isa : Siesta.Test.ExtJS,
methods: {
navigation: function (callback) {
var t = this;
t.chain(
{waitForCQ: 'treelist[itemId=navigationTreeList]'},
function (next) {
t.click('treelist[itemId=navigationTreeList]');
next();
},
{click: '>> treelistitem[_text=Package_Name]'},
{click: '>> treelistitem[_text=Package_Submodule]', desc: 'Package Submodule'+isDisplaying},
{click: '#main-navigation-btn => .fa-navicon', desc: collapseDesc},
function (next) {
console.log('navigation func log');
next();
},
callback
)
}
}
});
And this testClass calling from Package_Submodule and getting success:
describe('UI Testing: Submodule List Screen', function (t) {
//Extended method for navigation to submodule
t.it('Should open: Submodule Grid', function (t) {
t.chain(
{
navigation: t.next
}
)
});
});
The thing here is I want to call same TestClass method for another Submodule and override several things such as Package_Name and Package_Submodule. How can i be success to do this?
Thanks in advance
UPDATE through JackSamura's answer:
Dear #SamuraiJack I've refactored the Main Class (ListScreen) and inserted has attribute. As well modified the harness with config property but unfortunately it did not override myPackageName or mySubModule. Instead of i got this error:
Waiting for element ">> treelistitem[_text=packageName]" to appear
As well I've tried to use function arguments but it did not work too. Could you please give an idea why I couldn't override new values?
Main Class (Updated):
var isDisplaying = 'Grid is displaying now.';
var collapseDesc = 'Collapse Navbar';
Class('Siesta.Test.ListScreen', {
isa : Siesta.Test.ExtJS,
has : {
myPackageName : 'packageName',
mySubModule : 'subModule'
},
methods: {
navigation: function (callback) {
var t = this;
t.chain(
{waitForCQ: 'treelist[itemId=navigationTreeList]'},
function (next) {
t.click('treelist[itemId=navigationTreeList]');
next();
},
{click: '>> treelistitem[_text='+this.myPackageName+']'},
{click: '>> treelistitem[_text='+this.mySubModule+']', desc: this.mySubModule+isDisplaying},
{click: '#main-navigation-btn => .fa-navicon', desc: collapseDesc},
function (next) {
console.log('navigation func log');
next();
},
callback
)
}
}
});
index.js:
group: 'UI Tests',
items: [
{
group: 'Submodule List Screen',
testClass: Siesta.Test.ListScreen,
items: [
{
title : 'Submodule1',
hostPageUrl : localApp,
url : '02-ui-tests/02_01-submodule-list-screen/submodule1-list.t.js',
config : {
myPackageName : 'Package1',
mySubModule : 'Submodule1'
}
},
You can do it in 2 ways:
1) Add arguments to the "navigation" method:
// callback should be the last one
navigation: function (packageName, packageSubModule, callback) {
Probably self-explanatory
2) A bit more complex - add new attributes to your custom test class:
Class('Siesta.Test.ListScreen', {
isa : Siesta.Test.ExtJS,
has : {
// values goes into prototype, like in Ext
myPackageName : 'packageName',
mySubModule : 'subModule'
},
methods: {
Then you can refer to those attributes in "navigation" method as usual: this.myPackageName
Then, to override, you can either create a new test class (subclassing Siesta.Test.ListScreen) and re-define the attributes in it, or alternatively, use the config property of the test descriptor:
harness.start(
{
url : 'mytest.t.js',
config : {
myPackageName : 'value1',
mySubModule : 'value2'
}
},
...
)
Hint: To get the answer faster - post it to the Siesta forum: https://www.bryntum.com/forum/viewforum.php?f=20
UPDATE:
The errors you got are probably because "navigation" method is launched from the sub test (every "t.it()" or "t.describe()" section creates a separate "subtest"). Those sub tests won't have the config applied - it is applied only to the top-level test. One solution would be to copy the attribute values:
// in the "methods" of the custom test class
processSubTestConfig : function (config) {
var cfg = this.SUPER(config)
cfg.myPackage = this.myPackage
...
return cfg
},
But that is already advanced Siesta internals coding. Probably just using function arguments will be simpler..

Do I need any server adjustments in order to use fully HTML5 History API?

I am using HTML5 History API (on Chrome), at the following link:
http://jsbin.com/zuqijofole/1
You can see a simple application which shows/hides div (Views).
Script works fine using browser backward and forward buttons but if I type directly in the browser the following address (in order to see View 2)
http://jsbin.com/zuqijofole/2
the document is not found. I need instead the second View to be shown.
I would like to know:
Should I implement on server side some logic which map URL? Which
coul be a solution using latest PHP?
Or am I missing some implementation in my JS?
Notes: solution should work in a SPA application, so all data is rendered by JS app.
window.app = {
data: {
views: [
{ id: 0, isActive: false },
{ id: 1, isActive: false },
{ id: 2, isActive: false },
]
},
start: function () {
this.listeners();
// default entry
var activeView = this.wm.activeView;
history.replaceState({ activeView: activeView }, document.title, document.location.href);
window.app.wm.hideViews();
window.app.wm.showView();
},
listeners: function () {
window.addEventListener('popstate', function (event) {
// fires when backing/forwarding in history
console.log(event);
console.log(window.history.state);
this.wm.showHideBl(event.state);
}.bind(this));
var elm = document.getElementById('btn-prev');
elm.addEventListener('click', function () {
window.app.wm.snowPrevView();
});
elm = document.getElementById('btn-next');
elm.addEventListener('click', function () {
window.app.wm.snowNextView();
});
},
wm: {
activeView: 0, // default
showView: function () {
var elm = document.getElementById('view-' + this.activeView);
elm.style.display = '';
},
showHideBl: function (data) {
this.hideView();
this.activeView = data.activeView;
this.showView();
},
snowNextView: function () {
// bl
if (this.activeView < window.app.data.views.length - 1) {
this.hideView();
this.activeView++;
this.showView();
history.pushState({ activeView: this.activeView }, '', this.activeView);
}
},
snowPrevView: function () {
// bl
if (this.activeView > 0) {
this.hideView();
this.activeView--;
this.showView();
history.pushState({ activeView: this.activeView }, '', this.activeView);
}
},
hideView: function () {
var elm = document.getElementById('view-' + this.activeView);
elm.style.display = 'none';
},
hideViews: function () {
window.app.data.views.forEach(function (item, index, array) {
var elm = document.getElementById('view-' + item.id);
elm.style.display = 'none';
}.bind(this));
}
}
};
Yes, for a completely seamless experience, you want that all URLs created by the History API to be mapped to actual URLs that the server can use.
For example, if you have a table that you can sort client side, you can use the history API to save the sorting state into the URL. The server should be able to read that URL and serve a table already sorted when the page is refreshed.
The best way to make sure everything works as intended is to disable JavaScript and make sure you can still navigate and use the site correctly (even though the page refreshes all the time).

Preparing an automated testing using javascript for testing a module

The module has three pages which change one by one when clicked on the next or prev button. I am able to click it by writing the click method twice. How do I make it work in one test? Do I have to use a loop or any other way. Please suggest JavaScript, my arrow environment is new to me. We are using nodejs.
Secondly, they are adding an auto rotate feature to this module, for which also I have to prepare automation test. Please suggest how to go about automating testing this feature.
http://att.yahoo.com/
(check Attspotlight module)
For your convenience, here is the current code I wrote for the module:
YUI.add("cdt-att-spotlight-func-tests", function(Y) {
'use strict';
var Utils = Y.Media.Cdt.FuncTestUtils;
Y.Media.Cdt.FuncTestUtils.DebugMode=true;
var selectors = {
module: "#mediabcarouselmixedlpca_2",
/*title: ".heading",
numberSlot: ".yui-carousel-pagination",
clickButtons: ".ymg-nav-buttons",*/
nextButton: ".yui-carousel-next",
prevButton: ".yui-carousel-prev",
visibleImage:".img-wrap",
/*linkText_bestdeals: ".txt",
linkText_CheckGoPhone:".txt",
linkText_greatdeals:".txt",*/
linkText: ".txt"
};
var suite = new Y.Test.Suite("Cdt Att Spotlight Func Test Suite");
suite.add(new Y.Test.Case({
setUp: function() {
// Find our module...
this.module = Y.one(selectors.module);
// Define our components...
this.components = {
nextButton: this.module.one(selectors.nextButton),
prevButton: this.module.one(selectors.prevButton),
visibleImage: Utils.track.selector(this.module, selectors.visibleImage),
linkText: this.module.one(selectors.linkText)
};
this.module.scrollIntoView();
},
"Verify MediaCdtAttSpotlight module loaded": function() {
this.module.should.be.visibleToUser();
},
"Verify Image showed in the module": function() {
var visibleImage = this.components.visibleImage.current();
this.wait(function() {
visibleImage.should.be.visibleToUser();
}, 2000);
},
"Verify the Link Text is visible": function() {
this.components.linkText.should.be.visibleToUser();
},
"Verify clicking next button to scroll left": function() {
this.components.nextButton.simulate("click");
this.wait(function() {
}, 3000);
},
"Verify clicking next button1 to scroll left": function() {
this.components.nextButton.simulate("click");
this.wait(function() {
}, 3000);
},
"Verify clicking prev button to scroll right": function() {
this.components.prevButton.simulate("click");
this.wait(function() {
}, 2000);
},
"Verify clicking prev button1 to scroll right": function() {
this.components.prevButton.simulate("click");
this.wait(function() {
}, 2000);
}
}));
Y.Test.Runner.add(suite);
}, "0.1", { requires: ["test", "node", "node-event-simulate", "chai-yui", "cdt-func-test-utils"]});
Note: This question is targeted towards nodejs module testing in general, not Arrow. I don't want to delete it as the author is looking for clarification of some things in the comments of my anwser. I will be happy to delete this anwser if it is requested.
I would reccomend mocha http://visionmedia.github.io/mocha/. It is a great testing framework that is very popular. When combined with the module should, you can write simple tests, like this.
require('should');
describe('Array', function(){
describe('#indexOf()', function(done){
it('should return -1 when the value is not present', function(){
[1,2,3].indexOf(5).should.equal(-1);
[1,2,3].indexOf(0).should.equal(-1);
done();
})
})
})
You can then set up a free web service called travis ci https://travis-ci.org/ to run your tests whenever you push to github. I am using these services for my modules and am very happy.

Categories

Resources