Skip to content

Commit

Permalink
Emit stderr message type if identified (#5215)
Browse files Browse the repository at this point in the history
  • Loading branch information
seanpoulter authored and cpojer committed Jan 3, 2018
1 parent c321129 commit ca5d0fc
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 51 deletions.
8 changes: 8 additions & 0 deletions packages/jest-editor-support/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,11 @@ export interface JestTotalResults {
export interface JestTotalResultsMeta {
noTestsFound: boolean;
}

export enum MessageTypes {
noTests = 1,
unknown = 0,
watchUsage = 2,
}

export type MessageType = number;
46 changes: 26 additions & 20 deletions packages/jest-editor-support/src/Runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
* @flow
*/

import type {Options} from './types';
import type {Options, MessageType} from './types';
import {messageTypes} from './types';

import {ChildProcess, spawn} from 'child_process';
import {readFile} from 'fs';
Expand All @@ -29,7 +30,7 @@ export default class Runner extends EventEmitter {
) => ChildProcess;
watchMode: boolean;
options: Options;
prevMessageTypes: number[];
prevMessageTypes: MessageType[];

constructor(workspace: ProjectWorkspace, options?: Options) {
super();
Expand Down Expand Up @@ -79,7 +80,6 @@ export default class Runner extends EventEmitter {
this.emit('terminalError', message);
} else {
const noTestsFound = this.doResultsFollowNoTestsFoundMessage();

this.emit('executableJSON', JSON.parse(data), {noTestsFound});
}
});
Expand All @@ -90,16 +90,14 @@ export default class Runner extends EventEmitter {
});

this.debugprocess.stderr.on('data', (data: Buffer) => {
this.emit('executableStdErr', data);

const slice = data.toString('utf8', 0, 58);
if (
slice === 'No tests found related to files changed since last commit.'
) {
this.prevMessageTypes.push(messageType.noTests);
} else if (/^\s*Watch Usage\b/.test(slice)) {
this.prevMessageTypes.push(messageType.watchUsage);
const type = this.findMessageType(data);
if (type === messageTypes.unknown) {
this.prevMessageTypes.length = 0;
} else {
this.prevMessageTypes.push(type);
}

this.emit('executableStdErr', data, {type});
});

this.debugprocess.on('exit', () => {
Expand Down Expand Up @@ -142,23 +140,31 @@ export default class Runner extends EventEmitter {
delete this.debugprocess;
}

findMessageType(buf: Buffer) {
const str = buf.toString('utf8', 0, 58);
if (str === 'No tests found related to files changed since last commit.') {
return messageTypes.noTests;
}

if (/^\s*Watch Usage\b/.test(str)) {
return messageTypes.watchUsage;
}

return messageTypes.unknown;
}

doResultsFollowNoTestsFoundMessage() {
if (this.prevMessageTypes.length === 1) {
return this.prevMessageTypes[0] === messageType.noTests;
return this.prevMessageTypes[0] === messageTypes.noTests;
}

if (this.prevMessageTypes.length === 2) {
return (
this.prevMessageTypes[0] === messageType.noTests &&
this.prevMessageTypes[1] === messageType.watchUsage
this.prevMessageTypes[0] === messageTypes.noTests &&
this.prevMessageTypes[1] === messageTypes.watchUsage
);
}

return false;
}
}

const messageType = {
noTests: 1,
watchUsage: 2,
};
111 changes: 80 additions & 31 deletions packages/jest-editor-support/src/__tests__/runner.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const path = require('path');
const {readFileSync} = require('fs');
const fixtures = path.resolve(__dirname, '../../../../fixtures');
import ProjectWorkspace from '../project_workspace';
import {messageTypes} from '../types';

// Replace `readFile` with `readFileSync` so we don't get multiple threads
jest.doMock('fs', () => {
Expand Down Expand Up @@ -101,28 +102,14 @@ describe('events', () => {
expect(mockCreateProcess).toHaveBeenCalledTimes(2);
});

const messageType = {
noTests: 1,
watchUsage: 2,
};

describe('stdout.on("data")', () => {
it('should indicate when test results follow "No tests found related to files changed since the last commit"', () => {
const listener = jest.fn();
runner.on('executableJSON', listener);
runner.outputPath = `${fixtures}/failing_jsons/failing_jest_json.json`;
runner.prevMessageTypes.push(messageType.noTests);
fakeProcess.stdout.emit('data', 'Test results written to file');

expect(listener.mock.calls[0].length).toBe(2);
expect(listener.mock.calls[0][1]).toEqual({noTestsFound: true});
});

it('should indicate when test results follow "No tests found related to files changed since the last commit" and "Watch Usage"', () => {
it('should emit an "executableJSON" event with the "noTestsFound" meta data property set', () => {
const listener = jest.fn();
runner.on('executableJSON', listener);
runner.outputPath = `${fixtures}/failing_jsons/failing_jest_json.json`;
runner.prevMessageTypes.push(messageType.noTests, messageType.watchUsage);
(runner: any).doResultsFollowNoTestsFoundMessage = jest
.fn()
.mockReturnValueOnce(true);
fakeProcess.stdout.emit('data', 'Test results written to file');

expect(listener.mock.calls[0].length).toBe(2);
Expand All @@ -131,22 +118,51 @@ describe('events', () => {

it('should clear the message type history', () => {
runner.outputPath = `${fixtures}/failing_jsons/failing_jest_json.json`;
runner.prevMessageTypes.push(messageType.noTests);
runner.prevMessageTypes.push(messageTypes.noTests);
fakeProcess.stdout.emit('data', 'Test results written to file');

expect(runner.prevMessageTypes.length).toBe(0);
});
});

describe('stderr.on("data")', () => {
it('should emit an "executableStdErr" event', () => {
it('should identify the message type', () => {
(runner: any).findMessageType = jest.fn();
const expected = {};
fakeProcess.stderr.emit('data', expected);

expect(runner.findMessageType).toBeCalledWith(expected);
});

it('should add the type to the message type history when known', () => {
(runner: any).findMessageType = jest
.fn()
.mockReturnValueOnce(messageTypes.noTests);
fakeProcess.stderr.emit('data', Buffer.from(''));

expect(runner.prevMessageTypes).toEqual([messageTypes.noTests]);
});

it('should clear the message type history when the type is unknown', () => {
(runner: any).findMessageType = jest
.fn()
.mockReturnValueOnce(messageTypes.unknown);
fakeProcess.stderr.emit('data', Buffer.from(''));

expect(runner.prevMessageTypes).toEqual([]);
});

it('should emit an "executableStdErr" event with the type', () => {
const listener = jest.fn();
const expected = Buffer.from('');
const data = Buffer.from('');
const type = {};
const meta = {type};
(runner: any).findMessageType = jest.fn().mockReturnValueOnce(type);

runner.on('executableStdErr', listener);
fakeProcess.stderr.emit('data', expected);
fakeProcess.stderr.emit('data', data, meta);

expect(listener).toBeCalledWith(expected);
expect(listener).toBeCalledWith(data, meta);
});

it('should track when "No tests found related to files changed since the last commit" is received', () => {
Expand All @@ -156,14 +172,7 @@ describe('events', () => {
);
fakeProcess.stderr.emit('data', data);

expect(runner.prevMessageTypes).toEqual([messageType.noTests]);
});

it('should track when the "Watch Usage" prompt is received', () => {
const data = Buffer.from('\n\nWatch Usage\n...');
fakeProcess.stderr.emit('data', data);

expect(runner.prevMessageTypes).toEqual([messageType.watchUsage]);
expect(runner.prevMessageTypes).toEqual([messageTypes.noTests]);
});

it('should clear the message type history when any other other data is received', () => {
Expand All @@ -173,4 +182,44 @@ describe('events', () => {
expect(runner.prevMessageTypes).toEqual([]);
});
});

describe('findMessageType()', () => {
it('should return "unknown" when the message is not matched', () => {
const buf = Buffer.from('');
expect(runner.findMessageType(buf)).toBe(messageTypes.unknown);
});

it('should identify "No tests found related to files changed since last commit."', () => {
const buf = Buffer.from(
'No tests found related to files changed since last commit.\n' +
'Press `a` to run all tests, or run Jest with `--watchAll`.',
);
expect(runner.findMessageType(buf)).toBe(messageTypes.noTests);
});

it('should identify the "Watch Usage" prompt', () => {
const buf = Buffer.from('\n\nWatch Usage\n...');
expect(runner.findMessageType(buf)).toBe(messageTypes.watchUsage);
});
});

describe('doResultsFollowNoTestsFoundMessage()', () => {
it('should return true when the last message on stderr was "No tests found..."', () => {
runner.prevMessageTypes.push(messageTypes.noTests);
expect(runner.doResultsFollowNoTestsFoundMessage()).toBe(true);
});

it('should return true when the last two messages on stderr were "No tests found..." and "Watch Usage"', () => {
runner.prevMessageTypes.push(
messageTypes.noTests,
messageTypes.watchUsage,
);
expect(runner.doResultsFollowNoTestsFoundMessage()).toBe(true);
});

it('should return false otherwise', () => {
runner.prevMessageTypes.length = 0;
expect(runner.doResultsFollowNoTestsFoundMessage()).toBe(false);
});
});
});
8 changes: 8 additions & 0 deletions packages/jest-editor-support/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,11 @@ export type TestAssertionStatus = {
export type JestTotalResultsMeta = {
noTestsFound: boolean,
};

export const messageTypes = {
noTests: 1,
unknown: 0,
watchUsage: 2,
};

export type MessageType = number;

0 comments on commit ca5d0fc

Please sign in to comment.