Code Monkey home page Code Monkey logo

chromy's Introduction

Chromy

Chromy is a library for operating headless chrome.

Document Site: https://onetapinc.github.io/chromy/

Chromy is similar to Nightmare.js but has some differences:

  • Controlling Chrome via Chrome DevTools Protocol.
  • Supports mobile emulation.
  • No need to prepare a screen such as xvfb.

Requirements

  • Node 6 or later
  • Install Chrome60 or later to your machine before use Chromy.

headless mode is supported by Chrome59 or later.

Installation

npm i chromy

Usage

const Chromy = require('chromy')

// not headless
// let chromy = new Chromy({visible:true})
let chromy = new Chromy()
chromy.chain()
      .goto('http://example.com/')
      .evaluate(() => {
        return document.querySelectorAll('*').length
      })
      .result((r) => console.log(r))
      .end()
      .then(() => chromy.close())

You can also use async/await interfaces like this:

const Chromy = require('chromy')

async function main () {
  let chromy = new Chromy()
  await chromy.goto('http://example.com/')
  const result = await chromy.evaluate(() => {
          return document.querySelectorAll('*').length
        })
  console.log(result)
  await chromy.close()
}

main()

Mobile Emulation

Chromy provides mobile emulation.
The emulation changes a screen resolution, density, userAgent and provides touch emulation.

const Chromy = require('chromy')

let chromy = new Chromy()
chromy.chain()
      .emulate('iPhone6')
      .goto('http://example.com/')
      .tap(100, 100) // emulate tap action by synthesizing touch events.
      .evaluate(() => {
        return navigator.userAgent
      })
      .result(console.log)
      .end()
      .then(() => chromy.close())

FAQ

FAQ

API

Chromy(options)
options
  • host(default: localhost): host address
  • port(default: 9222): --remote-debugging-port
  • userDataDir(default: null): Chrome profile path. This option can be used to persist an user profile.
  • launchBrowser(default: true): If you want chromy to attach to the Chrome instance that is already launched, set to false.
  • visible(default: false): If set to true, chrome is launched in visible mode. This option is not used if launchBrowser is false.
  • chromePath(default: null): This option is used to find out an executable of Chrome. If set to null, executable is selected automatically. This option is not used if launchBrowser is false.
  • enableExtensions(default: false): Enable extension loading. (Generally, this options is used with userDataDir option)
  • chromeFlags(default: []): These flags is passed to Chrome. Each flag must have a prefix string "--". This option is not used if launchBrowser is false.
  • waitTimeout(default: 30000): If wait() doesn't finish in the specified time WaitTimeoutError will be thrown.
  • gotoTimeout(default: 30000): If goto() doesn't finish in the specified time GotoTimeoutError will be thrown.
  • evaluateTimeout(default: 30000): If evaluate() doesn't finish in the specified time EvaluateTimeError will be thrown.
  • waitFunctionPollingInterval(default: 100): polling interval for wait().
  • typeInterval(default: 20): This option is used only in type() method.
  • activateOnStartUp(default: true): activate a first tab on startup. this option is enable only in visible mode.
.start(startingUrl = null)

Launches Chrome browser.

options

startingUrl: a staring url. If you set to null 'about:blank' is used as a starting url.

.goto(url, options = {})

Goes to url. If you have not called start(), this method calls start(url) automatically.

options

waitLoadEvent(default: true): If set to false, goto() doesn't wait until load event is fired.

returns

Returns Response object

.waitLoadEvent()

wait until a load event is fired.

.userAgent(ua)

set a useragent.

ua: new user agent.

Chromy.addCustomDevice(device)

add custom device definitions to emulate it.

See src.

.emulate(deviceName)

emulate a device that is defined by Chromy.addCustomDevice().

.forward()

go forward to the next page and wait until load event is fired.

.back()

go back to the previous page and wait until load event is fired.

.inject(type, file)

Injects a file into browser as a javascript or a css.

type: must be 'js' or 'css' file: injected file.

.evaluate(func|source, args)

Evaluates a expression in the browser context.
If the expression returns a Promise object, the promise is resolved automatically.

.result(func)

result() receives a result of previous directive.

chromy.chain()
      .goto('http://example.com')
      .evaluate(() => {
        return document.querySelectorAll('*').length
      })
      .result((length) => {
        // length is a result of evaluate() directive.
        console.log(length)
      }
      .end()
.end()
.exists(selector)

Returns whether an node matched with the selector is exists.

.visible(selector)

Returns whether an node matched with the selector is exists and visible.

.wait(msec)

alias for .sleep(msec)

.wait(selector)

wait until selector you specified appear in a DOM tree.

.wait(func)

wait until function you supplied is evaluated as true. func() executes in browser window context.

.sleep(msec)

wait for milli seconds you specified.

.type(selector, text)
.insert(selector, text)
.check(selector)
.uncheck(selector)
.select(selector, value)
.setFile(selector, files)

Sets the files to a file field that matches the selector.

  • selector: selector for specifying the file field.
  • files: The array or string value that represents a local file path.
.click(selector, options)
options

waitLoadEvent(default: false): If set to true, wait until load event is fired after click event is fired.

.mouseMoved(x, y, options = {})

Dispatch mousemoved event.

.mousePressed(x, y, options = {})

Dispatch mousedown event.

.mouseReleased(x, y, options = {})

Dispatch mouseup event.

.tap(x, y, options = {})

Synthesize tap by dispatching touch events. (NOTE: To dispatch touch events you need to enable a mobile emulation before.)

.doubleTap(x, y, options = {})

Synthesize double tap by dispatching touch events. (NOTE: To dispatch touch events you need to enable a mobile emulation before.)

.scroll(x, y)

Scrolls to the position. x and y means relative position.

.scrollTo(x, y)

Scrolls to the position. x and y means absolute position.

.rect(selector)

Returns a rect of the element specified by selector.

.rectAll(selector)

Returns an array of rects that is specified by selector.

.defineFunction(func)
function outerFunc () {
  return 'VALUE'
}
chromy.chain()
      .goto('http://example.com')
      .defineFunction(outerFunc)
      .evaluate(() => {
        outerFunc()
      })
      .end()
.send(eventName, parameter)

Calls DevTools protocol directly.

.on(eventName, listener)

Adds the listener function.

.once(eventName, listener)

Adds one time listener function.

.removeListener(eventName, listener)

Removes the listener function.

.removeAllListeners(eventName)

Removes all listener function.

.screenshot(options= {})

Exports a current screen as an image data.

See examples: examples/screenshot.js

options
  • format(default: 'png'): must be either 'png' or 'jpeg'
  • quality(default: 100): quality of image.
  • fromSurface(default: true): if set to true, take screenshot from surface.
  • useDeviceResolution(default: false): if set to true, the image will have same resolution with device.
.screenshotSelector(selector, options={})

Exports an area of selector you specified as an image data.

See examples: examples/screenshot.js

Note:

  • The size of target specified by selector must be smaller than viewport size. If not, image gets cropped.
  • It has a side-effect. After this api is called, scroll position is moved to target position.
options

See screenshot()

.screenshotMultipleSelectors(selectors, callback, options = {})

Takes multiple screenshot specified by selector at once. Each image can be received by callback.

Limitation:

Parameter
  • selectors: An array of selector
  • callback: function(error, image, index, selectors, subIndex)
    • error: error information.
    • image: image data
    • index: index of selectors.
    • subIndex: this value is used only if useQuerySelecotrAll is true.
  • options:
    • model: see explanation of screenDocument()
    • format: see explanation of screenshot()
    • quality: see explanation of screenshot()
    • fromSurface: see explanation of screenshot()
    • useQuerySelectorAll(default: false): If set to true, take all the screenshot of elements returned from document.querySelectorAll() (Since v 0.2.13)
.screenshotDocument(options = {})

Exports a entire document as an image data.

See examples: examples/screenshot.js

Limitation:

Known Issue:

  • When this api is called to take large page sometimes strange white area is appeared. This result is caused by --disable-flag option passed to Chrome. After chrome 60 is officially released I remove --disable-flag option to fix this problem.
options
  • model: this parameter affect page size. must be which one of: 'box', 'scroll'. 'box' means box model of body element. 'scroll' means size of scroll area.
  • format: see explanation of screenshot()
  • quality: see explanation of screenshot()
  • fromSurface: see explanation of screenshot()
.pdf(options={})

Exports a current page's printing image as a PDF data. This function is supported only in headless mode (since Chrome60).

See examples: examples/screenshot.js

Parameters
.startScreencast(callback, options = {})

Starts screencast to take screenshots by every frame.

See examples: examples/screencast.js

Parameter

callback: callback function for receiving parameters of screencastFrame event. See details here options: See details here.

.stopScreencast()

Stops screencast.

.console(func)
chromy.chain()
      .goto('http://example.com')
      .console((text) => {
        console.log(text)
      })
      .evaluate(() => {
        console.log('HEY')
      })
      .end()
.receiveMessage(func)

receive a message from browser.

You can communicate with a browser by using receiveMessage() and sendToChromy(). sendToChromy() is a special function to communicate with Chromy. When you call receiveMessage() at the first time, sendToChromy() is defined in a browser automatically. A listener function passed to receiveMessage() receives parameters when sendToChromy() is executed in a browser.

chromy.chain()
      .goto('http://example.com')
      .receiveMessage((msg) => {
        console.log(msg[0].value)
      })
      .evaluate(() => {
        sendToChromy({value: 'foo'})
      })
.ignoreCertificateErrors()

Ignores all certificate errors.

chromy.chain()
      .ignoreCertificateErrors()
      .goto('https://xxxxx/')
      .end()
.blockUrls(urls)

blocks urls from loading.

Parameter

urls: array[string]
Wildcard('*') is allowed in url string.

.clearBrowserCache()

Removes all browser caches.

.setCookie(params)
Parameters

params: object or array

See chrome document If url parameter is not set, current url(location.href) is used as default value.

.getCookies(name = null)
Parameters

name: string or array of string

See chrome document

.deleteCookie(name, url = null)

Remove a cookie.

Parameters

name: string or array of string url: url associated with cookie. If url is not set, current url(location.href) is used as default value.

.clearAllCookies()

Removes all browser cookies.

.clearDataForOrigin (origin = null, type = 'all')

Clear data for origin.(cookies, local_storage, indexedDb, etc...)

See details here.

.getDOMCounters()

Get count of these item: document, node, jsEventListeners

See details here.

.static cleanup()

close all browsers.

process.on('SIGINT', async () => {
  await Chromy.cleanup()
  process.exit(1)
})

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/OnetapInc/chromy

chromy's People

Contributors

badsyntax avatar dotneet avatar fcastilloec avatar flancer64 avatar garris avatar holmesconan avatar ielgnaw avatar jonathanlking avatar nicolad avatar nimasoroush avatar rancow64 avatar smallfield avatar techquery avatar teppeis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

chromy's Issues

running multiple instances of chromy parallel

Hi , i'm trying to integrate chromy with my jasmine E2E testing environment(headless mode) .
this is my chrome conf file .

const Chromy = require('chromy')
const logger = require('../spec/specLogger')
const specUtils = require('../spec/specUtils')
const constants = require('../spec/specConstants')
const colors = require('colors');
const timeout = 2 * 60000

const chromy = new Chromy({waitTimeout: timeout, gotoTimeout: timeout, evaluateTimeout: timeout})

const chrome = chromy.chain();

const runnerNames = specUtils.getRunnerNames();
runnerNames.forEach(runnerName => {
const urlParams = {
query: {
jasmineSpec: constants.jasmineSpec + runnerName,
},
runnerName: runnerName
}

const url = specUtils.createTestUrl(urlParams);
try {
    chrome
        .goto(url)
        .wait(() => window.reporter && window.reporter.finished)
        .evaluate(() => window.reporter.specs())
        .result(specs => formatResults({url, runnerName, specs}))
} catch (e) {
    console.log(e)
}

})

as first look , i thought it should run the tests parallel but it seems it runs sync.
any thoughts how can i run the instances parallel ? thanks in advance!

Access to elements inside iframe

Hi, thanks for the nice library!

It would be even nicer if it will support accessing/clicking elements inside an iframe. Do you know how to do it via Chrome DevTools Protocol?

chromeFlag doesn't work

let chromy = new Chromy({visible:true, typeInterval:100, chromeFlags:['--disable-popup-blocking']});

Pop up blocking still works

solved -- Error: 'Emulation.resetViewport' wasn't found

looks like screenshotMultipleSelectors() may be broken?

$ node -v
v8.1.0

error:

~/Desktop/backstop test @gshipon-mn1(gshipon)
$ node chromyTest
error caught > Error: 'Emulation.resetViewport' wasn't found

script:

chromy
  .chain()
  .console(function (text, consoleObj) {
    if (console[consoleObj.level]) {
      console[consoleObj.level]((consoleObj.level).toUpperCase() + ' > ', text);
    }
  })
  .goto('examples/featureTests/index.html')
  .wait(1)
  .screenshotMultipleSelectors(
    ["body", "h1", "h2"],
    handlescreenshots,
    {useQuerySelectorAll: true}
  )
  .end()
  .then(_ => {
    chromy.close()
    console.log('success');
  })
  .catch(e => {
    chromy.close()
    console.log('error caught > ' + e);
  });


function handlescreenshots(error, png, index, selectors, sub){
  console.log('>>>',error, selectors[index], sub);
  fs.writeFileSync(`./screens/${selectors[index]}_${sub}.png`, png);
}

'frame' object has no 'type()' function

I try to type some text into the field that is placed in iframe and I see that there is no 'type()' function available:
image

This is my code:

await chromy.iframe('iframe#braintree-hosted-field-number', frame => {

    console.log('We are inside.');
    frame.type('input[name=credit-card-number]', '4111111111111111');

});

I try to create test scenario for Magento e-commerce app.

Can not hover an element that is outside viewport

@dotneet I think this may be a somewhat challenging issue.

I have a document with a height of 1000px and a viewport (window) with a height of only 800px, if I attempt to hover an item which starts at 900px (using mouseMoved()) the hover fails. This makes sense since in normal chrome it is impossible for a user to move the cursor beyond the window bounds. However, it causes confusion when taking screenshots in the document (whole page) context. This is especially true when using backstop because this was not a limitation of phantom.

I am wondering, would it be possible to maintain the user's intended cursor position (probably by simply aggregating arguments to all mouseMoved() calls) prior to switching to document context. If so, would it also be possible to set the user's intended cursor position prior to taking screenshots?

This is a pretty big issue for backstop usecases. What do you think?

setCookie example

It would be very helpful if there were a simple setCookie() example.

Does this command accept an array in the following format? e.g.

...
chromy.setCookie([
  {
    "domain": ".www.mydomain.com",
    "expirationDate": 1798790400,
    "hostOnly": false,
    "httpOnly": false,
    "name": "abc",
    "path": "/",
    "sameSite": "no_restriction",
    "secure": false,
    "session": false,
    "storeId": "0",
    "value": "renderMode=vanilla",
    "id": 112
  },
  {
    "domain": ".www.mydomain.com",
    "expirationDate": 1798790400,
    "hostOnly": false,
    "httpOnly": false,
    "name": "xyz",
    "path": "/",
    "sameSite": "no_restriction",
    "secure": false,
    "session": false,
    "storeId": "0",
    "value": "featureFlag=foo",
    "id": 112
  }
])
...

goto() returns http response

Hi,

I would be interested in seeing goto() function sending HTTP response as a promise call back which you could validate based on the response you get (e.g status code)

Any suggestion what would be the best way to achieve this using chromy?

npm install chromy fails

Hi,

Just tried to install chromy and got this error:

npm install chromy
npm ERR! code ETARGET
npm ERR! notarget No matching version found for async-chain-proxy@^0.1.3
npm ERR! notarget In most cases you or one of your dependencies are requesting
npm ERR! notarget a package version that doesn't exist.
npm ERR! notarget
npm ERR! notarget It was specified as a dependency of 'chromy'
npm ERR! notarget

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/y/.npm/_logs/2017-06-26T14_56_42_085Z-debug.log

For some reason, it can't find async-chain-proxy with that version? any idea?

opening HTML as data-uri

First off, thanks for chromy!

Is there a way to open HTML given as a data-URL?

For example, the following doesn't return anything:

chromy
    .chain()
    .goto('data:text/html,<h1>Hello%2C%20World!<%2Fh1>')
    .evaluate(() => {
        return document.body.innerHTML;

    })
    .result((r) => console.log(r))

This is not hard to work around (e.g., passing a string along and setting body.innerHTML) but it would be convenient to just open the data straight away.

Sharing variable between steps

Hello,

Thanks for Chromy, it's really useful :-)

I have been unable to use a shared variable in a wait function:

const timestamp = 'release-nnn-' + new Date().toISOString();
let chromy = new Chromy( { chromeFlags: [ '--window-size=1200,960' ] } );
chromy.chain()
    .goto( 'http://devenv/' )
    .click( '#somelink' )
    .wait( '#somecontent' )
    .type( '#titleField', timestamp )
    .wait( function(a,b,c) {
        return document.querySelector( '#titkeField' ).innerText.indexOf(timestamp ) > -1;
    } )

I get ReferenceError: timestamp is not defined. I tried to follow examples/define_function.js to wrap my variable in a function but I couldn't figure out how to get it to work.

Is what I am trying to do possible?

Thanks,

  • Gavin

ChromyJS returned an unexpected error while attempting to capture a selector.

Hello

I play with backstopJS and chromy seems to bug sometimes.

Maybe It’s because I try to find a only one selector and it’s not present in the tested page.

ChromyJS returned an unexpected error while attempting to capture a selector. Error: not opened
    at WebSocket.send (/home/travis/build/20minutes/colette/node_modules/ws/lib/WebSocket.js:356:18)
    at Chrome.enqueueCommand (/home/travis/build/20minutes/colette/node_modules/chrome-remote-interface/lib/chrome.js:115:16)
    at /home/travis/build/20minutes/colette/node_modules/chrome-remote-interface/lib/chrome.js:79:28
    at Promise (<anonymous>)
    at Chrome.send (/home/travis/build/20minutes/colette/node_modules/chrome-remote-interface/lib/chrome.js:78:16)
    at Object.handler [as evaluate] (/home/travis/build/20minutes/colette/node_modules/chrome-remote-interface/lib/api.js:32:23)
    at Chromy._callee$ (/home/travis/build/20minutes/colette/node_modules/chromy/dist/document.js:400:81)
    at tryCatch (/home/travis/build/20minutes/colette/node_modules/babel-runtime/node_modules/regenerator-runtime/runtime.js:65:40)
    at Generator.invoke [as _invoke] (/home/travis/build/20minutes/colette/node_modules/babel-runtime/node_modules/regenerator-runtime/runtime.js:299:22)
    at Generator.prototype.(anonymous function) [as next] (/home/travis/build/20minutes/colette/node_modules/babel-runtime/node_modules/regenerator-runtime/runtime.js:117:21)
    at tryCatch (/home/travis/build/20minutes/colette/node_modules/babel-runtime/node_modules/regenerator-runtime/runtime.js:65:40)
    at invoke (/home/travis/build/20minutes/colette/node_modules/babel-runtime/node_modules/regenerator-runtime/runtime.js:155:20)
    at /home/travis/build/20minutes/colette/node_modules/babel-runtime/node_modules/regenerator-runtime/runtime.js:198:11
    at Promise (<anonymous>)
    at callInvokeWithMethodAndArg (/home/travis/build/20minutes/colette/node_modules/babel-runtime/node_modules/regenerator-runtime/runtime.js:197:16)
    at AsyncIterator.enqueue [as _invoke] (/home/travis/build/20minutes/colette/node_modules/babel-runtime/node_modules/regenerator-runtime/runtime.js:220:13)

You can se the log of the test here:
https://travis-ci.org/20minutes/colette/jobs/267365456

watching network requests/responses

I have a use case where I need to watch for a network response.

I need to know the status code of a specific request and take action based on the response value.

Is there support for this?

Injecting scripts

Hi there,

Love the project. Currently migrating a service from nightmarejs to chromy and it's working great. Just wondering if you're planning on supporting an API similar to Nightmare#inject or if there is any way to achieve a similar result with the current API.

Error: Failed to launch a browser.

I'm not sure with repo this issue belongs in.

createBitmaps | Selcted 6 of 6 scenarios.
Starting Chromy: port:9222 --window-size=320,480
Starting Chromy: port:9223 --window-size=1280,768
Starting Chromy: port:9224 --window-size=320,480
Starting Chromy: port:9225 --window-size=1280,768
Starting Chromy: port:9226 --window-size=320,480
Starting Chromy: port:9227 --window-size=1280,768
Starting Chromy: port:9228 --window-size=320,480
Starting Chromy: port:9229 --window-size=1280,768
Starting Chromy: port:9230 --window-size=320,480
Starting Chromy: port:9231 --window-size=1280,768
Error: Failed to launch a browser.
    at Chromy.start$ (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\chromy\dist\index.js:147:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at GeneratorFunctionPrototype.invoke [as _invoke] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:303:22)
    at GeneratorFunctionPrototype.prototype.(anonymous function) [as next] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:117:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at invoke (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:155:20)
    at C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:165:13
Error: Failed to launch a browser.
    at Chromy.start$ (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\chromy\dist\index.js:147:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at GeneratorFunctionPrototype.invoke [as _invoke] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:303:22)
    at GeneratorFunctionPrototype.prototype.(anonymous function) [as next] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:117:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at invoke (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:155:20)
    at C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:165:13
Error: Failed to launch a browser.
    at Chromy.start$ (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\chromy\dist\index.js:147:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at GeneratorFunctionPrototype.invoke [as _invoke] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:303:22)
    at GeneratorFunctionPrototype.prototype.(anonymous function) [as next] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:117:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at invoke (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:155:20)
    at C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:165:13
Error: Failed to launch a browser.
    at Chromy.start$ (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\chromy\dist\index.js:147:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at GeneratorFunctionPrototype.invoke [as _invoke] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:303:22)
    at GeneratorFunctionPrototype.prototype.(anonymous function) [as next] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:117:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at invoke (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:155:20)
    at C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:165:13
Error: Failed to launch a browser.
    at Chromy.start$ (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\chromy\dist\index.js:147:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at GeneratorFunctionPrototype.invoke [as _invoke] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:303:22)
    at GeneratorFunctionPrototype.prototype.(anonymous function) [as next] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:117:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at invoke (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:155:20)
    at C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:165:13
Error: Failed to launch a browser.
    at Chromy.start$ (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\chromy\dist\index.js:147:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at GeneratorFunctionPrototype.invoke [as _invoke] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:303:22)
    at GeneratorFunctionPrototype.prototype.(anonymous function) [as next] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:117:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at invoke (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:155:20)
    at C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:165:13
Error: Failed to launch a browser.
    at Chromy.start$ (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\chromy\dist\index.js:147:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at GeneratorFunctionPrototype.invoke [as _invoke] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:303:22)
    at GeneratorFunctionPrototype.prototype.(anonymous function) [as next] (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:117:21)
    at tryCatch (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:65:40)
    at invoke (C:\Users\SATTA-WORK\AppData\Roaming\npm\node_modules\backstopjs\node_modules\regenerator-runtime\runtime.js:155:20)
    at C:\Users\SATTA-WOR

how do I set screenshot size?

Hi -- thanks for starting this project -- it is very cool!

  1. How would I set the size of the screenshot?

  2. Also, Can you explain why my PDF and PNG screenshots are different for the following example?

const Chromy = require('chromy')
const path = require('path')
const fs = require('fs')

let chromy = new Chromy()
chromy.chain()
      .goto('https://google.com/')
      .screenshot()
      .result((png) => {
        fs.writeFileSync('out.png', png)
      })
      .pdf()
      .result((pdf) => {
        fs.writeFileSync('out.pdf', pdf)
      })
      .end()
      .then(_ => chromy.close())
      .catch(e => chromy.close())

results files attached...

the PDF captures the document size
out.pdf

the PNG captures part of the document
out.png

Use case with Chrome extensions

I have a Chrome extension that I was hoping to use Chromy to load and test. However, since Chromy loads a fresh copy of Chrome on startup (no one signed in, etc.), this appears to be impossible.

Would it be possible to load an extension inside whichever instance Chromy runs?

Maintain 1:1 @72ppi resolution?

Is it be possible to ensure screenshots are captured at lower resolution -- even on high-resolution devices? Possibly through the emulation setting?

pdf() doesn't work for me

The pdf example doesn't work for me - disabling the "catch", I get the following error in the console:

Error: PrintToPDF is not implemented

Using Chrome Version 59.0.3071.86 (Official Build) (64-bit)

`evaluate` not accepting args

The test below should return 1.
Running document.querySelectorAll("div.content").length in the console on google.com returns 1.
It appears the Chromy does not yet support args passed in to evaluate (like nightmarejs).


let chromy = new Chromy({visible:true})

var selector = "div.content";

chromy.chain()
	.goto('https://www.google.com/')
	.evaluate( function(selector) {
		return document.querySelectorAll(selector).length;
	}, selector)
	.result((r) => console.log("selector length: " + r))
	.end()
	.then(_ => chromy.close())

is chromy able to open a local file?

I get this error...
Error: Cannot navigate to invalid URL

with this script...

const Chromy = require('chromy')
const path = require('path')
const fs = require('fs')

let chromy = new Chromy({chromeFlags: ['--window-size=600,400'], visible: true});
chromy
  .chain()
  .goto('examples/myCoolProject/index.html')
  .screenshotSelector('html')
  .result((png) => {
    fs.writeFileSync('./chromyTest.png', png)
  })
  .end()
  .then(_ => chromy.close())
  .catch(e => {
    console.log(' ' + e);
    chromy.close();
  });

how to disable the headless browser to load images?

First of all, thanks for creating this great tool for manipulating the browser api easily, and sorry i am just a newbie, and i wonder what should I do to disable the headless browser to load images ? and is it possible to wrap that sort of relevant event as a function ?
I've researched the document https://chromedevtools.github.io/devtools-protocol/tot/Page/ , and i have no cue where is the right direction may meet my demand. I hope there's a way to solve it. and I'll appreciate if this could be supported. thank you

Screenshotting on crash

I have a block of code to catch crashes and show the error:

    .catch( err => {
        console.log( "A problem was detected:" );
        console.log( err );
        chromy.close();

        setTimeout( () => {
            process.exit( 1 );
        }, 1000 );
    } );

It would be really useful if I could take a screenshot at this point. Is there a safe way to do so?

add custom device

hi @dotneet,

Can I add custom devices? I see source code, the device information is hard coded in devices.js, and used in index.js.

If you do not mind, I can submit a pr for this feature~~

text anti-aliasing inconsistent across environments

@dotneet This one has been coming up now for a lot of developers.

Do you know why bitmaps taken on my retina laptop would render different text anti-aliasing when attaching non-retina monitors?

Could this have something to do with the process you use to maintain 1:1 resolution across different configurations?

Here are two images taken on the same machine. The reference was created on my laptop -- the test was created on my laptop with an external (non-retina) monitor attached...
image

Termination of Chrome process

Chrome Launcher by default sets handleSIGINT to true which allow termination of chrome process on Ctrl-C.
I've tried to set this flag explicit, but no result.
Please advise any solution.

Attribute selectors

Testing the beta version of backstopjs and noticed that attribute selectors don't work (but they did with phantom).

Error: An error has occurred evaluating the script in the browser.SyntaxError: Unexpected identifier

works:
selectors: [ '.test' ]

doesn't work:
selectors: [ "[data-backstop='test']" ]

Hopefully it's an easy fix! Thanks!

Support for use case: interacting with iframe within iframe

Hi there @dotneet,

I have a case in which I'm trying to interact with iframe content that's nested within another iframe. While I'm using the .iframe method (of which there doesn't seem to be any API docs), I wanted to make sure that this is supported by chromy. Will the following snippet work to accomplish this?

.iframe('iframe', async iframe => {
    await iframe.chain()
    .evaluate(async (_) => {
      await iframe.chain()
      .click('#nested-iframe-button')
      .evaluate(_ => {
        console.log('Interacting with iframe inside of iframe');
        console.log(document.querySelector('#nested-content').innerText)
      })
      .end()
    })
    .end()
  })

Upload/Download File

Sorry if wrong place I am new to github/programming

Is it possible to upload, like say nightmare-upload?

great library,thanks

activate tab by targetId

Hi, in my project, the chromy has multiple tabs, I'm tring to change the activate tab by targetId.
this is my code:

let pages = await chromy.getPageTargets();
let targetPage = pages.filter(p => p.url.indexOf(someKeys) > -1)[0];
await chromy.Target.activateTarget({targetId: targetPage.targetId});

but I got some errors like this:
TypeError: Cannot read property 'activateTarget' of undefined

Is there any way to activate the other tab? Thanks in advance!

Type does not correctly escape double quotes

In the definition of type (in src/index.js) the selector is wrapped in double quotes and is not escaped. If there are any unescaped double quotes in the selector name this causes chromy to crash. In all other functions (that I've seen) selectors are wrapped in single quotes and escaped using escapeSingleQuote (from src/util.js).

Is there any reason why this is the case and could we change this?

Rendering broken when using non-headless mode {visible: true}

Hi @dotneet,

i think this is on chromy but i can't be entirely sure:

Reduced testcase:

const Chromy = require('chromy');

// not headless
let chromy = new Chromy({ visible: true });
//headless
// let chromy = new Chromy();

chromy.chain()
    .goto('http://github.com/')
    .sleep(500)
    .end()
    .then(() => chromy.close());

This is how it looks:
image

Environment:

Chrome 60
Chromy 0.4.7
Centos 7
Node 8

I think the problem occured first after updating from chrome59 to chrome60 but i can't be sure.
Headless Mode still works. But having the window visible helps a lot when working on complex test cases.
If i manually start chrome via google-chrome --remote-debugging-port=9222 and then run a chrome-remote-interface script against it, everything works and the rendering seems fine.

Reference: garris/BackstopJS#479

unclear local setup

Issue

I can understand smoothly because I have enough knowledge about chrome headless.
but
some developer who doesn't have any basic knowledge about headless chrome might be confused
Depending on his environment he can not proceed next step.
so It's better to add some example for setting up local environment to README.md.

Example Solution

ex1) Docker env

docker run --init -it --rm --name chrome --shm-size=1024m -p=127.0.0.1:9222:9222 --cap-add=SYS_ADMIN \
  yukinying/chrome-headless-browser

https://github.com/yukinying/chrome-headless-browser-docker

ex2) Other Linux or Mac??

chrome \
  --headless \                   # Runs Chrome in headless mode.
  --disable-gpu \                # Temporarily needed for now.
  --remote-debugging-port=9222 

https://developers.google.com/web/updates/2017/04/headless-chrome

Windows
I'm not sure

capture viewport with screenshotMultipleSelectors()?

Is it possible to use screenshotMultipleSelectors() to capture the viewport?
chromy.screenshot() does have this behavior but the resolution is not normalized.

Also, It would be great if screenshotMultipleSelectors() could accept 'DOCUMENT' and 'BODY' "magic" selectors -- where DOCUMENT would capture the entire document and BODY would capture only the viewport. FWIW: This is a convention used in backstopjs.

Do you have some thoughts?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.