Skip to content
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ Bug-fixes within the same version aren't needed

* upgrade to the latest jest version (24.7.x) - connectdotz

* [breaking change] Replace the `Settings` class with a `getSettings` function - stephtr

`getSettings` now simply returns a promise resolving to jest's config.

-->

### 25.0.0
Expand Down
8 changes: 7 additions & 1 deletion babel.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
module.exports = {
presets: ['@babel/preset-env', '@babel/flow'],
presets: [
[
'@babel/preset-env',
{ useBuiltIns: 'usage' }
],
'@babel/flow',
],
};
16 changes: 7 additions & 9 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import {EventEmitter} from 'events';
import {ChildProcess} from 'child_process';
import {Config as JestConfig} from '@jest/types';

export interface SpawnOptions {
shell?: boolean;
Expand All @@ -33,15 +34,12 @@ export class Runner extends EventEmitter {
runJestWithUpdateForSnapshots(completion: () => void, args?: string[]): void;
}

export class Settings extends EventEmitter {
constructor(workspace: ProjectWorkspace, options?: Options);
getConfig(completed: Function): void;
jestVersionMajor: number | null;
settings: {
testRegex: string,
testMatch: string[],
};
}
export interface JestSettings {
jestVersionMajor: number;
configs: JestConfig.ProjectConfig[];
};

export function getSettings(workspace: ProjectWorkspace, options?: Options): Promise<JestSettings>;

export class ProjectWorkspace {
constructor(
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@
},
"dependencies": {
"@babel/traverse": "^7.1.2",
"@jest/types": "^24.8.0",
"babylon": "^6.14.1",
"jest-config": "^24.7.0",
"jest-snapshot": "^24.7.0",
"typescript": "^3.4.3"
},
Expand Down
151 changes: 63 additions & 88 deletions src/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,113 +7,88 @@
* @flow
*/

import {ChildProcess} from 'child_process';
import EventEmitter from 'events';
import {defaults as jestConfigDefaults} from 'jest-config';
import type {Options, SpawnOptions} from './types';
import type {Options} from './types';
import ProjectWorkspace from './project_workspace';
import {createProcess} from './Process';

// This class represents the the configuration of Jest's process
// we want to start with the defaults then override whatever they output
// the interface below can be used to show what we use, as currently the whole
// settings object will be in memory.

// Ideally anything you care about adding should have a default in
// the constructor see https://jestjs.io/docs/configuration.html
// for full deets

// For now, this is all we care about inside the config

type Glob = string;

type ConfigRepresentation = {
// This class represents the configuration of Jest's process.
// The interface below can be used to show what we use, as currently the whole
// settings object will be in memory.
// As soon as the code will be converted to TypeScript, this will be removed
// in favor of `@jest/types`, which exports the full config interface.

type ProjectConfiguration = {
testRegex: string | Array<string>,
testMatch: Array<Glob>,
};

type ConfigRepresentations = Array<ConfigRepresentation>;

export default class Settings extends EventEmitter {
getConfigProcess: ChildProcess;

jestVersionMajor: number | null;

_createProcess: (workspace: ProjectWorkspace, args: Array<string>, options: SpawnOptions) => ChildProcess;

configs: ConfigRepresentations;

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,
};

const {testMatch, testRegex} = jestConfigDefaults;

this.settings = {testMatch, testRegex};

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

_parseConfig(text: string): void {
let settings = null;
type JestSettings = {
jestVersionMajor: number,
configs: ProjectConfiguration[],
};

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) {
// eslint-disable-next-line no-console
console.log(`skip config output noise: ${text.substring(0, idx)}`);
}
this._parseConfig(text.substring(idx));
return;
function parseSettings(text: string, debug: ?boolean = false): JestSettings {
const jsonPattern = new RegExp(/^[\s]*\{/gm);
let settings = null;

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

if (this.workspace.debug) {
// eslint-disable-next-line no-console
console.log(`found config jestVersionMajor=${this.jestVersionMajor}`);
}
const jestVersionMajor = parseInt(settings.version.split('.').shift(), 10);
if (debug) {
// eslint-disable-next-line no-console
console.log(`found config jestVersionMajor=${jestVersionMajor}`);
}

getConfigs(completed: any) {
this.getConfigProcess = this._createProcess(this.workspace, ['--showConfig'], this.spawnOptions);
return {
jestVersionMajor,
configs: Array.isArray(settings.configs) ? settings.configs : [settings.config],
};
}

export default function getSettings(workspace: ProjectWorkspace, options?: Options): Promise<JestSettings> {
return new Promise((resolve, reject) => {
const _createProcess = (options && options.createProcess) || createProcess;
const spawnOptions = {
shell: options && options.shell,
};
const getConfigProcess = _createProcess(workspace, ['--showConfig'], spawnOptions);

this.getConfigProcess.stdout.on('data', (data: Buffer) => {
this._parseConfig(data.toString());
let configString = '';
getConfigProcess.stdout.on('data', (data: Buffer) => {
configString += data.toString();
});

// They could have an older build of Jest which
// would error with `--showConfig`
this.getConfigProcess.on('close', () => {
completed();
let rejected = false;
getConfigProcess.stderr.on('data', (data: Buffer) => {
rejected = true;
reject(data.toString());
});
}

getConfig(completed: any, index: number = 0) {
this.getConfigs(() => {
this.settings = this.configs[index];
completed();
getConfigProcess.on('close', () => {
if (!rejected) {
try {
resolve(parseSettings(configString, workspace.debug));
} catch (err) {
reject(err);
}
}
});
}
});
}
Loading