Skip to content

Commit

Permalink
feat: add concurrently & wait-on command (#34)
Browse files Browse the repository at this point in the history
* refactor(install cmd): extract logic into their own functions
* refactor: ask for testFiles config in cucumber step & collect all paths
* feat: use concurrently and wait-on to start both app and cypress
* refactor(open & run cmd): extract shared code into tools modules
* fix(cypress config): spread object instead of array into object
  • Loading branch information
Mohammer5 authored May 7, 2020
1 parent 647ffad commit b1d067b
Show file tree
Hide file tree
Showing 16 changed files with 451 additions and 301 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,19 @@
},
"dependencies": {
"@dhis2/cli-helpers-engine": "^1.5.0",
"concurrently": "^5.2.0",
"cross-spawn": "^7.0.1",
"cypress": "^4.0.2",
"cypress-cucumber-preprocessor": "^2.0.1",
"fs-extra": "^8.1.0",
"inquirer": "^7.0.4"
"inquirer": "^7.0.4",
"wait-on": "^4.0.2"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@dhis2/cli-style": "^6.0.0",
"@dhis2/cli-utils-docsite": "^1.3.0",
"concurrently": "^5.1.0",
"wait-on": "^4.0.0"
"@dhis2/cli-utils-docsite": "^1.3.0"
}
}
16 changes: 16 additions & 0 deletions src/commands/common/sharedCLIOptions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const appStart = {
describe: 'Command to start app (disabled with empty string)',
type: 'string',
default: 'yarn start',
}

const waitOn = {
describe: 'Url to wait for before running cypress',
type: 'string',
default: 'http-get://localhost:3000',
}

module.exports = {
appStart,
waitOn,
}
253 changes: 15 additions & 238 deletions src/commands/install.js
Original file line number Diff line number Diff line change
@@ -1,112 +1,17 @@
const path = require('path')
const fs = require('fs-extra')

const inquirer = require('inquirer')

const log = require('@dhis2/cli-helpers-engine').reporter

const { createCucumberConfigs } = require('./install/createCucumberConfigs.js')
const { createCypressConfig } = require('./install/createCypressConfig.js')
const {
CONSUMING_ROOT,
CYPRESS_ROOT,
CYPRESS_FIXTURES,
CYPRESS_INTEGRATION,
CYPRESS_PLUGINS,
CYPRESS_SUPPORT,
} = require('../utils/paths.js')

const extractOrgName = moduleName => {
const matches = moduleName.match(/^@[^/]+(?=\/)/)

if (!matches || !matches.length) {
return 'dhis2'
}

const [orgNameWithAtSymbol] = matches
return orgNameWithAtSymbol.replace('@', '')
}

const extractAppName = moduleName => {
const matches = moduleName.match(/^@[^/]+\/(.+)$/)
const appName = matches && matches.length > 1 ? matches[1] : moduleName

return appName
.replace(/-app$/, '') // dhis2 apps' names end with "app"
.replace(/\W/g, '')
}

const readJson = filename => {
const filepath = path.join(CONSUMING_ROOT, filename)
const exists = fs.existsSync(filepath)

if (!exists) {
log.warn(`File: '${filename}' does not exist`)
return
}

let content
try {
content = JSON.parse(fs.readFileSync(filepath))
} catch (e) {
log.error(`Could not parse contents of file: '${filename}'`)
return
}

return content
}

const addToJson = (filename, data, overwrite = false) => {
const filepath = path.join(CONSUMING_ROOT, filename)
const exists = fs.existsSync(filepath)

if (!exists) {
log.warn(`File: '${filename}' does not exist`)
return
}

if (overwrite) {
return write(filename, data, true)
}

const existingData = readJson(filename)
return write(filename, { ...existingData, ...data }, true)
}

const write = (filename, data, overwrite) => {
const filepath = path.join(CONSUMING_ROOT, filename)
const exists = fs.existsSync(filepath)
const content = JSON.stringify(data, null, 4)

if (exists && !overwrite) {
log.warn(`Existing file: '${filename}', use --force to overwrite.`)
return
}

fs.writeFileSync(filepath, content, { encoding: 'utf8' })
}

function copy(from, to, overwrite = true) {
try {
const exists = fs.existsSync(to)
const empty = exists ? fs.statSync(to).size === 0 : false

const replace = empty ? true : overwrite

if (exists && !replace) {
log.print(`Skip existing: ${path.relative(process.cwd(), to)}`)
} else {
log.print(`Installing: ${path.relative(process.cwd(), to)}`)
}
fs.ensureDirSync(path.dirname(to))
fs.copySync(from, to, { overwrite: replace })
} catch (err) {
log.error(`Failed to install configuration file: ${to}`, err)
}
}
createCypressEnvConfig,
} = require('./install/createCypressEnvConfig.js')
const {
createCypressSupportFile,
} = require('./install/createCypressSupportFile.js')
const { ensureDirectories } = require('./install/ensureDirectories.js')

exports.command = 'install'

exports.aliases = ['i']

exports.desc = 'Install DHIS2 Cypress configuration into project'

exports.builder = yargs =>
Expand Down Expand Up @@ -140,153 +45,25 @@ exports.builder = yargs =>
exports.handler = async argv => {
log.info('d2-utils-cypress > install')

const { force, cypressConfig, cypressEnv, cucumber, support } = argv
try {
const { force, cypressConfig, cypressEnv, cucumber, support } = argv

const prompt = inquirer.createPromptModule()
ensureDirectories()

try {
if (cypressConfig) {
const cypressAnswers = await prompt([
{
type: 'input',
name: 'baseUrl',
message: 'URL that Cypress should run tests against:',
default: 'http://localhost:3000',
},
{
type: 'input',
name: 'testFiles',
message: 'Glob pattern for the test files to run:',
default: '**/*.feature',
},
{
type: 'confirm',
name: 'video',
message: 'Record video?',
default: false,
},
{
type: 'input',
name: 'projectId',
message: 'The unique Cypress project ID:',
},
])

write(
'cypress.json',
{
baseUrl: cypressAnswers.baseUrl,
testFiles: cypressAnswers.testFiles,
video: cypressAnswers.video,
...(cypressAnswers.projectId
? [cypressAnswers.projectId]
: []),
},
force
)
await createCypressConfig(force)
}

if (cypressEnv) {
const envAnswers = await prompt([
{
type: 'input',
name: 'dhis2Url',
message: 'The DHIS2 instance URL to use as backend:',
default: 'http://localhost:8080',
},
{
type: 'input',
name: 'username',
message: 'DHIS2 Username:',
default: 'admin',
},
{
type: 'input',
name: 'password',
message: 'DHIS2 Username password:',
default: 'district',
},
])

write(
'cypress.env.json',
{
dhis2_base_url: envAnswers.dhis2Url,
dhis2_username: envAnswers.username,
dhis2_password: envAnswers.password,
},
force
)

log.info(
'Make sure to add `cypress.env.json` to the `.gitignore` file!'
)
await createCypressEnvConfig(force)
}

fs.ensureDirSync(CYPRESS_ROOT)
fs.ensureDirSync(CYPRESS_FIXTURES)
fs.ensureDirSync(CYPRESS_INTEGRATION)
fs.ensureDirSync(CYPRESS_PLUGINS)
fs.ensureDirSync(CYPRESS_SUPPORT)

if (cucumber) {
const cucFrom = path.join(
__dirname,
'..',
'..',
'templates',
'plugins.js'
)
const cucTo = path.join(CYPRESS_PLUGINS, 'index.js')
copy(cucFrom, cucTo, force)

const cucConfFrom = path.join(
__dirname,
'..',
'..',
'templates',
'cucumber-config.js'
)
const cucConfTo = path.join(
CONSUMING_ROOT,
'cypress-cucumber-preprocessor.config.js'
)
copy(cucConfFrom, cucConfTo, force)
await createCucumberConfigs(force)
}

if (support) {
const supFrom = path.join(
__dirname,
'..',
'..',
'templates',
'support.js'
)
const supTo = path.join(CYPRESS_SUPPORT, 'index.js')
copy(supFrom, supTo, force)

const packageJson = readJson('package.json')
const moduleName = packageJson ? packageJson.name : ''
const orgName = extractOrgName(moduleName)
const appName = extractAppName(moduleName)
const prefixDefault = [
...(orgName ? [orgName] : []),
...(appName ? [appName] : []),
].join('-')

const envAnswers = await prompt([
{
type: 'input',
name: 'dhis2DatatestPrefix',
message:
'The prefix for the cy.get data-test attributes of the app (e. g. "dhis2-appname-"):',
...(prefixDefault ? { default: prefixDefault } : {}),
},
])

addToJson('cypress.env.json', {
dhis2_datatest_prefix: envAnswers.dhis2DatatestPrefix,
})
await createCypressSupportFile(force)
}
} catch (e) {
log.error(e)
Expand Down
39 changes: 39 additions & 0 deletions src/commands/install/createCucumberConfigs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const inquirer = require('inquirer')
const { addToJson } = require('../../utils/fs.js')
const { copy } = require('../../utils/fs.js')
const {
CYPRESS_CONFIG_PATH,
CUCUMBER_PLUGIN_TEMPLATE_SOURCE,
CUCUMBER_PLUGIN_TEMPLATE_DESTINATION,
CUCUMBER_CONFIG_TEMPLATE_SOURCE,
CUCUMBER_CONFIG_TEMPLATE_DESTINATION,
} = require('../../utils/paths.js')

const createCucumberConfigs = async force => {
const prompt = inquirer.createPromptModule()

copy(
CUCUMBER_PLUGIN_TEMPLATE_SOURCE,
CUCUMBER_PLUGIN_TEMPLATE_DESTINATION,
force
)

copy(
CUCUMBER_CONFIG_TEMPLATE_SOURCE,
CUCUMBER_CONFIG_TEMPLATE_DESTINATION,
force
)

const { testFiles } = await prompt([
{
type: 'input',
name: 'testFiles',
message: 'Glob pattern for the test files to run:',
default: '**/*.feature',
},
])

addToJson(CYPRESS_CONFIG_PATH, { testFiles })
}

module.exports = { createCucumberConfigs }
Loading

0 comments on commit b1d067b

Please sign in to comment.