Skip to content

Commit

Permalink
address jest 23 compatibility issues (#6586)
Browse files Browse the repository at this point in the history
  • Loading branch information
connectdotz authored and orta committed Jul 1, 2018
1 parent b21a36e commit d787040
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 52 deletions.
14 changes: 13 additions & 1 deletion packages/jest-editor-support/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ export class Settings extends EventEmitter {
getConfig(completed: Function): void;
jestVersionMajor: number | null;
settings: {
testRegex: string;
testRegex: string,
testMatch: string[],
};
}

Expand All @@ -49,12 +50,14 @@ export class ProjectWorkspace {
pathToConfig: string,
localJestMajorVersin: number,
collectCoverage?: boolean,
debug?: boolean,
);
pathToJest: string;
pathToConfig: string;
rootPath: string;
localJestMajorVersion: number;
collectCoverage?: boolean;
debug?: boolean;
}

export interface IParseResults {
Expand Down Expand Up @@ -163,6 +166,7 @@ export interface JestTotalResultsMeta {

export enum messageTypes {
noTests = 1,
testResults = 3,
unknown = 0,
watchUsage = 2,
}
Expand All @@ -182,3 +186,11 @@ export class Snapshot {
constructor(parser?: any, customMatchers?: string[]);
getMetadata(filepath: string): SnapshotMetadata[];
}

type FormattedTestResults = {
testResults: TestResult[]
}

type TestResult = {
name: string
}
7 changes: 7 additions & 0 deletions packages/jest-editor-support/src/Process.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,12 @@ export const createProcess = (
env,
shell: options.shell,
};

if (workspace.debug) {
console.log(
`spawning process with command=${command}, args=${runtimeArgs.toString()}`,
);
}

return spawn(command, runtimeArgs, spawnOptions);
};
80 changes: 51 additions & 29 deletions packages/jest-editor-support/src/Runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,37 +82,14 @@ export default class Runner extends EventEmitter {

this.debugprocess = this._createProcess(this.workspace, args, options);
this.debugprocess.stdout.on('data', (data: Buffer) => {
// Make jest save to a file, otherwise we get chunked data
// and it can be hard to put it back together.
const stringValue = data.toString().trim();

if (stringValue.startsWith('Test results written to')) {
readFile(this.outputPath, 'utf8', (err, data) => {
if (err) {
const message = `JSON report not found at ${this.outputPath}`;
this.emit('terminalError', message);
} else {
const noTestsFound = this.doResultsFollowNoTestsFoundMessage();
this.emit('executableJSON', JSON.parse(data), {noTestsFound});
}
});
} else {
this.emit('executableOutput', stringValue.replace('', ''));
}
this.prevMessageTypes.length = 0;
this._parseOutput(data, false);
});

this.debugprocess.stderr.on('data', (data: Buffer) => {
const type = this.findMessageType(data);
if (type === messageTypes.unknown) {
this.prevMessageTypes.length = 0;
} else {
this.prevMessageTypes.push(type);
}

this.emit('executableStdErr', data, {type});
// jest 23 could send test results message to stderr
// see https://github.com/facebook/jest/pull/4858
this._parseOutput(data, true);
});

this.debugprocess.on('exit', () => {
this.emit('debuggerProcessExit');
this.prevMessageTypes.length = 0;
Expand All @@ -129,10 +106,52 @@ export default class Runner extends EventEmitter {
});
}

_parseOutput(data: Buffer, isStdErr: boolean): MessageType {
const msgType = this.findMessageType(data);
switch (msgType) {
case messageTypes.testResults:
readFile(this.outputPath, 'utf8', (err, data) => {
if (err) {
const message = `JSON report not found at ${this.outputPath}`;
this.emit('terminalError', message);
} else {
const noTestsFound = this.doResultsFollowNoTestsFoundMessage();
this.emit('executableJSON', JSON.parse(data), {
noTestsFound,
});
}
});
this.prevMessageTypes.length = 0;
break;
case messageTypes.watchUsage:
case messageTypes.noTests:
this.prevMessageTypes.push(msgType);
this.emit('executableStdErr', data, {
type: msgType,
});
break;
default:
// no special action needed, just report the output by its source
if (isStdErr) {
this.emit('executableStdErr', data, {
type: msgType,
});
} else {
this.emit('executableOutput', data.toString().replace('', ''));
}
this.prevMessageTypes.length = 0;
break;
}

return msgType;
}

runJestWithUpdateForSnapshots(completion: any, args: string[]) {
const defaultArgs = ['--updateSnapshot'];

const options = {shell: this.options.shell};
const options = {
shell: this.options.shell,
};
const updateProcess = this._createProcess(
this.workspace,
[...defaultArgs, ...(args ? args : [])],
Expand All @@ -156,7 +175,7 @@ export default class Runner extends EventEmitter {
delete this.debugprocess;
}

findMessageType(buf: Buffer) {
findMessageType(buf: Buffer): MessageType {
const str = buf.toString('utf8', 0, 58);
if (str === 'No tests found related to files changed since last commit.') {
return messageTypes.noTests;
Expand All @@ -166,6 +185,9 @@ export default class Runner extends EventEmitter {
return messageTypes.watchUsage;
}

if (str.trim().startsWith('Test results written to')) {
return messageTypes.testResults;
}
return messageTypes.unknown;
}

Expand Down
38 changes: 33 additions & 5 deletions packages/jest-editor-support/src/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,15 @@ export default class Settings extends EventEmitter {
settings: ConfigRepresentation;
workspace: ProjectWorkspace;
spawnOptions: SpawnOptions;
_jsonPattern: RegExp;

constructor(workspace: ProjectWorkspace, options?: Options) {
super();
this.workspace = workspace;
this._createProcess = (options && options.createProcess) || createProcess;
this.spawnOptions = {shell: options && options.shell};
this.spawnOptions = {
shell: options && options.shell,
};

// Defaults for a Jest project
this.settings = {
Expand All @@ -60,6 +63,34 @@ export default class Settings extends EventEmitter {
};

this.configs = [this.settings];
this._jsonPattern = new RegExp(/^[\s]*\{/gm);
}

_parseConfig(text: string): void {
let settings = null;

try {
settings = JSON.parse(text);
} catch (err) {
// skip the non-json content, if any
const idx = text.search(this._jsonPattern);
if (idx > 0) {
if (this.workspace.debug) {
console.log(`skip config output noise: ${text.substring(0, idx)}`);
}
this._parseConfig(text.substring(idx));
return;
}
console.warn(`failed to parse config: \n${text}\nerror: ${err}`);
throw err;
}
this.jestVersionMajor = parseInt(settings.version.split('.').shift(), 10);
this.configs =
this.jestVersionMajor >= 21 ? settings.configs : [settings.config];

if (this.workspace.debug) {
console.log(`found config jestVersionMajor=${this.jestVersionMajor}`);
}
}

getConfigs(completed: any) {
Expand All @@ -70,10 +101,7 @@ export default class Settings extends EventEmitter {
);

this.getConfigProcess.stdout.on('data', (data: Buffer) => {
const settings = JSON.parse(data.toString());
this.jestVersionMajor = parseInt(settings.version.split('.').shift(), 10);
this.configs =
this.jestVersionMajor >= 21 ? settings.configs : [settings.config];
this._parseConfig(data.toString());
});

// They could have an older build of Jest which
Expand Down
23 changes: 15 additions & 8 deletions packages/jest-editor-support/src/__tests__/runner.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -345,20 +345,27 @@ describe('events', () => {
runner.start();
});

it('expects JSON from stdout, then it passes the JSON', () => {
it('expects JSON from both stdout and stderr, then it passes the JSON', () => {
const data = jest.fn();
runner.on('executableJSON', data);

runner.outputPath = `${fixtures}/failing-jsons/failing_jest_json.json`;

// Emitting data through stdout should trigger sending JSON
fakeProcess.stdout.emit('data', 'Test results written to file');
expect(data).toBeCalled();
const doTest = (out: stream$Readable) => {
data.mockClear();

// And lets check what we emit
const dataAtPath = readFileSync(runner.outputPath);
const storedJSON = JSON.parse(dataAtPath.toString());
expect(data.mock.calls[0][0]).toEqual(storedJSON);
// Emitting data through stdout should trigger sending JSON
out.emit('data', 'Test results written to file');
expect(data).toBeCalled();

// And lets check what we emit
const dataAtPath = readFileSync(runner.outputPath);
const storedJSON = JSON.parse(dataAtPath.toString());
expect(data.mock.calls[0][0]).toEqual(storedJSON);
};

doTest(fakeProcess.stdout);
doTest(fakeProcess.stderr);
});

it('emits errors when process errors', () => {
Expand Down
Loading

0 comments on commit d787040

Please sign in to comment.