Skip to content

Commit

Permalink
Forward port PR segment-boneyard#579 from master.
Browse files Browse the repository at this point in the history
Pretty dang awesome. The parent PR removed a ton of code, a dependency
and made things clean! Synergize!!
  • Loading branch information
Oceanswave committed May 7, 2016
1 parent b9f0941 commit 589a45a
Show file tree
Hide file tree
Showing 11 changed files with 414 additions and 273 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ node_modules
test/tmp
test/DevTools Extensions
.vs/
.vscode/
coverage/
46 changes: 29 additions & 17 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This version of Nightmare relies on promises. The primary API change is that all

Since all functions return promises, it's easy to synchronize between other Promise-based apis.

```
``` js
Promise.race([nightmare.goto('http://foo.com'), timeout(500)])
.then(function() {
console.log("success!");
Expand All @@ -21,7 +21,7 @@ Since all functions return promises, it's easy to synchronize between other Prom

However, Nightmare is still chainable through the .chain() function.

```
``` js
var Nightmare = require("nightmare");
var title = new Nightmare().chain()
.goto("http://foo.com")
Expand All @@ -39,7 +39,7 @@ Starting with Nightmare v3 one can choose the specific base functions that are d

By default, all modules are associated with the nightmare instance whe using require("nightmare"). If you only want to use a portion of the functionality you can include only the modules you're interested in, or, if you're not happy with the included ones, completely rewrite your own actions.

```
``` js
const Nightmare = require("nightmare/lib/nightmare"); //require the base nightmare class.
require("nightmare/actions/core"); //only pull in the 'core' set of actions.
```
Expand All @@ -55,7 +55,7 @@ The available modules are:

Nightmare v3 can be extended by simply adding functions to Nightmare.prototype.

```
``` js
Nightmare.prototype.size = function (scale, offset) {
return this.evaluate_now(function (scale, offset) {
var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0)
Expand Down Expand Up @@ -242,7 +242,7 @@ var nightmare = new Nightmare({

With Nightmare v3, once a new Nightmare instance is created, the instance must first be initialized with the .init() function prior to calling any page interaction functions.

```
```js
var nightmare = new Nightmare();
yield nightmare.init();
yield nightmare.goto("http://foo.com");
Expand All @@ -253,7 +253,7 @@ With Nightmare v3, once a new Nightmare instance is created, the instance must f
##### Chain
With Nightmare v3, all functions return promises, however, the API can still be chained using the .chain() function which dynamically creates a chainable promise:

```
```js
var nightmare = new Nightmare();
yield nightmare.chain()
.goto("http://foo.com")
Expand Down Expand Up @@ -542,7 +542,7 @@ With nightmare v3 the primary mechanism of adding custom behavior is by adding f

Functions added to the prototype can be simple prototype functions that can return promises or values. Callback functions can be utilized, but are not required. Custom functions can be generators as well.

```
```js
Nightmare.prototype.size = function (scale, offset) {
return this.evaluate_now(function (scale, offset) {
var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0)
Expand All @@ -560,7 +560,7 @@ Nightmare.prototype.size = function (scale, offset) {
As described above, the built-in chain() function will make all functions exposed on the nightmare prototype chainable, so the 'this' object need not be returned by the extension function.

Thus, the above custom action can be called simply by:
```
```js
let scaleFactor = 2.0;
let offsetFactor = 1;

Expand All @@ -572,7 +572,7 @@ let size = yield nightmare.chain()

Custom 'namespaces' can be implemented by adding a psudo-class and calling the static function 'registerNamespace':

```
``` js
'use strict';
Nightmare.prototype.MyStyle = class {
*background() {
Expand All @@ -592,7 +592,7 @@ Nightmare.registerNamespace("MyStyle");

Nightmare v3 will automatically make these chainable as well.

```
``` js
let nightmare = new Nightmare();
let color = yield nightmare.chain()
.goto('http://www.github.com')
Expand All @@ -602,17 +602,15 @@ let color = yield nightmare.chain()

Custom electron behaviors can be attached by adding tuples of [ {electron function}, {function} ]to the Nightmare prototype. For instance:

```
``` js
Nightmare.prototype.getTitle = [
function (ns, options, parent, win, renderer) {
parent.on('getTitle', function () {
parent.emit('getTitle', {
result: win.webContents.getTitle()
});
parent.respondTo('getTitle', function (done) {
done.resolve(win.webContents.getTitle());
});
},
function (path, saveType) {
return this._invokeRunnerOperation("getTitle", path, saveType);
function () {
return this._invokeRunnerOperation("getTitle");
}
];

Expand Down Expand Up @@ -648,6 +646,20 @@ var size = yield new Nightmare().chain()

However, what is this is doing is associating a 'size' function property on the Nightmare prototype for you.

.action() can be used to define custom Electron actions like before.

```js
Nightmare.action('clearCache',
function(name, options, parent, win, renderer) {
parent.respondTo('clearCache', function(done) {
win.webContents.session.clearCache(done.resolve);
});
},
function(message) {
return this._invokeRunnerOperation("clearCache");
}
```
Any functions defined on the prototype can be called using the this. object. In Nightmare v3 the only difference between ```evaluate_now``` and ```evaluate``` is that evaluate checks that the argument passed is a function. Both return promises.
We can also create custom namespaces. We do this internally for `nightmare.cookies.get` and `nightmare.cookies.set`. These are useful if you have a bundle of actions you want to expose, but it will clutter up the main nightmare object. Here's an example of that:
Expand Down
24 changes: 9 additions & 15 deletions actions/cookies.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@ Nightmare.prototype.cookies = (function () { });
Nightmare.prototype.cookies.prototype.get = [
function (ns, options, parent, win, renderer) {
const _ = require("lodash");
parent.on('cookie.get', function (query) {
parent.respondTo('cookie.get', function (query, done) {
var details = _.assign({}, {
url: win.webContents.getURL(),
}, query);

parent.emit('log', 'getting cookie: ' + JSON.stringify(details));
win.webContents.session.cookies.get(details, function (err, cookies) {
if (err) return parent.emit('cookie.get', err);
parent.emit('cookie.get', {
result: details.name ? cookies[0] : cookies
});
if (err) return done.reject(err);
done.resolve(details.name ? cookies[0] : cookies);
});
});
},
Expand All @@ -48,7 +46,7 @@ Nightmare.prototype.cookies.prototype.get = [
Nightmare.prototype.cookies.prototype.set = [
function (ns, options, parent, win, renderer) {
const _ = require("lodash");
parent.on('cookie.set', function (cookies) {
parent.respondTo('cookie.set', function (cookies, done) {
var pending = cookies.length;
for (var cookie of cookies) {
var details = _.assign({}, {
Expand All @@ -57,10 +55,8 @@ Nightmare.prototype.cookies.prototype.set = [

parent.emit('log', 'setting cookie: ' + JSON.stringify(details));
win.webContents.session.cookies.set(details, function (err) {
if (err) parent.emit('cookie.set', {
error: err
});
else if (!--pending) parent.emit('cookie.set');
if (err) return done.reject(err);
if (!--pending) done.resolve();
});
}
});
Expand Down Expand Up @@ -90,7 +86,7 @@ Nightmare.prototype.cookies.prototype.set = [
*/
Nightmare.prototype.cookies.prototype.clear = [
function (ns, options, parent, win, renderer) {
parent.on('cookie.clear', function (cookies) {
parent.respondTo('cookie.clear', function (cookies,done) {
var pending = cookies.length;
parent.emit('log', 'listing params', cookies);

Expand All @@ -100,10 +96,8 @@ Nightmare.prototype.cookies.prototype.clear = [

parent.emit('log', 'clearing cookie: ' + JSON.stringify(cookie));
win.webContents.session.cookies.remove(url, name, function (err) {
if (err) parent.emit('cookie.clear', {
error: err,
});
else if (!--pending) parent.emit('cookie.clear');
if (err) return done.reject(err);
if (!--pending) done.resolve();
});
}
});
Expand Down
65 changes: 25 additions & 40 deletions actions/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,12 @@ Nightmare.prototype.getClientRects = function (selector) {
*/
Nightmare.prototype.html = [
function (ns, options, parent, win, renderer) {
parent.on('html', function (path, saveType) {
parent.respondTo('html', function (path, saveType, done) {
// https://github.com/atom/electron/blob/master/docs/api/web-contents.md#webcontentssavepagefullpath-savetype-callback
saveType = saveType || 'HTMLComplete';
win.webContents.savePage(path, saveType, function (err) {
parent.emit('html', {
err: err
});
if (err) return done.reject(err);
done.resolve();
});
});
},
Expand All @@ -117,7 +116,7 @@ Nightmare.prototype.html = [
Nightmare.prototype.pdf = [
function (ns, options, parent, win, renderer) {
const _ = require("lodash");
parent.on('pdf', function (path, options) {
parent.respondTo('pdf', function (path, options, done) {
// https://github.com/fraserxu/electron-pdf/blob/master/index.js#L98
options = _.defaults(options, {
marginType: 0,
Expand All @@ -127,10 +126,8 @@ Nightmare.prototype.pdf = [
});

win.webContents.printToPDF(options, function (err, data) {
if (err) return parent.emit('pdf', arguments);
parent.emit('pdf', {
result: data
});
if (err) return done.reject(err);
done.resolve(data);
});
});
},
Expand Down Expand Up @@ -160,12 +157,10 @@ Nightmare.prototype.pdf = [
*/
Nightmare.prototype.screenshot = [
function (ns, options, parent, win, renderer, frameManager) {
parent.on('screenshot', function (clip) {
parent.respondTo('screenshot', function (clip, done) {
// https://gist.github.com/twolfson/0d374d9d7f26eefe7d38
var args = [function handleCapture(img) {
parent.emit('screenshot', {
result: img.toPng()
});
done.resolve(img.toPng());
}];
if (clip) args.unshift(clip);
frameManager.requestFrame(function () {
Expand Down Expand Up @@ -199,11 +194,9 @@ Nightmare.prototype.screenshot = [
*/
Nightmare.prototype.setAudioMuted = [
function (ns, options, parent, win, renderer) {
parent.on('audio', function (audio) {
parent.respondTo('audio', function (audio, done) {
win.webContents.setAudioMuted(audio);
parent.emit('audio', {
result: win.webContents.isAudioMuted()
});
done.resolve(win.webContents.isAudioMuted());
});
},
function (isMuted) {
Expand All @@ -216,11 +209,11 @@ Nightmare.prototype.setAudioMuted = [
*/
Nightmare.prototype.setAuthenticationCredentials = [
function (ns, options, parent, win, renderer) {
parent.on('setAuthenticationCredentials', function (username, password) {
parent.respondTo('setAuthenticationCredentials', function (username, password, done) {
win.webContents.on('login', function (webContents, request, authInfo, callback) {
callback(username, password);
});
parent.emit('setAuthenticationCredentials');
done.resolve();
});
},
function (username, password) {
Expand All @@ -234,10 +227,8 @@ Nightmare.prototype.setAuthenticationCredentials = [
*/
Nightmare.prototype.title = [
function (ns, options, parent, win, renderer) {
parent.on('title', function () {
parent.emit("title", {
result: win.webContents.getTitle()
});
parent.respondTo('title', function (done) {
done.resolve(win.webContents.getTitle());
});
},
function () {
Expand All @@ -251,10 +242,8 @@ Nightmare.prototype.title = [
*/
Nightmare.prototype.url = [
function (ns, options, parent, win, renderer) {
parent.on('url', function () {
parent.emit("url", {
result: win.webContents.getURL()
});
parent.respondTo('url', function (done) {
done.resolve(win.webContents.getURL());
});
},
function () {
Expand All @@ -270,9 +259,9 @@ Nightmare.prototype.url = [
*/
Nightmare.prototype.useragent = [
function (ns, options, parent, win, renderer) {
parent.on('useragent', function (useragent) {
parent.respondTo('useragent', function (useragent, done) {
win.webContents.setUserAgent(useragent);
parent.emit('useragent');
done.resolve();
});
},
function (useragent) {
Expand All @@ -289,9 +278,9 @@ Nightmare.prototype.useragent = [
*/
Nightmare.prototype.viewport = [
function (ns, options, parent, win, renderer) {
parent.on('size', function (width, height) {
parent.respondTo('size', function (width, height, done) {
win.setSize(width, height);
parent.emit("size");
done.resolve();
});
},
function (width, height) {
Expand Down Expand Up @@ -342,7 +331,7 @@ Nightmare.prototype.wait = function () {
let fn = function (selector) {
var element = document.querySelector(selector);
return (element ? true : false);
}
};
return this.waitUntilTrue(fn, arg);
}
else if (_.isFunction(arg)) {
Expand Down Expand Up @@ -371,7 +360,7 @@ Nightmare.prototype.waitUntilTrue = function (fn/**, arg1, arg2...**/) {
let testResult = false;
do {
testResult = yield self.evaluate_now.apply(self, args);
} while (!testResult)
} while (!testResult);
});

return Promise.race([check, timeout]);
Expand All @@ -382,7 +371,7 @@ Nightmare.prototype.waitUntilTrue = function (fn/**, arg1, arg2...**/) {
*/
Nightmare.prototype.waitUntilFinishLoad = [
function (ns, options, parent, win, renderer) {
parent.on("waitUntilFinishLoad", function () {
parent.respondTo("waitUntilFinishLoad", function (done) {

var start;
var init = new Promise(function (resolve, reject) {
Expand Down Expand Up @@ -417,13 +406,9 @@ Nightmare.prototype.waitUntilFinishLoad = [
win.webContents.once('did-finish-load', resolveGoto);
});
}).then(function (url) {
parent.emit('waitUntilFinishLoad', {
result: url
});
done.resolve(url);
}, function (message) {
parent.emit('waitUntilFinishLoad', {
error: message
});
done.reject(message);
});

start();
Expand Down
Loading

0 comments on commit 589a45a

Please sign in to comment.