Skip to content

Commit

Permalink
fix: Modify doubleEscape to handle path with extra backslashes and la…
Browse files Browse the repository at this point in the history
…unch edge without browser key (#14723)
  • Loading branch information
SagarGaniga authored Feb 8, 2021
1 parent e71af5a commit 3337d85
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 25 deletions.
30 changes: 20 additions & 10 deletions packages/launcher/lib/windows/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fse from 'fs-extra'
import os from 'os'
import { join, normalize } from 'path'
import { join, normalize, win32 } from 'path'
import { tap, trim, prop } from 'ramda'
import { get } from 'lodash'
import { notInstalledErr } from '../errors'
Expand Down Expand Up @@ -132,15 +132,17 @@ function getWindowsBrowser (browser: Browser): Promise<FoundBrowser> {
throw notInstalledErr(browser.name)
}

return fse.pathExists(exePath)
let path = doubleEscape(exePath)

return fse.pathExists(path)
.then((exists) => {
log('found %s ?', exePath, exists)
log('found %s ?', path, exists)

if (!exists) {
return tryNextExePath()
}

return getVersionString(exePath)
return getVersionString(path)
.then(tap(log))
.then(getVersion)
.then((version: string) => {
Expand All @@ -163,18 +165,20 @@ function getWindowsBrowser (browser: Browser): Promise<FoundBrowser> {
return tryNextExePath()
}

export function getVersionString (path: string) {
const doubleEscape = (s: string) => {
return s.replace(/\\/g, '\\\\')
}
export function doubleEscape (s: string) {
// Converts all types of paths into windows supported double backslash path
// Handles any number of \\ in the given path
return win32.join(...s.split(win32.sep)).replace(/\\/g, '\\\\')
}

export function getVersionString (path: string) {
// on Windows using "--version" seems to always start the full
// browser, no matter what one does.

const args = [
'datafile',
'where',
`name="${doubleEscape(path)}"`,
`name="${path}"`,
'get',
'Version',
'/value',
Expand Down Expand Up @@ -203,15 +207,21 @@ export function getPathData (pathStr: string): PathData {
const pathParts = path.split(':')

browserKey = pathParts.pop() || ''
path = pathParts.join(':')
path = doubleEscape(pathParts.join(':'))

return { path, browserKey }
}

path = doubleEscape(path)

if (pathStr.indexOf('chrome.exe') > -1) {
return { path, browserKey: 'chrome' }
}

if (pathStr.indexOf('edge.exe') > -1) {
return { path, browserKey: 'edge' }
}

if (pathStr.indexOf('firefox.exe') > -1) {
return { path, browserKey: 'firefox' }
}
Expand Down
131 changes: 116 additions & 15 deletions packages/launcher/test/unit/windows_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { detectByPath } from '../../lib/detect'
import { goalBrowsers } from '../fixtures'

function stubBrowser (path: string, version: string) {
path = normalize(path.replace(/\\/g, '\\\\'))
path = windowsHelper.doubleEscape(normalize(path))

;(utils.execa as unknown as SinonStub)
.withArgs('wmic', ['datafile', 'where', `name="${path}"`, 'get', 'Version', '/value'])
Expand Down Expand Up @@ -91,39 +91,45 @@ describe('windows browser detection', () => {

it('works with :browserName format in Windows', () => {
sinon.stub(os, 'platform').returns('win32')
stubBrowser(`${HOMEDIR}/foo/bar/browser.exe`, '100')
let path = `${HOMEDIR}/foo/bar/browser.exe`
let win10Path = windowsHelper.doubleEscape(path)

return detectByPath(`${HOMEDIR}/foo/bar/browser.exe:foo-browser`, goalBrowsers as Browser[]).then((browser) => {
stubBrowser(path, '100')

return detectByPath(`${path}:foo-browser`, goalBrowsers as Browser[]).then((browser) => {
expect(browser).to.deep.equal(
Object.assign({}, goalBrowsers.find((gb) => {
return gb.name === 'foo-browser'
}), {
displayName: 'Custom Foo Browser',
info: `Loaded from ${HOMEDIR}/foo/bar/browser.exe`,
info: `Loaded from ${win10Path}`,
custom: true,
version: '100',
majorVersion: 100,
path: `${HOMEDIR}/foo/bar/browser.exe`,
path: win10Path,
}),
)
})
})

it('identifies browser if name in path', async () => {
sinon.stub(os, 'platform').returns('win32')
stubBrowser(`${HOMEDIR}/foo/bar/chrome.exe`, '100')
let path = `${HOMEDIR}/foo/bar/chrome.exe`
let win10Path = windowsHelper.doubleEscape(path)

stubBrowser(path, '100')

return detectByPath(`${HOMEDIR}/foo/bar/chrome.exe`).then((browser) => {
return detectByPath(path).then((browser) => {
expect(browser).to.deep.equal(
Object.assign({}, browsers.find((gb) => {
return gb.name === 'chrome'
}), {
displayName: 'Custom Chrome',
info: `Loaded from ${HOMEDIR}/foo/bar/chrome.exe`,
info: `Loaded from ${win10Path}`,
custom: true,
version: '100',
majorVersion: 100,
path: `${HOMEDIR}/foo/bar/chrome.exe`,
path: win10Path,
}),
)
})
Expand All @@ -149,24 +155,119 @@ describe('windows browser detection', () => {

context('#getPathData', () => {
it('returns path and browserKey given path with browser key', () => {
const res = windowsHelper.getPathData('C:\\foo\\bar.exe:firefox')
const browserPath = 'C:\\foo\\bar.exe'
const res = windowsHelper.getPathData(`${browserPath}:firefox`)

expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath))
expect(res.browserKey).to.eq('firefox')
})

it('returns path and browserKey given path with a lot of slashes plus browser key', () => {
const browserPath = 'C:\\\\\\\\foo\\\\\\bar.exe'
const res = windowsHelper.getPathData(`${browserPath}:firefox`)

expect(res.path).to.eq('C:\\foo\\bar.exe')
expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath))
expect(res.browserKey).to.eq('firefox')
})

it('returns path and browserKey given nix path with browser key', () => {
const browserPath = 'C:/foo/bar.exe'
const res = windowsHelper.getPathData(`${browserPath}:firefox`)

expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath))
expect(res.browserKey).to.eq('firefox')
})

it('returns path and chrome given just path', () => {
const res = windowsHelper.getPathData('C:\\foo\\bar\\chrome.exe')
const browserPath = 'C:\\foo\\bar\\chrome.exe'
const res = windowsHelper.getPathData(browserPath)

expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath))
expect(res.browserKey).to.eq('chrome')
})

it('returns path and chrome given just nix path', () => {
const browserPath = 'C:/foo/bar/chrome.exe'
const res = windowsHelper.getPathData(browserPath)

expect(res.path).to.eq('C:\\foo\\bar\\chrome.exe')
expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath))
expect(res.browserKey).to.eq('chrome')
})

it('returns path and edge given just path for edge', () => {
const browserPath = 'C:\\foo\\bar\\edge.exe'
const res = windowsHelper.getPathData(browserPath)

expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath))
expect(res.browserKey).to.eq('edge')
})

it('returns path and edge given just path for msedge', () => {
const browserPath = 'C:\\foo\\bar\\msedge.exe'
const res = windowsHelper.getPathData(browserPath)

expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath))
expect(res.browserKey).to.eq('edge')
})

it('returns path and edge given just nix path', () => {
const browserPath = 'C:/foo/bar/edge.exe'
const res = windowsHelper.getPathData(browserPath)

expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath))
expect(res.browserKey).to.eq('edge')
})

it('returns path and edge given just nix path for msedge', () => {
const browserPath = 'C:/foo/bar/msedge.exe'
const res = windowsHelper.getPathData(browserPath)

expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath))
expect(res.browserKey).to.eq('edge')
})

it('returns path and firefox given just path', () => {
const res = windowsHelper.getPathData('C:\\foo\\bar\\firefox.exe')
const browserPath = 'C:\\foo\\bar\\firefox.exe'
const res = windowsHelper.getPathData(browserPath)

expect(res.path).to.eq('C:\\foo\\bar\\firefox.exe')
expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath))
expect(res.browserKey).to.eq('firefox')
})

it('returns path and firefox given just nix path', () => {
const browserPath = 'C:/foo/bar/firefox.exe'
const res = windowsHelper.getPathData(browserPath)

expect(res.path).to.eq(windowsHelper.doubleEscape(browserPath))
expect(res.browserKey).to.eq('firefox')
})
})

context('#doubleEscape', () => {
let winPath = 'C:\\\\foo\\\\bar.exe'

it('converts nix path into double escaped win path', async () => {
let nixPath = 'C:/foo/bar.exe'

expect(windowsHelper.doubleEscape(nixPath)).to.eq(winPath)
})

it('converts win path with different backslash combination into double escaped win path', async () => {
let badWinPath = 'C:\\\\\\\\\\foo\\bar.exe'

expect(windowsHelper.doubleEscape(badWinPath)).to.eq(winPath)
})

it('converts single escaped win path into double escaped win path', async () => {
let badWinPath = 'C:\\foo\\bar.exe'

expect(windowsHelper.doubleEscape(badWinPath)).to.eq(winPath)
})

it('does not affect an already double escaped win path', async () => {
let badWinPath = 'C:\\\\foo\\\\bar.exe'

expect(windowsHelper.doubleEscape(badWinPath)).to.eq(badWinPath)
})
})
})

4 comments on commit 3337d85

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 3337d85 Feb 8, 2021

Choose a reason for hiding this comment

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

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/6.6.0/circle-develop-3337d85404848dbed753145814dc7c85f3c15997/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 3337d85 Feb 8, 2021

Choose a reason for hiding this comment

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

AppVeyor has built the win32 ia32 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/6.5.0/appveyor-develop-3337d85404848dbed753145814dc7c85f3c15997/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 3337d85 Feb 8, 2021

Choose a reason for hiding this comment

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

AppVeyor has built the win32 x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/6.5.0/appveyor-develop-3337d85404848dbed753145814dc7c85f3c15997/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 3337d85 Feb 8, 2021

Choose a reason for hiding this comment

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

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/6.6.0/circle-develop-3337d85404848dbed753145814dc7c85f3c15997/cypress.tgz

Please sign in to comment.