env.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*global it, describe, before */
  2. var fs = require('fs');
  3. var path = require('path');
  4. var util = require('util');
  5. var assert = require('assert');
  6. var generators = require('..');
  7. var helpers = generators.test;
  8. var events = require('events');
  9. var Base = generators.Base;
  10. var Environment = require('../lib/env');
  11. // https://gist.github.com/87550fd10b7440a37df4
  12. describe('Environment', function () {
  13. before(generators.test.before(path.join(__dirname, 'temp')));
  14. describe('Environment', function () {
  15. it('to init the system, you need to create a new handler', function () {
  16. var env = generators();
  17. assert.ok(env instanceof Environment);
  18. assert.ok(env instanceof events.EventEmitter);
  19. });
  20. it('adds new filepath to the loadpahts using appendLookup / prependLookup', function () {
  21. var env = generators();
  22. assert.ok(env.lookups.length);
  23. assert.ok(env.lookups.slice(-1)[0], 'lib/generators');
  24. env.appendLookup('support/scaffold');
  25. assert.ok(env.lookups.slice(-1)[0], 'support/scaffold');
  26. });
  27. // generators is an instance of event emitter.
  28. it('generators() is an instance of EventEmitter', function () {
  29. assert.ok(generators() instanceof events.EventEmitter, 'Not an instance of EventEmitter');
  30. });
  31. it('generators.Base is the Base generator class', function () {
  32. assert.equal(generators.Base.prototype.__proto__.constructor, events.EventEmitter, 'Not an EventEmitter');
  33. });
  34. it('generators.NamedBase is inheriting from Base generator class', function () {
  35. assert.equal(generators.NamedBase.prototype.__proto__.constructor, generators.Base, 'Not a Base class');
  36. });
  37. it('init the system using your own args / options', function () {
  38. // using a list of space-separated arguments as String
  39. var env = generators('model Post', { help: true });
  40. assert.deepEqual(env.arguments, ['model', 'Post']);
  41. assert.deepEqual(env.options, {
  42. help: true
  43. });
  44. // using a list of arguments as Array
  45. env = generators(['model', 'Post']);
  46. assert.deepEqual(env.arguments, ['model', 'Post']);
  47. assert.deepEqual(env.options, {});
  48. });
  49. it('registers generators using the .register() method', function () {
  50. var env = generators();
  51. assert.equal(Object.keys(env.generators).length, 0);
  52. env
  53. .register('../fixtures/custom-generator-simple', 'fixtures:custom-generator-simple')
  54. .register('../fixtures/custom-generator-extend', 'scaffold');
  55. assert.equal(Object.keys(env.generators).length, 2);
  56. var simple = env.generators['fixtures:custom-generator-simple'];
  57. assert.ok(simple);
  58. assert.ok(typeof simple === 'function');
  59. assert.ok(simple.namespace, 'fixtures:custom-generator-simple');
  60. var extend = env.generators.scaffold;
  61. assert.ok(extend);
  62. assert.ok(typeof extend === 'function');
  63. assert.ok(extend.namespace, 'scaffold');
  64. });
  65. it('get the list of namespaces', function () {
  66. var namespaces = generators()
  67. .register('../fixtures/custom-generator-simple')
  68. .register('../fixtures/custom-generator-extend')
  69. .register('../fixtures/custom-generator-extend', 'support:scaffold')
  70. .namespaces();
  71. assert.deepEqual(namespaces, ['simple', 'extend:support:scaffold', 'support:scaffold']);
  72. });
  73. it('output the general help', function () {
  74. var env = generators()
  75. .register('../fixtures/custom-generator-simple')
  76. .register('../fixtures/custom-generator-extend');
  77. var expected = fs.readFileSync(path.join(__dirname, 'fixtures/help.txt'), 'utf8');
  78. // lazy "update the help fixtures because something changed" statement
  79. // fs.writeFileSync(path.join(__dirname, 'fixtures/help.txt'), env.help().trim());
  80. assert.equal(env.help().trim(), expected.trim());
  81. // custom bin name
  82. assert.equal(env.help('gg').trim(), expected.replace('Usage: init', 'Usage: gg').trim());
  83. });
  84. it('get() can be used to get a specific generator', function () {
  85. var env = generators()
  86. .register('../fixtures/mocha-generator', 'fixtures:mocha-generator')
  87. .register('../fixtures/mocha-generator', 'mocha:generator');
  88. var expected = require('./fixtures/mocha-generator');
  89. assert.equal(env.get('mocha:generator'), expected);
  90. assert.equal(env.get('fixtures:mocha-generator'), expected);
  91. });
  92. it('create() can be used to get and instantiate a specific generator', function () {
  93. var env = generators().register('../fixtures/mocha-generator', 'mocha:generator');
  94. var mocha = env.create('mocha:generator');
  95. assert.deepEqual(mocha.arguments, []);
  96. mocha = env.create('mocha:generator', {
  97. arguments: ['another', 'set', 'of', 'arguments'],
  98. options: {
  99. 'assertion-framework': 'chai'
  100. }
  101. });
  102. assert.deepEqual(mocha.arguments, ['another', 'set', 'of', 'arguments']);
  103. assert.equal(mocha.options['assertion-framework'], 'chai');
  104. });
  105. it('invokes using the run() method, from generators handler', function (done) {
  106. var env = generators()
  107. .register('../fixtures/mocha-generator-base', 'fixtures:mocha-generator-base')
  108. .run(['fixtures:mocha-generator-base', 'foo', 'bar'], done);
  109. });
  110. it('invokes using the run() method, from specific generator', function (done) {
  111. var env = generators().register('../fixtures/mocha-generator', 'fixtures:mocha-generator');
  112. var mocha = env.create('fixtures:mocha-generator');
  113. mocha.run(done);
  114. });
  115. });
  116. describe('Engines', function () {
  117. before (function () {
  118. this.generator = new Base([], {
  119. env: generators(),
  120. resolved: __filename
  121. });
  122. });
  123. it('allows users to use their prefered engine', function () {
  124. // engine should be able to take a fn, or a named engine (which we
  125. // provide adapters to, currently only underscore is supported)
  126. generators().engine('underscore');
  127. });
  128. it('throws on wrong engine', function (done) {
  129. try {
  130. generators().engine('underscored');
  131. } catch (e) {
  132. done();
  133. }
  134. });
  135. it('properly compiles and renders template', function (done) {
  136. var filename = 'boyah.js';
  137. this.generator.template(path.join(__dirname, 'fixtures/template.jst'), filename, { foo: 'hey' });
  138. this.generator.conflicter.resolve(function (err) {
  139. if (err) {
  140. return done(err);
  141. }
  142. assert.equal(fs.readFileSync(filename, 'utf8'), "var hey = 'hey';" + '\n');
  143. done();
  144. });
  145. });
  146. it('lets you use %% and escape opening tags with underscore engine', function () {
  147. var tpl = 'prefix/<%%= yeoman.app %>/foo/bar';
  148. assert.equal(this.generator.engine(tpl), 'prefix/<%= yeoman.app %>/foo/bar');
  149. assert.equal(this.generator.engine('<%% if(true) { %>'), '<% if(true) { %>');
  150. });
  151. });
  152. // Events
  153. // ------
  154. // A series of events are emitted during the generation process. Both on
  155. // the global `generators` handler and each individual generators
  156. // involved in the process.
  157. describe('Events', function () {
  158. before(function () {
  159. var Generator = this.Generator = function () {
  160. generators.Base.apply(this, arguments);
  161. };
  162. Generator.namespace = 'angular:all';
  163. util.inherits(Generator, generators.Base);
  164. Generator.prototype.createSomething = function () {};
  165. Generator.prototype.createSomethingElse = function () {};
  166. });
  167. it('emits the series of event on a specific generator', function (done) {
  168. var angular = new this.Generator([], {
  169. env: generators(),
  170. resolved: __filename
  171. });
  172. var lifecycle = ['start', 'createSomething', 'createSomethingElse', 'end'];
  173. function assertEvent(e) {
  174. return function() {
  175. assert.equal(e, lifecycle.shift());
  176. if (e === 'end') {
  177. done();
  178. }
  179. };
  180. }
  181. angular
  182. // Start event, emitted right before "running" the generator.
  183. .on('start', assertEvent('start'))
  184. // End event, emitted after the generation process, when every generator method and hooks are executed
  185. .on('end', assertEvent('end'))
  186. // Emitted when a conflict is detected, right after the prompt happens.
  187. // .on('conflict', assertEvent('conflict'))
  188. // Emitted on every prompt, both for conflict state and generators one.
  189. // .on('prompt', assertEvent('prompt'))
  190. // Emitted right before a hook is invoked
  191. // .on('hook', assertEvent('hook'))
  192. // Emitted on each generator method
  193. .on('createSomething', assertEvent('createSomething'))
  194. .on('createSomethingElse', assertEvent('createSomethingElse'));
  195. angular.run();
  196. });
  197. it('hoists up the series of event from specific generator to the generators handler', function (done) {
  198. var lifecycle = [
  199. 'generators:start',
  200. 'angular:all:start',
  201. 'angular:all:createSomething',
  202. 'angular:all:createSomethingElse',
  203. 'angular:all:end',
  204. 'generators:end'
  205. ];
  206. function assertEvent(ev) {
  207. return function () {
  208. assert.equal(ev, lifecycle.shift());
  209. if (!lifecycle.length) {
  210. done();
  211. }
  212. };
  213. }
  214. generators()
  215. .register(this.Generator)
  216. // Series of events proxied from the resolved generator
  217. .on('generators:start', assertEvent('generators:start'))
  218. .on('generators:end', assertEvent('generators:end'))
  219. // .on('conflict', assertEvent('generators:conflict'))
  220. // .on('prompt', assertEvent('generators:prompt'))
  221. // .on('hook', assertEvent('generators:start'))
  222. // Emitted for each generator method invoked, prefix by the generator namespace
  223. .on('angular:all:createSomething', assertEvent('angular:all:createSomething'))
  224. .on('angular:all:createSomethingElse', assertEvent('angular:all:createSomethingElse'))
  225. // Additionally, for more specific events, same prefixing happens on
  226. // start, end, conflict, prompt and hook.
  227. .on('angular:all:start', assertEvent('angular:all:start'))
  228. .on('angular:all:end', assertEvent('angular:all:end'))
  229. .on('angular:all:conflict', assertEvent('angular:all:conflict'))
  230. .on('angular:all:prompt', assertEvent('angular:all:prompt'))
  231. // actual run
  232. .run('angular:all myapp');
  233. });
  234. });
  235. // Underscore String
  236. // > http://epeli.github.com/underscore.string/
  237. // > https://github.com/epeli/underscore.string#string-functions
  238. //
  239. // Underscore String set of utilities are very handy, especially in the
  240. // context of Generators. We often want to humanize, dasherize or underscore
  241. // a given variable.
  242. //
  243. // Since templates are invoked in the context of the Generator that render
  244. // them, all these String helpers are then available directly from templates.
  245. describe('Underscore String', function () {
  246. before(function () {
  247. this.dummy = new generators.Base([], {
  248. env: generators(),
  249. resolved: __filename
  250. });
  251. });
  252. it('has the whole Underscore String API available as prorotype mehtod', function () {
  253. var str = require('underscore.string').exports();
  254. Object.keys(str).forEach(function (prop) {
  255. if (typeof str[prop] !== 'function') {
  256. return;
  257. }
  258. assert.equal(typeof this.dummy._[prop], 'function');
  259. }, this);
  260. });
  261. });
  262. });