Installing/Using Phantom.js with Meteor - meteor

I'm currently struggling with using Phantom.js with a Meteor app of mine. I have it installed on my local machine (Ubuntu 14.04), it's added to my path (I can run it from my terminal), I also ran and installed the smart wrapper for Phantomjs: mrt add phantomjs.
I can see that in my .meteor > local > build > programs > server > npm directory there is a phantomjs directory.
My question is, how do I actually use Phantom? I'm attempting to scrape from the server side of things. I've tried the following things (using coffeescript):
phantom = Npm.require "phantomjs"
phantom = Npm.require "phantom"
phantom = Meteor.require "phantomjs"
phantom = Meteor.require "phantom"
(I've also tried using capital "P's")
All attempts in this way yield: Error: Cannot find module 'phantomjs'
Any clarification would be greatly appreciated!

[EDIT] now meteor is supporting npm packages out of the box: https://guide.meteor.com/using-npm-packages.html#installing-npm
Here is the procedure for Meteor > 1.0.0
Add the npm package
meteor add meteorhacks:npm
Run meteor to let the npm package to pre-initialise
meteor
A file packages.json has been created at the root. Edit it to:
{
"phantomjs": "1.9.13"
}
To use phantom into your server side code:
var phantomJS = Meteor.npmRequire("phantomjs");
Bonus: an example of usage (thanks Ben Green), put anywhere in your code:
if (Meteor.isServer) {
Meteor.startup(function () {
var phantomjs = Meteor.npmRequire('phantomjs');
var spawn = Meteor.npmRequire('child_process').spawn;
Meteor.methods({
runTest: function (options) {
command = spawn(phantomjs.path, ['assets/app/phantomDriver.js']);
command.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
command.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
command.on('exit', function (code) {
console.log('child process exited with code ' + code);
});
}
});
Meteor.call("runTest");// run the test as soon as meteor server starts
});
}
Create the phantomjs script file ./private/phantomDriver.js and edit it to
var page = require('webpage').create();
page.open('http://github.com/', function (){
console.log('Page Loaded');
page.render('github.png');
phantom.exit();
});

The phantomjs wrapper in atmosphere doesn't look like it produces anything that works.
But you can easily add npm packages useing the npm meteorite package
First add the npm package to your project
mrt add npm
Then add the required phantomjs version to the packages.json file
{
"phantomjs": "1.9.7-6"
}
Then use the following code to require the phantomjs npm module:
var phantomjs = Meteor.require('phantomjs');

Related

Save protractor allure html report locally

I'm using Protractor and jasmine-allure-reporter. After executing test I am getting the XML files in 'allure-results', from there I am generating the HTML report using the command "allure serve allure-results". While executing this command the html report is getting generated in the 'Temp' folder (%Temp%\8691932647422029\allure-report). I want to generate/save this report locally, how can I do that. Because after the test run I may have to share the html report. Could you please help me on this.
Below is the Config.js part for allure-report
onPrepare: function() {
var AllureReporter = require('jasmine-allure-reporter');
jasmine.getEnv().addReporter(new AllureReporter());
jasmine.getEnv().afterEach(function(done){
//allure.addEnvironment(Path, 'Chrome'),
browser.takeScreenshot().then(function (png) {
allure.createAttachment('Screenshot', function () {
return new Buffer(png, 'base64')
},'image/png')();
done();
})
});
}
Please follow this setup for generating output in your local directory. 'Allure Command Line Tool' will help you to generate allure report.
Install it by running this command npm install allure-commandline --save-dev
After that, add "posttest": "allure generate allure-results --clean -o allure-report" section into your package.json. So when running the test by using npm test , the command mensioned in the posttest will generate report in your local directory. You can refer a sample script section of package.json file below.
"scripts": {
"pretest": "rm -rf allure-report",
"test": "protractor conf.js",
"posttest": "allure generate allure-results --clean -o allure-report || true"
}
In the posttest section you are refering the output directory location after --clean -o part.
Also change your conf.js file like this and add local directory path in resultsDir section to store generated xml files.
onPrepare: function () {
var AllureReporter = require('jasmine-allure-reporter');
//allure report
jasmine.getEnv().addReporter(new AllureReporter({
resultsDir: 'allure-results'
}));
/*
* It will take screenshot after each Jasmine function 'it'
*/
jasmine.getEnv().afterEach(function (done) {
browser.takeScreenshot().then(function (png) {
allure.createAttachment('Screenshot', function () {
return new Buffer(png, 'base64')
}, 'image/png')();
done();
})
});
}
The current setup will generate all the xml files in allure-results and html report in allure-report folder(both are in root directory).
|-allure-results
|-allure-report
|-node_modules
|-src-|-conf.js
|-package.json
Please refer a sample project in github

proper way of copying files to destination with gulp

I'm toying around with ASP.NET 5 and am using gulp. I added angularjs and angular-route to my package.json file which stored the files at Dependencies->NPM. I added this to my gulpfile.js thinking that it would copy over the the correct JS files. It did copy over the files, however, it also crashed the project. I had to manually go into the lib folder and remove everything that gulp added. What's the proper way to copy files from the NPM folder a destination folder. I'd like to be able to just run the task from Task Runner.
I'm assuming this is incorrect: (which is what I ran)
gulp.task("copyJs", function () {
return gulp.src('./node_modules/**/*.js')
.pipe(gulp.dest('./wwwroot/lib/'))
});
*I think the trailing '/' in gulp.dest('./wwwroot/lib/') might be the cause of the problem, try gulp.dest('./wwwroot/lib') instead.
This is the gulp workflow I use for Angular 2 with Asp.Net 5.
var gulp = require("gulp"),
merge = require("merge-stream"),
rimraf = require("rimraf");
var paths = {
webroot: "./wwwroot/",
node_modules: "./node_modules/"
};
paths.libDest = paths.webroot + "lib/";
gulp.task("clean:libs", function (cb) {
rimraf(paths.libDest, cb);
});
gulp.task("copy:libs", ["clean:libs"], function () {
var angular2 = gulp.src(paths.node_modules + "angular2/bundles/**/*.js")
.pipe(gulp.dest(paths.libDest + "angular2"));
var es6_shim = gulp.src([
paths.node_modules + "es6-shim/*.js",
"!**/Gruntfile.js"])
.pipe(gulp.dest(paths.libDest + "es6-shim"));
var systemjs = gulp.src(paths.node_modules + "systemjs/dist/*.js")
.pipe(gulp.dest(paths.libDest + "systemjs"));
var rxjs = gulp.src(paths.node_modules + "rxjs/bundles/**/*.js")
.pipe(gulp.dest(paths.libDest + "rxjs"));
return merge(angular2, es6_shim, systemjs, rxjs);
});
There are many ways to do it but one of the good simple ways I found was this: http://www.hanselman.com/blog/ControlHowYourBowerPackagesAreInstalledWithAGulpfileInASPNET5.aspx
Which do an update to the bowerrc file and everything after this update makes more sense.
UPDATE YOUR .BOWERRC AND PROJECT.JSON
In the root of your project is a .bowerrc file. It looks like this:
> { "directory": "wwwroot/lib" } Change it to something like this, and
> delete your actual wwwroot/lib folder.
>
> { "directory": "bower_components" } EXCLUDE YOUR SOURCE BOWER FOLDER
> FROM YOUR PROJECT.JSON
You'll also want to go into your project.json file for ASP.NET 5 and
make sure that your source bower_components folder is excluded from
the project and any packing and publishing process.
> "exclude": [
> "wwwroot",
> "node_modules",
> "bower_components" ],
UPDATE YOUR GULPFILE.JS
In your gulpfile, make sure that path is present in paths. There are
totally other ways to do this, including having gulp install bower and
figure out the path. It's up to you how sophisticated you want your
gulpfile to get as long as the result is that production ready .js
ends up in your wwwroot ready to be served to the customer. Also
include a lib or destination for where your resulting JavaScript gets
copied. Could be scripts, could be js, could be lib as in my case.
var paths = {
webroot: "./" + project.webroot + "/",
bower: "./bower_components/",
lib: "./" + project.webroot + "/lib/" }; ADD A COPY TASK TO YOUR GULPFILE
Now open your Gulpfile and note all the tasks. You're going to add a
copy task to copy in just the files you want for deployment with your
web app.
Here is an example copy task:
> gulp.task("copy", ["clean"], function () {
> var bower = {
> "bootstrap": "bootstrap/dist/**/*.{js,map,css,ttf,svg,woff,eot}",
> "bootstrap-touch-carousel": "bootstrap-touch-carousel/dist/**/*.{js,css}",
> "hammer.js": "hammer.js/hammer*.{js,map}",
> "jquery": "jquery/jquery*.{js,map}",
> "jquery-validation": "jquery-validation/jquery.validate.js",
> "jquery-validation-unobtrusive": "jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"
> }
>
> for (var destinationDir in bower) {
> gulp.src(paths.bower + bower[destinationDir])
> .pipe(gulp.dest(paths.lib + destinationDir));
> } });
Do note this is a very simple and very explicit copy tasks. Others
might just copy more or less, or even use a globbing wildcard.
It's up to you. The point is, if you don't like a behavior in ASP.NET
5 or in the general build flow of your web application you have more
power than ever before.
Right click the Bower node in the Solution Explorer and "Restore
Packages." You can also do this in the command line or just let it
happen at build time.
Looking in this simplified screenshot, you can see the bower
dependencies that come down into the ~/bower_components folder. Just
the parts I want are moved into the ~/wwwroot/lib/** folder when the
gulpfile runs the copy task.
I manage very complex monorepos, I don't like hardcoded file paths and prefer to mirror my source code for transparency. I explored a LOT of solutions for doing a lot of files at once and find them all opaque and bloated. I recommend a factory that ultimately does this with source-like file module references:
gulp.parallel(
() =>
gulp
.src(require.resolve('#bootstrap/core/dist/bootstrap.all.min.js'))
.pipe(gulp.dest(DIST)),
() =>
gulp
.src(require.resolve('foobar/dist/foobar.all.min.js'))
.pipe(gulp.dest(DIST))
You can make them named functions for visibility as well.

How can I set ENV variable in terminal before I run the meteor command?

if (Meteor.isServer) {
Meteor.startup(function() {
return Meteor.Mandrill.config({
username: USERNAME_MAIL,
key: KEY_MAIL
});
});
}
And I would like to set the USERNAME_MAIL and KEY_MAIL variable before running the server or to a deploy meteor app. How can this be done ?
Thanks !
you can either do it directly in front of the meteor command
USERNAME_MAIL="xxx" meteor
or export them just like any other ENV var and then fire up meteor
export USERNAME_MAIL="xxx"
export KEY_MAIL="yyy"
meteor // start meteor
see also this meteorpedia article.

Howto recursively remove directory in Meteor?

What is the best way for recursively directory removing with Meteor ?
Use an existing npm module like rimraf. Here's how you do it starting from an empty project:
$ meteor add meteorhacks:npm meteorhacks:async
$ meteor
Once meteor starts, stop it and edit packages.json to look like:
{
"rimraf": "2.2.8"
}
Then add something like this in a file under your server directory:
var removeDirectory = Async.wrap(Meteor.npmRequire('rimraf'));
Meteor.startup(function() {
removeDirectory('/dir/to/remove');
});
Where /dir/to/remove is, you guessed it, the directory you want to recursively remove.
Here's how I do it (in CoffeeScript):
fs = requre('fs')
_emptyDirectory = (target) ->
_rm(path.join(target, p)) for p in fs.readdirSync(target)
_rm = (target) ->
if fs.statSync(target).isDirectory()
_emptyDirectory(target)
fs.rmdirSync(target)
else
fs.unlinkSync(target)

Where to put native code for push notifications with new Meteor Mobile platform

After reviewing the new Mobile features with latest 1.0 version of Meteor, I'm not seeing where I would modify the Cordova code to add custom capabilities. For instance, I want to implement push notifications for my application on both iOS and Android. In both cases I would need to write some native code so that I could get devices registered and accept push notification messages.
Currently, I'm using MeteorRider to accomplish this and it works great. I have 3 separate projects for Meteor, Android and iOS. In the latter 2, I put the native code there necessary to accomplish this. One thing is for certain, you have to update the bootstrap classes in Cordova to allow registrations to work.
In Meteor 1.0, how would I go about accomplishing this with the out-of-the-box mobile feature?
Here's the objective-C code for accepting push notification registration responses that is required in Cordova's AppDelegate:
- (void) application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSLog( #"Device token is: %#", deviceToken);
// Convert to string that can be stored in DB
NSString *regId = [[deviceToken description] stringByReplacingOccurrencesOfString:#"<" withString:#""];
regId = [regId stringByReplacingOccurrencesOfString:#">" withString:#""];
regId = [regId stringByReplacingOccurrencesOfString: #" " withString: #""];
[[ApplePushNotificationService sharedInstance] application:application uploadDeviceToken:regId];
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(#"Failed to get token, error: %#", error);
}
TL;DR : The cordova project is in the .meteor/local/cordova-build subfolder.
The default AppDelegate.m gets created in the .meteor/local/cordova-build/platforms/ios/***YOUR_APP_NAME***/Classes subfolder.
If you add a top-level folder called cordova-build-override to your meteor project, the directory tree that it contains will be added to the .meteor/local/cordova-build folder just before the build and compilation step.
So, put your custom AppDelegate.m in a new folder called cordova-build-override/platforms/ios/***YOUR_APP_NAME***/Classes .
mkdir -p cordova-build-override/platforms/ios/foo/Classes
cp .meteor/local/cordova-build/platforms/ios/foo/Classes/AppDelegate.m cordova-build-override/platforms/ios/foo/Classes
The Meteor-Cordova integration page on the GitHub Meteor wiki is the best place (so far) to find the details of cordova development with meteor.
You put your cordova-specific code in plain javascript. It's best not to modify the native code if at all possible; instead, see if you can write your own cordova plugin and use it from your meteor app. The cordova PushPlugin plugin might do what you're looking for, but if not, you can use it as a reference.
This example below will create a new iOS app that uses a non-meteor cordova plugin, from scratch.
NOTE: This is a bare minimum example. Look at the meteor cordova camera plugin for a full example. The code below is based on that plugin.
# create a meteor app foo
meteor create foo
cd foo
# add the iOS cordova platform
meteor add-platform ios
# create a new meteor package, foo-camera.
# NOTE: You need to substitute your own meteor.com developer ID here
meteor create --package your_meteor_developer_id:foo-camera
Now, edit the packages/your_meteor_developer_id:foo-camera/package.js file to add the following:
// Add the camera cordova plugin at version 0.3.3
Cordova.depends({
'org.apache.cordova.camera': '0.3.3'
});
EDIT 1: This causes the plugin to be downloaded to your cordova plugins folder.
You can refer to a git tarball instead of a version number e.g. :
Cordova.depends({
'com.phonegap.plugins.facebookconnect': 'https://github.com/Wizcorp/phonegap-facebook-plugin/tarball/0e61babb65bc1716b957b6294c7fdef3ce6ace79'
});
source: meteor cordova wiki
While we're at it, limit our code to run only on the client, and export our FooCamera object so it can be used in the rest of our meteor javascript:
Package.onUse(function(api) {
api.versionsFrom('1.0');
api.export('FooCamera');
api.addFiles('your_meteor_developer_id:foo-camera.js','client');
});
Edit 2:
If your cordova plugin needs special configuration, you can define this in your meteor app's
mobile configuration file. It will get copied into
your app's config.xml .
E.g.
// ===== mobile-config.js ======
// Set PhoneGap/Cordova preferences
App.setPreference('SOME_SPECIFIC_PLUGIN_KEY','SOME_SPECIFIC_PLUGIN_VAL');
Your app's config.xml will then eventually result in the following:
<preference name="SOME_SPECIFIC_PLUGIN_KEY" value="SOME_SPECIFIC_PLUGIN_VAL"/>
Next, edit the JavaScript file in your package ( packages/your_meteor_developer_id:foo-camera/your_meteor_developer_id:foo-camera.js ) to expose the cordova functionality in a meteor-like manner. Use the official meteor mobile package examples as a reference.
(the code below is stolen shamelessly from the meteor github repo ) :
FooCamera = {};
FooCamera.getPicture = function (options, callback) {
// if options are not passed
if (! callback) {
callback = options;
options = {};
}
var success = function (data) {
callback(null, "data:image/jpeg;base64," + data);
};
var failure = function (error) {
callback(new Meteor.Error("cordovaError", error));
};
// call the cordova plugin here, and pass the result to our callback.
navigator.camera.getPicture(success, failure,
_.extend(options, {
quality: options.quality || 49,
targetWidth: options.width || 640,
targetHeight: options.height || 480,
destinationType: Camera.DestinationType.DATA_URL
})
);
};
Now, add your new (local) package to your meteor app.
meteor add your_meteor_developer_id:foo-camera
Edit your application's main HTML and JS to use your new meteor package.
In your foo.html , replace the hello template with this:
<template name="hello">
<button>Take a Photo</button>
{{#if photo}}
<div>
<img src={{photo}} />
</div>
{{/if}}
</template>
In your foo.js , replace the button click event handler with this:
Template.hello.helpers({
photo: function () {
return Session.get("photo");
}
});
Template.hello.events({
'click button': function () {
var cameraOptions = {
width: 800,
height: 600
};
FooCamera.getPicture(cameraOptions, function (error, data) {
Session.set("photo", data);
});
}
});
Now, plug your device in, make sure it's on the same network as your computer, and start both the meteor server and the ios app.
meteor run ios-device
# If you want to just use the emulator, use the following instead.
# but of course the camera won't work on the emulator.
#meteor run ios
XCode will open. You may need to set up your certificates and provisioning profiles before running your app (from XCode).
In another terminal, tail the logs:
tail -f .meteor/local/cordova-build/platforms/ios/cordova/console.log
Finally, publish your excellent meteor cordova plugin so that everyone else can use it. Edit package.js as per the meteor docs. Then:
cd packages/your_meteor_developer_id\:foo-camera
meteor publish

Resources