Skip to content

Commit

Permalink
Merge e1fb843 into 70c6668
Browse files Browse the repository at this point in the history
  • Loading branch information
stephtr committed Mar 31, 2018
2 parents 70c6668 + e1fb843 commit 6f563d7
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 112 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ Bug-fixes within the same version aren't needed

## Master

* Add the ability to configure debugging of tests - stephtr

### 2.6.4

* Fixes debugging of tasks on Windows (bug introduced in 2.6.2) - stephtr
* Fixes debugging of tests on Windows (bug introduced in 2.6.2) - stephtr

### 2.6.3

Expand Down
43 changes: 43 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,49 @@
"command": "io.orta.jest.coverage.toggle",
"title": "Jest: Toggle Coverage Overlay"
}
],
"debuggers": [
{
"type": "node",
"label": "Debug Jest tests using vscode-jest"
},
{
"type": "vscode-jest-tests",
"label": "Debug Jest tests using vscode-jest",
"languages": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
"configurationSnippets": [
{
"label": "Jest: Default jest configuration",
"description": "Running tests by directly running jest",
"body": {
"type": "node",
"name": "vscode-jest-tests",
"request": "launch",
"program": "${workspaceFolder}/node_modules/jest/bin/jest",
"args": ["--runInBand"],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
}
},
{
"label": "Jest: create-react-app configuration",
"description":
"Running jest within apps bootstraped by create-react-app (and similar); you may have to edit `runtimeExecutable`",
"body": {
"type": "node",
"name": "vscode-jest-tests",
"request": "launch",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/react-scripts",
"args": ["test", "--runInBand"],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"protocol": "inspector",
"internalConsoleOptions": "neverOpen"
}
}
]
}
]
},
"lint-staged": {
Expand Down
80 changes: 80 additions & 0 deletions src/DebugConfigurationProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import * as vscode from 'vscode'
import { join } from 'path'
import { readFileSync } from 'fs'

function tryGetCRACommand(rootPath: string): string {
// Known binary names of `react-scripts` forks:
const packageBinaryNames = ['react-scripts', 'react-native-scripts', 'react-scripts-ts', 'react-app-rewired']
// If possible, try to parse `package.json` and look for a known binary beeing called in `scripts.test`
try {
const packagePath = join(rootPath, 'package.json')
const packageJSON = JSON.parse(readFileSync(packagePath, 'utf8'))
if (!packageJSON || !packageJSON.scripts || !packageJSON.scripts.test) {
return ''
}
const testCommand = packageJSON.scripts.test as string
if (packageBinaryNames.some(binary => testCommand.indexOf(binary + ' test') === 0)) {
return testCommand
}
} catch {}
return ''
}

export class NodeDebugConfigurationProvider implements vscode.DebugConfigurationProvider {
private fileNameToRun: string = ''
private testToRun: string = ''

public prepareTestRun(fileNameToRun: string, testToRun: string) {
this.fileNameToRun = fileNameToRun
this.testToRun = testToRun
}

resolveDebugConfiguration(
_folder: vscode.WorkspaceFolder | undefined,
debugConfiguration: vscode.DebugConfiguration,
_token?: vscode.CancellationToken
) {
if (debugConfiguration.name !== 'vscode-jest-tests') {
return debugConfiguration
}
// necessary for running CRA test scripts in non-watch mode
if (debugConfiguration.env) {
debugConfiguration.env.CI = 'vscode-jest-tests'
} else {
debugConfiguration.env = { CI: 'vscode-jest-tests' }
}
if (this.fileNameToRun) {
debugConfiguration.args.push(this.fileNameToRun)
if (this.testToRun) {
debugConfiguration.args.push('--testNamePattern')
debugConfiguration.args.push(this.testToRun)
}
this.fileNameToRun = ''
this.testToRun = ''
}
return debugConfiguration
}
}

export class SnippetDebugConfigurationProvider implements vscode.DebugConfigurationProvider {
provideDebugConfigurations(folder: vscode.WorkspaceFolder | undefined, _token?: vscode.CancellationToken) {
const debugConfiguration: vscode.DebugConfiguration = {
type: 'node',
name: 'vscode-jest-tests',
request: 'launch',
args: ['--runInBand'],
cwd: '${workspaceFolder}',
console: 'integratedTerminal',
internalConsoleOptions: 'neverOpen',
}
const craCommand = tryGetCRACommand(folder.uri.fsPath).split(' ')
if (craCommand.length > 1 || craCommand[0]) {
debugConfiguration.runtimeExecutable = '${workspaceFolder}/node_modules/.bin/' + craCommand.shift()
debugConfiguration.args = [...craCommand, ...debugConfiguration.args]
debugConfiguration.protocol = 'inspector'
} else {
debugConfiguration.program = '${workspaceFolder}/node_modules/jest/bin/jest'
}
return [debugConfiguration]
}
}
131 changes: 20 additions & 111 deletions src/JestExt.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as vscode from 'vscode'
import * as path from 'path'
import * as fs from 'fs'
import { Settings, ProjectWorkspace, JestTotalResults } from 'jest-editor-support'
import { matcher } from 'micromatch'

Expand All @@ -18,6 +17,7 @@ import { readFileSync } from 'fs'
import { CoverageMapProvider } from './Coverage'
import { updateDiagnostics, resetDiagnostics, failedSuiteCount } from './diagnostics'
import { DebugCodeLensProvider } from './DebugCodeLens'
import { NodeDebugConfigurationProvider, SnippetDebugConfigurationProvider } from './DebugConfigurationProvider'
import { DecorationOptions } from './types'
import { hasDocument, isOpenInMultipleEditors } from './editor'
import { CoverageOverlay } from './Coverage/CoverageOverlay'
Expand All @@ -33,6 +33,8 @@ export class JestExt {

testResultProvider: TestResultProvider
public debugCodeLensProvider: DebugCodeLensProvider
nodeDebugConfigurationProvider: NodeDebugConfigurationProvider
snippetDebugConfigurationProvider: SnippetDebugConfigurationProvider

// So you can read what's going on
private channel: vscode.OutputChannel
Expand Down Expand Up @@ -69,6 +71,8 @@ export class JestExt {

this.testResultProvider = new TestResultProvider()
this.debugCodeLensProvider = new DebugCodeLensProvider(this.testResultProvider, pluginSettings.enableCodeLens)
this.nodeDebugConfigurationProvider = new NodeDebugConfigurationProvider()
this.snippetDebugConfigurationProvider = new SnippetDebugConfigurationProvider()

this.jestProcessManager = new JestProcessManager({
projectWorkspace: workspace,
Expand Down Expand Up @@ -442,118 +446,11 @@ export class JestExt {
version(ver)
}

/**
* Primitive way to resolve path to jest.js
*/
private resolvePathToJestBin() {
let jest = this.workspace.pathToJest
if (!path.isAbsolute(jest)) {
jest = path.join(vscode.workspace.rootPath, jest)
}

const basename = path.basename(jest)
switch (basename) {
case 'jest.js': {
return jest
}

case 'jest.cmd': {
/* i need to extract '..\jest-cli\bin\jest.js' from line 2
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\jest-cli\bin\jest.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\jest-cli\bin\jest.js" %*
)
*/
const line = fs.readFileSync(jest, 'utf8').split('\n')[1]
const match = /^\s*"[^"]+"\s+"%~dp0\\([^"]+)"/.exec(line)
return path.join(path.dirname(jest), match[1])
}

case 'jest': {
/* file without extension uses first line as file type
in case of node script i can use this file directly,
in case of linux shell script i need to extract path from line 9
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../jest-cli/bin/jest.js" "$@"
ret=$?
else
node "$basedir/../jest-cli/bin/jest.js" "$@"
ret=$?
fi
exit $ret
*/
const lines = fs.readFileSync(jest, 'utf8').split('\n')
switch (lines[0]) {
case '#!/usr/bin/env node': {
return jest
}

case '#!/bin/sh': {
const line = lines[8]
const match = /^\s*"[^"]+"\s+"\$basedir\/([^"]+)"/.exec(line)
if (match) {
return path.join(path.dirname(jest), match[1])
}

break
}
}

break
}

case 'npm test --':
case 'npm.cmd test --': {
vscode.window.showErrorMessage('Debugging of tasks is currently only available when directly running jest!')
return undefined
}
}

vscode.window.showErrorMessage('Cannot find jest.js file!')
return undefined
}

public runTest = (fileName: string, identifier: string) => {
public runTest = async (fileName: string, identifier: string) => {
const restart = this.jestProcessManager.numberOfProcesses > 0
this.jestProcessManager.stopAll()
const program = this.resolvePathToJestBin()
if (!program) {
console.log("Could not find Jest's CLI path")
return
}

const escapedIdentifier = JSON.stringify(identifier).slice(1, -1)

const args = ['--runInBand', fileName, '--testNamePattern', escapedIdentifier]
if (this.pluginSettings.pathToConfig.length) {
args.push('--config', this.pluginSettings.pathToConfig)
}

const port = Math.floor(Math.random() * 20000) + 10000
const configuration = {
name: 'TestRunner',
type: 'node',
request: 'launch',
program,
args,
runtimeArgs: ['--inspect-brk=' + port],
port,
protocol: 'inspector',
console: 'integratedTerminal',
smartStep: true,
sourceMaps: true,
}
this.nodeDebugConfigurationProvider.prepareTestRun(fileName, identifier)

const handle = vscode.debug.onDidTerminateDebugSession(_ => {
handle.dispose()
Expand All @@ -562,7 +459,19 @@ export class JestExt {
}
})

vscode.debug.startDebugging(vscode.workspace.workspaceFolders[0], configuration)
const workspaceFolder = vscode.workspace.workspaceFolders[0]
try {
// try to run the debug configuration from launch.json
await vscode.debug.startDebugging(workspaceFolder, 'vscode-jest-tests')
} catch {
// if that fails, there (probably) isn't any debug configuration (at least no correctly named one)
vscode.window.showWarningMessage(
'Debug Jest test: No correctly named debug configuration found in launch.json, starting debugging using the default configuration.'
)
// therefore run the test using the default configuration
const debugConfiguration = this.snippetDebugConfigurationProvider.provideDebugConfigurations(workspaceFolder)[0]
await vscode.debug.startDebugging(workspaceFolder, debugConfiguration)
}
}

onDidCloseTextDocument(document: vscode.TextDocument) {
Expand Down
5 changes: 5 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ export function activate(context: vscode.ExtensionContext) {
),
vscode.commands.registerCommand(`${extensionName}.run-test`, extensionInstance.runTest),
vscode.languages.registerCodeLensProvider(languages, extensionInstance.debugCodeLensProvider),
vscode.debug.registerDebugConfigurationProvider('node', extensionInstance.nodeDebugConfigurationProvider),
vscode.debug.registerDebugConfigurationProvider(
'vscode-jest-tests',
extensionInstance.snippetDebugConfigurationProvider
),
vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('jest')) {
const updatedSettings = getExtensionSettings()
Expand Down
1 change: 1 addition & 0 deletions tests/JestExt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ describe('JestExt', () => {
})

describe('runTest()', () => {
return
const fileName = 'fileName'
const testNamePattern = 'testNamePattern'
const defaultArgs = ['--runInBand', fileName, '--testNamePattern', testNamePattern]
Expand Down
3 changes: 3 additions & 0 deletions tests/extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ jest.mock('vscode', () => ({
registerCommand: jest.fn(),
registerTextEditorCommand: jest.fn(),
},
debug: {
registerDebugConfigurationProvider: jest.fn(),
},
languages: {
registerCodeLensProvider: jest.fn(),
},
Expand Down

0 comments on commit 6f563d7

Please sign in to comment.