UNPKG

32.4 kBMarkdownView Raw
1[![Build Status](https://img.shields.io/circleci/project/segmentio/nightmare/master.svg)](https://circleci.com/gh/segmentio/nightmare)
2[![Join the chat at https://gitter.im/rosshinkley/nightmare](https://badges.gitter.im/rosshinkley/nightmare.svg)](https://gitter.im/rosshinkley/nightmare?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
3
4# Nightmare
5
6Nightmare is a high-level browser automation library from [Segment](https://segment.com).
7
8The goal is to expose a few simple methods that mimic user actions (like `goto`, `type` and `click`), with an API that feels synchronous for each block of scripting, rather than deeply nested callbacks. It was originally designed for automating tasks across sites that don't have APIs, but is most often used for UI testing and crawling.
9
10Under the covers it uses [Electron](http://electron.atom.io/), which is similar to [PhantomJS](http://phantomjs.org/) but roughly [twice as fast](https://github.com/segmentio/nightmare/issues/484#issuecomment-184519591) and more modern.
11
12**⚠️ Security Warning:** We've implemented [many](https://github.com/segmentio/nightmare/issues/1388) of the security recommendations [outlined by Electron](https://github.com/electron/electron/blob/master/docs/tutorial/security.md) to try and keep you safe, but undiscovered vulnerabilities may exist in Electron that could allow a malicious website to execute code on your computer. Avoid visiting untrusted websites.
13
14**🛠 Migrating to 3.x:** You'll want to check out [this issue](https://github.com/segmentio/nightmare/issues/1396) before upgrading. We've worked hard to make improvements to nightmare while limiting the breaking changes and there's a good chance you won't need to do anything.
15
16[Niffy](https://github.com/segmentio/niffy) is a perceptual diffing tool built on Nightmare. It helps you detect UI changes and bugs across releases of your web app.
17
18[Daydream](https://github.com/segmentio/daydream) is a complementary chrome extension built by [@stevenmiller888](https://github.com/stevenmiller888) that generates Nightmare scripts for you while you browse.
19
20Many thanks to [@matthewmueller](https://github.com/matthewmueller) and [@rosshinkley](https://github.com/rosshinkley) for their help on Nightmare.
21
22* [Examples](#examples)
23 * [UI Testing Quick Start](https://segment.com/blog/ui-testing-with-nightmare/)
24 * [Perceptual Diffing with Niffy & Nightmare](https://segment.com/blog/perceptual-diffing-with-niffy/)
25* [API](#api)
26 * [Set up an instance](#nightmareoptions)
27 * [Interact with the page](#interact-with-the-page)
28 * [Extract from the page](#extract-from-the-page)
29 * [Cookies](#cookies)
30 * [Proxies](#proxies)
31 * [Promises](#promises)
32 * [Extending Nightmare](#extending-nightmare)
33* [Usage](#usage)
34* [Debugging](#debugging)
35* [Additional Resources](#additional-resources)
36
37## Examples
38
39Let's search on DuckDuckGo:
40
41```js
42const Nightmare = require('nightmare')
43const nightmare = Nightmare({ show: true })
44
45nightmare
46 .goto('https://duckduckgo.com')
47 .type('#search_form_input_homepage', 'github nightmare')
48 .click('#search_button_homepage')
49 .wait('#r1-0 a.result__a')
50 .evaluate(() => document.querySelector('#r1-0 a.result__a').href)
51 .end()
52 .then(console.log)
53 .catch(error => {
54 console.error('Search failed:', error)
55 })
56```
57
58You can run this with:
59
60```shell
61npm install --save nightmare
62node example.js
63```
64
65Or, let's run some mocha tests:
66
67```js
68const Nightmare = require('nightmare')
69const chai = require('chai')
70const expect = chai.expect
71
72describe('test duckduckgo search results', () => {
73 it('should find the nightmare github link first', function(done) {
74 this.timeout('10s')
75
76 const nightmare = Nightmare()
77 nightmare
78 .goto('https://duckduckgo.com')
79 .type('#search_form_input_homepage', 'github nightmare')
80 .click('#search_button_homepage')
81 .wait('#links .result__a')
82 .evaluate(() => document.querySelector('#links .result__a').href)
83 .end()
84 .then(link => {
85 expect(link).to.equal('https://github.com/segmentio/nightmare')
86 done()
87 })
88 })
89})
90```
91
92You can see examples of every function [in the tests here](https://github.com/segmentio/nightmare/blob/master/test/index.js).
93
94To get started with UI Testing, check out this [quick start guide](https://segment.com/blog/ui-testing-with-nightmare).
95
96### To install dependencies
97
98```
99npm install
100```
101
102### To run the mocha tests
103
104```
105npm test
106```
107
108### Node versions
109
110Nightmare is intended to be run on NodeJS 4.x or higher.
111
112## API
113
114#### Nightmare(options)
115
116Creates a new instance that can navigate around the web. The available options are [documented here](https://github.com/atom/electron/blob/master/docs/api/browser-window.md#new-browserwindowoptions), along with the following nightmare-specific options.
117
118##### waitTimeout (default: 30s)
119
120Throws an exception if the `.wait()` didn't return `true` within the set timeframe.
121
122```js
123const nightmare = Nightmare({
124 waitTimeout: 1000 // in ms
125})
126```
127
128##### gotoTimeout (default: 30s)
129
130Throws an exception if the `.goto()` didn't finish loading within the set timeframe. Note that, even though `goto` normally waits for all the resources on a page to load, a timeout exception is only raised if the DOM itself has not yet loaded.
131
132```js
133const nightmare = Nightmare({
134 gotoTimeout: 1000 // in ms
135})
136```
137
138##### loadTimeout (default: infinite)
139
140Forces Nightmare to move on if a page transition caused by an action (eg, `.click()`) didn't finish within the set timeframe. If `loadTimeout` is shorter than `gotoTimeout`, the exceptions thrown by `gotoTimeout` will be suppressed.
141
142```js
143const nightmare = Nightmare({
144 loadTimeout: 1000 // in ms
145})
146```
147
148##### executionTimeout (default: 30s)
149
150The maximum amount of time to wait for an `.evaluate()` statement to complete.
151
152```js
153const nightmare = Nightmare({
154 executionTimeout: 1000 // in ms
155})
156```
157
158##### paths
159
160The default system paths that Electron knows about. Here's a list of available paths: https://github.com/atom/electron/blob/master/docs/api/app.md#appgetpathname
161
162You can overwrite them in Nightmare by doing the following:
163
164```js
165const nightmare = Nightmare({
166 paths: {
167 userData: '/user/data'
168 }
169})
170```
171
172##### switches
173
174The command line switches used by the Chrome browser that are also supported by Electron. Here's a list of supported Chrome command line switches:
175https://github.com/atom/electron/blob/master/docs/api/chrome-command-line-switches.md
176
177```js
178const nightmare = Nightmare({
179 switches: {
180 'proxy-server': '1.2.3.4:5678',
181 'ignore-certificate-errors': true
182 }
183})
184```
185
186##### electronPath
187
188The path to the prebuilt Electron binary. This is useful for testing on different versions of Electron. Note that Nightmare only supports the version on which this package depends. Use this option at your own risk.
189
190```js
191const nightmare = Nightmare({
192 electronPath: require('electron')
193})
194```
195
196##### dock (OS X)
197
198A boolean to optionally show the Electron icon in the dock (defaults to `false`). This is useful for testing purposes.
199
200```js
201const nightmare = Nightmare({
202 dock: true
203})
204```
205
206##### openDevTools
207
208Optionally shows the DevTools in the Electron window using `true`, or use an object hash containing `mode: 'detach'` to show in a separate window. The hash gets passed to [`contents.openDevTools()`](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#contentsopendevtoolsoptions) to be handled. This is also useful for testing purposes. Note that this option is honored only if `show` is set to `true`.
209
210```js
211const nightmare = Nightmare({
212 openDevTools: {
213 mode: 'detach'
214 },
215 show: true
216})
217```
218
219##### typeInterval (default: 100ms)
220
221How long to wait between keystrokes when using `.type()`.
222
223```js
224const nightmare = Nightmare({
225 typeInterval: 20
226})
227```
228
229##### pollInterval (default: 250ms)
230
231How long to wait between checks for the `.wait()` condition to be successful.
232
233```js
234const nightmare = Nightmare({
235 pollInterval: 50 //in ms
236})
237```
238
239##### maxAuthRetries (default: 3)
240
241Defines the number of times to retry an authentication when set up with `.authenticate()`.
242
243```js
244const nightmare = Nightmare({
245 maxAuthRetries: 3
246})
247```
248
249#### certificateSubjectName
250
251A string to determine the client certificate selected by electron. If this options is set, the [`select-client-certificate`](https://github.com/electron/electron/blob/master/docs/api/app.md#event-select-client-certificate) event will be set to loop through the certificateList and find the first certificate that matches `subjectName` on the electron [`Certificate Object`](https://electronjs.org/docs/api/structures/certificate).
252
253```js
254const nightmare = Nightmare({
255 certificateSubjectName: 'tester'
256})
257```
258
259#### .engineVersions()
260
261Gets the versions for Electron and Chromium.
262
263#### .useragent(useragent)
264
265Sets the `useragent` used by electron.
266
267#### .authentication(user, password)
268
269Sets the `user` and `password` for accessing a web page using basic authentication. Be sure to set it before calling `.goto(url)`.
270
271#### .end()
272
273Completes any queue operations, disconnect and close the electron process. Note that if you're using promises, `.then()` must be called after `.end()` to run the `.end()` task. Also note that if using an `.end()` callback, the `.end()` call is equivalent to calling `.end()` followed by `.then(fn)`. Consider:
274
275```js
276nightmare
277 .goto(someUrl)
278 .end(() => 'some value')
279 //prints "some value"
280 .then(console.log)
281```
282
283#### .halt(error, done)
284
285Clears all queued operations, kills the electron process, and passes error message or 'Nightmare Halted' to an unresolved promise. Done will be called after the process has exited.
286
287### Interact with the Page
288
289#### .goto(url[, headers])
290
291Loads the page at `url`. Optionally, a `headers` hash can be supplied to set headers on the `goto` request.
292
293When a page load is successful, `goto` returns an object with metadata about the page load, including:
294
295* `url`: The URL that was loaded
296* `code`: The HTTP status code (e.g. 200, 404, 500)
297* `method`: The HTTP method used (e.g. "GET", "POST")
298* `referrer`: The page that the window was displaying prior to this load or an empty string if this is the first page load.
299* `headers`: An object representing the response headers for the request as in `{header1-name: header1-value, header2-name: header2-value}`
300
301If the page load fails, the error will be an object with the following properties:
302
303* `message`: A string describing the type of error
304* `code`: The underlying error code describing what went wrong. Note this is NOT the HTTP status code. For possible values, see https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h
305* `details`: A string with additional details about the error. This may be null or an empty string.
306* `url`: The URL that failed to load
307
308Note that any valid response from a server is considered “successful.” That means things like 404 “not found” errors are successful results for `goto`. Only things that would cause no page to appear in the browser window, such as no server responding at the given address, the server hanging up in the middle of a response, or invalid URLs, are errors.
309
310You can also adjust how long `goto` will wait before timing out by setting the [`gotoTimeout` option](#gototimeout-default-30s) on the Nightmare constructor.
311
312#### .back()
313
314Goes back to the previous page.
315
316#### .forward()
317
318Goes forward to the next page.
319
320#### .refresh()
321
322Refreshes the current page.
323
324#### .click(selector)
325
326Clicks the `selector` element once.
327
328#### .mousedown(selector)
329
330Mousedowns the `selector` element once.
331
332#### .mouseup(selector)
333
334Mouseups the `selector` element once.
335
336#### .mouseover(selector)
337
338Mouseovers the `selector` element once.
339
340#### .mouseout(selector)
341
342Mouseout the `selector` element once.
343
344#### .type(selector[, text])
345
346Enters the `text` provided into the `selector` element. Empty or falsey values provided for `text` will clear the selector's value.
347
348`.type()` mimics a user typing in a textbox and will emit the proper keyboard events.
349
350Key presses can also be fired using Unicode values with `.type()`. For example, if you wanted to fire an enter key press, you would write `.type('body', '\u000d')`.
351
352> If you don't need the keyboard events, consider using `.insert()` instead as it will be faster and more robust.
353
354#### .insert(selector[, text])
355
356Similar to `.type()`, `.insert()` enters the `text` provided into the `selector` element. Empty or falsey values provided for `text` will clear the selector's value.
357
358`.insert()` is faster than `.type()` but does not trigger the keyboard events.
359
360#### .check(selector)
361
362Checks the `selector` checkbox element.
363
364#### .uncheck(selector)
365
366Unchecks the `selector` checkbox element.
367
368#### .select(selector, option)
369
370Changes the `selector` dropdown element to the option with attribute [value=`option`]
371
372#### .scrollTo(top, left)
373
374Scrolls the page to desired position. `top` and `left` are always relative to the top left corner of the document.
375
376#### .viewport(width, height)
377
378Sets the viewport size.
379
380#### .inject(type, file)
381
382Injects a local `file` onto the current page. The file `type` must be either `js` or `css`.
383
384#### .evaluate(fn[, arg1, arg2,...])
385
386Invokes `fn` on the page with `arg1, arg2,...`. All the `args` are optional. On completion it returns the return value of `fn`. Useful for extracting information from the page. Here's an example:
387
388```js
389const selector = 'h1'
390nightmare
391 .evaluate(selector => {
392 // now we're executing inside the browser scope.
393 return document.querySelector(selector).innerText
394 }, selector) // <-- that's how you pass parameters from Node scope to browser scope
395 .then(text => {
396 // ...
397 })
398```
399
400Error-first callbacks are supported as a part of `evaluate()`. If the arguments passed are one fewer than the arguments expected for the evaluated function, the evaluation will be passed a callback as the last parameter to the function. For example:
401
402```js
403const selector = 'h1'
404nightmare
405 .evaluate((selector, done) => {
406 // now we're executing inside the browser scope.
407 setTimeout(
408 () => done(null, document.querySelector(selector).innerText),
409 2000
410 )
411 }, selector)
412 .then(text => {
413 // ...
414 })
415```
416
417Note that callbacks support only one value argument (eg `function(err, value)`). Ultimately, the callback will get wrapped in a native Promise and only be able to resolve a single value.
418
419Promises are also supported as a part of `evaluate()`. If the return value of the function has a `then` member, `.evaluate()` assumes it is waiting for a promise. For example:
420
421```js
422const selector = 'h1';
423nightmare
424 .evaluate((selector) => (
425 new Promise((resolve, reject) => {
426 setTimeout(() => resolve(document.querySelector(selector).innerText), 2000);
427 )}, selector)
428 )
429 .then((text) => {
430 // ...
431 })
432```
433
434#### .wait(ms)
435
436Waits for `ms` milliseconds e.g. `.wait(5000)`.
437
438#### .wait(selector)
439
440Waits until the element `selector` is present e.g. `.wait('#pay-button')`.
441
442#### .wait(fn[, arg1, arg2,...])
443
444Waits until the `fn` evaluated on the page with `arg1, arg2,...` returns `true`. All the `args` are optional. See `.evaluate()` for usage.
445
446#### .header(header, value)
447
448Adds a header override for all HTTP requests. If `header` is undefined, the header overrides will be reset.
449
450### Extract from the Page
451
452#### .exists(selector)
453
454Returns whether the selector exists or not on the page.
455
456#### .visible(selector)
457
458Returns whether the selector is visible or not.
459
460#### .on(event, callback)
461
462Captures page events with the callback. You have to call `.on()` before calling `.goto()`. Supported events are [documented here](http://electron.atom.io/docs/api/web-contents/#class-webcontents).
463
464##### Additional "page" events
465
466###### .on('page', function(type="error", message, stack))
467
468This event is triggered if any javascript exception is thrown on the page. But this event is not triggered if the injected javascript code (e.g. via `.evaluate()`) is throwing an exception.
469
470##### "page" events
471
472Listens for `window.addEventListener('error')`, `alert(...)`, `prompt(...)` & `confirm(...)`.
473
474###### .on('page', function(type="error", message, stack))
475
476Listens for top-level page errors. This will get triggered when an error is thrown on the page.
477
478###### .on('page', function(type="alert", message))
479
480Nightmare disables `window.alert` from popping up by default, but you can still listen for the contents of the alert dialog.
481
482###### .on('page', function(type="prompt", message, response))
483
484Nightmare disables `window.prompt` from popping up by default, but you can still listen for the message to come up. If you need to handle the confirmation differently, you'll need to use your own preload script.
485
486###### .on('page', function(type="confirm", message, response))
487
488Nightmare disables `window.confirm` from popping up by default, but you can still listen for the message to come up. If you need to handle the confirmation differently, you'll need to use your own preload script.
489
490###### .on('console', function(type [, arguments, ...]))
491
492`type` will be either `log`, `warn` or `error` and `arguments` are what gets passed from the console. This event is not triggered if the injected javascript code (e.g. via `.evaluate()`) is using `console.log`.
493
494#### .once(event, callback)
495
496Similar to `.on()`, but captures page events with the callback one time.
497
498#### .removeListener(event, callback)
499
500Removes a given listener callback for an event.
501
502#### .screenshot([path][, clip])
503
504Takes a screenshot of the current page. Useful for debugging. The output is always a `png`. Both arguments are optional. If `path` is provided, it saves the image to the disk. Otherwise it returns a `Buffer` of the image data. If `clip` is provided (as [documented here](https://github.com/atom/electron/blob/master/docs/api/browser-window.md#wincapturepagerect-callback)), the image will be clipped to the rectangle.
505
506#### .html(path, saveType)
507
508Saves the current page as html as files to disk at the given path. Save type options are [here](https://github.com/atom/electron/blob/master/docs/api/web-contents.md#webcontentssavepagefullpath-savetype-callback).
509
510#### .pdf(path, options)
511
512Saves a PDF to the specified `path`. Options are [here](https://github.com/electron/electron/blob/v1.4.4/docs/api/web-contents.md#contentsprinttopdfoptions-callback).
513
514#### .title()
515
516Returns the title of the current page.
517
518#### .url()
519
520Returns the url of the current page.
521
522#### .path()
523
524Returns the path name of the current page.
525
526### Cookies
527
528#### .cookies.get(name)
529
530Gets a cookie by it's `name`. The url will be the current url.
531
532#### .cookies.get(query)
533
534Queries multiple cookies with the `query` object. If a `query.name` is set, it will return the first cookie it finds with that name, otherwise it will query for an array of cookies. If no `query.url` is set, it will use the current url. Here's an example:
535
536```js
537// get all google cookies that are secure
538// and have the path `/query`
539nightmare
540 .goto('http://google.com')
541 .cookies.get({
542 path: '/query',
543 secure: true
544 })
545 .then(cookies => {
546 // do something with the cookies
547 })
548```
549
550Available properties are documented here: https://github.com/atom/electron/blob/master/docs/api/session.md#sescookiesgetdetails-callback
551
552#### .cookies.get()
553
554Gets all the cookies for the current url. If you'd like get all cookies for all urls, use: `.get({ url: null })`.
555
556#### .cookies.set(name, value)
557
558Sets a cookie's `name` and `value`. This is the most basic form, and the url will be the current url.
559
560#### .cookies.set(cookie)
561
562Sets a `cookie`. If `cookie.url` is not set, it will set the cookie on the current url. Here's an example:
563
564```js
565nightmare
566 .goto('http://google.com')
567 .cookies.set({
568 name: 'token',
569 value: 'some token',
570 path: '/query',
571 secure: true
572 })
573 // ... other actions ...
574 .then(() => {
575 // ...
576 })
577```
578
579Available properties are documented here: https://github.com/atom/electron/blob/master/docs/api/session.md#sescookiessetdetails-callback
580
581#### .cookies.set(cookies)
582
583Sets multiple cookies at once. `cookies` is an array of `cookie` objects. Take a look at the `.cookies.set(cookie)` documentation above for a better idea of what `cookie` should look like.
584
585#### .cookies.clear([name])
586
587Clears a cookie for the current domain. If `name` is not specified, all cookies for the current domain will be cleared.
588
589```js
590nightmare
591 .goto('http://google.com')
592 .cookies.clear('SomeCookieName')
593 // ... other actions ...
594 .then(() => {
595 // ...
596 })
597```
598
599#### .cookies.clearAll()
600
601Clears all cookies for all domains.
602
603```js
604nightmare
605 .goto('http://google.com')
606 .cookies.clearAll()
607 // ... other actions ...
608 .then(() => {
609 //...
610 })
611```
612
613### Proxies
614
615Proxies are supported in Nightmare through [switches](#switches).
616
617If your proxy requires authentication you also need the [authentication](#authenticationuser-password) call.
618
619The following example not only demonstrates how to use proxies, but you can run it to test if your proxy connection is working:
620
621```js
622import Nightmare from 'nightmare';
623
624const proxyNightmare = Nightmare({
625 switches: {
626 'proxy-server': 'my_proxy_server.example.com:8080' // set the proxy server here ...
627 },
628 show: true
629});
630
631proxyNightmare
632 .authentication('proxyUsername', 'proxyPassword') // ... and authenticate here before `goto`
633 .goto('http://www.ipchicken.com')
634 .evaluate(() => {
635 return document.querySelector('b').innerText.replace(/[^\d\.]/g, '');
636 })
637 .end()
638 .then((ip) => { // This will log the Proxy's IP
639 console.log('proxy IP:', ip);
640 });
641
642// The rest is just normal Nightmare to get your local IP
643const regularNightmare = Nightmare({ show: true });
644
645regularNightmare
646 .goto('http://www.ipchicken.com')
647 .evaluate(() =>
648 document.querySelector('b').innerText.replace(/[^\d\.]/g, '');
649 )
650 .end()
651 .then((ip) => { // This will log the your local IP
652 console.log('local IP:', ip);
653 });
654```
655
656### Promises
657
658By default, Nightmare uses default native ES6 promises. You can plug in your favorite [ES6-style promises library](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) like [bluebird](https://www.npmjs.com/package/bluebird) or [q](https://www.npmjs.com/package/q) for convenience!
659
660Here's an example:
661
662```js
663var Nightmare = require('nightmare')
664
665Nightmare.Promise = require('bluebird')
666// OR:
667Nightmare.Promise = require('q').Promise
668```
669
670You can also specify a custom Promise library per-instance with the `Promise` constructor option like so:
671
672```js
673var Nightmare = require('nightmare')
674
675var es6Nightmare = Nightmare()
676var bluebirdNightmare = Nightmare({
677 Promise: require('bluebird')
678})
679
680var es6Promise = es6Nightmare
681 .goto('https://github.com/segmentio/nightmare')
682 .then()
683var bluebirdPromise = bluebirdNightmare
684 .goto('https://github.com/segmentio/nightmare')
685 .then()
686
687es6Promise.isFulfilled() // throws: `TypeError: es6EndPromise.isFulfilled is not a function`
688bluebirdPromise.isFulfilled() // returns: `true | false`
689```
690
691### Extending Nightmare
692
693#### Nightmare.action(name, [electronAction|electronNamespace], action|namespace)
694
695You can add your own custom actions to the Nightmare prototype. Here's an example:
696
697```js
698Nightmare.action('size', function(done) {
699 this.evaluate_now(() => {
700 const w = Math.max(
701 document.documentElement.clientWidth,
702 window.innerWidth || 0
703 )
704 const h = Math.max(
705 document.documentElement.clientHeight,
706 window.innerHeight || 0
707 )
708 return {
709 height: h,
710 width: w
711 }
712 }, done)
713})
714
715Nightmare()
716 .goto('http://cnn.com')
717 .size()
718 .then(size => {
719 //... do something with the size information
720 })
721```
722
723> Remember, this is attached to the static class `Nightmare`, not the instance.
724
725You'll notice we used an internal function `evaluate_now`. This function is different than `nightmare.evaluate` because it runs it immediately, whereas `nightmare.evaluate` is queued.
726
727An easy way to remember: when in doubt, use `evaluate`. If you're creating custom actions, use `evaluate_now`. The technical reason is that since our action has already been queued and we're running it now, we shouldn't re-queue the evaluate function.
728
729We 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:
730
731```js
732Nightmare.action('style', {
733 background(done) {
734 this.evaluate_now(
735 () => window.getComputedStyle(document.body, null).backgroundColor,
736 done
737 )
738 }
739})
740
741Nightmare()
742 .goto('http://google.com')
743 .style.background()
744 .then(background => {
745 // ... do something interesting with background
746 })
747```
748
749You can also add custom Electron actions. The additional Electron action or namespace actions take `name`, `options`, `parent`, `win`, `renderer`, and `done`. Note the Electron action comes first, mirroring how `.evaluate()` works. For example:
750
751```javascript
752Nightmare.action(
753 'clearCache',
754 (name, options, parent, win, renderer, done) => {
755 parent.respondTo('clearCache', done => {
756 win.webContents.session.clearCache(done)
757 })
758 done()
759 },
760 function(done) {
761 this.child.call('clearCache', done)
762 }
763)
764
765Nightmare()
766 .clearCache()
767 .goto('http://example.org')
768 //... more actions ...
769 .then(() => {
770 // ...
771 })
772```
773
774...would clear the browser’s cache before navigating to `example.org`.
775
776See [this document](https://github.com/rosshinkley/nightmare-examples/blob/master/docs/beginner/action.md) for more details on creating custom actions.
777
778#### .use(plugin)
779
780`nightmare.use` is useful for reusing a set of tasks on an instance. Check out [nightmare-swiftly](https://github.com/segmentio/nightmare-swiftly) for some examples.
781
782#### Custom preload script
783
784If you need to do something custom when you first load the window environment, you
785can specify a custom preload script. Here's how you do that:
786
787```js
788import path from 'path'
789
790const nightmare = Nightmare({
791 webPreferences: {
792 preload: path.resolve('custom-script.js')
793 //alternative: preload: "absolute/path/to/custom-script.js"
794 }
795})
796```
797
798The only requirement for that script is that you'll need the following prelude:
799
800```js
801window.__nightmare = {}
802__nightmare.ipc = require('electron').ipcRenderer
803```
804
805To benefit of all of nightmare's feedback from the browser, you can instead copy the contents of nightmare's [preload script](lib/preload.js).
806
807#### Storage Persistence between nightmare instances
808
809By default nightmare will create an in-memory partition for each instance. This means that any localStorage or cookies or any other form of persistent state will be destroyed when nightmare is ended. If you would like to persist state between instances you can use the [webPreferences.partition](http://electron.atom.io/docs/api/browser-window/#new-browserwindowoptions) api in electron.
810
811```js
812import Nightmare from 'nightmare';
813
814nightmare = Nightmare(); // non persistent paritition by default
815yield nightmare
816 .evaluate(() => {
817 window.localStorage.setItem('testing', 'This will not be persisted');
818 })
819 .end();
820
821nightmare = Nightmare({
822 webPreferences: {
823 partition: 'persist: testing'
824 }
825});
826yield nightmare
827 .evaluate(() => {
828 window.localStorage.setItem('testing', 'This is persisted for other instances with the same paritition name');
829 })
830 .end();
831```
832
833If you specify a `null` paritition then it will use the electron default behavior (persistent) or any string that starts with `'persist:'` will persist under that partition name, any other string will result in in-memory only storage.
834
835## Usage
836
837#### Installation
838
839Nightmare is a Node.js module, so you'll need to [have Node.js installed](http://nodejs.org/). Then you just need to `npm install` the module:
840
841```bash
842$ npm install --save nightmare
843```
844
845#### Execution
846
847Nightmare is a node module that can be used in a Node.js script or module. Here's a simple script to open a web page:
848
849```js
850import Nightmare from 'nightmare';
851
852const nightmare = Nightmare();
853
854nightmare.goto('http://cnn.com')
855 .evaluate(() => {
856 return document.title;
857 })
858 .end()
859 .then((title) => {
860 console.log(title);
861 })
862```
863
864If you save this as `cnn.js`, you can run it on the command line like this:
865
866```bash
867npm install --save nightmare
868node cnn.js
869```
870
871#### Common Execution Problems
872
873Nightmare heavily relies on [Electron](http://electron.atom.io/) for heavy lifting. And Electron in turn relies on several UI-focused dependencies (eg. libgtk+) which are often missing from server distros.
874
875For help running nightmare on your server distro check out [How to run nightmare on Amazon Linux and CentOS](https://gist.github.com/dimkir/f4afde77366ff041b66d2252b45a13db) guide.
876
877#### Debugging
878
879There are three good ways to get more information about what's happening inside the headless browser:
880
8811. Use the `DEBUG=*` flag described below.
8822. Pass `{ show: true }` to the [nightmare constructor](#nightmareoptions) to have it create a visible, rendered window where you can watch what is happening.
8833. Listen for [specific events](#onevent-callback).
884
885To run the same file with debugging output, run it like this `DEBUG=nightmare node cnn.js` (on Windows use `set DEBUG=nightmare & node cnn.js`).
886
887This will print out some additional information about what's going on:
888
889```bash
890nightmare queueing action "goto" +0ms
891nightmare queueing action "evaluate" +4ms
892Breaking News, U.S., World, Weather, Entertainment & Video News - CNN.com
893```
894
895##### Debug Flags
896
897All nightmare messages
898
899`DEBUG=nightmare*`
900
901Only actions
902
903`DEBUG=nightmare:actions*`
904
905Only logs
906
907`DEBUG=nightmare:log*`
908
909## Additional Resources
910
911* [Ross Hinkley's Nightmare Examples](https://github.com/rosshinkley/nightmare-examples) is a great resource for setting up nightmare, learning about custom actions, and avoiding common pitfalls.
912
913* [Nightmare Issues](https://github.com/matthewmueller/nightmare-issues) has a bunch of standalone runnable examples. The script numbers correspond to nightmare issue numbers.
914
915* [Nightmarishly good scraping](https://hackernoon.com/nightmarishly-good-scraping-with-nightmare-js-and-async-await-b7b20a38438f) is a great tutorial by [Ændrew Rininsland](https://twitter.com/@aendrew) on getting up & running with Nightmare using real-life data.
916
917## Tests
918
919Automated tests for nightmare itself are run using [Mocha](http://mochajs.org/) and Chai, both of which will be installed via `npm install`. To run nightmare's tests, just run `make test`.
920
921When the tests are done, you'll see something like this:
922
923```bash
924make test
925 ․․․․․․․․․․․․․․․․․․
926 18 passing (1m)
927```
928
929Note that if you are using `xvfb`, `make test` will automatically run the tests under an `xvfb-run` wrapper. If you are planning to run the tests headlessly without running `xvfb` first, set the `HEADLESS` environment variable to `0`.
930
931## License (MIT)
932
933```
934WWWWWW||WWWWWW
935 W W W||W W W
936 ||
937 ( OO )__________
938 / | \
939 /o o| MIT \
940 \___/||_||__||_|| *
941 || || || ||
942 _||_|| _||_||
943 (__|__|(__|__|
944```
945
946Copyright (c) 2015 Segment.io, Inc. <mailto:friends@segment.com>
947
948Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
949
950The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
951
952THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.