@adobe/generator-aio-app
Version:
Adobe I/O application yeoman code generator
274 lines (235 loc) • 8.63 kB
JavaScript
/*
Copyright 2021 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/
const helpers = require('yeoman-test')
const assert = require('yeoman-assert')
const fs = require('fs-extra')
const path = require('path')
jest.mock('fs-extra')
const theGeneratorPath = require.resolve('../../../generators/add-vscode-config')
const Generator = require('yeoman-generator')
const createOptions = () => {
return {
'app-config': {
app: {
hasBackend: true,
hasFrontend: true
},
ow: {
package: 'my-package',
apihost: 'https://my-api.host'
},
manifest: {
packagePlaceholder: '__APP_PACKAGE__',
full: {
packages: {
__APP_PACKAGE__: {
actions: {
'action-1': { function: 'src/actions/action-1' }
}
}
}
}
},
web: {
src: 'html',
distDev: 'dist-dev'
},
root: 'root'
},
'frontend-url': 'https://localhost:9080',
'env-file': 'my/.env'
}
}
const createTestLaunchConfiguration = (packageName) => {
return {
configurations: [
{
type: 'pwa-node',
name: `Action:${packageName}/action-1`,
request: 'launch',
runtimeExecutable: '${workspaceFolder}/node_modules/.bin/wskdebug', // eslint-disable-line no-template-curly-in-string
envFile: '${workspaceFolder}/my/.env', // eslint-disable-line no-template-curly-in-string
timeout: 30000,
localRoot: '${workspaceFolder}', // eslint-disable-line no-template-curly-in-string
remoteRoot: '/code',
outputCapture: 'std',
attachSimplePort: 0,
runtimeArgs: [
`${packageName}/__secured_action-1`,
'${workspaceFolder}/src/actions/action-1', // eslint-disable-line no-template-curly-in-string
'-v',
'--kind',
'nodejs:14'
]
},
{
type: 'chrome',
name: 'Web',
request: 'launch',
url: 'https://localhost:9080',
webRoot: 'html',
breakOnLoad: true,
sourceMapPathOverrides: {
'*': path.join('dist-dev', '*')
}
}
],
compounds: [
{
name: 'Actions',
configurations: [
`Action:${packageName}/action-1`
]
},
{
name: 'WebAndActions',
configurations: [
`Action:${packageName}/action-1`,
'Web'
]
}
]
}
}
beforeEach(() => {
fs.lstatSync.mockReset()
fs.existsSync.mockReset()
})
test('exports a yeoman generator', () => {
expect(require(theGeneratorPath).prototype).toBeInstanceOf(Generator)
})
test('option app-config incomplete', async () => {
const options = {
'app-config': {
app: {
}
}
}
const result = helpers.run(theGeneratorPath).withOptions(options)
await expect(result).rejects.toEqual(new Error(
'App config missing keys: app.hasFrontend, app.hasBackend, ow.package, ow.apihost, manifest.packagePlaceholder, manifest.full.packages, web.src, web.distDev, root'))
})
test('option frontend-url missing', async () => {
const options = createOptions()
options['app-config'].app.hasBackend = false
options['app-config'].app.hasFrontend = true
options['frontend-url'] = undefined
options['env-file'] = 'env-file'
const result = helpers.run(theGeneratorPath).withOptions(options)
await expect(result).rejects.toEqual(new Error('Missing option for generator: frontend-url'))
})
test('option env-file missing', async () => {
const options = createOptions()
options['app-config'].app.hasBackend = true
options['app-config'].app.hasFrontend = true
options['frontend-url'] = 'https://localhost:9999'
delete options['env-file']
const result = helpers.run(theGeneratorPath).withOptions(options)
await expect(result).rejects.toEqual(new Error('Missing option for generator: env-file'))
})
test('no missing options (action is a file)', async () => {
const options = createOptions()
options['app-config'].app.hasBackend = false
options['app-config'].app.hasFrontend = false
fs.lstatSync.mockReturnValue({
isDirectory: () => false
})
const result = helpers.run(theGeneratorPath).withOptions(options)
await expect(result).resolves.not.toThrow()
})
test('no missing options (action is a folder)', async () => {
const options = createOptions()
let result
fs.lstatSync.mockReturnValue({
isDirectory: () => true
})
fs.readJsonSync.mockReturnValue({}) // no main property in package.json
result = helpers.run(theGeneratorPath).withOptions(options)
await expect(result).resolves.not.toThrow()
fs.readJsonSync.mockReturnValue({ main: 'main.js' }) // has main property in package.json
result = helpers.run(theGeneratorPath).withOptions(options)
await expect(result).resolves.not.toThrow()
})
test('no missing options (coverage: action has a runtime specifier)', async () => {
const options = createOptions()
const pkg = options['app-config'].manifest.full.packages.__APP_PACKAGE__
pkg.actions['action-1'].runtime = 'nodejs:14'
fs.lstatSync.mockReturnValue({
isDirectory: () => false
})
const result = helpers.run(theGeneratorPath).withOptions(options)
await expect(result).resolves.not.toThrow()
})
test('no missing options (coverage: action has annotations)', async () => {
const options = createOptions()
options['app-config'].ow.apihost = 'https://adobeioruntime.net'
const pkg = options['app-config'].manifest.full.packages.__APP_PACKAGE__
pkg.actions['action-1'].annotations = { 'require-adobe-auth': true }
fs.lstatSync.mockReturnValue({
isDirectory: () => false
})
const result = helpers.run(theGeneratorPath).withOptions(options)
await expect(result).resolves.not.toThrow()
})
test('output check', async () => {
const options = createOptions()
const pkg = options['app-config'].manifest.full.packages.__APP_PACKAGE__
pkg.actions['action-1'].runtime = 'nodejs:14'
pkg.actions['action-1'].annotations = {
'require-adobe-auth': true
}
options['app-config'].ow.apihost = 'https://adobeioruntime.net'
options['destination-file'] = 'foo/bar.json'
fs.lstatSync.mockReturnValue({
isDirectory: () => false
})
const result = helpers.run(theGeneratorPath).withOptions(options)
await expect(result).resolves.not.toThrow()
const destFile = options['destination-file']
assert.file(destFile) // destination file is written
assert.JSONFileContent(destFile, createTestLaunchConfiguration(options['app-config'].ow.package))
})
test('output check (custom package)', async () => {
const customPackage = 'my-custom-package'
const options = createOptions()
const packages = options['app-config'].manifest.full.packages
packages[customPackage] = Object.assign({}, packages.__APP_PACKAGE__)
delete packages.__APP_PACKAGE__
packages[customPackage].actions['action-1'].runtime = 'nodejs:14'
packages[customPackage].actions['action-1'].annotations = {
'require-adobe-auth': true
}
options['app-config'].ow.apihost = 'https://adobeioruntime.net'
options['destination-file'] = 'foo/bar.json'
fs.lstatSync.mockReturnValue({
isDirectory: () => false
})
const result = helpers.run(theGeneratorPath).withOptions(options)
await expect(result).resolves.not.toThrow()
const destFile = options['destination-file']
assert.file(destFile) // destination file is written
assert.JSONFileContent(destFile, createTestLaunchConfiguration(customPackage))
})
test('vscode launch configuration exists', async () => {
const options = createOptions()
options['destination-file'] = 'foo/bar.json'
fs.lstatSync.mockReturnValue({
isDirectory: () => false
})
fs.existsSync.mockReturnValue(true) // destination file exists
const result = helpers
.run(theGeneratorPath)
.withOptions(options)
.withPrompts({ overwriteVsCodeConfig: false })
await expect(result).resolves.not.toThrow()
const destFile = options['destination-file']
assert.noFile(destFile) // destination file is not written
})