# Chrome 59 headless support

**URL:** https://meta.discourse.org/t/chrome-59-headless-support/62060
**Category:** Development
**Created:** [May 3, 2017, 5:44pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060 "2017-05-03T17:44:27Z")
**Posts on this page:** 19
**Page:** 1

<div class="post-metadata">

### Author: ![riking](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/riking/32/170938_2.png) [@riking](https://meta.discourse.org/u/riking)
#### Post date: [May 3, 2017, 5:44pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/1 "2017-05-03T17:44:27Z")

</div>

> **[Getting Started with Headless Chrome  |  Blog  |  Chrome for Developers](https://developer.chrome.com/blog/headless-chrome/?utm_source=frontendfocus&utm_medium=email)**
>
> Getting started with Headless Chrome

It would be possible to start using Headless Chrome for smoke tests instead of PhantomJS.

The bare-bones implementation would be to run:

```
% CHROME_PATH=/opt/google/chrome-beta/google-chrome-beta
% $CHROME_PATH --headless --disable-gpu --dump-dom https://meta.discourse.org

```

(pointing to the localhost:xxxx url) and check that the topic list shows up.

This command takes several (~8?) seconds on my machine on the first run, then is very fast (~1sec) afterwards.

More complicated integration tests - such as typing a topic and posting it - could be done with the debugger port.

Making this change will probably speed up the CI workflow due to the more optimized JS implementation.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [May 3, 2017, 7:25pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/2 "2017-05-03T19:25:38Z")

</div>

Looks like phantomJS may cease to be maintained because of this

> **[Redirecting to Google Groups](https://groups.google.com/forum/m/#!topic/phantomjs/9aI5d-LDuNE)**

---

<div class="post-metadata">

### Author: ![fantasticfears](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/fantasticfears/32/119608_2.png) [@fantasticfears](https://meta.discourse.org/u/fantasticfears)
#### Post date: [May 4, 2017, 8:48am UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/3 "2017-05-04T08:48:14Z")

</div>

PhantomJS API supports scripting for tests, not sure how Chrome team will support them.

---

<div class="post-metadata">

### Author: ![riking](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/riking/32/170938_2.png) [@riking](https://meta.discourse.org/u/riking)
#### Post date: [May 5, 2017, 12:01am UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/4 "2017-05-05T00:01:47Z")

</div>

qunit - what our current tests are written in - has support for a Chrome Remote Debugging backend. I’m not sure if they’ll work out of the box due to the fixtures stuff, though. And I’m not sure if it’s possible to write true integration tests with just the qunit API.

Ideally would be a Ruby interface to the remote debugging port, to coordinate tests of things like a thread live-updating over the message bus when a new post is made.

```ruby
# Set up
browser.log_in(user1)
browser_2.log_in(user2)
topic = create_topic(user1, ...)
browser.navigate("/t/#{topic.id}")
browser_2.navigate("/t/#{topic.id}").wait!
browser.wait!

# Action: Create a post in the thread
## or make this into a helper function that manages the composer
browser_2.click('#topic-footer-buttons button.create')
browser_2.type_post('#reply-control .d-editor-textarea-wrapper textarea', "A reply to the topic that satisfies minimum length requirements")
th = Thread.new do ||
  browser.wait_for_message_bus
end
browser_2.click('#reply-control .submit-panel button')
browser_2.wait!

# Check: Post is created on the server
topic.reload
expect(topic.posts.count).to eq(2)

# Check: post is delivered to other browser
new_post = topic.posts.last
th.join # browser.wait_for_message_bus
expect(browser.find_element("article[data-post-id=\"#{new_post.id}\"]")).to #not be nil, I forget how to spell that

```

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [August 16, 2017, 9:03am UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/5 "2017-08-16T09:03:21Z")

</div>

I’ve had a play with getting the qunit tests running in headless chrome, and it seems to work alright. The performance improvement isn’t as dramatic as I’d hoped - on my computer phantomjs runs the core tests in 227s, and headless chrome runs them in 201s.

I’ve written a JS script, which depends on a couple of NPM modules: [chrome-launcher](https://www.npmjs.com/package/chrome-launcher) and [chrome-remote-interface](https://www.npmjs.com/package/chrome-remote-interface), which provide an interface to the Chrome Remote Debugging system @riking mentioned.

~~I’ve then given the `rake qunit:test` an optional third parameter to use chrome instead of phantomJS.~~ Set the USE\_CHROME environment variable to use chrome instead of phantomJS

So, assuming you have chrome and node/npm installed, using it works like this:

```plaintext
npm install chrome-launcher chrome-remote-interface
USE_CHROME=1 rake qunit:test

```

[https://github.com/discourse/discourse/pull/5054](https://github.com/discourse/discourse/pull/5054)

In summary, there’s not much advantage over PhantomJS at the moment, but that will change if [PhantomJS stops being developed](https://groups.google.com/forum/m/#!topic/phantomjs/9aI5d-LDuNE) in future.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [August 16, 2017, 11:42am UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/6 "2017-08-16T11:42:31Z")

</div>

10% faster is a pretty big advantage! great work!

Next step is adding this into our docker test image and docker dev image.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [August 17, 2017, 8:37pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/7 "2017-08-17T20:37:56Z")

</div>

> [@sam](#):
>
> Next step is adding this into our docker test image and docker dev image.

Having a look at this at the moment. It looks to me like PhantomJS is currently included in the base image.

> <https://github.com/discourse/discourse_docker/blob/master/image/base/Dockerfile#L100>

Is there any reason for this, and if not shall I move it to only be in the dev/test images? Seems to me like unnecessary bulk for the image used in every install of Discourse. On the other hand, it’s only 22mb, so not a big deal `¯\_(ツ)_/¯`

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [August 17, 2017, 8:40pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/8 "2017-08-17T20:40:03Z")

</div>

> [@david](#):
>
> Is there any reason for this, and if not shall I move it to only be in the dev/test images?

Yeah it was kind of “historical” cause you can not run the smoke test without it. But I am open to just moving this stuff out, we will just have to be careful with our CI.

I think for the time being just add chrome to the dev/test image and we will move to that.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [August 18, 2017, 4:58pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/9 "2017-08-18T16:58:53Z")

</div>

Good news: These two PRs combined allow use of chrome in `discourse_test` by setting the `USE_CHROME` environment variable: 🙂

[https://github.com/discourse/discourse/pull/5062](https://github.com/discourse/discourse/pull/5062)

[https://github.com/discourse/discourse\_docker/pull/369](https://github.com/discourse/discourse_docker/pull/369)

Bad news: Chrome is huge - it adds 415mb to the image 🤒

---

<div class="post-metadata">

### Author: ![elijah](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/elijah/32/104055_2.png) [@elijah](https://meta.discourse.org/u/elijah)
#### Post date: [August 18, 2017, 6:34pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/10 "2017-08-18T18:34:46Z")

</div>

> [@david](#):
>
> Having a look at this at the moment. It looks to me like PhantomJS is currently included in the base image.

> [@sam](#):
>
> Yeah it was kind of “historical” cause you can not run the smoke test without it. But I am open to just moving this stuff out, we will just have to be careful with our CI.

Incidentally, I noticed when I tried to build my own base image this week, that `docker build` died on that `ADD`. The file is not included in the repo.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [August 18, 2017, 6:39pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/11 "2017-08-18T18:39:29Z")

</div>

> [@elijah](#):
>
> The file is not included in the repo.

There’s some magic that occurs to obtain phantomJS

The build.rb script executes the `download_phantomjs` script on the host, which spins up a docker container, which I’m guessing builds a custom version of phantomJS.

So if you run that download\_phantomjs script first it should work 🙂

[https://github.com/discourse/discourse\_docker/blob/master/image/build.rb#L98](https://github.com/discourse/discourse_docker/blob/master/image/build.rb#L98)

[https://github.com/discourse/discourse\_docker/blob/master/image/base/download\_phantomjs](https://github.com/discourse/discourse_docker/blob/master/image/base/download_phantomjs)

---

<div class="post-metadata">

### Author: ![elijah](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/elijah/32/104055_2.png) [@elijah](https://meta.discourse.org/u/elijah)
#### Post date: [August 18, 2017, 7:11pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/12 "2017-08-18T19:11:37Z")

</div>

The comment at the top said “Run by Sam” (or similar), so I just skipped to a manual `docker build`. Guess I should have read further. 😊

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [August 18, 2017, 7:13pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/13 "2017-08-18T19:13:09Z")

</div>

A lot of the phantom mess can go very very shortly, cause we don’t want to carry it for too much longer.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [August 18, 2017, 7:16pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/14 "2017-08-18T19:16:17Z")

</div>

@sam I should probably mention - the chrome stuff is currently off by default, so if you want to try it in CI you need to set `USE_CHROME=1` 🙂

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [August 20, 2017, 3:09pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/15 "2017-08-20T15:09:23Z")

</div>

Something I just stumbled across is [Puppeteer](https://github.com/GoogleChrome/puppeteer), which is created and maintained by the Chromium devtools team. It bundles a version of chromium that skips all the UI dependencies, bringing it in at just under 100mb. Seems like a far tidier option than having to install chrome separately and use a third party library for the API.

It requires node 7 though, so not an option for Discourse quite yet (discourse\_docker ships the LTS version, which is version 6). Maybe once version 8 LTS is released in October it could be an option.

The API looks very similar to the chrome-remote-interface module I’ve used, so hopefully will be trivial to switch over once the time comes 🙂

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [August 20, 2017, 3:11pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/16 "2017-08-20T15:11:44Z")

</div>

More than happy to upgrade to node 7, this is not an issue

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [August 20, 2017, 3:14pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/17 "2017-08-20T15:14:43Z")

</div>

Oh cool, in that case I’ll have a quick look at it next week. What are the critical things that depend on node/npm in Discourse? (so I can check they don’t break)

Am I correct in saying most of the critical stuff is run in mini-racer instead?

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [August 20, 2017, 3:22pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/18 "2017-08-20T15:22:05Z")

</div>

At the moment we package assets in node, but we can easily migrate to mini racer now that I added explicit support for disposing contexts

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [August 21, 2017, 2:48pm UTC](https://meta.discourse.org/t/chrome-59-headless-support/62060/19 "2017-08-21T14:48:36Z")

</div>

I’ve made a PR to install node8 in the base image

[https://github.com/discourse/discourse\_docker/pull/370](https://github.com/discourse/discourse_docker/pull/370)

I also had a play with puppeteer, and it is much easier/cleaner than what I had before. I’ve published an NPM module to do exactly what we need - I figure it might be useful for other projects using QUnit. So once node has been upgraded it should be as simple as

```plaintext
npm install -g qunit-puppeteer
qunit-puppeteer http://localhost:3000

```

The `npm install` installs puppeteer as a dependency, which in turn pulls in a recent version of chromium 🙂

[https://github.com/davidtaylorhq/qunit-puppeteer](https://github.com/davidtaylorhq/qunit-puppeteer)

Then I think the next step would be trying to figure out how this can slot into AutoSpec…
