Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP #13

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open

WIP #13

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 10 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ const _ = require('lodash');
const path = require('path');
const fs = require('fs-extra');
const parseConfig = require('./lib/config');
const StreamWriter = require('./lib/stream-writer');
const DataFile = require('./lib/data-file');
const wrapCommands = require('./lib/commands-wrapper');

module.exports = (hermione, opts) => {
const pluginConfig = parseConfig(opts);

if (!pluginConfig.enabled) {
return;
}

let writeStream;
if (hermione.isWorker()) {
hermione.on(hermione.events.NEW_BROWSER, wrapCommands);
return;
}

let dataFile = DataFile.create(pluginConfig.path);
const retriesMap = _(hermione.config.getBrowserIds())
.zipObject()
.mapValues(() => new Map())
.value();

hermione.on(hermione.events.RUNNER_START, () => {
writeStream = StreamWriter.create(pluginConfig.path);
});

hermione.on(hermione.events.RETRY, (test) => {
const fullTitle = test.fullTitle();

Expand All @@ -49,15 +49,11 @@ module.exports = (hermione, opts) => {
}

test.timeEnd = Date.now();
writeStream.write(test);
dataFile.write(test);
});

hermione.on(hermione.events.ERROR, () => writeStream.end());

hermione.on(hermione.events.NEW_BROWSER, wrapCommands);

hermione.on(hermione.events.RUNNER_END, () => {
writeStream.end();
hermione.on(hermione.events.RUNNER_END, async () => {
await dataFile.end();
copyToReportDir(pluginConfig.path, ['index.html', 'bundle.min.js', 'styles.css']);
});
};
Expand Down
24 changes: 12 additions & 12 deletions lib/stream-writer.js → lib/data-file.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ const path = require('path');
const fs = require('fs-extra');
const _ = require('lodash');

module.exports = class StreamWriter {
module.exports = class DataFile {
static create(reportPath) {
return new StreamWriter(reportPath);
return new this(reportPath);
}

constructor(reportPath) {
fs.ensureDirSync(reportPath);
this._stream = fs.createWriteStream(path.join(reportPath, 'data.js'));
this._promise = fs.ensureDir(reportPath)
.then(() => fs.open(path.join(reportPath, 'data.js')))
.then((fd) => this._fd = fd)
.then(() => fs.appendFile(this._fd, 'const data = ['));
}

write(data) {
Expand All @@ -31,16 +33,14 @@ module.exports = class StreamWriter {
testInfo.r = retry;
}

this._writeDelim();
this._stream.write(JSON.stringify(testInfo));
const chunk = `${JSON.stringify(testInfo)},`;
this._promise = this._promise
.then(() => fs.appendFile(this._fd, chunk));
}

end() {
this._stream.end(']');
}

_writeDelim() {
this._stream.write('const data = [');
this._writeDelim = () => this._stream.write(',');
return this._promise
.then(() => fs.appendFile(this._fd, ']'))
.then(() => fs.close(this._fd));
}
};
15 changes: 12 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Plugin for hermione for commands execution profiling",
"scripts": {
"lint": "eslint .",
"test": "npm run lint && npm run test-unit",
"test": "npm run test-unit && npm run lint",
"test-unit": "mocha test",
"build": "webpack --config webpack.prod.js",
"prepublish": "npm run build",
Expand Down Expand Up @@ -41,9 +41,10 @@
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"chai": "^4.0.2",
"chai-as-promised": "^7.1.1",
"css-loader": "^0.28.7",
"eslint": "^3.19.0",
"eslint-config-gemini-testing": "^2.4.0",
"eslint-config-gemini-testing": "^2.8.0",
"material-ui": "^0.19.3",
"mocha": "^3.4.2",
"proxyquire": "^1.8.0",
Expand Down
224 changes: 224 additions & 0 deletions test/lib/data-file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
'use strict';

const fs = require('fs-extra');
const DataFile = require('../../lib/data-file');

describe('stream writer', () => {
const sandbox = sinon.sandbox.create();
// let streamStub;

const dataStub = (opts = {}) => {
return Object.assign(
{browserId: 'default-browser'},
opts,
{fullTitle: () => opts.fullTitle || 'defaultFullTitle'}
);
};

const mkDataFile = (reportPath = 'default/path') => {
return DataFile.create(reportPath);
};

beforeEach(() => {
// streamStub = {
// write: sinon.stub().named('write'),
// end: sinon.stub().named('end')
// };
// sandbox.stub(fs, 'ensureDirSync');
// sandbox.stub(fs, 'createWriteStream').returns(streamStub);

sandbox.stub(fs, 'appendFile');
sandbox.stub(fs, 'ensureDir').resolves();
sandbox.stub(fs, 'open').resolves(12345);
sandbox.stub(fs, 'close').resolves();
});

afterEach(() => sandbox.restore());

it('should return promise on end call');
it('should not do any fs stuff on create');

describe('create', () => {
it('should create ensure target dir is exists', async () => {
const dataFile = mkDataFile('report/path');

await dataFile.end();

assert.calledOnceWith(fs.ensureDir, 'report/path');
});

it('should open data file in target dir', async () => {
const dataFile = mkDataFile('report/path');

await dataFile.end();

assert.calledOnceWith(fs.open, 'report/path/data.js');
});

it('should write opening bracket into data file', async () => {
fs.open.resolves(100500);
const dataFile = mkDataFile();

await dataFile.end();

assert.calledWith(fs.appendFile, 100500, 'const data = [');
});
});

describe('write', () => {
const getWrittenData = () => {
return JSON.parse(fs.appendFile.secondCall.args[1].replace(/,$/, ''));
};

const write = async (data) => {
const dataFile = mkDataFile();
dataFile.write(data);
await dataFile.end();
};

it('should append data to file', async () => {
fs.open.resolves(100500);
const dataFile = mkDataFile();

dataFile.write(dataStub());
await dataFile.end();

assert.calledThrice(fs.appendFile);
assert.alwaysCalledWith(fs.appendFile, 100500, sinon.match.string);
});

it('should write data with coma at the end', async () => {
await write(dataStub());

const writtenData = fs.appendFile.secondCall.args[1];
assert.match(writtenData, /,$/);
});

it('should write test full title', async () => {
await write(dataStub({
fullTitle: 'test1'
}));

assert.match(getWrittenData(), {
n: 'test1'
});
});

it('should write command list from hermioneCtx', async () => {
await write(dataStub({
hermioneCtx: {
commandList: [{cl: [1]}]
}
}));

assert.match(getWrittenData(), {
cl: [1]
});
});

it('should write empty command list if there is no command list in data')

it('should write timings', async () => {
await write(dataStub({
timeStart: 100400,
timeEnd: 100500
}));

assert.match(getWrittenData(), {
ts: 100400,
te: 100500,
d: 100 // duration
});
});

it('should write browser data', async () => {
await write(dataStub({
browserId: 'bro',
sessionId: '100500'
}));

assert.match(getWrittenData(), {
bid: 'bro',
sid: '100500'
});
});

it('should write retry', async () => {
await write(dataStub({
retry: 100500
}));

assert.match(getWrittenData(), {
r: 100500
});
});

it('should not write retry there is no retry in data', async () => {
await write(dataStub());

assert.notProperty(getWrittenData(), 'r');
});

// it('should write object with command list from data', () => {
// const stream = DataFile.create('report/path');
// const data = dataStub({
// fullTitle: 'test1',
// hermioneCtx: {
// commandList: [{cl: [1]}]
// }
// });

// stream.write(data);
// const passedData = JSON.parse(streamStub.write.secondCall.args[0]);

// assert.deepEqual(passedData.cl, [1]);
// });

// it('should write object with empty command list if it does not exist in data', () => {
// const stream = DataFile.create('report/path');
// const data = dataStub({fullTitle: 'test1'});

// stream.write(data);
// const passedData = JSON.parse(streamStub.write.secondCall.args[0]);

// assert.deepEqual(passedData.cl, []);
// });

// it('should divide data chains with comma delimiter', () => {
// const stream = DataFile.create('report/path');

// stream.write(dataStub());
// stream.write(dataStub());

// // calls: 1 - open bracket, 2 - first data, 3 - delim, 4 - second data
// assert.calledWithExactly(streamStub.write.thirdCall, ',');
// });
});

describe('end', () => {
it('should reject if failed to open file', async () => {
fs.open.rejects(new Error('foo'));
const dataFile = mkDataFile();

await assert.isRejected(dataFile.end(), /foo/);
});

it('should add closing bracket to data file', async () => {
fs.open.resolves(100500);
const dataFile = mkDataFile();

await dataFile.end();

assert.calledWith(fs.appendFile, 100500, ']');
});

it('should close file', async () => {
fs.open.resolves(100500);
const dataFile = mkDataFile();

await dataFile.end();

assert.calledOnceWith(fs.close, 100500);
});
});
});
Loading