SpookyJS has no Start Method while using it in Meteor - node.js

I have an weird error and can't find the cause of it for the last few hours...
I have a meteor app, that scrapes some webpages for information and everything works fine as long as I use reuqest and cheerio for static pages, but now I have a dynamic site and I wanted to use phantomjs, casperjs and spookyjs for this one, but here I get some bug...
My code is as follows, I import the npm modules at the start:
if (Meteor.isServer) {
var cheerio = Meteor.npmRequire('cheerio');
var request = Meteor.npmRequire('request');
var phantomJS = Meteor.npmRequire('phantomjs');
var spooky = Meteor.npmRequire('spooky');
And sometime later I want to use spooky to scrape some webpage:
spooky.start("https://www.coursera.org/");
spooky.then( function () {
this.fill("form", {email: user, password: pass}, true);
});`
But as soon as I call the method I get the following error message:
20150224-21:16:39.100(-5)? Exception while invoking method 'getLecturesCoursera' TypeError: Object function Spooky(options, callback) {
....
I20150224-21:16:39.281(-5)? } has no method 'start'
I20150224-21:16:39.281(-5)? at [object Object].Meteor.methods.getLecturesCoursera (app/moocis.js:72:14)
I am doing something completly wrong and I have no clue why it isn't working...
I tried to verify that spookyjs and phantomjs are installed correctly in my app, but that isn't as easy as it sounds for someone who uses them for the first time...

Like normally with spooky you have to create a new Spooky Object before you can start and run it...
if (Meteor.isServer) {
Meteor.startup( function () {
var Spooky = Meteor.npmRequire('spooky');
var spooky = new Spooky({
child: {
transport: 'http'
},
casper: {
logLevel: 'debug',
verbose: true,
ignoreSslErrors: true,
sslProtocol: 'tlsv1'
}
}, function (err) {
if (err) {
e = new Error('Failed to initialize SpookyJS');
e.details = err;
throw e;
}
spooky.start(
'https://www.google.com');
spooky.then(function () {
this.emit('hello', 'Hello, from ' + this.evaluate(function () {
return document.title;
}));
});
spooky.run();
});
spooky.on('error', function (e, stack) {
console.error(e);
if (stack) {
console.log(stack);
}
});
spooky.on('hello', function (greeting) {
console.log(greeting);
});
spooky.on('log', function (log) {
if (log.space === 'remote') {
console.log(log.message.replace(/ \- .*/, ''));
}
});
})
}

Related

Use mocha programmatically via rest

currently I try to figure out, how I can run mocha tests on a GET request of localhost:3000/run/tests resource.
Most things seems to work fine, but mocha .on('end') is probably not fired correctly so my res.json(...) function is not called and node still hangs.
var Mocha = require('mocha');
...
app.get('/run/tests', (req, res) => {
var mocha = new Mocha({
reporter: 'json'
});
myTestFiles.forEach(testfile => mocha.addFile('./tests/' + testfile + '.js'));
mocha.run()
.on('end', function() {
console.log(this.testResults);
res.json(this.testResults);
});
});
I get expected output except the "0 passing" lines :
> ...
> CALL element.text()
> GET /session/:sessionID/element/9/text
> RESPONSE element.text() "Username"
√ App login finished: 37685ms
0 passing (0ms)
0 passing (16ms)
My testfile looks like this:
'use strict';
require('./helpers/setup');
var wd = require('wd');
var serverConfigs = require('./helpers/appium-servers');
describe('Carnet App', function () {
this.timeout(120000);
var driver;
var allPassed = true;
before(function () {
var serverConfig = serverConfigs.local;
driver = wd.promiseChainRemote(serverConfig);
require('./helpers/logging').configure(driver);
var desired = {
'appium-version': '1.4.16',
platformVersion: '6.0.1',
device: 'Android',
platformName: 'Android',
app: myapp.apk'
};
return driver
.init(desired)
.setImplicitWaitTimeout(120000);
});
after(function (done) {
return driver
.quit()
.done();
});
afterEach(function () {
allPassed = allPassed && this.currentTest.state === 'passed';
});
it('App login finished', function () {
return driver
.elementById('...')
.click()
.sendKeys('...')
.elementById('...')
.text().should.become('Username');
});
});
Do I make a mistake? Does anybody have expirence with wd + mocha programmatically? Thanks for help!
Ok I solved my problem by only modify the following:
mocha.run(function(failures){
res.json({ ... })
})
.on('test', function() {
// do some logging stuff (into a var retured by res.json above)
})
// ... all mocha events possible
// see https://github.com/mochajs/mocha/blob/master/lib/runner.js#L49
.on('test end', function() {
// do some advanced logging stuff
});

How can I test my asynchronous code in a restify HTTP handler?

I have a function in my Restify project that handles an HTTP GET request. After some processing it uses Sequelize to find the user entity for my current session. The User.findOne function returns a promise and depending on the result of that promise, I'm sending an HTTP response with 200 or 404.
static getMe(req, res, next) {
const userInfo = BaseController.getUserSession(req);
// hard to test this part
User.findOne({
where: {email: userInfo.email}
}).then(function(user) {
if (user) BaseController.respondWith200(res, user);
else BaseController.respondWith404(res, 'User not found.');
}, function(error) {
BaseController.respondWith404(res, error);
}).then(function() {
return next();
});
}
I've tried a few different libraries to help with testing so I'm sorry if this is a messy combination of things. This is in my beforeEach function for my tests:
const usersFixture = [
{id:2, email:'ozzy#osbourne.com', facebookId:54321, displayName: 'Ozzy Osbourne'},
{id:3, email:'zakk#wylde.com', facebookId:34521, displayName: 'Zakk Wylde'},
{id:4, email:'john#lennon.com', facebookId:12453, displayName: 'John Lennon'}
];
this.findOneSpy = sinon.spy(function(queryObj) {
return new Promise(function(resolve, reject) {
const user = usersFixture.find(function(el) { return el.email === queryObj.where.email });
if (user) resolve(user);
else resolve(null);
});
});
this.respondWith200Spy = sinon.spy(function(res, data) {});
this.respondWith400Spy = sinon.spy(function(res, error) {});
this.respondWith404Spy = sinon.spy(function(res, error) {});
this.controller = proxyquire('../../controllers/user-controller', {
'../models/user': {
findOne: this.findOneSpy
},
'./base-controller': {
respondWith200: this.respondWith200Spy,
respondWith400: this.respondWith400Spy,
respondWith404: this.respondWith404Spy
}
});
And here is what one of my tests looks like:
it('should return 200 with user data if user email matches existing user', function() {
// THIS FUNCTION IS NEVER HIT
this.respondWith200Spy = function(res, data) {
data.should.equal({id:4, email:'john#lennon.com', facebookId:12453, displayName: 'John Lennon'});
done();
};
const req = {session:{user:{email:'john#lennon.com'}}};
this.controller.getMe(req, this.res, this.nextSpy);
this.findOneSpy.should.have.been.called;
});
Since we aren't actually passing a callback to the function and the function doesn't really return anything (just does asynchronous things elsewhere), I can't figure out how to test it to make sure it's working right. Any help is appreciated.
The actual code works just fine. I'm just trying to get some quality unit testing into the project. Thanks!
I ended up finding a way to do it using proxyquire. I just re-stubbed the controller class that I am testing and made the respondWith200 callback make an assertion. Then I created a new spy for the next function that just calls done (which is passed into the test case). I verified that the code is all getting hit.
it('should return 200 with user data if user email matches existing user', function(done) {
const controller = proxyquire('../../controllers/user-controller', {
'../models/user': {
findOne: this.findOneSpy
},
'./base-controller': {
respondWith200: function(res, data) {
data.displayName.should.equal('John Lennon');
},
respondWith400: this.respondWith400Spy,
respondWith404: this.respondWith404Spy
}
});
const req = {grft_session:{user:{email:'john#lennon.com'}}};
const nextSpy = sinon.spy(function() {
done();
});
controller.getMe(req, this.res, nextSpy);
this.findOneSpy.should.have.been.called;
});

How to create a Node JS constructor to initialize a callback function

I am new to Node JS + Javascript. I have a module where I expect it to work as a constructor and initialize some data. And expect those data(array) to be available when I require it from another module. I referred couple of stackoverflow questions and couldn't figure it out.
I have mentioned those links below. Appreciate if anyone can help to resolve this.
Initialize a module when it's required
Node.js - use of module.exports as a constructor
var answers = function() {
this.getAnswers = function(callback) {
conversations.getRequestData(function(conArr) {
var results = [];
// some code here
callback(results);
});
}
}
module.exports = answers
This is your independent module with callback function and getting the output in other file:
//test.js
exports.answers = function(callback){
conversations.getRequestData(function(err,result){
if(!err){
callback(result);
}else{
callback(err);
}
}
}
//main.js
var test = requires('./test');
server.route({
method: 'GET',
path: '/testing_exports',
handler: function (req, reply) {
test.answers(function(resp){
console.log(resp); // your callback result
});
}
});
You can use classes in Node.js. To achieve that your class acts as a singleton, initialize it in module.exports.
class Answers {
constructor(){
//...
}
getAnswers(callback) {
conversations.getRequestData(function(conArr) {
var results = [];
// some code here
return callback(results);
});
}
}
module.exports = new Answers();

How can I access PhantomJS WebPage module from inside Mocha tests in NodeJS?

I'm basing this off of the Page Loading section of http://phantomjs.org/quick-start.html
I want to do something like this:
tests.js
var should = require('chai').should();
var page = require('webpage').create();
describe('test website with phantomJS', function() {
it('should load html from page', function() {
page.open('myHomePageToTest.html', function(status) {
if (status === 'success') {
page.content.should.equal('<!DOCTYPE html>...etc...</html>');
}
});
});
});
If I try to run this with 'mocha-phantomjs test.js' I get the error 'Failed to start mocha: Init timeout'
If I try to run this with 'mocha test.js' I get the error 'Cannot find module "webpage"'
I'm sure those are the expected error messages given the code. It's my understanding that is failing. The code is my description of what I want to do. After several hours of treading water last night, I have no idea how to actually do it.
Thank you for any help or nudge in the right direction.
var assert = require('assert');
var phantom = require('phantom');
describe('Mocha and phantom', function () {
this.timeout(150000);
it('Tweeking with phantomjs', function (done) {
phantom.create(function (ph) {
ph.createPage(function (page) {
page.open('https://www.facebook.com/', function (status) {
page.evaluate(function () {
return document.all[0].outerHTML //can check different elements
}, function (result) {
console.log('----------->>>>result',result);
assert.equal(status,'success','Not appropriate status');
done();
})
})
})
})
})
})

Using external modules within AppJs and nodejs

I've built a basic demo application using AppJS/NodeJS and edge.
Heres the relevant part of the the app.js config file - Basically it just references the external modules.
.......
window.on('ready', function(){
console.log("Window Ready");
window.process = process;
window.module = module;
window.dns = require('native-dns');
window.edge = require('edge');
window.fs = require('fs');
window.frame.openDevTools();
..........
And heres the relevant javascript part of the main index.html page:
.......
function myFunction1()
{
var question = dns.Question({
name: 'www.google.com',
type: 'A'
});
var req = dns.Request({
question: question,
server: { address: '8.8.8.8', port: 53, type: 'udp' },
timeout: 1000
});
req.on('timeout', function () {
console.log('Timeout in making request');
});
req.on('message', function (err, answer) {
answer.answer.forEach(function (a) {
console.log(a.address);
});
});
req.on('end', function () {
console.log('Finished processing request');
});
req.send();
}
function myFunction2()
{
var helloWorld = edge.func('async (input) => { return ".NET Welcomes " + input.ToString(); }');
helloWorld('JavaScript', function (error, result) {
if (error) throw error;
console.log(result);
});
}
..........
If I call myFunction1() which uses another nodejs module (DNS lookup) it works perfectly. However if I call myFunction2() which uses edge I get the following error!
Uncaught TypeError: Property 'func' of object [object Object] is not a function
I've spent hours on this and for cannot work out why this happening!
Have you tried running the same myFunction2 code inside app.js i.e. in nodejs? Maybe the func function does not exist on the edge object. Check the docs maybe you need to do something like
window.edge = require('edge').Edge;
or something similar to get hold of the object that you think you have at the moment. You can also do console.log(window.edge) and see what it outputs (both in node and in browser running dev tools (F12)).
/Simon

Resources