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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Bug-fixes within the same version aren't needed
text editor - seanpoulter
* Restart Jest with --watchAll when --watch is not supported without git/hg
- seanpoulter
* Fix regression in handling workspaces that have been bootstrapped with
create-react-app - seanpoulter

-->

Expand Down
4 changes: 2 additions & 2 deletions src/DebugConfigurationProvider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as vscode from 'vscode'
import { getTestCommand, isCRATestCommand } from './helpers'
import { getTestCommand, isCreateReactAppTestCommand } from './helpers'

export class DebugConfigurationProvider implements vscode.DebugConfigurationProvider {
private fileNameToRun: string = ''
Expand Down Expand Up @@ -63,7 +63,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
}

const testCommand = folder && getTestCommand(folder.uri.fsPath)
if (isCRATestCommand(testCommand)) {
if (isCreateReactAppTestCommand(testCommand)) {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this talk about improving maintainability made me remember just how long it took to figure out what "CRA" was from reading the issues. Let's spell it out for folks.

const craCommand = testCommand.split(' ')
// Settings specific for projects bootstrapped with `create-react-app`
debugConfiguration.runtimeExecutable = '${workspaceFolder}/node_modules/.bin/' + craCommand.shift()
Expand Down
2 changes: 1 addition & 1 deletion src/JestExt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Settings, ProjectWorkspace, JestTotalResults } from 'jest-editor-suppor
import { matcher } from 'micromatch'

import * as decorations from './decorations'
import { IPluginSettings } from './IPluginSettings'
import { IPluginSettings } from './Settings'
import * as status from './statusBar'
import {
TestReconciliationState,
Expand Down
16 changes: 16 additions & 0 deletions src/Settings/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
jest.unmock('../index')
import { isDefaultPathToJest } from './index'

describe('isDefaultPathToJest', () => {
it('returns true when the value is null', () => {
expect(isDefaultPathToJest(null)).toBe(true)
})

it('returns true for the legacy default ""', () => {
expect(isDefaultPathToJest('')).toBe(true)
})

it('returns false otherwise', () => {
expect(isDefaultPathToJest('')).toBe(false)
})
})
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seanpoulter after merge this PR, realized you put some tests in the src directory, while the others are in tests directory. Is this intentional? it seems inconsistent... most importantly, the jest.json only look for files within tests directory ("testRegex": "tests/.*\.ts$") today, therefore, the tests within src are not being executed right now. I am ok either way (test or src) as long as they are consistent and executed. please advice...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I will move this test into the normal tests directory in #341

10 changes: 9 additions & 1 deletion src/IPluginSettings.ts → src/Settings/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TestState } from './DebugCodeLens'
import { TestState } from '../DebugCodeLens'

export interface IPluginSettings {
autoEnable?: boolean
Expand All @@ -17,3 +17,11 @@ export interface IPluginSettings {
showCoverageOnLoad: boolean
coverageFormatter: string
}

export function isDefaultPathToJest(str) {
return str === null || str === ''
}

export function hasUserSetPathToJest(str) {
return !isDefaultPathToJest(str)
}
2 changes: 1 addition & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as path from 'path'
import { extensionName } from './appGlobals'
import { pathToJest, pathToConfig } from './helpers'
import { JestExt } from './JestExt'
import { IPluginSettings } from './IPluginSettings'
import { IPluginSettings } from './Settings'
import { registerStatusBar } from './statusBar'
import { registerSnapshotCodeLens, registerSnapshotPreview } from './SnapshotCodeLens'
import { registerCoverageCodeLens } from './Coverage'
Expand Down
47 changes: 25 additions & 22 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { platform } from 'os'
import { existsSync, readFileSync } from 'fs'
import { normalize, join } from 'path'

import { IPluginSettings } from './IPluginSettings'
import { IPluginSettings, hasUserSetPathToJest } from './Settings'

/**
* Known binary names of `react-scripts` forks
Expand All @@ -11,7 +11,7 @@ const createReactAppBinaryNames = ['react-scripts', 'react-native-scripts', 'rea

/**
* Tries to read the test command from the scripts section within `package.json`
*
*
* Returns the test command in case of success,
* `undefined` if there was an exception while reading and parsing `package.json`
* `null` if there is no test script
Expand All @@ -29,24 +29,24 @@ export function getTestCommand(rootPath: string): string | undefined | null {
}
}

/**
/**
* Checks if the supplied test command could have been generated by create-react-app
*/
export function isCRATestCommand(testCommand: string): boolean {
export function isCreateReactAppTestCommand(testCommand: string): boolean {
return testCommand && createReactAppBinaryNames.some(binary => testCommand.indexOf(binary + ' test') === 0)
}

/**
* Checks if the project in `rootPath` was bootstrapped by `create-react-app`.
*/
function isBootstrappedWithCRA(rootPath: string): boolean {
function isBootstrappedWithCreateReactApp(rootPath: string): boolean {
const testCommand = getTestCommand(rootPath)
if (testCommand === undefined) {
// In case parsing `package.json` failed or was unconclusive,
// fallback to checking for the presence of the binaries in `./node_modules/.bin`
return createReactAppBinaryNames.some(binary => hasNodeExecutable(rootPath, binary))
}
return isCRATestCommand(testCommand)
return isCreateReactAppTestCommand(testCommand)
}

function hasNodeExecutable(rootPath: string, executable: string): boolean {
Expand All @@ -56,29 +56,32 @@ function hasNodeExecutable(rootPath: string, executable: string): boolean {
}

/**
* Handles getting the jest runner, handling the OS and project specific work too
* Handles getting the jest runner, handling the OS and project specific work too
*
* @returns {string}
*/
export function pathToJest(pluginSettings: IPluginSettings) {
if (pluginSettings.pathToJest) {
if (isBootstrappedWithCRA(pluginSettings.rootPath)) {
return 'npm test --'
}
return normalize(pluginSettings.pathToJest)
export function pathToJest({ pathToJest, rootPath }: IPluginSettings) {
if (hasUserSetPathToJest(pathToJest)) {
return normalize(pathToJest)
}

const platform = process.platform
if (platform === 'win32' && existsSync(join(pluginSettings.rootPath, 'node_modules', '.bin', 'jest.cmd'))) {
return normalize(join(pluginSettings.rootPath, 'node_modules', '.bin', 'jest.cmd'))
} else if (
(platform === 'linux' || platform === 'darwin') &&
existsSync(join(pluginSettings.rootPath, 'node_modules', '.bin', 'jest'))
) {
return normalize(join(pluginSettings.rootPath, 'node_modules', '.bin', 'jest'))
if (isBootstrappedWithCreateReactApp(rootPath)) {
return 'npm test --'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we here also add the .cmd file extension on Windows? (at least until #297 hopefully solves all extension related issues)

Copy link
Copy Markdown
Member Author

@seanpoulter seanpoulter Jun 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is a known problem but that's not the problem I'm trying to solve. It was intended to be a fast fix to get the extension usable for everyone again. This preserves behaviour from Line 65 on the left, and is same before from before the regression (here).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I bumped into this problem today while testing another PR. I agree #324 was flawed, but to override jest.pathToJest without checking if it has already been customized by users will be problematic too, for example, consider for yarn users whose jest.pathToJest was set to yarn test, now it will be silently override...

If our goal is to provide a "default" setting when jest.pathToJest is null, then let's do just that, no more and no less. In general, we should never override users' custom config programmatically (we can suggest, but they should be the one to carry out the change, simply because we could be wrong) and definitely not silently. Actually, giving jest.pathToJest is so critical, if we did end up using the default value, I think we should make this information available some where (maybe a new channel: vscode-jest?), we could also use the new channel to communicate the plugin specific info such as workspace info, settings, recommedations etc.

BTW, this PR has been sitting for a while, what is the plan? People are adopting custom jest.pathToConfig that made the regression issue less urgent, but nevertheless we could take this opportunity to improve quality and reduce confusion...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function starts with a if (isNotDefaultPathToJest(pathToJest)) return normalize(pathToJest), so there isn't any possibility to override the user setting anymore.

I think the best place would be the Jest output window, which also shows the errors, when there's an issue with the setting or our guess about it.

The PR is waiting for a review by Orta, but I guess we could skip that since this issue in the meantime got quite old.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so there isn't any possibility to override the user setting anymore.

oh that's right, my bad, great!

I think the best place would be the Jest output window

that might work too... however it currently tries to reset the window (channel) on each jest run, so we will have to output this info at each run, no big deal. BTW, I did seen empty buffer at times, so probably some bugs in our channel reset logic.

The PR is waiting for a review by Orta, but I guess we could skip that since this issue in the meantime got quite old.

I am going to submit a new PR to address jest 23 compatibility issue, if you merged this PR soon, I could pick up your change and test them together (except windows) before we cut the next release... Of course that is if @orta has no objection.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could pick up your change and test them together (except windows) before we cut the next release…

I would like to also include a PR like #297, such that all pathToJest and Windows problems should be fixed. But that should be a matter of minutes as soon as we can merge this PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's get them all in, I'll handle the jest ones and get that released in a few days - can we try get those two merged in that timeframe and we'll ship a new release?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Can we merge this one or is there something speaking against?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stephtr this PR has no jest-editor-supports dependency, if you and @seanpoulter all have tested it and are satisfied with it, then it's probably safe to merge, IMHO.

@orta If you can merge facebook/jest/6586 and cut a beta jest release, then we can proceed on this end for the PRs depending on the new jest-editor-supports.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I've requested a release for editor-support - so let's get this PR in then, and #297 can happen whenever

}

return 'jest'
const localJestExecutable = pathToLocalJestExecutable(rootPath)
if (existsSync(localJestExecutable)) {
return localJestExecutable
}
return `jest${isWindows() ? '.cmd' : ''}`
}

function pathToLocalJestExecutable(rootDir) {
return normalize(join(rootDir, `node_modules/.bin/jest${isWindows() ? '.cmd' : ''}`))
}

function isWindows() {
return platform() === 'win32'
}

/**
Expand Down
4 changes: 2 additions & 2 deletions tests/DebugConfigurationProvider.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
jest.unmock('../src/DebugConfigurationProvider')

import { DebugConfigurationProvider } from '../src/DebugConfigurationProvider'
import { getTestCommand, isCRATestCommand } from '../src/helpers'
import { getTestCommand, isCreateReactAppTestCommand } from '../src/helpers'

describe('DebugConfigurationProvider', () => {
it('should by default return a DebugConfiguration for Jest', () => {
Expand All @@ -18,7 +18,7 @@ describe('DebugConfigurationProvider', () => {
})
it('should return a valid CRA DebugConfiguration', () => {
;(getTestCommand as jest.Mock<Function>).mockReturnValueOnce('react-scripts test --env=jsdom')
;(isCRATestCommand as jest.Mock<Function>).mockReturnValueOnce(true)
;(isCreateReactAppTestCommand as jest.Mock<Function>).mockReturnValueOnce(true)

const folder: any = { uri: { fsPath: null } }
const sut = new DebugConfigurationProvider()
Expand Down
Loading