add "cypress info" command (#6372)

* WIP: add cli info command to list detected browsers

* print found browsers

* change to list

* start work on info command calling into binary

* move info command into binary

* print OS info during cypress info command

* add binary cache path to info command

* add browser profile path

* add memory

* get browser profile path without partition

* pick real browsers as examples

* output same info as desired

* better names

* changed colors

* add list of cached binary versions

* do not put stable into name

* add underlined link

* conditionally show profile path, only if the folder exists

* do not list cached binaries

* human-friendly memory print

* print env proxy vars

* print CYPRESS_ env variables

* use _.sample

* update order

* store cypress info output on CI as HTML page artifact

* add percy CLI screenshots

* sanitize cypress info command

* store CLI snapshots in cli/visual-snapshots folder

* update cli unit snapshot

* add cli unit test

* start e2e testing for cypress info

* add test with proxy and cypress vars

* make sure we call the binary

* stricter start check

* start unit testing modes info

* test info mode browser print

* add test for profile path

* add cypress info command to test binary Circle job

* add cypress info to test-binary-as-specific-user circle

* print cypress info --dev on circle and on appveyor

* update .gitignore

* move error in environment load to debug
This commit is contained in:
Gleb Bahmutov
2020-02-20 10:54:25 -05:00
committed by GitHub
parent 72c9c7dbe4
commit 070fceff20
24 changed files with 1300 additions and 51 deletions
+1
View File
@@ -58,3 +58,4 @@ binary-url.json
# Allows us to dynamically create eslint rules that override the default for Decaffeinate scripts
.eslintrc.js
cli/visual-snapshots
+12
View File
@@ -0,0 +1,12 @@
# https://docs.percy.io/v1/docs/configuration
version: 1
snapshot:
widths: [1280]
min-height: 1024
agent:
asset-discovery:
# let Percy wait for network to fetch static resources
# like images and fonts to avoid missing icons
network-idle-timeout: 250 # ms
# assets that don't change could be cached
cache-responses: true
+2 -2
View File
@@ -73,8 +73,8 @@ test_script:
- node --version
- yarn --version
- 7z
- echo *** Browsers installed on this system ***
- cd packages/launcher && node index.js && cd ../..
- echo *** System info ***
- node cli/bin/cypress info --dev
- echo *** Kitchensink tests run on Chrome browser ***
- npm run dev -- --run-project %CD%/packages/example --browser chrome
+46
View File
@@ -255,8 +255,35 @@ jobs:
at: ~/
## this will catch .only's in js/coffee as well
- run: yarn lint-all
- run:
name: cypress info (dev)
command: node cli/bin/cypress info --dev
- store-npm-logs
cli-visual-tests:
<<: *defaults
parallelism: 1
steps:
- attach_workspace:
at: ~/
- run: mkdir -p cli/visual-snapshots
- run:
# TODO sanitize "cypress info" output to be consistent
command: node cli/bin/cypress info --dev | yarn --silent term-to-html | node scripts/sanitize --type cli-info > cli/visual-snapshots/cypress-info.html
environment:
FORCE_COLOR: 2
- run:
command: node cli/bin/cypress help | yarn --silent term-to-html > cli/visual-snapshots/cypress-help.html
environment:
FORCE_COLOR: 2
- store_artifacts:
path: cli/visual-snapshots
- run:
name: Upload CLI snapshots for diffing
command: |
PERCY_TOKEN=$PERCY_TOKEN_CLI \
yarn percy snapshot ./cli/visual-snapshots
unit-tests:
<<: *defaults
parallelism: 1
@@ -901,6 +928,14 @@ jobs:
name: Verify Cypress binary
working_directory: test-binary
command: $(yarn bin)/cypress verify
- run:
name: Cypress help
working_directory: test-binary
command: $(yarn bin)/cypress help
- run:
name: Cypress info
working_directory: test-binary
command: $(yarn bin)/cypress info
- store-npm-logs
# install NPM + binary zip and run against staging API
@@ -1027,6 +1062,14 @@ jobs:
working_directory: test-binary
# force installing the freshly built binary
command: CYPRESS_INSTALL_BINARY=~/cypress/cypress.zip npm i ~/cypress/cypress.tgz
- run:
name: Cypress help
working_directory: test-binary
command: $(yarn bin)/cypress help
- run:
name: Cypress info
working_directory: test-binary
command: $(yarn bin)/cypress info
- run:
name: Add Cypress demo
working_directory: test-binary
@@ -1052,6 +1095,9 @@ linux-workflow: &linux-workflow
requires:
- build
# unit, integration and e2e tests
- cli-visual-tests:
requires:
- build
- unit-tests:
requires:
- build
+4
View File
@@ -205,6 +205,7 @@ exports['cli help command shows help 1'] = `
verify [options] Verifies that Cypress is installed correctly and
executable
cache [options] Manages the Cypress binary cache
info [options] Prints Cypress and system information
-------
stderr:
-------
@@ -240,6 +241,7 @@ exports['cli help command shows help for -h 1'] = `
verify [options] Verifies that Cypress is installed correctly and
executable
cache [options] Manages the Cypress binary cache
info [options] Prints Cypress and system information
-------
stderr:
-------
@@ -275,6 +277,7 @@ exports['cli help command shows help for --help 1'] = `
verify [options] Verifies that Cypress is installed correctly and
executable
cache [options] Manages the Cypress binary cache
info [options] Prints Cypress and system information
-------
stderr:
-------
@@ -311,6 +314,7 @@ exports['cli unknown command shows usage and exits 1'] = `
verify [options] Verifies that Cypress is installed correctly and
executable
cache [options] Manages the Cypress binary cache
info [options] Prints Cypress and system information
-------
stderr:
-------
+55
View File
@@ -0,0 +1,55 @@
exports['cypress info without browsers or vars'] = `
Proxy Settings: none detected
Environment Variables: none detected
Application Data: /user/app/data/path
Browser Profiles: /user/app/data/path/to/browsers
Binary Caches: /user/path/to/binary/cache
Cypress Version: 0.0.0
System Platform: linux (Foo-OsVersion)
System Memory: 1.2 GB free 400 MB
`
exports['cypress info with proxy and vars'] = `
Proxy Settings:
PROXY_ENV_VAR1: some proxy variable
PROXY_ENV_VAR2: another proxy variable
Learn More: https://on.cypress.io/proxy-configuration
Environment Variables:
CYPRESS_ENV_VAR1: my Cypress variable
CYPRESS_ENV_VAR2: my other Cypress variable
Application Data: /user/app/data/path
Browser Profiles: /user/app/data/path/to/browsers
Binary Caches: /user/path/to/binary/cache
Cypress Version: 0.0.0
System Platform: linux (Foo-OsVersion)
System Memory: 1.2 GB free 400 MB
`
exports['cypress redacts sensitive vars'] = `
Proxy Settings: none detected
Environment Variables:
CYPRESS_ENV_VAR1: my Cypress variable
CYPRESS_ENV_VAR2: my other Cypress variable
CYPRESS_PROJECT_ID: abc123
CYPRESS_RECORD_KEY: <redacted>
Application Data: /user/app/data/path
Browser Profiles: /user/app/data/path/to/browsers
Binary Caches: /user/path/to/binary/cache
Cypress Version: 0.0.0
System Platform: linux (Foo-OsVersion)
System Memory: 1.2 GB free 400 MB
`
+13
View File
@@ -129,6 +129,7 @@ const knownCommands = [
'-v',
'--version',
'version',
'info',
]
const text = (description) => {
@@ -298,6 +299,18 @@ module.exports = {
cache[command]()
})
program
.command('info')
.usage('[command]')
.description('Prints Cypress and system information')
.option('--dev', text('dev'), coerceFalse)
.action((opts) => {
require('./exec/info')
.start(opts)
.then(util.exit)
.catch(util.logErrorExit1)
})
debug('cli starts with arguments %j', args)
util.printNodeOptions()
+1 -11
View File
@@ -1,4 +1,3 @@
const os = require('os')
const chalk = require('chalk')
const { stripIndent, stripIndents } = require('common-tags')
const { merge } = require('ramda')
@@ -245,17 +244,8 @@ const CYPRESS_RUN_BINARY = {
},
}
function getPlatformInfo () {
return util.getOsVersionAsync().then((version) => {
return stripIndent`
Platform: ${os.platform()} (${version})
Cypress Version: ${util.pkgVersion()}
`
})
}
function addPlatformInformation (info) {
return getPlatformInfo().then((platform) => {
return util.getPlatformInfo().then((platform) => {
return merge(info, { platform })
})
}
+93
View File
@@ -0,0 +1,93 @@
/* eslint-disable no-console */
const spawn = require('./spawn')
const util = require('../util')
const state = require('../tasks/state')
const os = require('os')
const chalk = require('chalk')
const prettyBytes = require('pretty-bytes')
const _ = require('lodash')
const R = require('ramda')
// color for numbers and show values
const g = chalk.green
// color for paths
const p = chalk.cyan
// urls
const link = chalk.blue.underline
// to be exported
const methods = {}
methods.findProxyEnvironmentVariables = () => {
return _.pick(process.env, ['HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY'])
}
const maskSensitiveVariables = R.evolve({
CYPRESS_RECORD_KEY: R.always('<redacted>'),
})
methods.findCypressEnvironmentVariables = () => {
const isCyVariable = (val, key) => key.startsWith('CYPRESS_')
return R.pickBy(isCyVariable)(process.env)
}
const formatCypressVariables = () => {
const vars = methods.findCypressEnvironmentVariables()
return maskSensitiveVariables(vars)
}
methods.start = (options = {}) => {
const args = ['--mode=info']
return spawn.start(args, {
dev: options.dev,
})
.then(() => {
console.log()
const proxyVars = methods.findProxyEnvironmentVariables()
if (_.isEmpty(proxyVars)) {
console.log('Proxy Settings: none detected')
} else {
console.log('Proxy Settings:')
_.forEach(proxyVars, (value, key) => {
console.log('%s: %s', key, g(value))
})
console.log()
console.log('Learn More: %s', link('https://on.cypress.io/proxy-configuration'))
console.log()
}
})
.then(() => {
const cyVars = formatCypressVariables()
if (_.isEmpty(cyVars)) {
console.log('Environment Variables: none detected')
} else {
console.log('Environment Variables:')
_.forEach(cyVars, (value, key) => {
console.log('%s: %s', key, g(value))
})
}
})
.then(() => {
console.log()
console.log('Application Data:', p(util.getApplicationDataFolder()))
console.log('Browser Profiles:', p(util.getApplicationDataFolder('browsers')))
console.log('Binary Caches: %s', p(state.getCacheDir()))
})
.then(() => {
console.log()
return util.getOsVersionAsync().then((osVersion) => {
console.log('Cypress Version: %s', g(util.pkgVersion()))
console.log('System Platform: %s (%s)', g(os.platform()), g(osVersion))
console.log('System Memory: %s free %s', g(prettyBytes(os.totalmem())), g(prettyBytes(os.freemem())))
})
})
}
module.exports = methods
+8 -3
View File
@@ -14,16 +14,21 @@ const clear = () => {
}
const list = () => {
return fs
.readdirAsync(state.getCacheDir())
.filter(util.isSemver)
return getCachedVersions()
.then((versions) => {
logger.log(versions.join(', '))
})
}
const getCachedVersions = () => {
return fs
.readdirAsync(state.getCacheDir())
.filter(util.isSemver)
}
module.exports = {
path,
clear,
list,
getCachedVersions,
}
+32
View File
@@ -1,6 +1,7 @@
const _ = require('lodash')
const R = require('ramda')
const os = require('os')
const ospath = require('ospath')
const crypto = require('crypto')
const la = require('lazy-ass')
const is = require('check-more-types')
@@ -225,6 +226,26 @@ const parseOpts = (opts) => {
return cleanOpts
}
/**
* Copy of packages/server/lib/browsers/utils.ts
* because we need same functionality in CLI to show the path :(
*/
const getApplicationDataFolder = (...paths) => {
const { env } = process
// allow overriding the app_data folder
const folder = env.CYPRESS_KONFIG_ENV || env.CYPRESS_ENV || 'development'
const PRODUCT_NAME = pkg.productName || pkg.name
const OS_DATA_PATH = ospath.data()
const ELECTRON_APP_DATA_PATH = path.join(OS_DATA_PATH, PRODUCT_NAME)
const p = path.join(ELECTRON_APP_DATA_PATH, 'cy', folder, ...paths)
return p
}
const util = {
normalizeModuleOptions,
parseOpts,
@@ -380,6 +401,15 @@ const util = {
})
},
getPlatformInfo () {
return util.getOsVersionAsync().then((version) => {
return stripIndent`
Platform: ${os.platform()} (${version})
Cypress Version: ${util.pkgVersion()}
`
})
},
// attention:
// when passing relative path to NPM post install hook, the current working
// directory is set to the `node_modules/cypress` folder
@@ -457,6 +487,8 @@ const util = {
getFileChecksum,
getFileSize,
getApplicationDataFolder,
}
module.exports = util
+2
View File
@@ -46,6 +46,8 @@
"log-symbols": "3.0.0",
"minimist": "1.2.0",
"moment": "2.24.0",
"ospath": "1.2.2",
"pretty-bytes": "5.3.0",
"ramda": "0.26.1",
"request": "2.88.0",
"request-progress": "3.0.0",
+19 -1
View File
@@ -4,12 +4,14 @@ const os = require('os')
const cli = require(`${lib}/cli`)
const util = require(`${lib}/util`)
const logger = require(`${lib}/logger`)
const info = require(`${lib}/exec/info`)
const run = require(`${lib}/exec/run`)
const open = require(`${lib}/exec/open`)
const state = require(`${lib}/tasks/state`)
const verify = require(`${lib}/tasks/verify`)
const install = require(`${lib}/tasks/install`)
const snapshot = require('../support/snapshot')
const debug = require('debug')('test')
const execa = require('execa-wrap')
describe('cli', () => {
@@ -22,7 +24,11 @@ describe('cli', () => {
// sinon.stub(util, 'exit')
sinon.stub(util, 'logErrorExit1')
this.exec = (args) => {
return cli.init(`node test ${args}`.split(' '))
const cliArgs = `node test ${args}`.split(' ')
debug('calling cli.init with: %o', cliArgs)
return cli.init(cliArgs)
}
})
@@ -449,4 +455,16 @@ describe('cli', () => {
})
})
})
context('cypress info', () => {
beforeEach(() => {
sinon.stub(info, 'start').resolves(0)
sinon.stub(util, 'exit').withArgs(0)
})
it('calls info start', () => {
this.exec('info')
expect(info.start).to.have.been.calledWith()
})
})
})
+71
View File
@@ -0,0 +1,71 @@
require('../../spec_helper')
const os = require('os')
const util = require(`${lib}/util`)
const state = require(`${lib}/tasks/state`)
const info = require(`${lib}/exec/info`)
const spawn = require(`${lib}/exec/spawn`)
const snapshot = require('../../support/snapshot')
const stdout = require('../../support/stdout')
const normalize = require('../../support/normalize')
describe('exec info', function () {
beforeEach(function () {
sinon.stub(process, 'exit')
// common stubs
sinon.stub(spawn, 'start').resolves()
os.platform.returns('linux')
sinon.stub(os, 'totalmem').returns(1.2e+9)
sinon.stub(os, 'freemem').returns(4e+8)
sinon.stub(info, 'findProxyEnvironmentVariables').returns({})
sinon.stub(info, 'findCypressEnvironmentVariables').returns({})
sinon.stub(util, 'getApplicationDataFolder')
.withArgs('browsers').returns('/user/app/data/path/to/browsers')
.withArgs().returns('/user/app/data/path')
sinon.stub(state, 'getCacheDir').returns('/user/path/to/binary/cache')
})
const startInfoAndSnapshot = async (snapshotName) => {
expect(snapshotName, 'missing snapshot name').to.be.a('string')
const output = stdout.capture()
await info.start()
stdout.restore()
snapshot(snapshotName, normalize(output.toString()))
}
it('prints collected info without env vars', async () => {
await startInfoAndSnapshot('cypress info without browsers or vars')
expect(spawn.start).to.be.calledWith(['--mode=info'], { dev: undefined })
})
it('prints proxy and cypress env vars', async () => {
info.findProxyEnvironmentVariables.returns({
PROXY_ENV_VAR1: 'some proxy variable',
PROXY_ENV_VAR2: 'another proxy variable',
})
info.findCypressEnvironmentVariables.returns({
CYPRESS_ENV_VAR1: 'my Cypress variable',
CYPRESS_ENV_VAR2: 'my other Cypress variable',
})
await startInfoAndSnapshot('cypress info with proxy and vars')
})
it('redacts sensitive cypress variables', async () => {
info.findCypressEnvironmentVariables.returns({
CYPRESS_ENV_VAR1: 'my Cypress variable',
CYPRESS_ENV_VAR2: 'my other Cypress variable',
CYPRESS_PROJECT_ID: 'abc123', // not sensitive
CYPRESS_RECORD_KEY: 'really really secret stuff', // should not be printed
})
await startInfoAndSnapshot('cypress redacts sensitive vars')
})
})
+8 -3
View File
@@ -8,9 +8,12 @@ const removeExcessWhiteSpace = (str) => {
return str.replace(whitespaceAtEndOfLineRe, '')
}
module.exports = (str) => {
// strip dates and ansi codes
// and excess whitespace
/**
* strip dates and ansi codes and excess whitespace
* @param {string} str input string
* @returns {string} cleaned output string
*/
const normalize = (str) => {
return stripAnsi(
str
.replace(datesRe, 'xx:xx:xx')
@@ -20,3 +23,5 @@ module.exports = (str) => {
.replace(downloadQueryRe, '?platform=OS&arch=ARCH')
)
}
module.exports = normalize
+2
View File
@@ -159,6 +159,7 @@
"mock-fs": "4.9.0",
"parse-github-repo-url": "1.4.1",
"patch-package": "6.2.0",
"percy": "0.21.0",
"plist": "2.1.0",
"pluralize": "8.0.0",
"postinstall-postinstall": "2.0.0",
@@ -175,6 +176,7 @@
"snap-shot-it": "7.9.1",
"stop-only": "3.0.1",
"strip-ansi": "4.0.0",
"term-to-html": "1.0.0",
"terminal-banner": "1.1.0",
"through": "2.3.8",
"ts-node": "8.3.0",
@@ -0,0 +1,82 @@
exports['two browsers with firefox having profile folder'] = `
Displaying Cypress info...
Detected 2 browsers installed:
1. Chrome
- Name: chrome
- Channel: stable
- Version: 12.34.56
- Executable: /path/to/google-chrome
2. Firefox Dev
- Name: firefox
- Channel: dev
- Version: 79.0a1
- Executable: /path/to/firefox
- Profile: /path/to/user/firefox/profile
Note: to run these browsers, pass <name>:<channel> to the '--browser' field
Examples:
- cypress run --browser chrome
- cypress run --browser firefox:dev
Learn More: https://on.cypress.io/launching-browsers
`
exports['output without any browsers'] = `
Displaying Cypress info...
Detected no known browsers installed
`
exports['single chrome:stable'] = `
Displaying Cypress info...
Detected 1 browser installed:
1. Chrome
- Name: chrome
- Channel: stable
- Version: 12.34.56
- Executable: /path/to/google-chrome
Note: to run these browsers, pass <name>:<channel> to the '--browser' field
Examples:
- cypress run --browser chrome
Learn More: https://on.cypress.io/launching-browsers
`
exports['two browsers'] = `
Displaying Cypress info...
Detected 2 browsers installed:
1. Chrome
- Name: chrome
- Channel: stable
- Version: 12.34.56
- Executable: /path/to/google-chrome
2. Firefox Dev
- Name: firefox
- Channel: dev
- Version: 79.0a1
- Executable: /path/to/firefox
Note: to run these browsers, pass <name>:<channel> to the '--browser' field
Examples:
- cypress run --browser chrome
- cypress run --browser firefox:dev
Learn More: https://on.cypress.io/launching-browsers
`
+3
View File
@@ -19,6 +19,7 @@ const PATH_TO_BROWSERS = appData.path('browsers')
const pathToProfiles = path.join(PATH_TO_BROWSERS, '*')
const getBrowserPath = (browser) => {
// TODO need to check if browser.name is an unempty string
return path.join(
PATH_TO_BROWSERS,
`${browser.name}-${browser.channel}`
@@ -178,6 +179,8 @@ export = {
copyExtension,
getBrowserPath,
getProfileDir,
getExtensionDir,
+5
View File
@@ -188,6 +188,11 @@ module.exports = {
}).then(exit0)
.catch(exitErr)
case 'info':
return require('./modes/info')(options)
.then(exit0)
.catch(exitErr)
case 'smokeTest':
return this.runElectron(mode, options)
.then((pong) => {
+2 -2
View File
@@ -8,6 +8,7 @@ os = require("os")
## to the "packages/server" folder
cwd = require("./cwd")
Promise = require("bluebird")
debug = require("debug")("cypress:server")
## never cut off stack traces
Error.stackTraceLimit = Infinity
@@ -64,7 +65,6 @@ try
electronLaunchArguments.forEach app.commandLine.appendArgument
catch e
if env is "development"
console.error(e.message)
debug("environment error %s", e.message)
module.exports = env
+139
View File
@@ -0,0 +1,139 @@
/* eslint-disable no-console */
const debug = require('debug')('cypress:server:info')
const launcher = require('@packages/launcher')
const pluralize = require('pluralize')
const { stripIndent } = require('common-tags')
const { sortWith, ascend, prop } = require('ramda')
const browserUtils = require('../browsers/utils')
const _ = require('lodash')
const chalk = require('chalk')
const fs = require('../util/fs')
// color for numbers and short values
const n = chalk.green
// color for paths
const p = chalk.cyan
// color for accents and examples
const a = chalk.yellow
// urls
const link = chalk.blue.underline
/**
* If the list has at least 1 item, picks a random item
* and returns it AND the remaining items.
*/
const pickRandomItem = (list) => {
if (!list.length) {
return {
item: null,
remaining: list,
}
}
const item = _.sample(list)
const remaining = _.without(list, item)
return {
item, remaining,
}
}
// Usually the full browser name to pass via --browser
// is <name>:<channel>. If the channel is stable, you
// can just do "--browser <name>"
const formBrowserName = (browser) => {
if (browser.channel === 'stable') {
return browser.name
}
return `${browser.name}:${browser.channel}`
}
// for each browser computes the profile folder
// and checks if the folder exists. If exists,
// adds it to the browser object as a property
const addProfilePath = async (browsers = []) => {
for (const browser of browsers) {
const profilePath = browserUtils.getBrowserPath(browser)
debug('checking profile path %s for browser %s:%s', profilePath, browser.name, browser.channel)
try {
const profileExists = await fs.statAsync(profilePath)
if (profileExists && profileExists.isDirectory()) {
debug('profile folder exists %s', profilePath)
browser.profilePath = profilePath
}
} catch (e) {
debug('problem checking profile folder %s %s', profilePath, e.message)
}
}
return browsers
}
const print = (browsers = []) => {
console.log('Displaying Cypress info...')
console.log('')
if (browsers.length) {
console.log('Detected %s %s installed:', n(browsers.length), pluralize('browser', browsers.length))
} else {
console.log('Detected no known browsers installed')
}
console.log('')
const sortByNameAndMajor = sortWith([
ascend(prop('name')),
ascend(prop('majorVersion')),
])
const sortedByNameAndMajorVersion = sortByNameAndMajor(browsers)
sortedByNameAndMajorVersion.forEach((browser, k) => {
const text = stripIndent`
${k + 1}. ${a(browser.displayName)}
- Name: ${browser.name}
- Channel: ${browser.channel}
- Version: ${n(browser.version)}
- Executable: ${p(browser.path)}
${browser.profilePath ? `- Profile: ${browser.profilePath}` : ''}
`
console.log(text)
console.log('')
})
// randomly a few detected browsers to use as examples
if (browsers.length) {
const highlightedBrowser = a('--browser')
console.log('Note: to run these browsers, pass <name>:<channel> to the \'%s\' field',
highlightedBrowser)
console.log('')
const firstDraw = pickRandomItem(browsers)
if (firstDraw.item) {
console.log('Examples:')
console.log(a(`- cypress run --browser ${formBrowserName(firstDraw.item)}`))
const secondDraw = pickRandomItem(firstDraw.remaining)
if (secondDraw.item) {
console.log(a(`- cypress run --browser ${formBrowserName(secondDraw.item)}`))
}
}
console.log('')
console.log('Learn More: %s', link('https://on.cypress.io/launching-browsers'))
}
}
const info = () => {
return launcher.detect()
.then(addProfilePath)
.then(print)
}
module.exports = info
@@ -0,0 +1,96 @@
require('../../spec_helper')
const info = require(`${root}../lib/modes/info`)
const capture = require(`${root}../lib/capture`)
const browserUtils = require(`${root}../lib/browsers/utils`)
const fs = require(`${root}../lib/util/fs`)
const launcher = require('@packages/launcher')
const snapshot = require('snap-shot-it')
const stripAnsi = require('strip-ansi')
const _ = require('lodash')
describe('lib/modes/info', () => {
beforeEach(() => {
capture.restore()
})
afterEach(() => {
capture.restore()
})
const chromeStable = {
displayName: 'Chrome',
name: 'chrome',
channel: 'stable',
version: '12.34.56',
majorVersion: 12,
path: '/path/to/google-chrome',
}
const firefoxDev = {
displayName: 'Firefox Dev',
name: 'firefox',
channel: 'dev',
version: '79.0a1',
majorVersion: 79,
path: '/path/to/firefox',
}
const infoAndSnapshot = async (snapshotName) => {
expect(snapshotName, 'missing snapshot name').to.be.a('string')
const captured = capture.stdout()
await info()
capture.restore()
snapshot(snapshotName, stripAnsi(captured.toString()))
}
it('prints no browsers', async () => {
sinon.stub(launcher, 'detect').resolves([])
await infoAndSnapshot('output without any browsers')
})
it('prints 1 found browser', async () => {
sinon.stub(launcher, 'detect').resolves([chromeStable])
await infoAndSnapshot('single chrome:stable')
})
it('prints 2 found browsers', async () => {
sinon.stub(launcher, 'detect').resolves([chromeStable, firefoxDev])
// have to make sure random sampling from the browser list
// to create examples returns same order
// so Chrome will be picked first, Firefox will be second
const sample = sinon.stub(_, 'sample')
sample.onFirstCall().returns(chromeStable)
sample.onSecondCall().returns(firefoxDev)
await infoAndSnapshot('two browsers')
expect(sample, 'two browsers were picked to create examples').to.be.calledTwice
})
it('adds profile for browser if folder exists', async () => {
sinon.stub(launcher, 'detect').resolves([chromeStable, firefoxDev])
sinon.stub(browserUtils, 'getBrowserPath')
.withArgs(chromeStable).returns('/path/to/user/chrome/profile')
.withArgs(firefoxDev).returns('/path/to/user/firefox/profile')
sinon.stub(fs, 'statAsync')
.withArgs('/path/to/user/chrome/profile').throws('No Chrome profile folder')
.withArgs('/path/to/user/firefox/profile').resolves({
isDirectory: _.stubTrue,
})
// have to make sure random sampling from the browser list
// to create examples returns same order
// so Chrome will be picked first, Firefox will be second
const sample = sinon.stub(_, 'sample')
sample.onFirstCall().returns(chromeStable)
sample.onSecondCall().returns(firefoxDev)
await infoAndSnapshot('two browsers with firefox having profile folder')
})
})
+51
View File
@@ -0,0 +1,51 @@
// call this script to sanitize output of the command
// AFTER converting ANSI escape codes into HTML tags
const arg = require('arg')
const args = arg({
'--type': String,
})
const sanitizeCliInfo = () => {
const chromiumVersion = /- Version: (<.+>)(\d{2,3}.\d\.\d+.\d+)(<.+>)/g
const firefoxVersion = /- Version: (<.+>)(\d{2,3}.\d\.\d+|\d+\.[0-9a-z])(<.+>)+/g
const browserArgument = /--browser (\w+:?\w+)/g
// there is only a single line with memory usage
const systemMemory = /System Memory: (<.+>)([\w.]+ \w+)(<.+>) free (<.+>)([\w.]+ \w+)(<.+>)/
const replaceChromiumVersion = (match, openTag, version, closeTag) => {
return `- Version: ${openTag}***chromium version***${closeTag}`
}
const replaceFirefoxVersion = (match, openTag, version, closeTag) => {
return `- Version: ${openTag}***firefox version***${closeTag}`
}
const replaceBrowserArgument = (match, browserName) => {
return '--browser ***name:channel***'
}
const replaceSystemMemory = (match, tag1, total, tag2, tag3, free, tag4) => {
return `System Memory: ${tag1}***total memory***${tag2} free ${tag3}***free memory***${tag4}`
}
const sanitize = (chunk) => {
return chunk.replace(chromiumVersion, replaceChromiumVersion)
.replace(firefoxVersion, replaceFirefoxVersion)
.replace(browserArgument, replaceBrowserArgument)
.replace(systemMemory, replaceSystemMemory)
}
process.stdin.setEncoding('utf8')
process.stdin.on('data', function (chunk) {
return process.stdout.write(sanitize(chunk))
})
}
switch (args['--type']) {
case 'cli-info':
sanitizeCliInfo()
break
default:
throw new Error(`Unknown STDOUT type to sanitize "${args['--type']}"`)
}
+553 -29
View File
File diff suppressed because it is too large Load Diff