Skip to content

Commit

Permalink
Issue 1155 (#1272)
Browse files Browse the repository at this point in the history
* server: move hosts out of CLI args, keep as config only

* server, desktop-gui: fixes #1155 accept blacklistHosts from config CLI, display array on desktop gui settings

* server: pass args.config since its no longer flattened

* server: WIP trying to simplify config management

* server: fixes failing tests and circular refs

* server: fix failing tests with config hosts updates
  • Loading branch information
brian-mann authored Feb 7, 2018
1 parent 001a310 commit 31f22c2
Show file tree
Hide file tree
Showing 13 changed files with 233 additions and 80 deletions.
7 changes: 7 additions & 0 deletions packages/desktop-gui/cypress/fixtures/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"env": {

},
"blacklistHosts": ["www.google-analytics.com", "hotjar.com"],
"execTimeout": 60000,
"fileServerFolder": "/Users/jennifer/Dev/Projects/cypress-example-kitchensink",
"fixturesFolder": "/Users/jennifer/Dev/Projects/cypress-example-kitchensink/cypress/fixtures",
Expand Down Expand Up @@ -186,6 +187,12 @@
"from": "default",
"value": true
},
"blacklistHosts": {
"from": "config",
"value": [
"www.google-analytics.com", "hotjar.com"
]
},
"hosts": {
"from": "config",
"value": {
Expand Down
19 changes: 16 additions & 3 deletions packages/desktop-gui/cypress/integration/settings_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,26 @@ describe "Settings", ->
it "displays 'null' values", ->
cy.get(".line").contains("null")

it "displays 'object' values for environmentVariables and hosts", ->
it "displays 'object' values for env and hosts", ->
cy
.get(".nested").first()
.get(".nested-obj").eq(0)
.contains("fixturesFolder")
.get(".nested").eq(1)
.get(".nested-obj").eq(1)
.contains("*.foobar.com")

it "displays 'array' values for blacklistHosts", ->
cy
.get(".nested-arr")
.parent()
.should('contain', '[')
.and('contain', ']')
.and('not.contain', '0')
.and('not.contain', '1')
.find('.line .config').should ($lines) ->
expect($lines).to.have.length(2)
expect($lines).to.contain('www.google-analytics.com')
expect($lines).to.contain('hotjar.com')

it "opens help link on click", ->
cy
.get(".settings-config .learn-more").click().then ->
Expand Down
61 changes: 51 additions & 10 deletions packages/desktop-gui/src/settings/configuration.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,30 @@ const display = (obj) => {
return _.map(obj, (value, key) => {
const hasComma = lastKey !== key
if (value.from == null) {
return displayNested(key, value, hasComma)
} else if (_.isObject(value.value)) {
return displayNestedObj(key, value, hasComma)
}

if (value.isArray) {
return getSpan(key, value, hasComma, true)
}

if (_.isObject(value.value)) {
const realValue = value.value.toJS ? value.value.toJS() : value.value

if (_.isArray(realValue)) {
return displayArray(key, value, hasComma)
}

return displayObject(key, value, hasComma)
} else {
return getSpan(key, value, hasComma)
}

return getSpan(key, value, hasComma)
})
}

const displayNested = (key, value, hasComma) => (
const displayNestedObj = (key, value, hasComma) => (
<span key={key}>
<span className='nested'>
<span className='nested nested-obj'>
<span className='key'>{key}</span>
<span className='colon'>:</span>{' '}
{'{'}
Expand All @@ -34,21 +46,42 @@ const displayNested = (key, value, hasComma) => (
</span>
)

const displayNestedArr = (key, value, hasComma) => (
<span key={key}>
<span className='nested nested-arr'>
<span className='key'>{key}</span>
<span className='colon'>:</span>{' '}
{'['}
{display(value)}
</span>
<span className='line'>{']'}{getComma(hasComma)}</span>
<br />
</span>
)

const displayArray = (key, nestedArr, hasComma) => {
const arr = _.map(nestedArr.value, (value) => {
return { value, from: nestedArr.from, isArray: true }
})

return displayNestedArr(key, arr, hasComma)
}

const displayObject = (key, nestedObj, hasComma) => {
const obj = _.reduce(nestedObj.value, (obj, value, key) => {
return _.extend(obj, {
[key]: { value, from: nestedObj.from },
})
}, {})

return displayNested(key, obj, hasComma)
return displayNestedObj(key, obj, hasComma)
}

const getSpan = (key, obj, hasComma) => {
const getSpan = (key, obj, hasComma, isArray) => {
return (
<div key={key} className='line'>
<span className='key'>{key}</span>
<span className='colon'>:</span>{' '}
{getKey(key, isArray)}
{getColon(isArray)}
<Tooltip title={obj.from || ''} placement='right' className='cy-tooltip'>
<span className={obj.from}>
{getString(obj.value)}
Expand All @@ -61,6 +94,14 @@ const getSpan = (key, obj, hasComma) => {
)
}

const getKey = (key, isArray) => {
return isArray ? '' : <span className='key'>{key}</span>
}

const getColon = (isArray) => {
return isArray ? '' : <span className="colon">:{' '}</span>
}

const getString = (val) => {
return _.isString(val) ? '\'' : ''
}
Expand Down
33 changes: 31 additions & 2 deletions packages/server/lib/config.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pathHelpers = require("./util/path_helpers")
cypressEnvRe = /^(cypress_)/i
dashesOrUnderscoresRe = /^(_-)+/
oneOrMoreSpacesRe = /\s+/
everythingAfterFirstEqualRe = /=(.+)/

toWords = (str) ->
str.trim().split(oneOrMoreSpacesRe)
Expand All @@ -42,8 +43,9 @@ configKeys = toWords """
screenshotOnHeadlessFailure defaultCommandTimeout
testFiles execTimeout
trashAssetsBeforeHeadlessRuns pageLoadTimeout
userAgent requestTimeout
viewportWidth responseTimeout
blacklistHosts requestTimeout
userAgent responseTimeout
viewportWidth
viewportHeight
videoRecording
videoCompression
Expand All @@ -52,6 +54,27 @@ configKeys = toWords """
waitForAnimations
"""

toArrayFromPipes = (str) ->
if _.isArray(str)
return str

[].concat(str.split('|'))

toObjectFromPipes = (str) ->
if _.isObject(str)
return str

## convert foo=bar|version=1.2.3 to
## {foo: 'bar', version: '1.2.3'}
_
.chain(str)
.split("|")
.map (pair) ->
pair.split("=")
.fromPairs()
.mapValues(coerce)
.value()

defaults = {
port: null
hosts: null
Expand Down Expand Up @@ -213,6 +236,12 @@ module.exports = {
config.cypressEnv = process.env["CYPRESS_ENV"]
delete config.envFile

if hosts = config.hosts
config.hosts = toObjectFromPipes(hosts)

if blacklistHosts = config.blacklistHosts
config.blacklistHosts = toArrayFromPipes(blacklistHosts)

## when headless
if config.isTextTerminal
## dont ever watch for file changes
Expand Down
2 changes: 1 addition & 1 deletion packages/server/lib/open_project.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ create = ->
relaunchBrowser()
})

options = _.extend {}, config.whitelist(args), options
options = _.extend {}, args.config, options

browsers.get()
.then (b = []) ->
Expand Down
77 changes: 45 additions & 32 deletions packages/server/lib/util/args.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ coerce = require("./coerce")
config = require("../config")
cwd = require("../cwd")

whitelist = "cwd appPath execPath apiKey smokeTest getKey generateKey runProject project spec ci record updating ping key logs clearLogs returnPkg version mode autoOpen removeIds headed config exit exitWithCode hosts browser headless outputPath group groupId parallel parallelId".split(" ")
whitelist = whitelist.concat(config.getConfigKeys())

nestedObjectsInCurlyBracesRe = /\{(.+?)\}/g
nestedArraysInSquareBracketsRe = /\[(.+?)\]/g
everythingAfterFirstEqualRe = /=(.+)/

whitelist = "cwd appPath execPath apiKey smokeTest getKey generateKey runProject project spec reporter reporterOptions port env ci record updating ping key logs clearLogs returnPkg version mode removeIds headed config exit exitWithCode browser headless outputPath group groupId parallel parallelId".split(" ")

# returns true if the given string has double quote character "
# only at the last position.
hasStrayEndQuote = (s) ->
Expand Down Expand Up @@ -39,28 +40,37 @@ normalizeBackslashes = (options) ->

options

parseArrayValues = (vals) ->
[].concat(vals.split(','))
backup = (key, options) ->
options["_#{key}"] = options[key]

anyUnderscoredValuePairs = (val, key, obj) ->
return v if v = obj["_#{key}"]
return val

strToArray = (str) ->
[].concat(str.split(","))

commasForBars = (match, p1) ->
## swap out comma's for bars
p1.split(",").join("|")

sanitizeAndConvertNestedArgs = (str) ->
## find foo={a=b,b=c} and bar=[1,2,3] syntax first
## and turn those into
## foo: a=b|b=c
## bar: 1|2|3

parseNestedValues = (vals) ->
## convert foo=bar,version=1.2.3 to
## {foo: 'bar', version: '1.2.3'}
_
.chain(vals)
.chain(str)
.replace(nestedObjectsInCurlyBracesRe, commasForBars)
.replace(nestedArraysInSquareBracketsRe, commasForBars)
.split(",")
.map (pair) ->
pair.split(everythingAfterFirstEqualRe)
.fromPairs()
.mapValues(coerce)
.value()

backup = (key, options) ->
options["_#{key}"] = options[key]

anyUnderscoredValuePairs = (val, key, obj) ->
return v if v = obj["_#{key}"]
return val

module.exports = {
toObject: (argv) ->
## takes an array of args and converts
Expand All @@ -77,7 +87,6 @@ module.exports = {
"clear-logs": "clearLogs"
"run-project": "runProject"
"return-pkg": "returnPkg"
"auto-open": "autoOpen"
"headless": "isTextTerminal"
"exit-with-code": "exitWithCode"
"reporter-options": "reporterOptions"
Expand Down Expand Up @@ -115,32 +124,36 @@ module.exports = {
resolvePath = (p) ->
path.resolve(options.cwd, p)

options.spec = parseArrayValues(spec).map(resolvePath)

if hosts = options.hosts
backup("hosts", options)
options.hosts = parseNestedValues(hosts)
options.spec = strToArray(spec).map(resolvePath)

if envs = options.env
backup("env", options)
options.env = parseNestedValues(envs)
options.env = sanitizeAndConvertNestedArgs(envs)

if ro = options.reporterOptions
backup("reporterOptions", options)
options.reporterOptions = parseNestedValues(ro)
options.reporterOptions = sanitizeAndConvertNestedArgs(ro)

if c = options.config
backup("config", options)

## convert config to an object
c = parseNestedValues(c)

## store the config
options.config = c

## and pull up and flatten any whitelisted
## config directly into our options
_.extend options, config.whitelist(c)
## annd store the config
options.config = sanitizeAndConvertNestedArgs(c)

## get a list of the available config keys
configKeys = config.getConfigKeys()

## and if any of our options match this
configValues = _.pick(options, configKeys)

## then set them on config
## this solves situations where we accept
## root level arguments which also can
## be set in configuration
_.each configValues, (val, key) ->
options.config ?= {}
options.config[key] = val

options = normalizeBackslashes(options)

Expand Down
4 changes: 2 additions & 2 deletions packages/server/test/e2e/domain_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ e2e = require("../support/helpers/e2e")
HOSTS = [
"app.localhost=127.0.0.1"
"foo.bar.baz.com.au=127.0.0.1"
].join(",")
].join("|")

describe "e2e domain", ->
e2e.setup({
Expand All @@ -16,7 +16,7 @@ describe "e2e domain", ->
it "passing", ->
e2e.exec(@, {
spec: "domain_spec.coffee"
hosts: HOSTS
config: "hosts={#{HOSTS}}"
snapshot: true
expectedExitCode: 0
})
2 changes: 1 addition & 1 deletion packages/server/test/e2e/iframe_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ describe "e2e iframes", ->

it "passes", ->
e2e.exec(@, {
hosts: "*.foo.com=127.0.0.1,*.bar.com=127.0.0.1"
spec: "iframe_spec.coffee"
snapshot: true
expectedExitCode: 0
config: "hosts={*.foo.com=127.0.0.1|*.bar.com=127.0.0.1}"
})
2 changes: 1 addition & 1 deletion packages/server/test/e2e/subdomain_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ describe "e2e subdomain", ->
it "passes", ->
e2e.exec(@, {
spec: "subdomain_spec.coffee"
hosts: "*.foobar.com=127.0.0.1"
snapshot: true
expectedExitCode: 0
config: "hosts={*.foobar.com=127.0.0.1}"
})
Loading

0 comments on commit 31f22c2

Please sign in to comment.