diff --git a/CHANGELOG.md b/CHANGELOG.md index 430df865..5f3f15d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Please add your own contribution below inside the Master section Bug-fixes within the same version aren't needed ## Master +* fix debug problem for windows users (#694) - @connectdotz --> ### 4.0.1 diff --git a/package.json b/package.json index 717e5df7..0f6859f5 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "vscode-jest", "displayName": "Jest", "description": "Use Facebook's Jest With Pleasure.", - "version": "4.0.2-rc.1", + "version": "4.0.2", "publisher": "Orta", "engines": { "vscode": "^1.45.0" @@ -318,8 +318,7 @@ "program": "^\"\\${workspaceFolder}/node_modules/.bin/jest\"", "args": [ "--runInBand", - "--runTestsByPath", - "${file}" + "--watchAll=false" ], "cwd": "^\"\\${workspaceFolder}\"", "console": "integratedTerminal", @@ -342,8 +341,7 @@ "test", "--env=jsdom", "--runInBand", - "--runTestsByPath", - "${file}" + "--watchAll=false" ], "cwd": "^\"\\${workspaceFolder}\"", "console": "integratedTerminal", @@ -363,8 +361,7 @@ "args": [ "--env=jsdom", "--runInBand", - "--runTestsByPath", - "${file}" + "--watchAll=false" ], "cwd": "^\"\\${workspaceFolder}\"", "console": "integratedTerminal", diff --git a/src/DebugConfigurationProvider.ts b/src/DebugConfigurationProvider.ts index 97dfdc83..c9d660a1 100644 --- a/src/DebugConfigurationProvider.ts +++ b/src/DebugConfigurationProvider.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import { escapeFilePath, getTestCommand, isCreateReactAppTestCommand } from './helpers'; +import { toFilePath, getTestCommand, isCreateReactAppTestCommand } from './helpers'; export class DebugConfigurationProvider implements vscode.DebugConfigurationProvider { private fileNameToRun = ''; @@ -29,25 +29,21 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv // necessary for running CRA test scripts in non-watch mode debugConfiguration.env.CI = 'vscode-jest-tests'; - if (!debugConfiguration.args) { - debugConfiguration.args = []; - } + const args = debugConfiguration.args || []; + if (this.fileNameToRun) { if (this.testToRun) { - debugConfiguration.args.push('--testNamePattern'); - debugConfiguration.args.push(this.testToRun); - } - if (!debugConfiguration.args.includes('--runTestsByPath')) { - debugConfiguration.args.push('--runTestsByPath'); - } - if (!debugConfiguration.args.includes('${file}')) { - debugConfiguration.args.push(escapeFilePath(this.fileNameToRun)); + args.push('--testNamePattern'); + args.push(this.testToRun); } + args.push('--runTestsByPath'); + args.push(toFilePath(this.fileNameToRun)); this.fileNameToRun = ''; this.testToRun = ''; } + debugConfiguration.args = args; return debugConfiguration; } @@ -66,7 +62,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv type: 'node', name: 'vscode-jest-tests', request: 'launch', - args: ['--runInBand', '--runTestsByPath', '${file}'], + args: ['--runInBand', '--watchAll=false'], cwd: '${workspaceFolder}', console: 'integratedTerminal', internalConsoleOptions: 'neverOpen', diff --git a/src/JestProcessManagement/JestProcess.ts b/src/JestProcessManagement/JestProcess.ts index 022d1afb..4c9208a0 100644 --- a/src/JestProcessManagement/JestProcess.ts +++ b/src/JestProcessManagement/JestProcess.ts @@ -6,7 +6,7 @@ import { extensionId } from '../appGlobals'; import { Logging } from '../logging'; import { JestProcessRequest } from './types'; import { requestString } from './helper'; -import { escapeFilePath, removeSurroundingQuote } from '../helpers'; +import { toFilePath, removeSurroundingQuote } from '../helpers'; export const RunnerEvents: RunnerEvent[] = [ 'processClose', @@ -90,7 +90,7 @@ export class JestProcess { return join(extensionPath, 'out', 'reporter.js'); } private quoteFileName(fileName: string): string { - return `"${removeSurroundingQuote(fileName)}"`; + return `"${toFilePath(removeSurroundingQuote(fileName))}"`; } private startRunner(): Promise { if (this.task) { @@ -110,9 +110,7 @@ export class JestProcess { } break; case 'by-file': { - options.testFileNamePattern = this.quoteFileName( - escapeFilePath(this.request.testFileNamePattern) - ); + options.testFileNamePattern = this.quoteFileName(this.request.testFileNamePattern); const args: string[] = ['--findRelatedTests']; if (this.request.updateSnapshot) { args.push('--updateSnapshot'); @@ -122,9 +120,7 @@ export class JestProcess { } case 'by-file-test': { - options.testFileNamePattern = this.quoteFileName( - escapeFilePath(this.request.testFileNamePattern) - ); + options.testFileNamePattern = this.quoteFileName(this.request.testFileNamePattern); options.testNamePattern = this.request.testNamePattern; const args: string[] = ['--runTestsByPath']; if (this.request.updateSnapshot) { diff --git a/src/TestResults/TestResult.ts b/src/TestResults/TestResult.ts index 5cd6c7d1..ca5c7e9a 100644 --- a/src/TestResults/TestResult.ts +++ b/src/TestResults/TestResult.ts @@ -2,7 +2,7 @@ import { TestReconciliationStateType } from './TestReconciliationState'; import { JestFileResults, JestTotalResults } from 'jest-editor-support'; import { FileCoverage } from 'istanbul-lib-coverage'; import * as path from 'path'; -import { cleanAnsi } from '../helpers'; +import { cleanAnsi, toLowerCaseDriveLetter } from '../helpers'; export interface Location { /** Zero-based column number */ @@ -46,15 +46,8 @@ export interface TestResult extends LocationRange { reason?: MatchResultReason; } -export const withLowerCaseWindowsDriveLetter = (filePath: string): string | undefined => { - const match = filePath.match(/^([A-Z]:\\)(.*)$/); - if (match) { - return `${match[1].toLowerCase()}${match[2]}`; - } -}; - function testResultWithLowerCaseWindowsDriveLetter(testResult: JestFileResults): JestFileResults { - const newFilePath = withLowerCaseWindowsDriveLetter(testResult.name); + const newFilePath = toLowerCaseDriveLetter(testResult.name); if (newFilePath) { return { ...testResult, @@ -76,7 +69,7 @@ export const testResultsWithLowerCaseWindowsDriveLetters = ( }; function fileCoverageWithLowerCaseWindowsDriveLetter(fileCoverage: FileCoverage) { - const newFilePath = withLowerCaseWindowsDriveLetter(fileCoverage.path); + const newFilePath = toLowerCaseDriveLetter(fileCoverage.path); if (newFilePath) { return { ...fileCoverage, diff --git a/src/helpers.ts b/src/helpers.ts index 9c28f07c..0cc6ee6e 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -145,12 +145,28 @@ export function testIdString(type: IdStringType, identifier: TestIdentifier): st } } +/** convert the upper-case drive letter filePath to lower-case. If path does not contain upper-case drive letter, returns undefined. */ +// note: this should probably be replaced by vscode.URI.file(filePath).fsPath ... +export function toLowerCaseDriveLetter(filePath: string): string | undefined { + const match = filePath.match(/^([A-Z]:\\)(.*)$/); + if (match) { + return `${match[1].toLowerCase()}${match[2]}`; + } +} +/** convert the lower-case drive letter filePath (like vscode.URI.fsPath) to lower-case. If path does not contain lower-case drive letter, returns undefined. */ +export function toUpperCaseDriveLetter(filePath: string): string | undefined { + const match = filePath.match(/^([a-z]:\\)(.*)$/); + if (match) { + return `${match[1].toUpperCase()}${match[2]}`; + } +} + /** - * escape windows file path '\' to '\\', see https://jestjs.io/docs/cli#jest-regexfortestfiles + * convert vscode.URI.fsPath to the actual file system file-path, i.e. convert drive letter to upper-case for windows * @param filePath */ -export function escapeFilePath(filePath: string): string { - return filePath.replace(/\\/g, '\\\\'); +export function toFilePath(filePath: string): string { + return toUpperCaseDriveLetter(filePath) || filePath; } /** diff --git a/tests/DebugConfigurationProvider.test.ts b/tests/DebugConfigurationProvider.test.ts index ac010b26..b409a8db 100644 --- a/tests/DebugConfigurationProvider.test.ts +++ b/tests/DebugConfigurationProvider.test.ts @@ -1,9 +1,12 @@ jest.unmock('../src/DebugConfigurationProvider'); import { DebugConfigurationProvider } from '../src/DebugConfigurationProvider'; -import { getTestCommand, isCreateReactAppTestCommand, escapeFilePath } from '../src/helpers'; +import { getTestCommand, isCreateReactAppTestCommand, toFilePath } from '../src/helpers'; describe('DebugConfigurationProvider', () => { + const fileName = '/a/file'; + const testName = 'a test'; + it('should by default return a DebugConfiguration for Jest', () => { const folder: any = { uri: { fsPath: null } }; const sut = new DebugConfigurationProvider(); @@ -35,38 +38,28 @@ describe('DebugConfigurationProvider', () => { expect(config.args[0]).toBe('test'); expect(config.args).toContain('--env=jsdom'); expect(config.args).toContain('--runInBand'); + expect(config.args).toContain('--watchAll=false'); }); it.each` - debugConfigArgs | expectByPathArg | expectFileNameArg - ${[]} | ${true} | ${true} - ${['--runTestsByPath']} | ${false} | ${true} - ${['--runTestsByPath', '${file}']} | ${false} | ${false} - `( - 'should append the specified tests arguments', - ({ debugConfigArgs, expectByPathArg, expectFileNameArg }) => { - ((escapeFilePath as unknown) as jest.Mock<{}>).mockImplementation((s) => s); - const fileName = 'fileName'; - const testNamePattern = 'testNamePattern'; - const expected = [...debugConfigArgs, '--testNamePattern', testNamePattern]; + debugConfigArgs | expectedArgs + ${[]} | ${['--testNamePattern', testName, '--runTestsByPath', fileName]} + ${['--runInBand']} | ${['--runInBand', '--testNamePattern', testName, '--runTestsByPath', fileName]} + `('should append the specified tests arguments', ({ debugConfigArgs, expectedArgs }) => { + ((toFilePath as unknown) as jest.Mock<{}>).mockImplementation((s) => s); - let configuration: any = { name: 'vscode-jest-tests', args: debugConfigArgs }; + let configuration: any = { name: 'vscode-jest-tests', args: debugConfigArgs }; - const sut = new DebugConfigurationProvider(); - sut.prepareTestRun(fileName, testNamePattern); + const sut = new DebugConfigurationProvider(); + sut.prepareTestRun(fileName, testName); - configuration = sut.resolveDebugConfiguration(undefined, configuration); + configuration = sut.resolveDebugConfiguration(undefined, configuration); - expect(configuration).toBeDefined(); - expect(configuration.env && configuration.env.CI).toBeTruthy(); - if (expectByPathArg) { - expected.push('--runTestsByPath'); - } - if (expectFileNameArg) { - expected.push(fileName); - expect(escapeFilePath).toBeCalled(); - } - expect(configuration.args).toEqual(expected); + expect(configuration).toBeDefined(); + expect(configuration.env && configuration.env.CI).toBeTruthy(); + if (expectedArgs.includes('--runTestsByPath')) { + expect(toFilePath).toBeCalled(); } - ); + expect(configuration.args).toEqual(expectedArgs); + }); }); diff --git a/tests/JestProcessManagement/JestProcess.test.ts b/tests/JestProcessManagement/JestProcess.test.ts index 93eb6253..a7459692 100644 --- a/tests/JestProcessManagement/JestProcess.test.ts +++ b/tests/JestProcessManagement/JestProcess.test.ts @@ -137,7 +137,7 @@ describe('JestProcess', () => { ${'all-tests'} | ${undefined} | ${[false, false]} | ${true} | ${undefined} ${'watch-tests'} | ${undefined} | ${[true, false]} | ${true} | ${undefined} ${'watch-all-tests'} | ${undefined} | ${[true, true]} | ${true} | ${undefined} - ${'by-file'} | ${{ testFileNamePattern: '"c:\\a\\b.ts"' }} | ${[false, false]} | ${true} | ${{ args: { args: ['--findRelatedTests'] }, testFileNamePattern: '"c:\\\\a\\\\b.ts"' }} + ${'by-file'} | ${{ testFileNamePattern: '"c:\\a\\b.ts"' }} | ${[false, false]} | ${true} | ${{ args: { args: ['--findRelatedTests'] }, testFileNamePattern: '"C:\\a\\b.ts"' }} ${'by-file-test'} | ${{ testFileNamePattern: '"/a/b.js"', testNamePattern: 'test' }} | ${[false, false]} | ${true} | ${{ args: { args: ['--runTestsByPath'] }, testFileNamePattern: '"/a/b.js"' }} ${'not-test'} | ${{ args: ['--listTests'] }} | ${[false, false]} | ${false} | ${{ args: { args: ['--listTests'], replace: true } }} `( diff --git a/tests/TestResults/TestResult.test.ts b/tests/TestResults/TestResult.test.ts index 29e90942..17b70945 100644 --- a/tests/TestResults/TestResult.test.ts +++ b/tests/TestResults/TestResult.test.ts @@ -10,7 +10,6 @@ const { coverageMapWithLowerCaseWindowsDriveLetters, testResultsWithLowerCaseWindowsDriveLetters, resultsWithoutAnsiEscapeSequence, - withLowerCaseWindowsDriveLetter, } = TestResult; describe('TestResult', () => { @@ -137,16 +136,4 @@ describe('TestResult', () => { }); }); }); - - describe('withLowerCaseDriveLetter', () => { - it('should return a new file path when provided a path with an upper case drive letter', () => { - const filePath = 'C:\\path\\file.ext'; - expect(withLowerCaseWindowsDriveLetter(filePath)).toBe('c:\\path\\file.ext'); - }); - - it('should indicate no change is required otherwise', () => { - const filePath = 'c:\\path\\file.ext'; - expect(withLowerCaseWindowsDriveLetter(filePath)).toBeUndefined(); - }); - }); }); diff --git a/tests/helpers.test.ts b/tests/helpers.test.ts index 3fd1e125..7a7c76f5 100644 --- a/tests/helpers.test.ts +++ b/tests/helpers.test.ts @@ -32,7 +32,9 @@ import { testIdString, escapeRegExp, removeSurroundingQuote, - escapeFilePath, + toFilePath, + toLowerCaseDriveLetter, + toUpperCaseDriveLetter, } from '../src/helpers'; // Manually (forcefully) set the executable's file extension to test its addition independendly of the operating system. @@ -253,14 +255,40 @@ describe('removeSurroundingQuote', () => { }); }); -describe('escapeFilePath', () => { +describe('toFilePath', () => { it.each` path | expected ${'/a/b/c'} | ${'/a/b/c'} ${'C:/a/b/c.js'} | ${'C:/a/b/c.js'} - ${'c:\\a\\b\\c.ts'} | ${'c:\\\\a\\\\b\\\\c.ts'} + ${'c:/a/b/c.js'} | ${'c:/a/b/c.js'} + ${'z:\\a\\b\\c.js'} | ${'Z:\\a\\b\\c.js'} + ${'\\a\\b\\c.js'} | ${'\\a\\b\\c.js'} ${''} | ${''} `('escape $path => $expected', ({ path, expected }) => { - expect(escapeFilePath(path)).toEqual(expected); + expect(toFilePath(path)).toEqual(expected); + }); +}); + +describe('toLowerCaseDriveLetter', () => { + it.each` + filePath | expected + ${'C:\\path\\file.ext'} | ${'c:\\path\\file.ext'} + ${'c:\\path\\file.ext'} | ${undefined} + ${'c:/path/file.ext'} | ${undefined} + ${'/path/file.ext'} | ${undefined} + `('$filePath => $expected', ({ filePath, expected }) => { + expect(toLowerCaseDriveLetter(filePath)).toBe(expected); + }); +}); + +describe('toUpperCaseDriveLetter', () => { + it.each` + filePath | expected + ${'C:\\path\\file.ext'} | ${undefined} + ${'c:\\path\\file.ext'} | ${'C:\\path\\file.ext'} + ${'c:/path/file.ext'} | ${undefined} + ${'/path/file.ext'} | ${undefined} + `('$filePath => $expected', ({ filePath, expected }) => { + expect(toUpperCaseDriveLetter(filePath)).toBe(expected); }); });