Skip to content

Commit 51f97f8

Browse files
authored
Merge pull request #25 from NimaSoroush/getport
Add dynamic port allocation for chrome instances
2 parents 41c0274 + 96362ea commit 51f97f8

File tree

4 files changed

+97
-70
lines changed

4 files changed

+97
-70
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## [0.0.14] - 2017-08-01
2+
### Added
3+
- Assign free ports to run chrome instances
4+
15
## [0.0.13] - 2017-07-25
26
### Added
37
- Updating readme file

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "differencify",
3-
"version": "0.0.13",
3+
"version": "0.0.14",
44
"description": "Perceptual diffing tool",
55
"main": "dist/index.js",
66
"scripts": {
@@ -50,6 +50,7 @@
5050
"check-types": "^7.2.0",
5151
"chromy": "^0.3.6",
5252
"fs": "0.0.1-security",
53+
"get-port": "^3.1.0",
5354
"jimp": "^0.2.28"
5455
},
5556
"jest": {

src/index.js

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import 'babel-polyfill';
22
import fs from 'fs';
33
import Chromy from 'chromy';
4+
import getPort from 'get-port';
45
import { sanitiseGlobalConfiguration, sanitiseTestConfiguration } from './sanitiser';
56
import run from './chromyRunner';
67
import logger from './logger';
78
import { configTypes } from './defaultConfig';
89
import actions from './actions';
910

10-
const CHROME_PORT = 9222;
1111
const CHROME_WIDTH = 800;
1212
const CHROME_HEIGHT = 600;
1313

@@ -18,73 +18,84 @@ const createDir = (path) => {
1818
}
1919
};
2020

21+
const getFreePort = async () => {
22+
try {
23+
return await getPort();
24+
} catch (error) {
25+
logger.error('Failed to get a free port', error);
26+
return null;
27+
}
28+
};
29+
2130
export default class Differencify {
2231
constructor(conf) {
2332
this.configuration = sanitiseGlobalConfiguration(conf);
2433
this.chromeInstances = {};
25-
this.chromeInstancesId = CHROME_PORT;
2634
if (this.configuration.debug === true) {
2735
logger.enable();
2836
}
2937
createDir(this.configuration.screenshots);
3038
createDir(this.configuration.testReportPath);
3139
}
3240

33-
_createChromeInstance(testConfig) {
41+
async _createChromeInstance(testConfig) {
3442
const width = testConfig.resolution.width || CHROME_WIDTH;
3543
const height = testConfig.resolution.height || CHROME_HEIGHT;
3644
const flags = [`--window-size=${width},${height}`];
45+
const port = await getFreePort();
46+
if (!port) {
47+
return null;
48+
}
3749
const chromy = new Chromy({
50+
port,
3851
chromeFlags: flags,
39-
port: this.chromeInstancesId,
4052
waitTimeout: this.configuration.timeout,
4153
visible: this.configuration.visible,
4254
});
4355
return chromy;
4456
}
4557

46-
_updateChromeInstances(id, chromy) {
47-
this.chromeInstances[id] = chromy;
48-
this.chromeInstancesId += 1;
58+
_updateChromeInstances(chromy) {
59+
this.chromeInstances[chromy.options.port] = chromy;
4960
}
5061

51-
async _closeChrome(id, chromy) {
62+
async _closeChrome(chromy, testName) {
5263
try {
53-
logger.log('closing browser');
64+
logger.prefix(testName).log('closing browser');
5465
await chromy.close();
55-
delete this.chromeInstances[id];
66+
delete this.chromeInstances[chromy.options.port];
5667
} catch (error) {
57-
logger.error(error);
68+
logger.prefix(testName).log(error);
5869
}
5970
}
6071

61-
async _run(config, type, step) {
72+
async _run(config, type) {
6273
const testConfig = sanitiseTestConfiguration(config);
63-
const chromy = this._createChromeInstance(testConfig);
64-
const testId = this.chromeInstancesId;
65-
this._updateChromeInstances(testId, chromy);
66-
testConfig.type = type;
67-
if (step) {
68-
testConfig.steps.push(step);
74+
const chromy = await this._createChromeInstance(testConfig);
75+
if (!chromy) {
76+
return false;
6977
}
78+
this._updateChromeInstances(chromy);
79+
testConfig.type = type;
7080
const result = await run(chromy, this.configuration, testConfig);
71-
await this._closeChrome(testId, chromy);
81+
await this._closeChrome(chromy, testConfig.name);
7282
return result;
7383
}
7484

7585
async update(config) {
76-
return await this._run(config, configTypes.update, null);
86+
return await this._run(config, configTypes.update);
7787
}
7888

7989
async test(config) {
80-
const testStep = { name: actions.test, value: this.configuration.testReportPath };
81-
return await this._run(config, configTypes.test, testStep);
90+
config.steps.push({ name: actions.test, value: this.configuration.testReportPath });
91+
return await this._run(config, configTypes.test);
8292
}
8393

8494
async cleanup() {
8595
await Promise.all(
8696
Object.values(this.chromeInstances).map(chromeInstance => chromeInstance.close()),
8797
);
98+
this.chromeInstances = {};
8899
logger.log('All browsers been closed');
89100
}
90101
}

src/index.test.js

Lines changed: 58 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,33 @@
11
import fs from 'fs';
22
import Chromy from 'chromy';
3+
import getPort from 'get-port';
34
import Differencify from './index';
45
import logger from './logger';
6+
import run from './chromyRunner';
57

6-
let chromyCloseCallsCounter = 0;
7-
jest.mock('chromy', () => jest.fn(() =>
8-
({
9-
goto: jest.fn(),
10-
close: jest.fn(() => { chromyCloseCallsCounter += 1; }),
11-
screenshotDocument: jest.fn(() => 'png file'),
12-
screenshotSelector: jest.fn(() => 'png file'),
13-
}),
14-
));
8+
jest.mock('get-port', () => jest.fn(() => 3000));
9+
const mockClose = jest.fn();
10+
jest.mock('chromy', () => () =>
11+
({
12+
close: mockClose,
13+
options: { port: 3000 },
14+
}));
15+
jest.mock('./chromyRunner', () => jest.fn(() => true));
1516

16-
jest.mock('./compareImage', () => jest.fn(arg =>
17-
new Promise((resolve, reject) => {
18-
if (arg.screenshots === 'screenshots') {
19-
return resolve('Saving the diff image to disk');
20-
}
21-
return reject('error');
22-
}),
23-
));
17+
jest.mock('fs', () => ({
18+
mkdirSync: jest.fn(),
19+
existsSync: jest.fn(),
20+
}));
2421

25-
let writeFileSyncCalls = [];
26-
fs.writeFileSync = (...args) => {
27-
writeFileSyncCalls.push(...args);
28-
};
29-
fs.mkdirSync = (...args) => {
30-
writeFileSyncCalls.push(...args);
31-
};
32-
33-
let loggerCalls = [];
34-
logger.prefix = () => logger;
35-
logger.log = (...args) => {
36-
loggerCalls.push(...args);
37-
};
22+
const mockLog = jest.fn();
23+
jest.mock('./logger', () => ({
24+
prefix: jest.fn(() => ({
25+
log: mockLog,
26+
})),
27+
log: jest.fn(),
28+
error: jest.fn(),
29+
enable: jest.fn(),
30+
}));
3831

3932
const globalConfig = {
4033
screenshots: 'screenshots',
@@ -59,35 +52,53 @@ const differencify = new Differencify(globalConfig);
5952

6053
describe('Differencify', () => {
6154
afterEach(() => {
62-
loggerCalls = [];
63-
writeFileSyncCalls = [];
64-
chromyCloseCallsCounter = 0;
55+
mockLog.mockClear();
56+
logger.log.mockClear();
57+
run.mockClear();
58+
mockClose.mockClear();
59+
});
60+
it('constructor fn', async () => {
61+
expect(fs.mkdirSync).toHaveBeenCalledWith('screenshots');
62+
expect(fs.mkdirSync).toHaveBeenCalledWith('./differencify_report');
6563
});
6664
it('update fn', async () => {
6765
const result = await differencify.update(testConfig);
6866
expect(result).toEqual(true);
69-
expect(differencify.chromeInstancesId).toEqual(9223);
70-
expect(loggerCalls[0]).toEqual('goto -> www.example.com');
71-
expect(loggerCalls[1]).toEqual('capturing screenshot of whole DOM');
72-
expect(loggerCalls[2]).toEqual('screenshot saved in -> screenshots/default.png');
73-
expect(writeFileSyncCalls).toEqual(['screenshots', './differencify_report', 'screenshots/default.png', 'png file']);
67+
expect(differencify.chromeInstances[3000]).toEqual(undefined);
68+
expect(mockClose).toHaveBeenCalledTimes(1);
69+
expect(mockLog).toHaveBeenCalledWith('closing browser');
70+
expect(run).toHaveBeenCalledTimes(1);
7471
});
7572
it('test fn', async () => {
7673
const result = await differencify.test(testConfig);
7774
expect(result).toEqual(true);
78-
expect(differencify.chromeInstancesId).toEqual(9224);
79-
expect(loggerCalls[0]).toEqual('goto -> www.example.com');
80-
expect(loggerCalls[1]).toEqual('capturing screenshot of whole DOM');
81-
expect(loggerCalls[2]).toEqual('screenshot saved in -> ./differencify_report/default.png');
82-
expect(writeFileSyncCalls).toEqual(['./differencify_report/default.png', 'png file']);
75+
expect(differencify.chromeInstances[3000]).toEqual(undefined);
76+
expect(mockClose).toHaveBeenCalledTimes(1);
77+
expect(mockLog).toHaveBeenCalledWith('closing browser');
78+
expect(run).toHaveBeenCalledTimes(1);
79+
});
80+
it('chromyRunner will fail test fn', async () => {
81+
run.mockReturnValueOnce(Promise.resolve(false));
82+
const result = await differencify.test(testConfig);
83+
expect(result).toEqual(false);
84+
expect(differencify.chromeInstances[3000]).toEqual(undefined);
85+
expect(mockClose).toHaveBeenCalledTimes(1);
86+
expect(mockLog).toHaveBeenCalledWith('closing browser');
87+
expect(run).toHaveBeenCalledTimes(1);
8388
});
8489
it('cleanup fn', async () => {
8590
const chromy1 = new Chromy();
86-
differencify.chromeInstances[1] = chromy1;
8791
const chromy2 = new Chromy();
88-
differencify.chromeInstances[2] = chromy2;
92+
differencify.chromeInstances = [chromy1, chromy2];
8993
await differencify.cleanup();
90-
expect(chromyCloseCallsCounter).toEqual(2);
91-
expect(loggerCalls[0]).toEqual('All browsers been closed');
94+
expect(mockClose).toHaveBeenCalledTimes(2);
95+
expect(differencify.chromeInstances).toEqual({});
96+
expect(logger.log).toHaveBeenCalledWith('All browsers been closed');
97+
});
98+
it('get-port fails test', async () => {
99+
getPort.mockReturnValueOnce(Promise.reject());
100+
const result = await differencify.test(testConfig);
101+
expect(result).toEqual(false);
102+
expect(logger.error).toHaveBeenCalledWith('Failed to get a free port', undefined);
92103
});
93104
});

0 commit comments

Comments
 (0)