diff --git a/generators/add-action/index.js b/generators/add-action/index.js index 9f4e0463..9ae66e90 100644 --- a/generators/add-action/index.js +++ b/generators/add-action/index.js @@ -48,6 +48,7 @@ class AddActions extends Generator { // options are inputs from CLI or yeoman parent generator this.option('skip-prompt', { default: false }) this.option('adobe-services', { type: String, default: '' }) + this.option('skip-install', { type: String, default: false }) // todo throw meaningful error if add actions in a non existing project, but what defines a project? } diff --git a/generators/add-web-assets/index.js b/generators/add-web-assets/index.js index 631de345..60602b32 100644 --- a/generators/add-web-assets/index.js +++ b/generators/add-web-assets/index.js @@ -36,6 +36,7 @@ class AddWebAssets extends Generator { this.option('adobe-services', { type: String, default: '' }) // todo use real sdkCodes from console this.option('project-name', { type: String, default: guessProjectName(this) }) // project name is used in html template + this.option('skip-install', { type: String, default: false }) // todo throw meaningful error if add actions/webassets in a non existing project, but how to know if we are in a project? } diff --git a/generators/app/index.js b/generators/app/index.js index 8239969f..ece94b55 100644 --- a/generators/app/index.js +++ b/generators/app/index.js @@ -33,6 +33,7 @@ class CodeGenerator extends Generator { this.option('skip-prompt', { default: false }) this.option('adobe-services', { type: String, default: '' }) this.option('project-name', { type: String, default: path.basename(process.cwd()) }) // todo get name from console + this.option('skip-install', { type: String, default: false }) // props are passed to templates this.props = {} diff --git a/test/generators/add-action/index.test.js b/test/generators/add-action/index.test.js index 5d87b289..1f8ee210 100644 --- a/test/generators/add-action/index.test.js +++ b/test/generators/add-action/index.test.js @@ -1,4 +1,3 @@ -/* eslint-disable jest/expect-expect */ /* Copyright 2019 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); @@ -9,152 +8,149 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -jest.mock('yeoman-generator') +const helpers = require('yeoman-test') const utils = require('../../../lib/utils') - -const TheGenerator = require('../../../generators/add-action') +const theGeneratorPath = require.resolve('../../../generators/add-action') const Generator = require('yeoman-generator') +// spies +const prompt = jest.spyOn(Generator.prototype, 'prompt') +const composeWith = jest.spyOn(Generator.prototype, 'composeWith') +const installDependencies = jest.spyOn(Generator.prototype, 'installDependencies') +beforeAll(() => { + // mock implementations + composeWith.mockReturnValue(undefined) + installDependencies.mockReturnValue(undefined) +}) +beforeEach(() => { + prompt.mockClear() + composeWith.mockClear() + installDependencies.mockClear() +}) +afterAll(() => { + composeWith.mockRestore() + installDependencies.mockRestore() +}) + +jest.mock('../../../lib/utils') + describe('prototype', () => { test('exports a yeoman generator', () => { - expect(TheGenerator.prototype).toBeInstanceOf(Generator) + expect(require(theGeneratorPath).prototype).toBeInstanceOf(Generator) }) }) -describe('implementation', () => { - describe('constructor', () => { - test('accepts adobe-services option', () => { - const spy = jest.spyOn(TheGenerator.prototype, 'option') - // eslint-disable-next-line no-new - new TheGenerator() - expect(spy).toHaveBeenCalledWith('adobe-services', { type: String, default: '' }) - spy.mockRestore() - }) - test('accepts skip-prompt option', () => { - const spy = jest.spyOn(TheGenerator.prototype, 'option') - // eslint-disable-next-line no-new - new TheGenerator() - expect(spy).toHaveBeenCalledWith('skip-prompt', { default: false }) - spy.mockRestore() - }) +describe('run', () => { + test('--skip-prompt --adobe-services="analytics,target,campaign-standard"', async () => { + await helpers.run(theGeneratorPath) + .withOptions({ 'skip-prompt': true, 'adobe-services': 'analytics,target,campaign-standard', 'skip-install': false }) + // with skip prompt defaults to generic action + // make sure sub generators have been called + expect(composeWith).toHaveBeenCalledTimes(1) + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('generic/index.js'), expect.objectContaining({ + 'skip-prompt': true + })) + expect(installDependencies).toHaveBeenCalledTimes(1) + }) + + test('--skip-prompt --skip-install', async () => { + await helpers.run(theGeneratorPath) + .withOptions({ 'skip-prompt': true, 'skip-install': true }) + + // with skip prompt defaults to generic action + // make sure sub generators have been called + expect(composeWith).toHaveBeenCalledTimes(1) + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('generic/index.js'), expect.objectContaining({ + 'skip-prompt': true + })) + expect(installDependencies).toHaveBeenCalledTimes(0) }) - describe('prompting with composition', () => { - let prompt - let composeWith - let theGenerator - beforeEach(() => { - prompt = jest.spyOn(TheGenerator.prototype, 'prompt') - composeWith = jest.spyOn(TheGenerator.prototype, 'composeWith') - theGenerator = new TheGenerator() - }) - afterEach(() => { - prompt.mockRestore() - composeWith.mockRestore() - }) - - async function testPromptChoices (adobeServices, expectedChoices) { - // mock selected generator - prompt.mockResolvedValue({ - actionGenerators: ['fakeSelection'] - }) - theGenerator.options = { 'skip-prompt': false, 'adobe-services': adobeServices } - await theGenerator.prompting() + test('--adobe-services="NOTEXISTING" and selects fake generator a', async () => { + await helpers.run(theGeneratorPath) + .withOptions({ 'adobe-services': 'NOTEXITING', 'skip-install': false }) + .withPrompts({ actionGenerators: ['a'] }) - expect(prompt).toHaveBeenCalledWith([expect.objectContaining({ + // first make sure choices are displayed + expect(prompt).toHaveBeenCalledTimes(1) + expect(prompt).toHaveBeenCalledWith([ + expect.objectContaining({ + type: 'checkbox', name: 'actionGenerators', - choices: expectedChoices, validate: utils.atLeastOne, - type: 'checkbox' - })]) - } - - test('skip-prompt=false, check prompt choices for adobe-services=""', testPromptChoices.bind(this, '', [ - { name: 'Generic', value: expect.stringContaining('generic/index.js'), checked: true } - ])) - - // todo should we throw instead of ignore ? - test('skip-prompt=false, check prompt choices for adobe-services="notAservice"', testPromptChoices.bind(this, 'notAService', [ - { name: 'Generic', value: expect.stringContaining('generic/index.js'), checked: true } - ])) - - test('skip-prompt=false, check prompt choices for adobe-services="analytics"', testPromptChoices.bind(this, 'analytics', [ - { name: 'Adobe Analytics', value: expect.stringContaining('analytics/index.js') }, - { name: 'Generic', value: expect.stringContaining('generic/index.js'), checked: true } - ])) - - test('skip-prompt=false, check prompt choices for adobe-services=" analytics ,target "', testPromptChoices.bind(this, ' analytics ,target ', [ - { name: 'Adobe Analytics', value: expect.stringContaining('analytics/index.js') }, - { name: 'Adobe Target', value: expect.stringContaining('target/index.js') }, - { name: 'Generic', value: expect.stringContaining('generic/index.js'), checked: true } - ])) - - test('skip-prompt=false, check prompt choices for adobe-services=" analytics ,target , campaign-standard"', testPromptChoices.bind(this, ' analytics ,target , campaign-standard', [ - { name: 'Adobe Analytics', value: expect.stringContaining('analytics/index.js') }, - { name: 'Adobe Target', value: expect.stringContaining('target/index.js') }, - { name: 'Adobe Campaign Standard', value: expect.stringContaining('campaign-standard/index.js') }, - { name: 'Generic', value: expect.stringContaining('generic/index.js'), checked: true } - ])) - - test('skip-prompt=true"', async () => { - theGenerator.options = { 'skip-prompt': true, 'adobe-services': 'analytics, target, campaign-standard' } - await theGenerator.prompting() - - expect(prompt).toHaveBeenCalledTimes(0) - - expect(composeWith).toHaveBeenCalledTimes(1) - // if skip prompt makes sure defaults to generic - expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('generic/index.js'), { - 'skip-prompt': true + choices: [ + { name: 'Generic', value: expect.stringContaining('generic/index.js'), checked: true } + ] }) - }) + ]) - test('skip-prompt=false and user selected ["a", "b", "c"] (should call all three generators)', async () => { - // mock selection of generators - prompt.mockResolvedValue({ - actionGenerators: ['a', 'b', 'c'] - }) + expect(composeWith).toHaveBeenCalledTimes(1) + expect(composeWith).toHaveBeenCalledWith('a', expect.objectContaining({ + 'skip-prompt': false + })) + expect(installDependencies).toHaveBeenCalledTimes(1) + }) - theGenerator.options = { 'skip-prompt': false, 'adobe-services': '' } - await theGenerator.prompting() + test('--adobe-services="analytics" and selects fake generator a', async () => { + await helpers.run(theGeneratorPath) + .withOptions({ 'adobe-services': 'analytics', 'skip-install': false }) + .withPrompts({ actionGenerators: ['a'] }) - expect(prompt).toHaveBeenCalledTimes(1) - expect(composeWith).toHaveBeenCalledTimes(3) - // if skip prompt makes sure defaults to generic - expect(composeWith).toHaveBeenCalledWith('a', { - 'skip-prompt': false - }) - expect(composeWith).toHaveBeenCalledWith('b', { - 'skip-prompt': false - }) - expect(composeWith).toHaveBeenCalledWith('c', { - 'skip-prompt': false + // first make sure choices are displayed + expect(prompt).toHaveBeenCalledTimes(1) + expect(prompt).toHaveBeenCalledWith([ + expect.objectContaining({ + type: 'checkbox', + name: 'actionGenerators', + validate: utils.atLeastOne, + choices: [ + { name: 'Adobe Analytics', value: expect.stringContaining('analytics/index.js') }, + { name: 'Generic', value: expect.stringContaining('generic/index.js'), checked: true } + ] }) - }) + ]) + + expect(composeWith).toHaveBeenCalledTimes(1) + expect(composeWith).toHaveBeenCalledWith('a', expect.objectContaining({ + 'skip-prompt': false + })) + expect(installDependencies).toHaveBeenCalledTimes(1) }) - describe('install', () => { - let installDependencies - let theGenerator - beforeEach(() => { - installDependencies = jest.spyOn(TheGenerator.prototype, 'installDependencies') - theGenerator = new TheGenerator() - }) - afterEach(() => { - installDependencies.mockRestore() - }) - - test('skip-install=false', async () => { - theGenerator.options = { 'skip-install': false } - await theGenerator.install() - expect(installDependencies).toBeCalledTimes(1) - }) - - test('skip-install=true', async () => { - theGenerator.options = { 'skip-install': true } - await theGenerator.install() - expect(installDependencies).toBeCalledTimes(0) - }) + test('--adobe-services="analytics,target,campaign-standard" and selects fake generators a,b,c', async () => { + await helpers.run(theGeneratorPath) + .withOptions({ 'adobe-services': 'analytics,target,campaign-standard', 'skip-install': false }) + .withPrompts({ actionGenerators: ['a', 'b', 'c'] }) + + // first make sure choices are displayed + expect(prompt).toHaveBeenCalledTimes(1) + expect(prompt).toHaveBeenCalledWith([ + expect.objectContaining({ + type: 'checkbox', + name: 'actionGenerators', + validate: utils.atLeastOne, + choices: [ + { name: 'Adobe Analytics', value: expect.stringContaining('analytics/index.js') }, + { name: 'Adobe Target', value: expect.stringContaining('target/index.js') }, + { name: 'Adobe Campaign Standard', value: expect.stringContaining('campaign-standard/index.js') }, + { name: 'Generic', value: expect.stringContaining('generic/index.js'), checked: true } + ] + }) + ]) + + expect(composeWith).toHaveBeenCalledTimes(3) + expect(composeWith).toHaveBeenCalledWith('a', expect.objectContaining({ + 'skip-prompt': false + })) + expect(composeWith).toHaveBeenCalledWith('b', expect.objectContaining({ + 'skip-prompt': false + })) + expect(composeWith).toHaveBeenCalledWith('c', expect.objectContaining({ + 'skip-prompt': false + })) + expect(installDependencies).toHaveBeenCalledTimes(1) }) }) + +// todo check with existing files in project diff --git a/test/generators/add-web-assets/index.test.js b/test/generators/add-web-assets/index.test.js index ef21c57d..d0166af6 100644 --- a/test/generators/add-web-assets/index.test.js +++ b/test/generators/add-web-assets/index.test.js @@ -8,123 +8,116 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -jest.mock('yeoman-generator') +const helpers = require('yeoman-test') +const path = require('path') -const TheGenerator = require('../../../generators/add-web-assets') +const utils = require('../../../lib/utils') + +const theGeneratorPath = require.resolve('../../../generators/add-web-assets') const Generator = require('yeoman-generator') -jest.mock('../../../lib/utils') -const utils = require('../../../lib/utils') +// spies +const prompt = jest.spyOn(Generator.prototype, 'prompt') +const composeWith = jest.spyOn(Generator.prototype, 'composeWith') +const installDependencies = jest.spyOn(Generator.prototype, 'installDependencies') +beforeAll(() => { + // mock implementations + composeWith.mockReturnValue(undefined) + installDependencies.mockReturnValue(undefined) +}) +beforeEach(() => { + prompt.mockClear() + composeWith.mockClear() + installDependencies.mockClear() +}) +afterAll(() => { + composeWith.mockRestore() + installDependencies.mockRestore() +}) describe('prototype', () => { test('exports a yeoman generator', () => { - expect(TheGenerator.prototype).toBeInstanceOf(Generator) + expect(require(theGeneratorPath).prototype).toBeInstanceOf(Generator) }) }) -describe('implementation', () => { - describe('constructor', () => { - test('accepts adobe-services option', () => { - const spy = jest.spyOn(TheGenerator.prototype, 'option') - // eslint-disable-next-line no-new - new TheGenerator() - expect(spy).toHaveBeenCalledWith('adobe-services', { type: String, default: '' }) - spy.mockRestore() - }) - test('accepts skip-prompt option', () => { - const spy = jest.spyOn(TheGenerator.prototype, 'option') - // eslint-disable-next-line no-new - new TheGenerator() - expect(spy).toHaveBeenCalledWith('skip-prompt', { default: false }) - spy.mockRestore() - }) - test('accepts project-name option', () => { - const spy = jest.spyOn(TheGenerator.prototype, 'option') - - utils.guessProjectName.mockReturnValue('fake') - // eslint-disable-next-line no-new - new TheGenerator() - expect(spy).toHaveBeenCalledWith('project-name', { type: String, default: 'fake' }) - spy.mockRestore() - utils.guessProjectName.mockReset() - }) +describe('run', () => { + test('--skip-prompt', async () => { + const dir = await helpers.run(theGeneratorPath) + .withOptions({ 'skip-prompt': true, 'skip-install': false }) + + const expectProjectName = path.basename(dir) + + expect(composeWith).toHaveBeenCalledTimes(1) + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('raw/index.js'), expect.objectContaining({ + 'skip-prompt': true, + 'adobe-services': '', + 'project-name': expectProjectName + })) + expect(installDependencies).toHaveBeenCalledTimes(1) + }) + + test('--skip-prompt --project-name fake', async () => { + await helpers.run(theGeneratorPath) + .withOptions({ 'skip-prompt': true, 'skip-install': false, 'project-name': 'fake' }) + + expect(composeWith).toHaveBeenCalledTimes(1) + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('raw/index.js'), expect.objectContaining({ + 'skip-prompt': true, + 'adobe-services': '', + 'project-name': 'fake' + })) + expect(installDependencies).toHaveBeenCalledTimes(1) }) - describe('prompting with composition', () => { - let prompt - let composeWith - let theGenerator - beforeEach(() => { - prompt = jest.spyOn(TheGenerator.prototype, 'prompt') - composeWith = jest.spyOn(TheGenerator.prototype, 'composeWith') - theGenerator = new TheGenerator() - }) - afterEach(() => { - prompt.mockRestore() - composeWith.mockRestore() - }) - - test('project-name="fake", skip-prompt="true", adobe-services="some,string"', async () => { - theGenerator.options = { 'project-name': 'fake', 'skip-prompt': true, 'adobe-services': 'some,string' } - await theGenerator.prompting() - - expect(prompt).toHaveBeenCalledTimes(0) - - expect(composeWith).toHaveBeenCalledTimes(1) - - expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('raw/index.js'), { - 'skip-prompt': true, - 'project-name': 'fake', - 'adobe-services': 'some,string' - }) - }) - - test('project-name="fake", skip-prompt="false", adobe-services="some,string"', async () => { - // mock empty generators => behavior of when = false - prompt.mockResolvedValue({ - webAssetsGenerator: 'fakeSelectedGenerator' - }) - - theGenerator.options = { 'project-name': 'fake', 'skip-prompt': false, 'adobe-services': 'some,string' } - await theGenerator.prompting() - - expect(prompt).toHaveBeenCalledWith([expect.objectContaining({ + + test('--skip-prompt --skip-install --project-name fake', async () => { + await helpers.run(theGeneratorPath) + .withOptions({ 'skip-prompt': true, 'skip-install': true, 'project-name': 'fake' }) + + expect(composeWith).toHaveBeenCalledTimes(1) + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('raw/index.js'), expect.objectContaining({ + 'skip-prompt': true, + 'adobe-services': '', + 'project-name': 'fake' + })) + expect(installDependencies).toHaveBeenCalledTimes(0) + }) + + test('--skip-prompt --project-name fake --adobe-services=some,string', async () => { + await helpers.run(theGeneratorPath) + .withOptions({ 'skip-prompt': true, 'skip-install': false, 'project-name': 'fake', 'adobe-services': 'some,string' }) + + expect(composeWith).toHaveBeenCalledTimes(1) + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('raw/index.js'), expect.objectContaining({ + 'skip-prompt': true, + 'adobe-services': 'some,string', + 'project-name': 'fake' + })) + expect(installDependencies).toHaveBeenCalledTimes(1) + }) + + test('--project-name fake and selected prompt is fake generator "a"', async () => { + await helpers.run(theGeneratorPath) + .withOptions({ 'skip-install': false, 'project-name': 'fake' }) + .withPrompts({ webAssetsGenerator: 'a' }) + + // check choices + expect(prompt).toHaveBeenCalledWith( + [expect.objectContaining({ type: 'list', name: 'webAssetsGenerator', choices: [{ name: 'Raw HTML/JS', value: expect.stringContaining('raw/index.js') }], validate: utils.atLeastOne })]) - expect(composeWith).toHaveBeenCalledTimes(1) - // if skip prompt makes sure defaults to generic - expect(composeWith).toHaveBeenCalledWith('fakeSelectedGenerator', { - 'skip-prompt': false, - 'project-name': 'fake', - 'adobe-services': 'some,string' - }) - }) - }) - - describe('install', () => { - let installDependencies - let theGenerator - beforeEach(() => { - installDependencies = jest.spyOn(TheGenerator.prototype, 'installDependencies') - theGenerator = new TheGenerator() - }) - afterEach(() => { - installDependencies.mockRestore() - }) - - test('skip-install=false', async () => { - theGenerator.options = { 'skip-install': false } - await theGenerator.install() - expect(installDependencies).toBeCalledTimes(1) - }) - - test('skip-install=true', async () => { - theGenerator.options = { 'skip-install': true } - await theGenerator.install() - expect(installDependencies).toBeCalledTimes(0) - }) + expect(composeWith).toHaveBeenCalledTimes(1) + expect(composeWith).toHaveBeenCalledWith('a', expect.objectContaining({ + 'skip-prompt': false, + 'adobe-services': '', + 'project-name': 'fake' + })) + expect(installDependencies).toHaveBeenCalledTimes(1) }) }) + +// todo check with existing files in project diff --git a/test/generators/add-web-assets/raw.test.js b/test/generators/add-web-assets/raw.test.js index a105ed42..c17a8190 100644 --- a/test/generators/add-web-assets/raw.test.js +++ b/test/generators/add-web-assets/raw.test.js @@ -9,10 +9,75 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ +/* +Copyright 2019 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. +*/ + +/* eslint-disable jest/expect-expect */ // => use assert + +const helpers = require('yeoman-test') +const assert = require('yeoman-assert') + +const theGeneratorPath = require.resolve('../../../generators/add-web-assets/raw') const Generator = require('yeoman-generator') + describe('prototype', () => { - test('exports', () => { - const webAssetsGen = require('../../../generators/add-web-assets/raw') - expect(webAssetsGen.prototype).toBeInstanceOf(Generator) + test('exports a yeoman generator', () => { + expect(require(theGeneratorPath).prototype).toBeInstanceOf(Generator) }) }) + +describe('run', () => { + test('--project-name abc --adobe-services analytics,target,campaign-standard', async () => { + await helpers.run(theGeneratorPath) + .withOptions({ 'adobe-services': 'analytics,target,campaign-standard', 'project-name': 'abc' }) + + // added files + assert.file('web-src/index.html') + assert.file('web-src/404.html') + assert.file('web-src/src/index.js') + + // greats with projectName + assert.fileContent('web-src/index.html', '

Welcome to abc!

') + + // make sure service specific doc is here + assert.fileContent('web-src/index.html', '
  • Adobe Target API
  • ') + assert.fileContent('web-src/index.html', '
  • Adobe Analytics API
  • ') + assert.fileContent('web-src/index.html', '
  • Adobe Campaign Standard API
  • ') + + // make sure calls index.js to get the list of actions + assert.fileContent('web-src/index.html', '') + assert.fileContent('web-src/index.html', '') + }) + + test('--project-name abc --adobe-services analytics', async () => { + await helpers.run(theGeneratorPath) + .withOptions({ 'adobe-services': 'analytics', 'project-name': 'abc' }) + + // added files + assert.file('web-src/index.html') + assert.file('web-src/404.html') + assert.file('web-src/src/index.js') + + // greats with projectName + assert.fileContent('web-src/index.html', '

    Welcome to abc!

    ') + + // make sure service specific doc is here + assert.noFileContent('web-src/index.html', '
  • Adobe Target API
  • ') + assert.fileContent('web-src/index.html', '
  • Adobe Analytics API
  • ') + assert.noFileContent('web-src/index.html', '
  • Adobe Campaign Standard API
  • ') + + // make sure calls index.js to get the list of actions + assert.fileContent('web-src/index.html', '') + assert.fileContent('web-src/index.html', '') + }) +}) + +// todo check with existing files in project diff --git a/test/generators/app/index.test.js b/test/generators/app/index.test.js index 0f932642..beaf5818 100644 --- a/test/generators/app/index.test.js +++ b/test/generators/app/index.test.js @@ -9,262 +9,185 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -jest.mock('yeoman-generator') +const path = require('path') + +const helpers = require('yeoman-test') +const assert = require('yeoman-assert') -const TheGenerator = require('../../../generators/app') +const theGeneratorPath = require.resolve('../../../generators/app') const Generator = require('yeoman-generator') -jest.mock('../../../lib/utils') -const utils = require('../../../lib/utils') +// spies +const composeWith = jest.spyOn(Generator.prototype, 'composeWith') +const installDependencies = jest.spyOn(Generator.prototype, 'installDependencies') +beforeAll(() => { + composeWith.mockReturnValue(undefined) + installDependencies.mockReturnValue(undefined) +}) +beforeEach(() => { + composeWith.mockClear() + installDependencies.mockClear() +}) +afterAll(() => { + composeWith.mockRestore() + installDependencies.mockRestore() +}) -const path = require('path') +jest.mock('../../../lib/utils') describe('prototype', () => { test('exports a yeoman generator', () => { - expect(TheGenerator.prototype).toBeInstanceOf(Generator) + expect(require(theGeneratorPath).prototype).toBeInstanceOf(Generator) }) }) -describe('implementation', () => { - describe('constructor', () => { - test('accepts adobe-services option', () => { - const spy = jest.spyOn(TheGenerator.prototype, 'option') - // eslint-disable-next-line no-new - new TheGenerator() - expect(spy).toHaveBeenCalledWith('adobe-services', { type: String, default: '' }) - spy.mockRestore() - }) - test('accepts skip-prompt option', () => { - const spy = jest.spyOn(TheGenerator.prototype, 'option') - // eslint-disable-next-line no-new - new TheGenerator() - expect(spy).toHaveBeenCalledWith('skip-prompt', { default: false }) - spy.mockRestore() - }) - test('accepts project-name option', () => { - const spy = jest.spyOn(TheGenerator.prototype, 'option') - - const cwd = process.cwd - process.cwd = () => 'yolo/fake' - // eslint-disable-next-line no-new - new TheGenerator() - expect(spy).toHaveBeenCalledWith('project-name', { type: String, default: 'fake' }) - spy.mockRestore() - process.cwd = cwd - }) +describe('run', () => { + function expectBaseFiles () { + // expected files + assert.file('.aio') + assert.file('.env') + assert.file('.gitignore') + assert.file('README.md') + assert.file('package.json') + assert.file('test/jest.setup.js') + } + + function expectDotEnv () { + assert.fileContent('.env', '# AIO_RUNTIME_AUTH=\n# AIO_RUNTIME_NAMESPACE=') + } + + test('--skip-prompt --project-name fake', async () => { + await helpers.run(theGeneratorPath) + .withOptions({ 'skip-prompt': true, 'project-name': 'fake-name', 'skip-install': false }) + + expectBaseFiles() + expectDotEnv() + assert.JSONFileContent('package.json', { name: 'fake-name', version: '0.0.1' }) + // make sure sub generators have been called + expect(composeWith).toHaveBeenCalledTimes(2) + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-web-assets/index.js'), expect.objectContaining({ + 'skip-install': true, + 'skip-prompt': true, + 'adobe-services': '', + 'project-name': 'fake-name' + })) + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-action/index.js'), expect.objectContaining({ + 'skip-install': true, + 'skip-prompt': true, + 'adobe-services': '' + })) + + expect(installDependencies).toHaveBeenCalledTimes(1) }) - describe('prompting with composition', () => { - TheGenerator.prototype.log = () => {} - let prompt - let composeWith - let theGenerator - beforeEach(() => { - prompt = jest.spyOn(TheGenerator.prototype, 'prompt') - composeWith = jest.spyOn(TheGenerator.prototype, 'composeWith') - theGenerator = new TheGenerator() - }) - afterEach(() => { - prompt.mockRestore() - composeWith.mockRestore() - }) - - test('project-name="fake", skip-prompt="true", adobe-services="some,string"', async () => { - theGenerator.options = { 'project-name': 'fake', 'skip-prompt': true, 'adobe-services': 'some,string' } - await theGenerator.prompting() - - expect(prompt).toHaveBeenCalledTimes(0) - - expect(composeWith).toHaveBeenCalledTimes(2) - - expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-web-assets/index.js'), { - 'skip-install': true, - 'skip-prompt': true, - 'project-name': 'fake', - 'adobe-services': 'some,string' - }) - expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-action/index.js'), { - 'skip-install': true, - 'skip-prompt': true, - 'adobe-services': 'some,string' - }) - }) - - test('skip-prompt="false", selected components are "actions"', async () => { - prompt.mockReturnValue({ - components: ['actions'] - }) - theGenerator.options = { 'project-name': 'fake', 'skip-prompt': false, 'adobe-services': 'some,string' } - await theGenerator.prompting() - - expect(prompt).toHaveBeenCalledWith([expect.objectContaining({ - type: 'checkbox', - name: 'components', - choices: [ - { - name: 'Actions: Deploy Runtime actions', - value: 'actions', - checked: true - }, - { - name: 'Web Assets: Deploy hosted static assets', - value: 'webAssets', - checked: true - } - ], - validate: utils.atLeastOne - })]) - - expect(composeWith).toHaveBeenCalledTimes(1) - expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-action/index.js'), { - 'skip-install': true, - 'skip-prompt': false, - 'adobe-services': 'some,string' - }) - }) - - test('skip-prompt="false", selected components are "web-assets, actions"', async () => { - prompt.mockReturnValue({ - components: ['actions', 'webAssets'] - }) - theGenerator.options = { 'project-name': 'fake', 'skip-prompt': false, 'adobe-services': 'some,string' } - await theGenerator.prompting() - - expect(prompt).toHaveBeenCalledWith([expect.objectContaining({ - type: 'checkbox', - name: 'components', - choices: [ - { - name: 'Actions: Deploy Runtime actions', - value: 'actions', - checked: true - }, - { - name: 'Web Assets: Deploy hosted static assets', - value: 'webAssets', - checked: true - } - ], - validate: utils.atLeastOne - })]) - - expect(composeWith).toHaveBeenCalledTimes(2) - - expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-web-assets/index.js'), { - 'skip-install': true, - 'skip-prompt': false, - 'project-name': 'fake', - 'adobe-services': 'some,string' - }) - expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-action/index.js'), { - 'skip-install': true, - 'skip-prompt': false, - 'adobe-services': 'some,string' - }) - }) - - test('skip-prompt="false", selected components are "web-assets"', async () => { - prompt.mockReturnValue({ - components: ['webAssets'] - }) - theGenerator.options = { 'project-name': 'fake', 'skip-prompt': false, 'adobe-services': 'some,string' } - await theGenerator.prompting() - - expect(prompt).toHaveBeenCalledWith([expect.objectContaining({ - type: 'checkbox', - name: 'components', - choices: [ - { - name: 'Actions: Deploy Runtime actions', - value: 'actions', - checked: true - }, - { - name: 'Web Assets: Deploy hosted static assets', - value: 'webAssets', - checked: true - } - ], - validate: utils.atLeastOne - })]) - - expect(composeWith).toHaveBeenCalledTimes(1) - - expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-web-assets/index.js'), { - 'skip-install': true, - 'skip-prompt': false, - 'project-name': 'fake', - 'adobe-services': 'some,string' - }) - }) + test('--skip-prompt --adobe-services some,string', async () => { + const dir = await helpers.run(theGeneratorPath) + .withOptions({ 'skip-prompt': true, 'adobe-services': 'some,string', 'skip-install': false }) + + expectBaseFiles() + expectDotEnv() + const expectedProjectName = path.basename(dir) + assert.JSONFileContent('package.json', { name: expectedProjectName, version: '0.0.1' }) + // make sure sub generators have been called + expect(composeWith).toHaveBeenCalledTimes(2) + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-web-assets/index.js'), expect.objectContaining({ + 'skip-install': true, + 'skip-prompt': true, + 'adobe-services': 'some,string', + 'project-name': expectedProjectName + })) + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-action/index.js'), expect.objectContaining({ + 'skip-install': true, + 'skip-prompt': true, + 'adobe-services': 'some,string' + })) + expect(installDependencies).toHaveBeenCalledTimes(1) }) - describe('writing', () => { - let sourceRoot - const copyTpl = jest.fn() - let theGenerator - let templatePath - let destinationPath - beforeEach(() => { - sourceRoot = jest.spyOn(TheGenerator.prototype, 'sourceRoot') - templatePath = jest.spyOn(TheGenerator.prototype, 'templatePath') - destinationPath = jest.spyOn(TheGenerator.prototype, 'destinationPath') - theGenerator = new TheGenerator() - theGenerator.fs = { - copyTpl - } - }) - afterEach(() => { - copyTpl.mockReset() - sourceRoot.mockRestore() - templatePath.mockRestore() - destinationPath.mockRestore() - }) - - test('sets sourceRoot to ./templates/', async () => { - await theGenerator.writing() - expect(sourceRoot).toHaveBeenCalledWith(path.join(__dirname, '../../../generators/app/templates/')) - }) - - test('copies base template files', async () => { - theGenerator.props = { projectName: 'fakeName' } // todo pass it via options - templatePath.mockImplementation((p = '') => path.join('/fake', p)) - destinationPath.mockImplementation((p = '') => path.join('/dest', p)) - await theGenerator.writing() - - // first copy all files that do not start with _ - expect(copyTpl).toHaveBeenCalledWith( - '/fake/**/!(_)*/', - '/dest', - { projectName: 'fakeName' }) // tmpl context - // copy _dotenv => .env - expect(copyTpl).toHaveBeenCalledWith( - '/fake/_dot.env', - '/dest/.env', - { projectName: 'fakeName' }) // tmpl context - }) + test('--adobe-services some,string and prompt selection "actions"', async () => { + const dir = await helpers.run(theGeneratorPath) + .withOptions({ 'adobe-services': 'some,string', 'skip-install': false }) + .withPrompts({ components: ['actions'] }) + + expectBaseFiles() + expectDotEnv() + const expectedProjectName = path.basename(dir) + assert.JSONFileContent('package.json', { name: expectedProjectName, version: '0.0.1' }) + // make sure sub generators have been called + expect(composeWith).toHaveBeenCalledTimes(1) + + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-action/index.js'), expect.objectContaining({ + 'skip-install': true, + 'skip-prompt': false, + 'adobe-services': 'some,string' + })) + expect(installDependencies).toHaveBeenCalledTimes(1) }) - describe('install', () => { - let installDependencies - let theGenerator - beforeEach(() => { - installDependencies = jest.spyOn(TheGenerator.prototype, 'installDependencies') - theGenerator = new TheGenerator() - }) - afterEach(() => { - installDependencies.mockRestore() - }) - - test('skip-install=false', async () => { - theGenerator.options = { 'skip-install': false } - await theGenerator.install() - expect(installDependencies).toBeCalledTimes(1) - }) - - test('skip-install=true', async () => { - theGenerator.options = { 'skip-install': true } - await theGenerator.install() - expect(installDependencies).toBeCalledTimes(0) - }) + test('--adobe-services some,string and prompt selection "web-assets"', async () => { + const dir = await helpers.run(theGeneratorPath) + .withOptions({ 'adobe-services': 'some,string', 'skip-install': false }) + .withPrompts({ components: ['webAssets'] }) + + expectBaseFiles() + expectDotEnv() + const expectedProjectName = path.basename(dir) + assert.JSONFileContent('package.json', { name: expectedProjectName, version: '0.0.1' }) + // make sure sub generators have been called + expect(composeWith).toHaveBeenCalledTimes(1) + + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-web-assets/index.js'), expect.objectContaining({ + 'skip-install': true, + 'adobe-services': 'some,string', + 'project-name': expectedProjectName + })) + + expect(installDependencies).toHaveBeenCalledTimes(1) + }) + test('--adobe-services some,string and prompt selection "web-assets, actions"', async () => { + const dir = await helpers.run(theGeneratorPath) + .withOptions({ 'adobe-services': 'some,string', 'skip-install': false }) + .withPrompts({ components: ['webAssets', 'actions'] }) + + expectBaseFiles() + expectDotEnv() + const expectedProjectName = path.basename(dir) + assert.JSONFileContent('package.json', { name: expectedProjectName, version: '0.0.1' }) + // make sure sub generators have been called + expect(composeWith).toHaveBeenCalledTimes(2) + + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-web-assets/index.js'), expect.objectContaining({ + 'skip-install': true, + 'adobe-services': 'some,string', + 'project-name': expectedProjectName + })) + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-web-assets/index.js'), expect.objectContaining({ + 'skip-install': true, + 'adobe-services': 'some,string', + 'project-name': expectedProjectName + })) + expect(installDependencies).toHaveBeenCalledTimes(1) + }) + test('--skip-prompt --skip-install', async () => { + const dir = await helpers.run(theGeneratorPath) + .withOptions({ 'skip-prompt': true, 'skip-install': true }) + + expectBaseFiles() + expectDotEnv() + const expectedProjectName = path.basename(dir) + assert.JSONFileContent('package.json', { name: expectedProjectName, version: '0.0.1' }) + // make sure sub generators have been called + expect(composeWith).toHaveBeenCalledTimes(2) + + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-web-assets/index.js'), expect.objectContaining({ + 'skip-install': true, + 'adobe-services': '', + 'project-name': expectedProjectName + })) + expect(composeWith).toHaveBeenCalledWith(expect.stringContaining('add-web-assets/index.js'), expect.objectContaining({ + 'skip-install': true, + 'adobe-services': '', + 'project-name': expectedProjectName + })) + expect(installDependencies).toHaveBeenCalledTimes(0) }) }) diff --git a/test/jest.setup.js b/test/jest.setup.js index f4726b04..fea31b8f 100644 --- a/test/jest.setup.js +++ b/test/jest.setup.js @@ -15,7 +15,3 @@ process.on('unhandledRejection', error => { // dont touch the real fs jest.mock('fs-extra') - -beforeEach(() => { - expect.hasAssertions() -})