Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: issue with array environment variables not being handled correct… #8151

Merged
merged 8 commits into from Aug 14, 2020
26 changes: 25 additions & 1 deletion packages/server/lib/util/coerce.js
Expand Up @@ -7,12 +7,36 @@ const isValue = (value) => {
}
}

// https://github.com/cypress-io/cypress/issues/6810
const toArray = (value) => {
dmoini marked this conversation as resolved.
Show resolved Hide resolved
const valueIsNotStringOrArray = typeof (value) !== 'string' || (value[0] !== '[' && value[value.length - 1] !== ']')

if (valueIsNotStringOrArray) {
return
}

// '[foo,bar]' => ['foo', 'bar']
const convertStringToArray = () => value.substring(1, value.length - 1).split(',')
const arr = convertStringToArray()

// The default `toString` array method returns one string containing each array element separated
// by commas, but without '[' or ']'. If an environment variable is intended to be an array, it
// will begin and end with '[' and ']' respectively. To correctly compare the value argument to
// the value in `process.env`, the `toString` method must be updated to include '[' and ']'.
// Default `toString()` on array: ['foo', 'bar'].toString() => 'foo,bar'
// Custom `toString()` on array: ['foo', 'bar'].toString() => '[foo,bar]'
arr.toString = () => `[${arr.join(',')}]`

return arr
}

module.exports = (value) => {
const num = _.toNumber(value)
const bool = toBoolean(value)
const arr = toArray(value)

return _
.chain([num, bool])
.chain([num, bool, arr])
.find(isValue(value))
.defaultTo(value)
.value()
Expand Down
9 changes: 9 additions & 0 deletions packages/server/test/unit/args_spec.js
Expand Up @@ -169,6 +169,15 @@ describe('lib/util/args', () => {
hash: '769e98018',
})
})

// https://github.com/cypress-io/cypress/issues/6810
it('handles values that are arrays', function () {
const options = this.setup('--env', 'foo="[bar1,bar2,bar3]"')

expect(options.config.env).to.deep.eq({
foo: '[bar1|bar2|bar3]',
})
})
})

context('--reporterOptions', () => {
Expand Down
69 changes: 69 additions & 0 deletions packages/server/test/unit/coerce_spec.js
@@ -0,0 +1,69 @@
require('../spec_helper')

const coerce = require(`${root}lib/util/coerce`)
const getProcessEnvVars = require(`${root}lib/config`).getProcessEnvVars

describe('lib/util/coerce', () => {
beforeEach(function () {
this.env = process.env
})

afterEach(function () {
process.env = this.env
})

context('coerce', () => {
it('coerces string', () => {
expect(coerce('foo')).to.eq('foo')
})

it('coerces string from process.env', () => {
process.env['CYPRESS_STRING'] = 'bar'
const cypressEnvVar = getProcessEnvVars(process.env)

expect(coerce(cypressEnvVar)).to.deep.include({ STRING: 'bar' })
})

it('coerces number', () => {
expect(coerce('123')).to.eq(123)
})

// NOTE: When exporting shell variables, they are saved in `process.env` as strings, hence why
// all `process.env` variables are assigned as strings in these unit tests
it('coerces number from process.env', () => {
process.env['CYPRESS_NUMBER'] = '8000'
const cypressEnvVar = getProcessEnvVars(process.env)

expect(coerce(cypressEnvVar)).to.deep.include({ NUMBER: 8000 })
})

it('coerces boolean', () => {
expect(coerce('true')).to.be.true
})

it('coerces boolean from process.env', () => {
process.env['CYPRESS_BOOLEAN'] = 'false'
const cypressEnvVar = getProcessEnvVars(process.env)

expect(coerce(cypressEnvVar)).to.deep.include({ BOOLEAN: false })
})

it('coerces array', () => {
expect(coerce('[foo,bar]')).to.have.members(['foo', 'bar'])
})

it('coerces array from process.env', () => {
process.env['CYPRESS_ARRAY'] = '[google.com,yahoo.com]'
const cypressEnvVar = getProcessEnvVars(process.env)

const coercedCypressEnvVar = coerce(cypressEnvVar)

expect(coercedCypressEnvVar).to.have.keys('ARRAY')
expect(coercedCypressEnvVar['ARRAY']).to.have.members(['google.com', 'yahoo.com'])
})

it('defaults value with multiple types to string', () => {
expect(coerce('123foo456')).to.eq('123foo456')
})
})
})