From f76ae0cc2b2f307ba3a82fd4def52dd77e2d49d0 Mon Sep 17 00:00:00 2001 From: Mojadev Date: Mon, 3 Sep 2018 22:16:42 +0200 Subject: [PATCH] jest-editor-support: Add support for Windows Subsystem for Linux in Runner * Add useWsl configuration flag to project worksapce * Translate windows paths in call args to POSIX paths valid in WSL see https://github.com/jest-community/vscode-jest/issues/331 --- packages/jest-editor-support/index.d.ts | 15 ++-- packages/jest-editor-support/package.json | 1 + packages/jest-editor-support/src/Process.js | 27 +++++- .../src/__tests__/process.test.js | 85 ++++++++++++++++--- .../src/project_workspace.js | 4 + 5 files changed, 114 insertions(+), 18 deletions(-) diff --git a/packages/jest-editor-support/index.d.ts b/packages/jest-editor-support/index.d.ts index a69949aedb72..240ab58f8eaf 100644 --- a/packages/jest-editor-support/index.d.ts +++ b/packages/jest-editor-support/index.d.ts @@ -22,6 +22,7 @@ export interface Options { testNamePattern?: string; testFileNamePattern?: string; shell?: boolean; + useWsl?: boolean; } export class Runner extends EventEmitter { @@ -38,8 +39,8 @@ export class Settings extends EventEmitter { getConfig(completed: Function): void; jestVersionMajor: number | null; settings: { - testRegex: string, - testMatch: string[], + testRegex: string; + testMatch: string[]; }; } @@ -51,6 +52,7 @@ export class ProjectWorkspace { localJestMajorVersin: number, collectCoverage?: boolean, debug?: boolean, + useWsl?: boolean, ); pathToJest: string; pathToConfig: string; @@ -58,6 +60,7 @@ export class ProjectWorkspace { localJestMajorVersion: number; collectCoverage?: boolean; debug?: boolean; + useWsl?: boolean; } export interface IParseResults { @@ -188,9 +191,9 @@ export class Snapshot { } type FormattedTestResults = { - testResults: TestResult[] -} + testResults: TestResult[]; +}; type TestResult = { - name: string -} \ No newline at end of file + name: string; +}; diff --git a/packages/jest-editor-support/package.json b/packages/jest-editor-support/package.json index 6b836825675b..99e063ada74b 100644 --- a/packages/jest-editor-support/package.json +++ b/packages/jest-editor-support/package.json @@ -11,6 +11,7 @@ "babel-traverse": "^6.14.1", "babylon": "^6.14.1", "jest-snapshot": "^23.6.0" + "wsl-path": "^1.0.3" }, "typings": "index.d.ts" } diff --git a/packages/jest-editor-support/src/Process.js b/packages/jest-editor-support/src/Process.js index 52e3c7623a46..b83f17a7484a 100644 --- a/packages/jest-editor-support/src/Process.js +++ b/packages/jest-editor-support/src/Process.js @@ -9,6 +9,7 @@ import {ChildProcess, spawn} from 'child_process'; import ProjectWorkspace from './project_workspace'; +import {windowsToWslSync} from 'wsl-path'; import type {SpawnOptions} from './types'; /** @@ -27,9 +28,9 @@ export const createProcess = ( // any other bits into the args const runtimeExecutable = workspace.pathToJest; const parameters = runtimeExecutable.split(' '); - const command = parameters[0]; const initialArgs = parameters.slice(1); - const runtimeArgs = [].concat(initialArgs, args); + let command = parameters[0]; + let runtimeArgs = [].concat(initialArgs, args); // If a path to configuration file was defined, push it to runtimeArgs if (workspace.pathToConfig) { @@ -37,6 +38,11 @@ export const createProcess = ( runtimeArgs.push(workspace.pathToConfig); } + if (workspace.useWsl) { + runtimeArgs = [command, ...runtimeArgs.map(convertWslPath)]; + command = 'wsl'; + } + // To use our own commands in create-react, we need to tell the command that // we're in a CI environment, or it will always append --watch const env = process.env; @@ -56,3 +62,20 @@ export const createProcess = ( return spawn(command, runtimeArgs, spawnOptions); }; + +const convertWslPath = (maybePath: string): string => { + if (!/^\w:\\/.test(maybePath)) { + return maybePath; + } + // not every string containing a windows delimiter needs to be a + // path, but if it starts with C:\ or similar the chances are very high + try { + return windowsToWslSync(maybePath); + } catch (exception) { + console.log( + `Tried to translate ${maybePath} but received exception`, + exception, + ); + return maybePath; + } +}; diff --git a/packages/jest-editor-support/src/__tests__/process.test.js b/packages/jest-editor-support/src/__tests__/process.test.js index 7b4bc0e844b5..b551ac5c7348 100644 --- a/packages/jest-editor-support/src/__tests__/process.test.js +++ b/packages/jest-editor-support/src/__tests__/process.test.js @@ -10,9 +10,10 @@ 'use strict'; jest.mock('child_process'); - +jest.mock('wsl-path'); import {createProcess} from '../Process'; import {spawn} from 'child_process'; +import * as wslPath from 'wsl-path'; describe('createProcess', () => { afterEach(() => { @@ -20,7 +21,9 @@ describe('createProcess', () => { }); it('spawns the process', () => { - const workspace: any = {pathToJest: ''}; + const workspace: any = { + pathToJest: '', + }; const args = []; createProcess(workspace, args); @@ -28,7 +31,9 @@ describe('createProcess', () => { }); it('spawns the command from workspace.pathToJest', () => { - const workspace: any = {pathToJest: 'jest'}; + const workspace: any = { + pathToJest: 'jest', + }; const args = []; createProcess(workspace, args); @@ -37,7 +42,9 @@ describe('createProcess', () => { }); it('spawns the first arg from workspace.pathToJest split on " "', () => { - const workspace: any = {pathToJest: 'npm test --'}; + const workspace: any = { + pathToJest: 'npm test --', + }; const args = []; createProcess(workspace, args); @@ -60,7 +67,9 @@ describe('createProcess', () => { }); it('appends args', () => { - const workspace: any = {pathToJest: 'npm test --'}; + const workspace: any = { + pathToJest: 'npm test --', + }; const args = ['--option', 'value', '--another']; createProcess(workspace, args); @@ -86,9 +95,13 @@ describe('createProcess', () => { }); it('defines the "CI" environment variable', () => { - const expected = Object.assign({}, process.env, {CI: 'true'}); + const expected = Object.assign({}, process.env, { + CI: 'true', + }); - const workspace: any = {pathToJest: ''}; + const workspace: any = { + pathToJest: '', + }; const args = []; createProcess(workspace, args); @@ -107,7 +120,9 @@ describe('createProcess', () => { }); it('should not set the "shell" property when "options" are not provided', () => { - const workspace: any = {pathToJest: ''}; + const workspace: any = { + pathToJest: '', + }; const args = []; createProcess(workspace, args); @@ -116,11 +131,61 @@ describe('createProcess', () => { it('should set the "shell" property when "options" are provided', () => { const expected = {}; - const workspace: any = {pathToJest: ''}; + const workspace: any = { + pathToJest: '', + }; const args = []; - const options: any = {shell: expected}; + const options: any = { + shell: expected, + }; createProcess(workspace, args, options); expect(spawn.mock.calls[0][2].shell).toBe(expected); }); + + it('should prepend wsl when useWsl is set in the ProjectWorkspace', () => { + const workspace: any = { + pathToJest: 'npm run jest', + useWsl: true, + }; + const args = []; + const options: any = { + shell: true, + }; + createProcess(workspace, args, options); + + expect(spawn.mock.calls[0][0]).toEqual('wsl'); + }); + + it('should keep the original command in the spawn arguments when using wsl', () => { + const expected = ['npm', 'run', 'jest']; + const workspace: any = { + pathToJest: expected.join(' '), + useWsl: true, + }; + const args = []; + const options: any = { + shell: true, + }; + createProcess(workspace, args, options); + + expect(spawn.mock.calls[0][1]).toEqual(expected); + }); + + it('should translate file paths in the spawn command into the wsl context', () => { + const expected = ['npm', 'run', '/mnt/c/Users/Bob/path']; + wslPath.windowsToWslSync = jest.fn(() => expected[2]); + + const workspace: any = { + pathToJest: 'npm run C:\\Users\\Bob\\path', + useWsl: true, + }; + const args = []; + const options: any = { + shell: true, + }; + createProcess(workspace, args, options); + + expect(spawn.mock.calls[0][1]).toEqual(expected); + }); }); diff --git a/packages/jest-editor-support/src/project_workspace.js b/packages/jest-editor-support/src/project_workspace.js index a092ea6a668e..4197f6348773 100644 --- a/packages/jest-editor-support/src/project_workspace.js +++ b/packages/jest-editor-support/src/project_workspace.js @@ -60,6 +60,8 @@ export default class ProjectWorkspace { */ debug: ?boolean; + useWsl: ?boolean; + constructor( rootPath: string, pathToJest: string, @@ -67,6 +69,7 @@ export default class ProjectWorkspace { localJestMajorVersion: number, collectCoverage: ?boolean, debug: ?boolean, + useWsl: ?boolean, ) { this.rootPath = rootPath; this.pathToJest = pathToJest; @@ -74,5 +77,6 @@ export default class ProjectWorkspace { this.localJestMajorVersion = localJestMajorVersion; this.collectCoverage = collectCoverage; this.debug = debug; + this.useWsl = useWsl; } }