UNPKG

16 kBTypeScriptView Raw
1import { EventEmitter } from "events";
2import Generator = require("yeoman-generator");
3import Environment = require("yeoman-environment");
4import { Store } from "mem-fs";
5import { Editor } from "mem-fs-editor";
6
7/**
8 * Represents a dictionary.
9 */
10export interface Dictionary<T> {
11 [key: string]: T;
12}
13
14/**
15 * Represents a constructor.
16 */
17export interface Constructor<T> {
18 new(...args: any[]): T;
19}
20
21/**
22 * Represents an environment for running yeoman-generators.
23 */
24export interface Env extends Environment {
25 queues: string[];
26}
27
28/**
29 * Dependencies can be path (autodiscovery) or an array [<generator>, <name>]
30 */
31export type Dependency = string | [Generator, string];
32
33/**
34 * Create a function that will clean up the test directory,
35 * cd into it, and create a dummy gruntfile inside. Intended for use
36 * as a callback for the mocha `before` hook.
37 *
38 * @param dir - path to the test directory
39 * @returns mocha callback
40 */
41export function setUpTestDirectory(dir: string): (done: (...args: any[]) => void) => void;
42
43/**
44 * Generates a new Gruntfile.js in the current working directory based on
45 * options hash passed in.
46 *
47 * @param options - Grunt configuration
48 * @param done - callback to call on completion
49 */
50export function gruntfile(options: Dictionary<any>, done?: (...args: any[]) => void): void;
51
52/**
53 * Clean-up the test directory and cd into it.
54 * Call given callback after entering the test directory.
55 * @param dir - path to the test directory
56 * @param cb - callback executed after setting working directory to dir
57 * @example
58 * testDirectory(path.join(__dirname, './temp'), function () {
59 * fs.writeFileSync('testfile', 'Roses are red.');
60 * });
61 */
62export function testDirectory(dir: string, cb?: (error?: any) => void): void;
63
64/**
65 * Answer prompt questions for the passed-in generator
66 * @param generator - a Yeoman generator
67 * @param answers - an object where keys are the
68 * generators prompt names and values are the answers to
69 * the prompt questions
70 * @example
71 * mockPrompt(angular, {'bootstrap': 'Y', 'compassBoostrap': 'Y'});
72 */
73export function mockPrompt(generator: Generator, answers: Generator.Answers): void;
74
75/**
76 * Restore defaults prompts on a generator.
77 */
78export function restorePrompt(generator: Generator): void;
79
80/**
81 * Provide mocked values to the config
82 * @param generator - a Yeoman generator
83 * @param localConfig - localConfig - should look just like if called config.getAll()
84 */
85export function mockLocalConfig(generator: Generator, localConfig: Dictionary<any>): void;
86
87/**
88 * Create a simple, dummy generator
89 */
90export function createDummyGenerator(): Generator;
91
92/**
93 * Create a generator, using the given dependencies and controller arguments
94 * Dependencies can be path (autodiscovery) or an array [<generator>, <name>]
95 *
96 * @param name - the name of the generator
97 * @param dependencies - paths to the generators dependencies
98 * @param args - arguments to the generator;
99 * if String, will be split on spaces to create an Array
100 * @param options - configuration for the generator
101 * @example
102 * var deps = ['../../app',
103 * '../../common',
104 * '../../controller',
105 * '../../main',
106 * [createDummyGenerator(), 'testacular:app']
107 * ];
108 * var angular = createGenerator('angular:app', deps);
109 */
110export function createGenerator(
111 name: string,
112 dependencies: Dependency[],
113 args?: string | string[],
114 options?: Dictionary<any>,
115): Generator;
116
117/**
118 * Register a list of dependent generators into the provided env.
119 * Dependencies can be path (autodiscovery) or an array [<generator>, <name>]
120 *
121 * @param dependencies - paths to the generators dependencies
122 */
123export function registerDependencies(env: Env, dependencies: Dependency[]): void;
124
125/**
126 * Run the provided Generator
127 * @param GeneratorOrNamespace - Generator constructor or namespace
128 */
129export function run(GeneratorOrNamespace: string | Constructor<Generator>, settings?: RunContextSettings): RunContext;
130
131/**
132 * Create a RunContext
133 * @param GeneratorOrNamespace - Generator constructor or namespace
134 * @param settings - Generator settings
135 * @param envOptions - Environment options
136 */
137export function create(
138 GeneratorOrNamespace: string | Constructor<Generator>,
139 settings?: RunContextSettings,
140 envOptions?: Environment.Options,
141): RunContext;
142
143/**
144 * Provides settings for creating a `RunContext`.
145 */
146export interface RunContextSettings {
147 /**
148 * Automatically run this generator in a tmp dir
149 * @default true
150 */
151 tmpdir?: boolean | undefined;
152
153 /**
154 * File path to the generator (only used if Generator is a constructor)
155 */
156 resolved?: string | undefined;
157
158 /**
159 * Namespace (only used if Generator is a constructor)
160 * @default 'gen:test'
161 */
162 namespace?: string | undefined;
163}
164
165/**
166 * Provides the functionality to initialize new `RunContext`s.
167 */
168export interface RunContextConstructor {
169 /**
170 * This class provide a run context object to façade the complexity involved in setting
171 * up a generator for testing
172 * @param Generator - Namespace or generator constructor. If the later
173 * is provided, then namespace is assumed to be
174 * 'gen:test' in all cases
175 */
176 new(Generator: string | Constructor<Generator>, settings?: RunContextSettings): RunContext;
177}
178
179/**
180 * Provides options for `RunResult`s.
181 */
182export interface RunResultOptions {
183 /**
184 * The environment of the generator.
185 */
186 env: Environment;
187
188 /**
189 * The working directory after running the generator.
190 */
191 cwd: string;
192
193 /**
194 * The working directory before on running the generator.
195 */
196 oldCwd: string;
197
198 /**
199 * The file-system of the generator.
200 */
201 memFs: Store;
202
203 /**
204 * The file-system editor of the generator.
205 */
206 fs: Editor;
207
208 /**
209 * The mocked generators of the context.
210 */
211 mockedGenerators: Dictionary<Generator>;
212}
213
214export interface RunResult extends RunResultOptions {
215 /**
216 * The options of this result.
217 */
218 options: RunResultOptions;
219
220 /**
221 * Either dumps the contents of the specified files or the name and the contents of each file to the console.
222 */
223 dumpFiles(...files: string[]): void;
224
225 /**
226 * Dumps the name of each file to the console.
227 */
228 dumpFilenames(): void;
229
230 /**
231 * Assert that a file exists
232 * @param path - path to a file
233 * @example
234 * result.assertFile('templates/user.hbs');
235 *
236 * @also
237 *
238 * Assert that each files in the array exists
239 * @param paths - an array of paths to files
240 * @example
241 * result.assertFile(['templates/user.hbs', 'templates/user/edit.hbs']);
242 */
243 assertFile(path: string | string[]): void;
244
245 /**
246 * Assert that a file doesn't exist
247 * @param file - path to a file
248 * @example
249 * result.assertNoFile('templates/user.hbs');
250 *
251 * @also
252 *
253 * Assert that each of an array of files doesn't exist
254 * @param pairs - an array of paths to files
255 * @example
256 * result.assertNoFile(['templates/user.hbs', 'templates/user/edit.hbs']);
257 */
258 assertNoFile(file: string | string[]): void;
259
260 /**
261 * Assert that a file's content matches a regex or string
262 * @param file - path to a file
263 * @param reg - regex / string that will be used to search the file
264 * @example
265 * result.assertFileContent('models/user.js', /App\.User = DS\.Model\.extend/);
266 * result.assertFileContent('models/user.js', 'App.User = DS.Model.extend');
267 *
268 * @also
269 *
270 * Assert that each file in an array of file-regex pairs matches its corresponding regex
271 * @param pairs - an array of arrays, where each subarray is a [String, RegExp] pair
272 * @example
273 * var arg = [
274 * [ 'models/user.js', /App\.User = DS\.Model\.extend/ ],
275 * [ 'controllers/user.js', /App\.UserController = Ember\.ObjectController\.extend/ ]
276 * ]
277 * result.assertFileContent(arg);
278 */
279 assertFileContent(file: string, reg: string | RegExp): void;
280 assertFileContent(pairs: Array<[string, string | RegExp]>): void;
281
282 /**
283 * Assert that a file's content is the same as the given string
284 * @param file - path to a file
285 * @param expectedContent - the expected content of the file
286 * @example
287 * result.assertEqualsFileContent(
288 * 'data.js',
289 * 'const greeting = "Hello";\nexport default { greeting }'
290 * );
291 *
292 * @also
293 *
294 * Assert that each file in an array of file-string pairs equals its corresponding string
295 * @param pairs - an array of arrays, where each subarray is a [String, String] pair
296 * @example
297 * result.assertEqualsFileContent([
298 * ['data.js', 'const greeting = "Hello";\nexport default { greeting }'],
299 * ['user.js', 'export default {\n name: 'Coleman',\n age: 0\n}']
300 * ]);
301 */
302 assertEqualsFileContent(file: string, expectedContent: string): void;
303 assertEqualsFileContent(pairs: Array<[string, string]>): void;
304
305 /**
306 * Assert that a file's content does not match a regex / string
307 * @param file - path to a file
308 * @param reg - regex / string that will be used to search the file
309 * @example
310 * result.assertNoFileContent('models/user.js', /App\.User = DS\.Model\.extend/);
311 * result.assertNoFileContent('models/user.js', 'App.User = DS.Model.extend');
312 *
313 * @also
314 *
315 * Assert that each file in an array of file-regex pairs does not match its corresponding regex
316 * @param pairs - an array of arrays, where each subarray is a [String, RegExp] pair
317 * var arg = [
318 * [ 'models/user.js', /App\.User \ DS\.Model\.extend/ ],
319 * [ 'controllers/user.js', /App\.UserController = Ember\.ObjectController\.extend/ ]
320 * ]
321 * result.assertNoFileContent(arg);
322 */
323 assertNoFileContent(file: string, reg: RegExp | string): void;
324 assertNoFileContent(pairs: Array<[string, string | RegExp]>): void;
325
326 /**
327 * Assert that two strings are equal after standardization of newlines
328 * @param value - a string
329 * @param expected - the expected value of the string
330 * @example
331 * result.assertTextEqual('I have a yellow cat', 'I have a yellow cat');
332 */
333 assertTextEqual(value: string, expected: string): void;
334
335 /**
336 * Assert an object contains the provided keys
337 * @param obj Object that should match the given pattern
338 * @param content An object of key/values the object should contains
339 */
340 assertObjectContent(obj: object, content: { [key: string]: any }): void;
341
342 /**
343 * Assert an object does not contain the provided keys
344 * @param obj Object that should not match the given pattern
345 * @param content An object of key/values the object should not contain
346 */
347 assertNoObjectContent(obj: object, content: { [key: string]: any }): void;
348
349 /**
350 * Assert a JSON file contains the provided keys
351 * @param filename
352 * @param content An object of key/values the file should contains
353 */
354 assertJsonFileContent(filename: string, content: { [key: string]: any }): void;
355
356 /**
357 * Assert a JSON file does not contain the provided keys
358 * @param filename
359 * @param content An object of key/values the file should not contain
360 */
361 assertNoJsonFileContent(filename: string, content: { [key: string]: any }): void;
362
363 /**
364 * Reverts to old cwd.
365 * @returns this
366 */
367 restore(): this;
368}
369
370/**
371 * Represents the context of a running generator.
372 */
373export interface RunContext extends RunContextConstructor, EventEmitter, Promise<RunResult> {
374 /**
375 * A value indicating whether the generator ran through.
376 */
377 ran: boolean;
378
379 /**
380 * A value indicating whether a current directory has been set.
381 */
382 inDirSet: boolean;
383
384 /**
385 * The arguments that are passed to the generator.
386 */
387 args: string[];
388
389 /**
390 * The options that are passed to the generator.
391 */
392 options: {};
393
394 /**
395 * The mocked `inquirer`-answers.
396 */
397 answers: Generator.Answers;
398
399 /**
400 * The mocked configuration.
401 */
402 localConfig: {};
403
404 /**
405 * A set of generators this generator depends on.
406 */
407 dependencies: Dependency[];
408
409 /**
410 * A set of mocked generators.
411 */
412 mockedGenerators: Dictionary<Generator>;
413
414 /**
415 * Hold the execution until the returned callback is triggered
416 * @return Callback to notify the normal execution can resume
417 */
418 async(): () => void;
419
420 /**
421 * Return a promise representing the generator run process
422 * @return Promise resolved on end or rejected on error
423 */
424 toPromise(): Promise<RunResult>;
425
426 /**
427 * Clean the provided directory, then change directory into it
428 * @param dirPath - Directory path (relative to CWD). Prefer passing an absolute
429 * file path for predictable results
430 * @param [cb] - callback who'll receive the folder path as argument
431 * @return run context instance
432 */
433 inDir(dirPath: string, cb?: (folderPath: string) => void): this;
434
435 /**
436 * Change directory without deleting directory content.
437 * @param dirPath - Directory path (relative to CWD). Prefer passing an absolute
438 * file path for predictable results
439 * @return run context instance
440 */
441 cd(dirPath: string): this;
442
443 /**
444 * Register an callback to prepare the destination folder.
445 * @param [cb] - callback who'll receive the folder path as argument
446 * @return this - run context instance
447 */
448 doInDir(cb: (folderPath: string) => void): this;
449
450 /**
451 * Cleanup a temporary directory and change the CWD into it
452 *
453 * This method is called automatically when creating a RunContext. Only use it if you need
454 * to use the callback.
455 *
456 * @param [cb] - callback who'll receive the folder path as argument
457 * @return this - run context instance
458 */
459 inTmpDir(cb: (folderPath: string) => void): this;
460
461 /**
462 * Clean the directory used for tests inside inDir/inTmpDir
463 */
464 cleanTestDirectory(): void;
465
466 /**
467 * Provide arguments to the run context
468 * @param args - command line arguments as Array or space separated string
469 */
470 withArguments(args: string | string[]): this;
471
472 /**
473 * Provide options to the run context
474 * @param options - command line options (e.g. `--opt-one=foo`)
475 */
476 withOptions(options: Dictionary<any>): this;
477
478 /**
479 * Mock the prompt with dummy answers
480 * @param answers - Answers to the prompt questions
481 */
482 withPrompts(answers: Generator.Answers): this;
483
484 /**
485 * Provide dependent generators
486 * @param dependencies - paths to the generators dependencies
487 * @example
488 * var angular = new RunContext('../../app');
489 * angular.withGenerators([
490 * '../../common',
491 * '../../controller',
492 * '../../main',
493 * [helpers.createDummyGenerator(), 'testacular:app']
494 * ]);
495 * angular.on('end', function () {
496 * // assert something
497 * });
498 */
499 withGenerators(dependencies: Dependency[]): this;
500
501 /**
502 * Mock the local configuration with the provided config
503 * @param localConfig - should look just like if called config.getAll()
504 */
505 withLocalConfig(localConfig: Dictionary<any>): this;
506
507 /**
508 * Creates mocked generators.
509 * @param namespaces - The namespaces of the mocked generators.
510 */
511 withMockedGenerators(namespaces: string[]): this;
512
513 /**
514 * Run the generator on the environment and returns the promise.
515 * @return Promise
516 */
517 run(): Promise<RunResult>;
518}
519
520export {};