├── index.js
├── examples
├── screenshots
│ ├── w3.png
│ └── google.png
├── screenshot.js
└── title.js
├── test
├── browser-tests
│ ├── ok.html
│ ├── alert.html
│ └── alert2.html
├── test_server
│ └── test_app.js
└── browser-emulator-tests.js
├── .gitignore
├── .travis.yml
├── package.json
├── lib
├── index.js
└── browser-emulator.js
└── README.md
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./lib/browser-emulator');
2 |
3 |
--------------------------------------------------------------------------------
/examples/screenshots/w3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2Cmo/mobile-web-browser-emulator/master/examples/screenshots/w3.png
--------------------------------------------------------------------------------
/examples/screenshots/google.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2Cmo/mobile-web-browser-emulator/master/examples/screenshots/google.png
--------------------------------------------------------------------------------
/test/browser-tests/ok.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | OK
5 |
6 | OK
7 |
--------------------------------------------------------------------------------
/test/browser-tests/alert.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Alert
6 |
7 | Alert
8 |
--------------------------------------------------------------------------------
/test/browser-tests/alert2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 | Alert2
10 |
11 | Alert2
12 |
--------------------------------------------------------------------------------
/examples/screenshot.js:
--------------------------------------------------------------------------------
1 | var MobileBrowser = require('../lib/index.js').MobileBrowser;
2 | var mobileBrowser = new MobileBrowser();
3 | mobileBrowser.emulate({
4 | url: 'http://google.com',
5 | width: 300,
6 | height: 700
7 | },
8 | function(browser) {
9 | browser.takeScreenshot(__dirname + "/../screenshot.png");
10 | });
--------------------------------------------------------------------------------
/examples/title.js:
--------------------------------------------------------------------------------
1 | var MobileBrowser = require('../lib/index.js').MobileBrowser;
2 | var mobileBrowser = new MobileBrowser();
3 | mobileBrowser.emulate({
4 | url: 'http://google.com',
5 | width: 300,
6 | height: 700
7 | },
8 | function(browser) {
9 | browser.do(function(driver) {
10 | driver.getTitle().then(function(title) {
11 | console.log(title);
12 | });
13 | });
14 | });
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Compiled binary addons (http://nodejs.org/api/addons.html)
12 | build/Release
13 |
14 | # Dependency directories
15 | node_modules
16 |
17 | # Optional npm cache directory
18 | .npm
19 |
20 | # Browsermob-proxy
21 | browsermob-proxy-2.1.4-bin.zip
22 | browsermob-proxy-2.1.4/
23 | browsermob-proxy-2.0-beta-9
24 |
--------------------------------------------------------------------------------
/test/test_server/test_app.js:
--------------------------------------------------------------------------------
1 | var express = require('express'),
2 | app = express(),
3 | http = require('http').Server(app),
4 | fs = require('fs');
5 |
6 |
7 | var serverport;
8 |
9 | exports.start = function(port, path) {
10 | path = __dirname + path;
11 | app.use(express.static(path));
12 |
13 | serverport = port || 3001;
14 | http.listen(port, function() {
15 | });
16 | };
17 |
18 | exports.close = function() {
19 | http.close();
20 | };
21 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | dist: trusty
3 | language: node_js
4 | node_js:
5 | - "4"
6 | addons:
7 | apt:
8 | sources:
9 | - google-chrome
10 | packages:
11 | - google-chrome-stable
12 | notifications:
13 | irc:
14 | channels:
15 | - "irc.w3.org#sysreq"
16 | skip_join: true
17 | install:
18 | - wget https://github.com/lightbody/browsermob-proxy/releases/download/browsermob-proxy-2.1.4/browsermob-proxy-2.1.4-bin.zip
19 | - unzip browsermob-proxy-2.1.4-bin.zip
20 | - ln -s browsermob-proxy-2.1.4 browsermob-proxy-2.0-beta-9
21 | - browsermob-proxy-2.1.4/bin/browsermob-proxy --use-littleproxy false &
22 | - npm install
23 | before_script:
24 | - export DISPLAY=:99.0
25 | - sh -e /etc/init.d/xvfb start
26 | script:
27 | - npm test
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mobile-web-browser-emulator",
3 | "description": "Emulation of a Chrome-based browser on a mobile device for Node.js",
4 | "version": "0.0.6",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://github.com/w3c/mobile-web-browser-emulator.git"
9 | },
10 | "bugs": {
11 | "url": "https://github.com/w3c/mobile-web-browser-emulator/issues"
12 | },
13 | "dependencies": {
14 | "browsermob-proxy": "^1.0.9",
15 | "chromedriver": "^2.29.0",
16 | "easyimage": "^2.1.0",
17 | "headless": "^1.2.0",
18 | "intl": "^1.2.5",
19 | "media-type": "^0.3.1",
20 | "metaviewport-parser": "^0.0.1",
21 | "rimraf": "^2.6.1",
22 | "selenium-webdriver": "^2.53.1",
23 | "uuid": "^3.0.1"
24 | },
25 | "devDependencies": {
26 | "expect.js": "^0.3.1",
27 | "express": "^4.15.2",
28 | "mocha": "^3.3.0"
29 | },
30 | "scripts": {
31 | "start": "node app.js",
32 | "test": "mocha --timeout 10000 --globals ErrorHandler"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | // Dependencies
2 | var headless = require('headless'),
3 | util = require("util"),
4 | events = require("events");
5 |
6 | function Sink() {}
7 | util.inherits(Sink, events.EventEmitter);
8 |
9 | var MobileBrowser = function() {};
10 |
11 | MobileBrowser.prototype.emulate = function(options, cb) {
12 | // options :
13 | // url : url of web application to load.
14 | // device.width : width of emulated device.
15 | // device.height : height of emulated device.
16 | // browser.width : width of displayed browser.
17 | // browser.height : height of displayed browser.
18 |
19 | var sink = new Sink();
20 | var self = this;
21 | self.sink = sink;
22 | self.options = options;
23 | self.cb = cb;
24 |
25 | var deviceOptions = {
26 | display: {
27 | width: options.width,
28 | height: options.width
29 | }
30 | }
31 |
32 | headless(deviceOptions, function(err, childProcess, servernum) {
33 | var Browser = require('./browser-emulator').Browser;
34 | var browser = new Browser({
35 | browserWidth: options.width,
36 | browserHeight: options.height,
37 | uaHeader: 'Mozilla/5.0 (Linux; Android 4.4.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/36.0.1025.133 Mobile Safari/535.19',
38 | displayServer: servernum,
39 | browsermobProxy: {
40 | port: 8080
41 | },
42 | trackNetwork: true
43 | });
44 | browser.open(self.options.url);
45 | browser.on('error', function(err) {
46 | console.log(err);
47 | });
48 | browser.on('done', function() {
49 | self.sink.emit('end');
50 | });
51 | browser.on('screenshot', function(path) {
52 | console.log('screenshot save as ' + __dirname + path);
53 | });
54 | self.cb(browser);
55 | browser.close();
56 | return;
57 | });
58 | };
59 |
60 | exports.MobileBrowser = MobileBrowser;
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://david-dm.org/w3c/mobile-web-browser-emulator)
2 | [](https://david-dm.org/w3c/mobile-web-browser-emulator#info=devDependencies)
3 |
4 | # Mobile Web Browser Emulator
5 |
6 | Mobile Web Browser Emulator is a Node.js tool which simulates a Chrome-based browser on a mobile device. This module also allows manipulation via Selenium WebDriver. It is an easy way to test mobile web applications on mobile devices.
7 |
8 | This module is used by the new version of the [Mobile Checker by W3C](https://validator.w3.org/mobile-alpha/).
9 |
10 | This application works in [headless](https://github.com/kesla/node-headless) mode (powered via XVFB). Using it on the server side is easy.
11 |
12 | 
13 | 
14 |
15 | ## Install
16 |
17 | Start by having [BrowserMob Proxy](http://bmp.lightbody.net/) set up and running. Then run the following command
18 |
19 | ```
20 | npm install mobile-web-browser-emulator
21 | ```
22 |
23 | ## API
24 |
25 | With Mobile Web Browser Emulator, it is easy test mobile web applications [using the Selenium WebDriver API](http://selenium.googlecode.com/git/docs/api/javascript/index.html).
26 |
27 | Emulation example:
28 |
29 | ```javascript
30 | var MobileBrowser = require('mobile-web-browser-emulator').MobileBrowser;
31 | var mobileBrowser = new MobileBrowser();
32 |
33 | mobileBrowser.emulate(
34 | // Parameters such as dimensions for tablets, smartphones or desktops.
35 | {
36 | url: 'https://www.google.com/', // URL to load. **required**
37 | width: 300, // Width of the device. **optional** (300 by default)
38 | height: 700 // Height of the device. **optional** (300 by default)
39 | },
40 | // The second parameter is a callback that takes a browser instance as an argument
41 | function(browser) { /* ... */ }
42 | );
43 | ```
44 |
45 | Methods on the `browser` object:
46 |
47 | ```javascript
48 | browser.do(function(driver) {
49 | // The driver object can then be used with Selenium WebDriver
50 | });
51 | browser.takeScreenshot('example.png');
52 | ```
53 |
54 | Manipulation with Selenium example :
55 |
56 | ```javascript
57 | var MobileBrowser = require('../lib/index.js').MobileBrowser;
58 | var mobileBrowser = new MobileBrowser();
59 |
60 | mobileBrowser.emulate({
61 | url: 'https://www.google.com',
62 | width: 300,
63 | height: 700
64 | }, function(browser) {
65 | browser.do(function(driver) {
66 | driver.getTitle().then(function(title) { // Selenium Webdriver Method
67 | console.log(title);
68 | });
69 | });
70 | });
71 | ```
72 |
73 | Screenshot example:
74 |
75 | ```javascript
76 | var MobileBrowser = require('../lib/index.js').MobileBrowser;
77 | var mobileBrowser = new MobileBrowser();
78 |
79 | mobileBrowser.emulate({
80 | url: 'https://www.google.com',
81 | width: 300,
82 | height: 700
83 | }, function(browser) {
84 | browser.takeScreenshot(__dirname + "/../screenshot.png");
85 | });
86 | ```
87 |
88 | ## Licence
89 |
90 | Copyright (c) 2014 Dominique Hazael Massieux, Guillaume Baudusseau
91 |
92 | MIT
93 |
--------------------------------------------------------------------------------
/test/browser-emulator-tests.js:
--------------------------------------------------------------------------------
1 | global.rootRequire = function(name) {
2 | return require(__dirname + '/../' + name);
3 | };
4 |
5 | var Browser = require("../lib/browser-emulator").Browser,
6 | expect = require("expect.js"),
7 | webdriver = require('selenium-webdriver');
8 |
9 |
10 |
11 | describe("Starting and quiting browser", function() {
12 | it('should start and stop without error with correct proxy', function(
13 | done) {
14 | var browser = new Browser({
15 | port: 8080,
16 | trackNetwork: true
17 | });
18 | browser.on('error', function(msg) {
19 | expect().fail(msg);
20 | done();
21 | });
22 | browser.open("file://" + __dirname + "/browser-tests/ok.html");
23 | browser.close().then(done);
24 | });
25 |
26 | it('should emit an error with incorrect proxy', function(done) {
27 | var browser = new Browser({
28 | browsermobProxy: {
29 | port: 9999
30 | },
31 | trackNetwork: true
32 | });
33 | browser.on('error', function(err) {
34 | expect(err.message).to.contain(
35 | 'Failed gathering network traffic: Error: connect ECONNREFUSED'
36 | );
37 | done();
38 | });
39 | browser.open("file://" + __dirname + "/browser-tests/ok.html");
40 | browser.close().then(done);
41 | });
42 |
43 | });
44 |
45 | describe("Getting data from network", function() {
46 | var server = require("./test_server/test_app.js");
47 | var browser = new Browser({
48 | browsermobProxy: {
49 | port: 8080
50 | },
51 | trackNetwork: true
52 | });
53 |
54 | before(function() {
55 | server.start(3001, '/../browser-tests');
56 | });
57 |
58 | it("should get the status code of a loadable page", function(done) {
59 | browser.on('har', function(har) {
60 | expect(har.log.entries[0].response.status).to.be(200);
61 | });
62 | browser.open("http://localhost:3001/ok.html");
63 | browser.close().then(done);
64 | });
65 |
66 | after(function() {
67 | server.close();
68 | });
69 | });
70 |
71 | describe("Getting data from browser and network", function() {
72 | var server = require("./test_server/test_app.js");
73 | var browser = new Browser({
74 | browsermobProxy: {
75 | port: 8080
76 | },
77 | trackNetwork: true
78 | });
79 | before(function() {
80 | server.start(3001, '/../browser-tests');
81 | });
82 |
83 | it("should get the status code and title of a loadable page", function(done) {
84 | browser.on('har', function(har) {
85 | expect(har.log.entries[0].response.status).to.be(200);
86 | });
87 |
88 | browser.open("http://localhost:3001/ok.html");
89 | browser.do(function(d) {
90 | return d.findElement(browser.webdriver.By.tagName('title')).then(
91 | function(title) {
92 | title.getInnerHtml().then(function(titleText) {
93 | expect(titleText).to.be('OK');
94 | });
95 | }
96 | );
97 | });
98 | browser.close().then(done);
99 | });
100 |
101 | after(function() {
102 | server.close();
103 | });
104 | });
105 |
106 | describe("Getting data from browser", function() {
107 |
108 | it('should return the title of the page "OK"', function(done) {
109 | var browser = new Browser();
110 |
111 | browser.open("file://" + __dirname + "/browser-tests/ok.html");
112 | browser.do(function(driver) {
113 | return driver.findElement(webdriver.By.tagName('title'))
114 | .then(function(title) {
115 | title.getInnerHtml().then(function(
116 | titleText) {
117 | expect(titleText).to.be('OK');
118 | });
119 | });
120 | });
121 | browser.close().then(done);
122 | });
123 |
124 | it('should return the title of the page "Alert1", even with an alert',
125 | function(done) {
126 | var browser = new Browser();
127 |
128 | browser.open("file://" + __dirname + "/browser-tests/alert.html");
129 | browser.on('alert', function(text) {
130 | expect(text).to.be('test');
131 | });
132 | browser.do(function(driver) {
133 | return driver.findElement(webdriver.By.tagName('title'))
134 | .then(function(title) {
135 | title.getInnerHtml().then(function(
136 | titleText) {
137 | expect(titleText).to.be('Alert');
138 | });
139 | });
140 | });
141 | browser.close().then(done);
142 | });
143 |
144 | it('should return the title of the page "Alert2", even with a delayed alert',
145 | function(done) {
146 | var browser = new Browser();
147 | browser.open("file://" + __dirname +
148 | "/browser-tests/alert2.html");
149 | browser.on('alert', function(text) {
150 | expect(text).to.be('test');
151 | });
152 | setTimeout(function() {
153 | browser.do(function(driver) {
154 | return driver.findElement(webdriver.By.tagName(
155 | 'title')).then(function(title) {
156 | title.getInnerHtml().then(function(
157 | titleText) {
158 | expect(titleText).to.be('Alert2');
159 | });
160 | });
161 | });
162 | }, 3500);
163 | browser.close().then(done);
164 | });
165 | });
166 |
--------------------------------------------------------------------------------
/lib/browser-emulator.js:
--------------------------------------------------------------------------------
1 | var webdriver = require('selenium-webdriver');
2 | var metaparser = require('metaviewport-parser');
3 | var fs = require("fs");
4 | var easyimg = require('easyimage');
5 | var EventEmitter = require('events').EventEmitter;
6 | var util = require('util');
7 | var uuid = require('uuid');
8 | var rimraf = require('rimraf');
9 |
10 | var Browser = function(config) {
11 | var display, uaHeader, trackNetwork, browsermobProxy, proxy, driver,
12 | tmpdir, uadir;
13 | var chromeservice;
14 | var networkDataGatheringDone = function() {};
15 | var pendingNetworkDataGathering = 0;
16 | var self = this;
17 | var flow = webdriver.promise.controlFlow();
18 | var driverPromise = new webdriver.promise.Deferred();
19 |
20 | function init() {
21 | config = config || {};
22 | self.webdriver = webdriver;
23 | self.viewport = {};
24 | self.width = config.browserWidth || 320;
25 | self.height = config.browserHeight || 480;
26 | self.desktopWidth = config.browserDekstopWidth || self.width * 3;
27 | self.desktopHeight = config.browserDekstopHeight || self.height * 3;
28 | display = config.displayServer || 0;
29 | uaHeader = config.uaHeader || "";
30 | tmpdir = config.tmpdir || "/tmp";
31 | uadir = tmpdir + "/mobile-checker-" + uuid.v4();
32 | trackNetwork = config.trackNetwork || false;
33 | browsermobProxy = config.browsermobProxy || {
34 | 'host': 'localhost',
35 | 'port': 8080
36 | };
37 | }
38 |
39 | function setupProxy() {
40 | var Proxy = require('browsermob-proxy').Proxy;
41 | proxy = new Proxy({
42 | port: browsermobProxy.port,
43 | host: browsermobProxy.host
44 | });
45 | }
46 |
47 | function setupBrowser(proxyAddr) {
48 | var chromedriver = require("chromedriver");
49 | var chrome = require("selenium-webdriver/chrome");
50 | var proxy = require('selenium-webdriver/proxy');
51 | var capabilities = webdriver.Capabilities.chrome();
52 |
53 | if (proxyAddr) {
54 | var proxyPrefs = proxy.manual({
55 | http: proxyAddr,
56 | https: proxyAddr
57 | });
58 | capabilities.set(webdriver.Capability.PROXY, proxyPrefs);
59 | }
60 |
61 | // enabling metaviewport
62 | var options = new chrome.Options();
63 | //options.addArguments(["--enable-viewport-meta"]);
64 | options.addArguments(["--user-data-dir=" + uadir]);
65 |
66 | if (uaHeader) {
67 | options.addArguments(['--user-agent=' + uaHeader]);
68 | }
69 | options.addArguments(['--disable-bundled-ppapi-flash']);
70 | options.setUserPreferences({"session.startup_urls": ["about:blank"],
71 | "session.restore_on_startup": 4});
72 | capabilities.merge(options.toCapabilities());
73 |
74 | options.detachDriver(false);
75 | process.env.DISPLAY = ':' + display;
76 | chromeservice = new chrome.ServiceBuilder(chromedriver.path)
77 | .withEnvironment(process.env)
78 | .build();
79 | driver = new chrome.Driver(capabilities, chromeservice);
80 | }
81 |
82 | function get(url, done) {
83 | var time = Date.now();
84 | return driver.get(url).then(function() {
85 | time = Date.now() - time;
86 | self.emit('pageSpeed', time);
87 | }).then(function() {
88 | return dontGiveUpOnModal(function(d) {
89 | return setViewPort(d);
90 | }, driver);
91 | });
92 | }
93 |
94 | function reportNetworkTraffic(err, har) {
95 | var data;
96 | if (err) {
97 | self.emit('error', new Error(
98 | "Failed gathering network traffic: " + err));
99 | return;
100 | }
101 | try {
102 | data = JSON.parse(har);
103 | } catch (e) {
104 | self.emit('error', new Error(
105 | "Failed to parse network traffic data from proxy"));
106 | return;
107 | }
108 | pendingNetworkDataGathering = EventEmitter.listenerCount(self, 'har');
109 |
110 | self.emit('har', data, finishNetworkTrafficReport);
111 | if (pendingNetworkDataGathering === 0) {
112 | self.emit('networkdone');
113 | }
114 | }
115 |
116 | function finishNetworkTrafficReport() {
117 | pendingNetworkDataGathering--;
118 | if (pendingNetworkDataGathering === 0) {
119 | self.emit('networkdone');
120 | pendingNetworkDataGathering = null;
121 | }
122 | }
123 |
124 | // dontGiveUp from https://gist.github.com/domenic/2936696
125 | // we need to protect any code sent to the drivder
126 | // from UnexpectedAlertOpenError
127 | // we dismiss alerts 10 times at most
128 | function dontGiveUpOnModal(f, d, count) {
129 | if (!count) {
130 | count = 10;
131 | }
132 | return f(d).then(
133 | undefined, // pass through success
134 | function(err) {
135 | if (err.name === "UnexpectedAlertOpenError" && count >
136 | 0) {
137 | // dismiss alert and retry
138 | var alert = d.switchTo().alert();
139 | alert.getText().then(function(text) {
140 | self.emit('alert', text);
141 | });
142 | return alert.dismiss().then(function() {
143 | dontGiveUpOnModal(f, d, count - 1);
144 | });
145 | }
146 | self.emit('error', err);
147 | self.close();
148 | }
149 | );
150 | }
151 |
152 |
153 | function setViewPort(d) {
154 | var contentAttr;
155 | return d.findElements(webdriver.By.css('meta[name="viewport"]')).then(
156 | function(viewportDecls) {
157 | // return all the metaviewports found
158 | webdriver.promise.map(
159 | viewportDecls,
160 | function(el) {
161 | return el.getAttribute("content");
162 | }
163 | ).then(
164 | function(contentAttrs) {
165 | contentAttr = contentAttrs[contentAttrs.length -
166 | 1];
167 | }
168 | );
169 | }).then(function() {
170 | if (contentAttr) {
171 | var viewportProps = metaparser.parseMetaViewPortContent(
172 | contentAttr);
173 | self.viewport = metaparser.getRenderingDataFromViewport(
174 | viewportProps.validProperties, self.width, self
175 | .height, 4, 0.25);
176 | } else {
177 | self.viewport = {
178 | zoom: null,
179 | width: self.desktopWidth,
180 | height: self.desktopHeight
181 | };
182 | }
183 | return d.manage().window().setSize(
184 | self.viewport.width,
185 | self.viewport.height + 97 //97px for the browser UI
186 | );
187 | }).then(function() {
188 | return d.executeScript(function() {
189 | // remove scrollbar
190 | // TODO webkit specific
191 |
192 | var style = document.createElement("style");
193 | var cssNoScrollbar = document.createTextNode(
194 | "::-webkit-scrollbar { width: 0; height: 0;} body { overflow: hidden}"
195 | );
196 | style.appendChild(cssNoScrollbar);
197 | document.getElementsByTagName("head")[0].appendChild(
198 | style);
199 | }).then(driverPromise.fulfill(d));
200 | });
201 | }
202 |
203 | this.close = function(processToKill) {
204 | return self.do(function(d) {
205 | var p = new webdriver.promise.Promise(function(res, rej) {
206 | networkDataGatheringDone();
207 | self.on('networkdone', res);
208 | }).then(function() {
209 | self.emit('done');
210 | return d.close().then(d.quit.bind(d)).then(chromeservice.stop.bind(chromeservice)).then(function() {
211 | rimraf(uadir, function () {});
212 | processToKill.kill();
213 | });
214 | });
215 | return p;
216 | });
217 | };
218 |
219 | this.open = function(url) {
220 | if (trackNetwork) {
221 | setupProxy();
222 | var setupProxyAndGet = function() {
223 | return function(proxyAddr, done) {
224 | setupBrowser(proxyAddr);
225 | networkDataGatheringDone = done;
226 | flow.execute(function() {
227 | get(url);
228 | });
229 | };
230 | };
231 | flow.execute(function() {
232 | proxy.cbHAR({
233 | name: url,
234 | captureHeaders: true,
235 | captureContent: true,
236 | captureBinaryContent: true
237 | }, setupProxyAndGet(), reportNetworkTraffic);
238 | });
239 | } else {
240 | setupBrowser();
241 | return get(url);
242 | }
243 | };
244 |
245 | this.do = function(fn) {
246 | return driverPromise.then(function(d) {
247 | return dontGiveUpOnModal(function() {
248 | return flow.execute(
249 | function() {
250 | fn(d);
251 | });
252 | }, d);
253 | });
254 | };
255 |
256 | this.takeScreenshot = function(path) {
257 | return self.do(function(d) {
258 | d.takeScreenshot().then(function(data) {
259 | var base64Data = data.replace(
260 | /^data:image\/png;base64,/, "");
261 | fs.writeFile(path, base64Data, 'base64',
262 | function(err) {
263 | if (err) {
264 | self.emit('error', err);
265 | } else {
266 | console.log(path);
267 | // resize the screenshot
268 | easyimg.resize({
269 | src: path,
270 | dst: path,
271 | width: self.width,
272 | height: self.height
273 | })
274 | .then(function() {
275 | self.emit('screenshot',
276 | path);
277 | }, function(err) {
278 | console.log(err);
279 | self.emit('error', err);
280 | });
281 | }
282 | });
283 | });
284 | });
285 | };
286 |
287 | init();
288 | };
289 |
290 | util.inherits(Browser, EventEmitter);
291 |
292 | exports.Browser = Browser;
293 |
--------------------------------------------------------------------------------