1 | import { EventEmitter } from "events";
|
2 | import Generator = require("yeoman-generator");
|
3 | import Environment = require("yeoman-environment");
|
4 | import { Store } from "mem-fs";
|
5 | import { Editor } from "mem-fs-editor";
|
6 |
|
7 | /**
|
8 | * Represents a dictionary.
|
9 | */
|
10 | export interface Dictionary<T> {
|
11 | [key: string]: T;
|
12 | }
|
13 |
|
14 | /**
|
15 | * Represents a constructor.
|
16 | */
|
17 | export interface Constructor<T> {
|
18 | new(...args: any[]): T;
|
19 | }
|
20 |
|
21 | /**
|
22 | * Represents an environment for running yeoman-generators.
|
23 | */
|
24 | export interface Env extends Environment {
|
25 | queues: string[];
|
26 | }
|
27 |
|
28 | /**
|
29 | * Dependencies can be path (autodiscovery) or an array [<generator>, <name>]
|
30 | */
|
31 | export 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 | */
|
41 | export 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 | */
|
50 | export 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 | */
|
62 | export 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 | */
|
73 | export function mockPrompt(generator: Generator, answers: Generator.Answers): void;
|
74 |
|
75 | /**
|
76 | * Restore defaults prompts on a generator.
|
77 | */
|
78 | export 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 | */
|
85 | export function mockLocalConfig(generator: Generator, localConfig: Dictionary<any>): void;
|
86 |
|
87 | /**
|
88 | * Create a simple, dummy generator
|
89 | */
|
90 | export 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 | */
|
110 | export 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 | */
|
123 | export function registerDependencies(env: Env, dependencies: Dependency[]): void;
|
124 |
|
125 | /**
|
126 | * Run the provided Generator
|
127 | * @param GeneratorOrNamespace - Generator constructor or namespace
|
128 | */
|
129 | export 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 | */
|
137 | export 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 | */
|
146 | export 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 | */
|
168 | export 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 | */
|
182 | export 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 |
|
214 | export 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 | */
|
373 | export 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 |
|
520 | export {};
|