From 89ed1007482842077afaf363bf7a152e55026bd2 Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 3 Jan 2018 18:52:51 -0500 Subject: [PATCH] test for Generator/GeneratorAPI --- packages/@vue/cli-shared-utils/index.js | 9 +- packages/@vue/cli/lib/Generator.js | 2 +- packages/@vue/cli/lib/GeneratorAPI.js | 40 +-- ...CreatorPrompts.test.js => Creator.test.js} | 0 .../@vue/cli/lib/__tests__/Generator.test.js | 308 ++++++++++++++++++ packages/@vue/cli/lib/util/mergeDeps.js | 1 + 6 files changed, 335 insertions(+), 25 deletions(-) rename packages/@vue/cli/lib/__tests__/{CreatorPrompts.test.js => Creator.test.js} (100%) create mode 100644 packages/@vue/cli/lib/__tests__/Generator.test.js diff --git a/packages/@vue/cli-shared-utils/index.js b/packages/@vue/cli-shared-utils/index.js index 21bea1044..4852874db 100644 --- a/packages/@vue/cli-shared-utils/index.js +++ b/packages/@vue/cli-shared-utils/index.js @@ -47,13 +47,18 @@ exports.clearConsole = title => { } } -// make all logs except error noop during tests +// silent all logs except errors during tests and keep record if (process.env.VUE_CLI_TEST) { + const logs = {} Object.keys(exports).forEach(key => { if (key !== 'error') { - exports[key] = () => {} + exports[key] = (...args) => { + if (!logs[key]) logs[key] = [] + logs[key].push(args) + } } }) + exports.logs = logs } exports.hasYarn = (() => { diff --git a/packages/@vue/cli/lib/Generator.js b/packages/@vue/cli/lib/Generator.js index 2aca5266f..2b98b7b92 100644 --- a/packages/@vue/cli/lib/Generator.js +++ b/packages/@vue/cli/lib/Generator.js @@ -5,7 +5,7 @@ const sortObject = require('./util/sortObject') const writeFileTree = require('./util/writeFileTree') module.exports = class Generator { - constructor (context, pkg, plugins, completeCbs) { + constructor (context, pkg, plugins, completeCbs = []) { this.context = context this.plugins = plugins this.pkg = pkg diff --git a/packages/@vue/cli/lib/GeneratorAPI.js b/packages/@vue/cli/lib/GeneratorAPI.js index fb937f7b5..821dd4a6e 100644 --- a/packages/@vue/cli/lib/GeneratorAPI.js +++ b/packages/@vue/cli/lib/GeneratorAPI.js @@ -25,28 +25,24 @@ module.exports = class GeneratorAPI { const pkg = this.generator.pkg const toMerge = isFunction(fields) ? fields(pkg) : fields for (const key in toMerge) { - if (!options.merge || !(key in pkg)) { - pkg[key] = toMerge[key] + const value = toMerge[key] + const existing = pkg[key] + if (isObject(value) && (key === 'dependencies' || key === 'devDependencies')) { + // use special version resolution merge + pkg[key] = mergeDeps( + this.id, + existing || {}, + value, + this.generator.depSources + ) + } else if (!options.merge || !(key in pkg)) { + pkg[key] = value + } else if (Array.isArray(value) && Array.isArray(existing)) { + pkg[key] = existing.concat(value) + } else if (isObject(value) && isObject(existing)) { + pkg[key] = Object.assign({}, existing, value) } else { - const value = toMerge[key] - const existing = pkg[key] - if (Array.isArray(value) && Array.isArray(existing)) { - pkg[key] = existing.concat(value) - } else if (isObject(value) && isObject(existing)) { - if (key === 'dependencies' || key === 'devDependencies') { - // use special version resolution merge - pkg[key] = mergeDeps( - this.id, - existing, - value, - this.generator.depSources - ) - } else { - pkg[key] = Object.assign({}, existing, value) - } - } else { - pkg[key] = value - } + pkg[key] = value } } } @@ -94,7 +90,7 @@ module.exports = class GeneratorAPI { hasPlugin (_id) { const prefixRE = /^(@vue\/|vue-)cli-plugin-/ return this.generator.plugins.some(({ id }) => { - return id.replace(prefixRE, '') === _id + return id === _id || id.replace(prefixRE, '') === _id }) } } diff --git a/packages/@vue/cli/lib/__tests__/CreatorPrompts.test.js b/packages/@vue/cli/lib/__tests__/Creator.test.js similarity index 100% rename from packages/@vue/cli/lib/__tests__/CreatorPrompts.test.js rename to packages/@vue/cli/lib/__tests__/Creator.test.js diff --git a/packages/@vue/cli/lib/__tests__/Generator.test.js b/packages/@vue/cli/lib/__tests__/Generator.test.js new file mode 100644 index 000000000..3f05e8d20 --- /dev/null +++ b/packages/@vue/cli/lib/__tests__/Generator.test.js @@ -0,0 +1,308 @@ +jest.mock('fs') + +const fs = require('fs') +const path = require('path') +const Generator = require('../Generator') +const { logs } = require('@vue/cli-shared-utils') + +// prepare template fixtures +const mkdirp = require('mkdirp') +const templateDir = path.resolve(__dirname, 'template') +mkdirp.sync(templateDir) +fs.writeFileSync(path.resolve(templateDir, 'foo.js'), 'foo(<%- options.n %>)') +mkdirp.sync(path.resolve(templateDir, 'bar')) +fs.writeFileSync(path.resolve(templateDir, 'bar/bar.js'), 'bar(<%- m %>)') + +it('api: extendPackage', async () => { + const generator = new Generator('/', { + name: 'hello', + list: [1], + vue: { + foo: 1, + bar: 2 + } + }, [{ + id: 'test', + apply: api => { + api.extendPackage({ + name: 'hello2', + list: [2], + vue: { + foo: 2, + baz: 3 + } + }) + } + }]) + + await generator.generate() + + const pkg = JSON.parse(fs.readFileSync('/package.json', 'utf-8')) + expect(pkg).toEqual({ + name: 'hello2', + list: [1, 2], + vue: { + foo: 2, + bar: 2, + baz: 3 + } + }) +}) + +it('api: extendPackage function', async () => { + const generator = new Generator('/', { foo: 1 }, [{ + id: 'test', + apply: api => { + api.extendPackage(pkg => ({ + foo: pkg.foo + 1 + })) + } + }]) + + await generator.generate() + + const pkg = JSON.parse(fs.readFileSync('/package.json', 'utf-8')) + expect(pkg).toEqual({ + foo: 2 + }) +}) + +it('api: extendPackage + { merge: false }', async () => { + const generator = new Generator('/', { + name: 'hello', + list: [1], + vue: { + foo: 1, + bar: 2 + } + }, [{ + id: 'test', + apply: api => { + api.extendPackage({ + name: 'hello2', + list: [2], + vue: { + foo: 2, + baz: 3 + } + }, { merge: false }) + } + }]) + + await generator.generate() + + const pkg = JSON.parse(fs.readFileSync('/package.json', 'utf-8')) + expect(pkg).toEqual({ + name: 'hello2', + list: [2], + vue: { + foo: 2, + baz: 3 + } + }) +}) + +it('api: extendPackage merge dependencies', async () => { + const generator = new Generator('/', {}, [ + { + id: 'test1', + apply: api => { + api.extendPackage({ + dependencies: { + foo: '^1.1.0', + bar: '^1.0.0' + } + }) + } + }, + { + id: 'test2', + apply: api => { + api.extendPackage({ + dependencies: { + foo: '^1.0.0', + baz: '^1.0.0' + } + }) + } + } + ]) + + await generator.generate() + + const pkg = JSON.parse(fs.readFileSync('/package.json', 'utf-8')) + expect(pkg).toEqual({ + dependencies: { + foo: '^1.1.0', + bar: '^1.0.0', + baz: '^1.0.0' + } + }) +}) + +it('api: warn invalid dep range', async () => { + new Generator('/', {}, [ + { + id: 'test1', + apply: api => { + api.extendPackage({ + dependencies: { + foo: 'foo' + } + }) + } + } + ]) + + expect(logs.warn.some(([msg]) => { + return ( + msg.match(/invalid version range for dependency "foo"/) && + msg.match(/injected by generator "test1"/) + ) + })).toBe(true) +}) + +it('api: extendPackage dependencies conflict', async () => { + new Generator('/', {}, [ + { + id: 'test1', + apply: api => { + api.extendPackage({ + dependencies: { + foo: '^1.0.0' + } + }) + } + }, + { + id: 'test2', + apply: api => { + api.extendPackage({ + dependencies: { + foo: '^2.0.0' + } + }) + } + } + ]) + + expect(logs.warn.some(([msg]) => { + return ( + msg.match(/conflicting versions for project dependency "foo"/) && + msg.match(/\^1\.0\.0 injected by generator "test1"/) && + msg.match(/\^2\.0\.0 injected by generator "test2"/) && + msg.match(/Using newer version \(\^2\.0\.0\)/) + ) + })).toBe(true) +}) + +it('api: render fs directory', async () => { + const generator = new Generator('/', {}, [ + { + id: 'test1', + apply: api => { + api.render('./template', { m: 2 }) + }, + options: { + n: 1 + } + } + ]) + + await generator.generate() + + expect(fs.readFileSync('/foo.js', 'utf-8')).toContain('foo(1)') + expect(fs.readFileSync('/bar/bar.js', 'utf-8')).toContain('bar(2)') +}) + +it('api: render object', async () => { + const generator = new Generator('/', {}, [ + { + id: 'test1', + apply: api => { + api.render({ + 'foo1.js': path.join(templateDir, 'foo.js'), + 'bar/bar1.js': path.join(templateDir, 'bar/bar.js') + }, { m: 3 }) + }, + options: { + n: 2 + } + } + ]) + + await generator.generate() + + expect(fs.readFileSync('/foo1.js', 'utf-8')).toContain('foo(2)') + expect(fs.readFileSync('/bar/bar1.js', 'utf-8')).toContain('bar(3)') +}) + +it('api: render middleware', async () => { + const generator = new Generator('/', {}, [ + { + id: 'test1', + apply: (api, options) => { + api.render((files, render) => { + files['foo2.js'] = render('foo(<%- n %>)', options) + files['bar/bar2.js'] = render('bar(<%- n %>)', options) + }) + }, + options: { + n: 3 + } + } + ]) + + await generator.generate() + + expect(fs.readFileSync('/foo2.js', 'utf-8')).toContain('foo(3)') + expect(fs.readFileSync('/bar/bar2.js', 'utf-8')).toContain('bar(3)') +}) + +it('api: hasPlugin', () => { + new Generator('/', {}, [ + { + id: 'foo', + apply: api => { + expect(api.hasPlugin('foo')).toBe(true) + expect(api.hasPlugin('bar')).toBe(true) + expect(api.hasPlugin('baz')).toBe(true) + expect(api.hasPlugin('vue-cli-plugin-bar')).toBe(true) + expect(api.hasPlugin('@vue/cli-plugin-baz')).toBe(true) + } + }, + { + id: 'vue-cli-plugin-bar', + apply: () => {} + }, + { + id: '@vue/cli-plugin-baz', + apply: () => {} + } + ]) +}) + +it('api: onCreateComplete', () => { + const fn = () => {} + const cbs = [] + new Generator('/', {}, [ + { + id: 'test', + apply: api => { + api.onCreateComplete(fn) + } + } + ], cbs) + expect(cbs).toContain(fn) +}) + +it('api: resolve', () => { + new Generator('/foo/bar', {}, [ + { + id: 'test', + apply: api => { + expect(api.resolve('baz')).toBe(path.resolve('/foo/bar', 'baz')) + } + } + ]) +}) diff --git a/packages/@vue/cli/lib/util/mergeDeps.js b/packages/@vue/cli/lib/util/mergeDeps.js index ed39d4317..269510e12 100644 --- a/packages/@vue/cli/lib/util/mergeDeps.js +++ b/packages/@vue/cli/lib/util/mergeDeps.js @@ -18,6 +18,7 @@ module.exports = function resolveDeps (generatorId, to, from, sources) { if (!r1) { res[name] = r2 + sources[name] = generatorId } else { const r = tryGetNewerRange(r1, r2) const didGetNewer = !!r