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

env config settings is displayed correctly #5879

Merged
merged 13 commits into from
Dec 12, 2019
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
85 changes: 85 additions & 0 deletions packages/desktop-gui/cypress/integration/settings_spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { _ } = Cypress
const { each, flow, get, isString, join, map, merge, set, sortBy, toPairs } = require('lodash/fp')

describe('Settings', () => {
beforeEach(function () {
Expand Down Expand Up @@ -181,6 +182,82 @@ describe('Settings', () => {
expect(this.ipc.externalOpen).to.be.calledWith('https://on.cypress.io/guides/configuration')
})
})

it('displays null when env settings are empty or not defined', function () {
this.ipc.openProject.resolves(setConfigEnv(this.config, undefined))
this.ipc.onConfigChanged.yield()

cy.contains('.line', 'env:null').then(() => {
this.ipc.openProject.resolves(this.config)
this.ipc.onConfigChanged.yield()

cy.contains('.line', 'env:fileServerFolder')
.then(() => {
this.ipc.openProject.resolves(setConfigEnv(this.config, null))
this.ipc.onConfigChanged.yield()
cy.contains('.line', 'env:null').then(() => {
this.ipc.openProject.resolves(this.config)
this.ipc.onConfigChanged.yield()

cy.contains('.line', 'env:fileServerFolder')
.then(() => {
this.ipc.openProject.resolves(setConfigEnv(this.config, {}))
this.ipc.onConfigChanged.yield()
cy.contains('.line', 'env:null')
})
})
})
})
})

it('displays env settings', () => {
cy.get('@config').then(({ resolved }) => {
const getEnvKeys = flow([
get('env'),
toPairs,
map(([key]) => key),
sortBy(get('')),
])

const assertKeyExists = each((key) => cy.contains('.line', key))
const assertKeyValuesExists = flow([
map((key) => {
return flow([
get(['env', key, 'value']),
(v) => {
if (isString(v)) {
return `"${v}"`
}

return v
},
])(resolved)
}),
each((v) => {
cy.contains('.key-value-pair-value', v)
}),
])

const assertFromTooltipsExist = flow([
map((key) => {
return [key,
flow([
get(['env', key, 'from']),
(from) => `.${from}`,
])(resolved)]
}),
each(([key, fromTooltipClassName]) => {
cy.contains(key).parents('.line').first().find(fromTooltipClassName)
}),
])

cy.contains('.line', 'env').contains(flow([getEnvKeys, join(', ')])(resolved))
cy.contains('.line', 'env').click()
flow([getEnvKeys, assertKeyExists])(resolved)
flow([getEnvKeys, assertKeyValuesExists])(resolved)
flow([getEnvKeys, assertFromTooltipsExist])(resolved)
})
})
})

describe('when project id panel is opened', () => {
Expand Down Expand Up @@ -519,3 +596,11 @@ describe('Settings', () => {
})
})
})

// --
function setConfigEnv (config, v) {
return flow([
merge(config),
set('resolved.env', v),
])({})
}
96 changes: 67 additions & 29 deletions packages/desktop-gui/src/settings/configuration.jsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,77 @@
import _ from 'lodash'
import { defaultTo, get, flow, isEmpty, join, map, reduce, take, toPairs, toPath } from 'lodash/fp'
import cn from 'classnames'
import { observer } from 'mobx-react'
import React from 'react'
import Tooltip from '@cypress/react-tooltip'
import { ObjectInspector, ObjectName } from 'react-inspector'

import { configFileFormatted } from '../lib/config-file-formatted'
import ipc from '../lib/ipc'

const formatData = (data) => {
if (Array.isArray(data)) {
return _.map(data, (v) => {
if (_.isObject(v) && (v.name || v.displayName)) {
return _.defaultTo(v.displayName, v.name)
}

return String(v)
}).join(', ')
const joinWithCommas = join(', ')
const objToString = (v) => flow([
defaultTo(v.name),
defaultTo(_.isObject(v) ? joinWithCommas(Object.keys(v)) : undefined),
defaultTo(String(v)),
])(v.displayName)

const formatValue = (value) => {
if (Array.isArray(value)) {
return flow([
map(objToString),
joinWithCommas,
])(value)
}

if (_.isObject(data)) {
return _.defaultTo(_.defaultTo(data.displayName, data.name), String(Object.keys(data).join(', ')))
if (_.isObject(value)) {
return objToString(value)
}

const excludedFromQuotations = ['null', 'undefined']

if (_.isString(data) && !excludedFromQuotations.includes(data)) {
return `"${data}"`
if (_.isString(value) && !excludedFromQuotations.includes(value)) {
return `"${value}"`
}

return String(data)
return String(value)
}

const normalizeWithoutMeta = flow([
defaultTo({}),
toPairs,
reduce((acc, [key, value]) => _.merge({}, acc, {
[key]: value ? value.value : {},
}), {}),
(v) => {
if (isEmpty(v)) {
return null
}

return v
},
])

const ObjectLabel = ({ name, data, expanded, from, isNonenumerable }) => {
const formattedData = formatData(data)
const formattedData = formatValue(data)

return (
<span className="line" key={name}>
<ObjectName name={name} dimmed={isNonenumerable} />
<span>:</span>
{!expanded && (
<>
<Tooltip title={from} placement='right' className='cy-tooltip'>
{from && (
<Tooltip title={from} placement='right' className='cy-tooltip'>
<span className={cn(from, 'key-value-pair-value')}>
<span>{formattedData}</span>
</span>
</Tooltip>
)}
{!from && (
<span className={cn(from, 'key-value-pair-value')}>
<span>{formattedData}</span>
</span>
</Tooltip>
)}
</>
)}
{expanded && Array.isArray(data) && (
Expand All @@ -58,25 +85,36 @@ ObjectLabel.defaultProps = {
data: 'undefined',
}

const createComputeFromValue = (obj) => {
return (name, path) => {
const pathParts = path.split('.')
const pathDepth = pathParts.length
const computeFromValue = (obj, name, path) => {
const normalizedPath = path.replace('$.', '').replace(name, `['${name}']`)
const getValueForPath = flow([
toPath,
_.partialRight(get, obj),
])

let value = getValueForPath(normalizedPath)

if (!value) {
const onlyFirstKeyInPath = flow([toPath, take(1)])

const rootKey = pathDepth <= 2 ? name : pathParts[1]
value = getValueForPath(onlyFirstKeyInPath(normalizedPath))
}

return obj[rootKey] ? obj[rootKey].from : undefined
if (!value) {
return undefined
}

return value.from ? value.from : undefined
}

const ConfigDisplay = ({ data: obj }) => {
const computeFromValue = createComputeFromValue(obj)
const getFromValue = _.partial(computeFromValue, obj)
const renderNode = ({ depth, name, data, isNonenumerable, expanded, path }) => {
if (depth === 0) {
return null
}

const from = computeFromValue(name, path)
const from = getFromValue(name, path)

return (
<ObjectLabel
Expand All @@ -89,9 +127,9 @@ const ConfigDisplay = ({ data: obj }) => {
)
}

const data = _.reduce(obj, (acc, value, key) => Object.assign(acc, {
[key]: value.value,
}), {})
const data = normalizeWithoutMeta(obj)

data.env = normalizeWithoutMeta(obj.env)

return (
<div className="config-vars">
Expand Down