Skip to content
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
5 changes: 5 additions & 0 deletions src/commands/templates/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ class InstallCommand extends BaseCommand {
const yeoman = await import('yeoman-environment')
const env = yeoman.createEnv()
env.options = { skipInstall: !flags.install }
// yeoman-environment v4 removed the env.error() method; add it back for backwards compatibility
// with generators that still call this.env.error() (e.g. @adobe/generator-app-common-lib)
if (typeof env.error !== 'function') {
env.error = (err) => { throw err instanceof Error ? err : new Error(err) }
}
spinner.info(`Running template ${templateName}`)

const templateOptions = flags['template-options'] || {}
Expand Down
58 changes: 58 additions & 0 deletions test/commands/templates/install.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ beforeEach(() => {
runHook: jest.fn().mockResolvedValue({ successes: [], failures: [] })
}
jest.clearAllMocks()
// The shim added by install.js sets env.error on createEnvReturnValue; remove it
// between tests so each test starts with the mock env having no error method.
delete createEnvReturnValue.error
})

test('exports', async () => {
Expand Down Expand Up @@ -192,6 +195,61 @@ describe('run', () => {
})
})

test('install adds env.error shim for yeoman-environment v4 compatibility', async () => {
const templateName = 'my-adobe-package'
command.argv = [templateName]

readPackageJson.mockResolvedValueOnce({
dependencies: { [templateName]: '^1.0.0' }
})

getNpmDependency.mockResolvedValueOnce([templateName, '1.0.0'])

await command.run()

// The shim should have been added to the env object
expect(typeof createEnvReturnValue.error).toBe('function')
// Calling shim with a plain string should throw a wrapped Error
expect(() => createEnvReturnValue.error('plain error')).toThrow('plain error')
// Calling shim with an Error instance should re-throw it unchanged
const err = new Error('real error')
expect(() => createEnvReturnValue.error(err)).toThrow(err)
})

test('install from package name - env already has error method (no shim needed)', async () => {
const templateName = 'my-adobe-package'
command.argv = [templateName]

readPackageJson.mockResolvedValueOnce({
dependencies: {
[templateName]: '^1.0.0'
}
})

getNpmDependency.mockResolvedValueOnce([templateName, '1.0.0'])

// Simulate yeoman-environment that already has the error method (e.g. v3)
// so that the backwards-compatibility shim branch is NOT entered
const existingErrorFn = jest.fn()
createEnvReturnValue.error = existingErrorFn

expect.assertions(9)
await expect(command.run()).resolves.toBeUndefined()
expect(runScript).toHaveBeenCalledWith('npm', process.cwd(), ['install', templateName])
expect(yeomanEnvInstantiate).toHaveBeenCalledWith(expect.any(Object), { options: { 'skip-prompt': false, force: true } })
expect(yeomanEnvOptionsSet).toHaveBeenCalledWith({ skipInstall: false })
expect(yeomanEnvRunGenerator).toHaveBeenCalledWith(expect.any(Object))
expect(mockTemplateHandlerInstance.installTemplate).toHaveBeenCalledWith('org-id', 'project-id')
expect(getTemplateRequiredServiceNames).not.toHaveBeenCalled()
expect(writeObjectToPackageJson).toHaveBeenCalledWith({
[TEMPLATE_PACKAGE_JSON_KEY]: [
templateName
]
})
// The original error fn must remain unchanged (shim was not applied)
expect(createEnvReturnValue.error).toBe(existingErrorFn)
})

test('install from package name skipping prompts', async () => {
const templateName = 'my-adobe-package'
command.argv = ['--yes', templateName]
Expand Down
Loading