yeoman-test 6.2.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/adapter.d.ts +24 -0
- package/dist/adapter.js +104 -0
- package/dist/helpers.d.ts +151 -0
- package/dist/helpers.js +258 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/run-context.d.ts +279 -0
- package/dist/run-context.js +541 -0
- package/dist/run-result.d.ts +214 -0
- package/dist/run-result.js +258 -0
- package/dist/test-context.d.ts +8 -0
- package/dist/test-context.js +9 -0
- package/package.json +37 -21
- package/lib/adapter.js +0 -107
- package/lib/index.js +0 -339
- package/lib/run-context.js +0 -552
- package/lib/run-result.js +0 -372
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import MemFsEditor, { type Editor } from 'mem-fs-editor';
|
|
2
|
+
import type { Store } from 'mem-fs';
|
|
3
|
+
import type Environment from 'yeoman-environment';
|
|
4
|
+
import type Generator from 'yeoman-generator';
|
|
5
|
+
import { type RunContextSettings } from './run-context.js';
|
|
6
|
+
import { type YeomanTest } from './helpers.js';
|
|
7
|
+
/**
|
|
8
|
+
* Provides options for `RunResult`s.
|
|
9
|
+
*/
|
|
10
|
+
export type RunResultOptions<GeneratorType extends Generator> = {
|
|
11
|
+
generator: GeneratorType;
|
|
12
|
+
/**
|
|
13
|
+
* The environment of the generator.
|
|
14
|
+
*/
|
|
15
|
+
env: Environment;
|
|
16
|
+
envOptions: Environment.Options;
|
|
17
|
+
/**
|
|
18
|
+
* The working directory after running the generator.
|
|
19
|
+
*/
|
|
20
|
+
cwd: string;
|
|
21
|
+
/**
|
|
22
|
+
* The working directory before on running the generator.
|
|
23
|
+
*/
|
|
24
|
+
oldCwd: string;
|
|
25
|
+
/**
|
|
26
|
+
* The file-system of the generator.
|
|
27
|
+
*/
|
|
28
|
+
memFs: Store;
|
|
29
|
+
fs?: MemFsEditor.Editor;
|
|
30
|
+
/**
|
|
31
|
+
* The mocked generators of the context.
|
|
32
|
+
*/
|
|
33
|
+
mockedGenerators: Record<string, Generator>;
|
|
34
|
+
settings: RunContextSettings;
|
|
35
|
+
helpers: YeomanTest;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* This class provides utilities for testing generated content.
|
|
39
|
+
*/
|
|
40
|
+
export default class RunResult<GeneratorType extends Generator> {
|
|
41
|
+
env: any;
|
|
42
|
+
generator: GeneratorType;
|
|
43
|
+
cwd: string;
|
|
44
|
+
oldCwd: string;
|
|
45
|
+
memFs: Store;
|
|
46
|
+
fs: Editor;
|
|
47
|
+
mockedGenerators: any;
|
|
48
|
+
options: RunResultOptions<GeneratorType>;
|
|
49
|
+
constructor(options: RunResultOptions<GeneratorType>);
|
|
50
|
+
/**
|
|
51
|
+
* Create another RunContext reusing the settings.
|
|
52
|
+
* See helpers.create api
|
|
53
|
+
*/
|
|
54
|
+
create(GeneratorOrNamespace: any, settings: any, envOptions: any): import("./run-context.js").default<Generator<Generator.GeneratorOptions>>;
|
|
55
|
+
/**
|
|
56
|
+
* Return an object with fs changes.
|
|
57
|
+
* @param {Function} filter - parameter forwarded to mem-fs-editor#dump
|
|
58
|
+
*/
|
|
59
|
+
getSnapshot(filter?: any): Record<string, {
|
|
60
|
+
contents: string;
|
|
61
|
+
stateCleared: string;
|
|
62
|
+
}>;
|
|
63
|
+
/**
|
|
64
|
+
* Return an object with filenames with state.
|
|
65
|
+
* @param {Function} filter - parameter forwarded to mem-fs-editor#dump
|
|
66
|
+
* @returns {Object}
|
|
67
|
+
*/
|
|
68
|
+
getStateSnapshot(filter?: any): Record<string, {
|
|
69
|
+
stateCleared: string;
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* Either dumps the contents of the specified files or the name and the contents of each file to the console.
|
|
73
|
+
*/
|
|
74
|
+
dumpFiles(...files: string[]): this;
|
|
75
|
+
/**
|
|
76
|
+
* Dumps the name of each file to the console.
|
|
77
|
+
*/
|
|
78
|
+
dumpFilenames(): this;
|
|
79
|
+
/**
|
|
80
|
+
* Reverts to old cwd.
|
|
81
|
+
* @returns this
|
|
82
|
+
*/
|
|
83
|
+
restore(): this;
|
|
84
|
+
/**
|
|
85
|
+
* Deletes the test directory recursively.
|
|
86
|
+
*/
|
|
87
|
+
cleanup(): this;
|
|
88
|
+
_fileName(filename: any): any;
|
|
89
|
+
_readFile(filename: any, json?: boolean): any;
|
|
90
|
+
_exists(filename: any): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Assert that a file exists
|
|
93
|
+
* @param path - path to a file
|
|
94
|
+
* @example
|
|
95
|
+
* result.assertFile('templates/user.hbs');
|
|
96
|
+
*
|
|
97
|
+
* @also
|
|
98
|
+
*
|
|
99
|
+
* Assert that each files in the array exists
|
|
100
|
+
* @param paths - an array of paths to files
|
|
101
|
+
* @example
|
|
102
|
+
* result.assertFile(['templates/user.hbs', 'templates/user/edit.hbs']);
|
|
103
|
+
*/
|
|
104
|
+
assertFile(path: string | string[]): void;
|
|
105
|
+
/**
|
|
106
|
+
* Assert that a file doesn't exist
|
|
107
|
+
* @param file - path to a file
|
|
108
|
+
* @example
|
|
109
|
+
* result.assertNoFile('templates/user.hbs');
|
|
110
|
+
*
|
|
111
|
+
* @also
|
|
112
|
+
*
|
|
113
|
+
* Assert that each of an array of files doesn't exist
|
|
114
|
+
* @param pairs - an array of paths to files
|
|
115
|
+
* @example
|
|
116
|
+
* result.assertNoFile(['templates/user.hbs', 'templates/user/edit.hbs']);
|
|
117
|
+
*/
|
|
118
|
+
assertNoFile(files: string | string[]): void;
|
|
119
|
+
/**
|
|
120
|
+
* Assert that a file's content matches a regex or string
|
|
121
|
+
* @param file - path to a file
|
|
122
|
+
* @param reg - regex / string that will be used to search the file
|
|
123
|
+
* @example
|
|
124
|
+
* result.assertFileContent('models/user.js', /App\.User = DS\.Model\.extend/);
|
|
125
|
+
* result.assertFileContent('models/user.js', 'App.User = DS.Model.extend');
|
|
126
|
+
*
|
|
127
|
+
* @also
|
|
128
|
+
*
|
|
129
|
+
* Assert that each file in an array of file-regex pairs matches its corresponding regex
|
|
130
|
+
* @param pairs - an array of arrays, where each subarray is a [String, RegExp] pair
|
|
131
|
+
* @example
|
|
132
|
+
* var arg = [
|
|
133
|
+
* [ 'models/user.js', /App\.User = DS\.Model\.extend/ ],
|
|
134
|
+
* [ 'controllers/user.js', /App\.UserController = Ember\.ObjectController\.extend/ ]
|
|
135
|
+
* ]
|
|
136
|
+
* result.assertFileContent(arg);
|
|
137
|
+
*/
|
|
138
|
+
assertFileContent(file: string, reg: string | RegExp): void;
|
|
139
|
+
assertFileContent(pairs: Array<[string, string | RegExp]>): void;
|
|
140
|
+
/**
|
|
141
|
+
* Assert that a file's content is the same as the given string
|
|
142
|
+
* @param file - path to a file
|
|
143
|
+
* @param expectedContent - the expected content of the file
|
|
144
|
+
* @example
|
|
145
|
+
* result.assertEqualsFileContent(
|
|
146
|
+
* 'data.js',
|
|
147
|
+
* 'const greeting = "Hello";\nexport default { greeting }'
|
|
148
|
+
* );
|
|
149
|
+
*
|
|
150
|
+
* @also
|
|
151
|
+
*
|
|
152
|
+
* Assert that each file in an array of file-string pairs equals its corresponding string
|
|
153
|
+
* @param pairs - an array of arrays, where each subarray is a [String, String] pair
|
|
154
|
+
* @example
|
|
155
|
+
* result.assertEqualsFileContent([
|
|
156
|
+
* ['data.js', 'const greeting = "Hello";\nexport default { greeting }'],
|
|
157
|
+
* ['user.js', 'export default {\n name: 'Coleman',\n age: 0\n}']
|
|
158
|
+
* ]);
|
|
159
|
+
*/
|
|
160
|
+
assertEqualsFileContent(file: string, expectedContent: string): void;
|
|
161
|
+
assertEqualsFileContent(pairs: Array<[string, string]>): void;
|
|
162
|
+
/**
|
|
163
|
+
* Assert that a file's content does not match a regex / string
|
|
164
|
+
* @param file - path to a file
|
|
165
|
+
* @param reg - regex / string that will be used to search the file
|
|
166
|
+
* @example
|
|
167
|
+
* result.assertNoFileContent('models/user.js', /App\.User = DS\.Model\.extend/);
|
|
168
|
+
* result.assertNoFileContent('models/user.js', 'App.User = DS.Model.extend');
|
|
169
|
+
*
|
|
170
|
+
* @also
|
|
171
|
+
*
|
|
172
|
+
* Assert that each file in an array of file-regex pairs does not match its corresponding regex
|
|
173
|
+
* @param pairs - an array of arrays, where each subarray is a [String, RegExp] pair
|
|
174
|
+
* var arg = [
|
|
175
|
+
* [ 'models/user.js', /App\.User \ DS\.Model\.extend/ ],
|
|
176
|
+
* [ 'controllers/user.js', /App\.UserController = Ember\.ObjectController\.extend/ ]
|
|
177
|
+
* ]
|
|
178
|
+
* result.assertNoFileContent(arg);
|
|
179
|
+
*/
|
|
180
|
+
assertNoFileContent(file: string, reg: RegExp | string): void;
|
|
181
|
+
assertNoFileContent(pairs: Array<[string, string | RegExp]>): void;
|
|
182
|
+
/**
|
|
183
|
+
* Assert that two strings are equal after standardization of newlines
|
|
184
|
+
* @param value - a string
|
|
185
|
+
* @param expected - the expected value of the string
|
|
186
|
+
* @example
|
|
187
|
+
* result.assertTextEqual('I have a yellow cat', 'I have a yellow cat');
|
|
188
|
+
*/
|
|
189
|
+
assertTextEqual(value: string, expected: string): void;
|
|
190
|
+
/**
|
|
191
|
+
* Assert an object contains the provided keys
|
|
192
|
+
* @param obj Object that should match the given pattern
|
|
193
|
+
* @param content An object of key/values the object should contains
|
|
194
|
+
*/
|
|
195
|
+
assertObjectContent(object: Record<string, unknown>, content: Record<string, any>): void;
|
|
196
|
+
/**
|
|
197
|
+
* Assert an object does not contain the provided keys
|
|
198
|
+
* @param obj Object that should not match the given pattern
|
|
199
|
+
* @param content An object of key/values the object should not contain
|
|
200
|
+
*/
|
|
201
|
+
assertNoObjectContent(object: Record<string, unknown>, content: Record<string, any>): void;
|
|
202
|
+
/**
|
|
203
|
+
* Assert a JSON file contains the provided keys
|
|
204
|
+
* @param filename
|
|
205
|
+
* @param content An object of key/values the file should contains
|
|
206
|
+
*/
|
|
207
|
+
assertJsonFileContent(filename: string, content: Record<string, any>): void;
|
|
208
|
+
/**
|
|
209
|
+
* Assert a JSON file does not contain the provided keys
|
|
210
|
+
* @param filename
|
|
211
|
+
* @param content An object of key/values the file should not contain
|
|
212
|
+
*/
|
|
213
|
+
assertNoJsonFileContent(filename: string, content: Record<string, any>): void;
|
|
214
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import { existsSync, readFileSync, rmSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import process from 'node:process';
|
|
5
|
+
import MemFsEditor from 'mem-fs-editor';
|
|
6
|
+
const isObject = object => typeof object === 'object' && object !== null && object !== undefined;
|
|
7
|
+
function convertArgs(args) {
|
|
8
|
+
if (args.length > 1) {
|
|
9
|
+
return [[...args]];
|
|
10
|
+
}
|
|
11
|
+
const arg = args[0];
|
|
12
|
+
return Array.isArray(arg) ? arg : [arg];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* This class provides utilities for testing generated content.
|
|
16
|
+
*/
|
|
17
|
+
export default class RunResult {
|
|
18
|
+
env;
|
|
19
|
+
generator;
|
|
20
|
+
cwd;
|
|
21
|
+
oldCwd;
|
|
22
|
+
memFs;
|
|
23
|
+
fs;
|
|
24
|
+
mockedGenerators;
|
|
25
|
+
options;
|
|
26
|
+
constructor(options) {
|
|
27
|
+
if (options.memFs && !options.cwd) {
|
|
28
|
+
throw new Error('CWD option is required for mem-fs tests');
|
|
29
|
+
}
|
|
30
|
+
this.env = options.env;
|
|
31
|
+
this.generator = options.generator;
|
|
32
|
+
this.cwd = options.cwd ?? process.cwd();
|
|
33
|
+
this.oldCwd = options.oldCwd;
|
|
34
|
+
this.memFs = options.memFs;
|
|
35
|
+
this.fs = this.memFs && MemFsEditor.create(this.memFs);
|
|
36
|
+
this.mockedGenerators = options.mockedGenerators || {};
|
|
37
|
+
this.options = options;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create another RunContext reusing the settings.
|
|
41
|
+
* See helpers.create api
|
|
42
|
+
*/
|
|
43
|
+
create(GeneratorOrNamespace, settings, envOptions) {
|
|
44
|
+
return this.options.helpers.create(GeneratorOrNamespace, {
|
|
45
|
+
...this.options.settings,
|
|
46
|
+
cwd: this.cwd,
|
|
47
|
+
oldCwd: this.oldCwd,
|
|
48
|
+
...settings,
|
|
49
|
+
autoCleanup: false,
|
|
50
|
+
}, { ...this.options.envOptions, memFs: this.memFs, ...envOptions });
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Return an object with fs changes.
|
|
54
|
+
* @param {Function} filter - parameter forwarded to mem-fs-editor#dump
|
|
55
|
+
*/
|
|
56
|
+
getSnapshot(filter) {
|
|
57
|
+
return this.fs.dump(this.cwd, filter);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Return an object with filenames with state.
|
|
61
|
+
* @param {Function} filter - parameter forwarded to mem-fs-editor#dump
|
|
62
|
+
* @returns {Object}
|
|
63
|
+
*/
|
|
64
|
+
getStateSnapshot(filter) {
|
|
65
|
+
const snapshot = this.getSnapshot(filter);
|
|
66
|
+
for (const dump of Object.values(snapshot)) {
|
|
67
|
+
delete dump.contents;
|
|
68
|
+
}
|
|
69
|
+
return snapshot;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Either dumps the contents of the specified files or the name and the contents of each file to the console.
|
|
73
|
+
*/
|
|
74
|
+
dumpFiles(...files) {
|
|
75
|
+
if (files.length === 0) {
|
|
76
|
+
this.memFs.each(file => {
|
|
77
|
+
console.log(file.path);
|
|
78
|
+
if (file.contents) {
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
80
|
+
console.log(file.contents.toString('utf8'));
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
for (const file of files) {
|
|
86
|
+
console.log(this.fs.read(this._fileName(file)));
|
|
87
|
+
}
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Dumps the name of each file to the console.
|
|
92
|
+
*/
|
|
93
|
+
dumpFilenames() {
|
|
94
|
+
this.memFs.each(file => {
|
|
95
|
+
console.log(file.path);
|
|
96
|
+
});
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Reverts to old cwd.
|
|
101
|
+
* @returns this
|
|
102
|
+
*/
|
|
103
|
+
restore() {
|
|
104
|
+
process.chdir(this.oldCwd);
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Deletes the test directory recursively.
|
|
109
|
+
*/
|
|
110
|
+
cleanup() {
|
|
111
|
+
process.chdir(this.oldCwd);
|
|
112
|
+
rmSync(this.cwd, { recursive: true });
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
_fileName(filename) {
|
|
116
|
+
if (path.isAbsolute(filename)) {
|
|
117
|
+
return filename;
|
|
118
|
+
}
|
|
119
|
+
return path.join(this.cwd, filename);
|
|
120
|
+
}
|
|
121
|
+
_readFile(filename, json) {
|
|
122
|
+
filename = this._fileName(filename);
|
|
123
|
+
const file = this.fs ? this.fs.read(filename) : readFileSync(filename, 'utf8');
|
|
124
|
+
return json ? JSON.parse(file) : file;
|
|
125
|
+
}
|
|
126
|
+
_exists(filename) {
|
|
127
|
+
filename = this._fileName(filename);
|
|
128
|
+
if (this.fs) {
|
|
129
|
+
return this.fs.exists(filename);
|
|
130
|
+
}
|
|
131
|
+
return existsSync(filename);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Assert that a file exists
|
|
135
|
+
* @param path - path to a file
|
|
136
|
+
* @example
|
|
137
|
+
* result.assertFile('templates/user.hbs');
|
|
138
|
+
*
|
|
139
|
+
* @also
|
|
140
|
+
*
|
|
141
|
+
* Assert that each files in the array exists
|
|
142
|
+
* @param paths - an array of paths to files
|
|
143
|
+
* @example
|
|
144
|
+
* result.assertFile(['templates/user.hbs', 'templates/user/edit.hbs']);
|
|
145
|
+
*/
|
|
146
|
+
assertFile(path) {
|
|
147
|
+
for (const file of convertArgs([path])) {
|
|
148
|
+
const here = this._exists(file);
|
|
149
|
+
assert.ok(here, `${file}, no such file or directory`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Assert that a file doesn't exist
|
|
154
|
+
* @param file - path to a file
|
|
155
|
+
* @example
|
|
156
|
+
* result.assertNoFile('templates/user.hbs');
|
|
157
|
+
*
|
|
158
|
+
* @also
|
|
159
|
+
*
|
|
160
|
+
* Assert that each of an array of files doesn't exist
|
|
161
|
+
* @param pairs - an array of paths to files
|
|
162
|
+
* @example
|
|
163
|
+
* result.assertNoFile(['templates/user.hbs', 'templates/user/edit.hbs']);
|
|
164
|
+
*/
|
|
165
|
+
assertNoFile(files) {
|
|
166
|
+
for (const file of convertArgs([files])) {
|
|
167
|
+
const here = this._exists(file);
|
|
168
|
+
assert.ok(!here, `${file} exists`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
assertFileContent(...args) {
|
|
172
|
+
for (const pair of convertArgs(args)) {
|
|
173
|
+
const file = pair[0];
|
|
174
|
+
const regex = pair[1];
|
|
175
|
+
this.assertFile(file);
|
|
176
|
+
const body = this._readFile(file);
|
|
177
|
+
let match = false;
|
|
178
|
+
match = typeof regex === 'string' ? body.includes(regex) : regex.test(body);
|
|
179
|
+
assert(match, `${file} did not match '${regex}'. Contained:\n\n${body}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
assertEqualsFileContent(...args) {
|
|
183
|
+
for (const pair of convertArgs(args)) {
|
|
184
|
+
const file = pair[0];
|
|
185
|
+
const expectedContent = pair[1];
|
|
186
|
+
this.assertFile(file);
|
|
187
|
+
this.assertTextEqual(this._readFile(file), expectedContent);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
assertNoFileContent(...args) {
|
|
191
|
+
for (const pair of convertArgs(args)) {
|
|
192
|
+
const file = pair[0];
|
|
193
|
+
const regex = pair[1];
|
|
194
|
+
this.assertFile(file);
|
|
195
|
+
const body = this._readFile(file);
|
|
196
|
+
if (typeof regex === 'string') {
|
|
197
|
+
assert.ok(!body.includes(regex), `${file} matched '${regex}'.`);
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
assert.ok(!regex.test(body), `${file} matched '${regex}'.`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Assert that two strings are equal after standardization of newlines
|
|
205
|
+
* @param value - a string
|
|
206
|
+
* @param expected - the expected value of the string
|
|
207
|
+
* @example
|
|
208
|
+
* result.assertTextEqual('I have a yellow cat', 'I have a yellow cat');
|
|
209
|
+
*/
|
|
210
|
+
assertTextEqual(value, expected) {
|
|
211
|
+
const eol = string => string.replace(/\r\n/g, '\n');
|
|
212
|
+
assert.equal(eol(value), eol(expected));
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Assert an object contains the provided keys
|
|
216
|
+
* @param obj Object that should match the given pattern
|
|
217
|
+
* @param content An object of key/values the object should contains
|
|
218
|
+
*/
|
|
219
|
+
assertObjectContent(object, content) {
|
|
220
|
+
for (const key of Object.keys(content)) {
|
|
221
|
+
if (isObject(content[key])) {
|
|
222
|
+
this.assertObjectContent(object[key], content[key]);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
assert.equal(object[key], content[key]);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Assert an object does not contain the provided keys
|
|
230
|
+
* @param obj Object that should not match the given pattern
|
|
231
|
+
* @param content An object of key/values the object should not contain
|
|
232
|
+
*/
|
|
233
|
+
assertNoObjectContent(object, content) {
|
|
234
|
+
for (const key of Object.keys(content)) {
|
|
235
|
+
if (isObject(content[key])) {
|
|
236
|
+
this.assertNoObjectContent(object[key], content[key]);
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
assert.notEqual(object[key], content[key]);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Assert a JSON file contains the provided keys
|
|
244
|
+
* @param filename
|
|
245
|
+
* @param content An object of key/values the file should contains
|
|
246
|
+
*/
|
|
247
|
+
assertJsonFileContent(filename, content) {
|
|
248
|
+
this.assertObjectContent(this._readFile(filename, true), content);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Assert a JSON file does not contain the provided keys
|
|
252
|
+
* @param filename
|
|
253
|
+
* @param content An object of key/values the file should not contain
|
|
254
|
+
*/
|
|
255
|
+
assertNoJsonFileContent(filename, content) {
|
|
256
|
+
this.assertNoObjectContent(this._readFile(filename, true), content);
|
|
257
|
+
}
|
|
258
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yeoman-test",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "Test utilities for Yeoman generators",
|
|
5
5
|
"homepage": "http://yeoman.io/authoring/testing.html",
|
|
6
6
|
"author": "The Yeoman Team",
|
|
7
|
+
"type": "module",
|
|
7
8
|
"files": [
|
|
8
|
-
"
|
|
9
|
+
"dist"
|
|
9
10
|
],
|
|
10
|
-
"
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
11
16
|
"keywords": [
|
|
12
17
|
"yeoman",
|
|
13
18
|
"unit test"
|
|
@@ -15,39 +20,50 @@
|
|
|
15
20
|
"repository": "yeoman/yeoman-test",
|
|
16
21
|
"license": "MIT",
|
|
17
22
|
"engines": {
|
|
18
|
-
"node": ">=12.
|
|
23
|
+
"node": "^14.15.0 || ^16.13.0 || >=18.12.0"
|
|
19
24
|
},
|
|
20
25
|
"config": {
|
|
21
26
|
"doc_path": "../yeoman-test-doc"
|
|
22
27
|
},
|
|
23
28
|
"devDependencies": {
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
29
|
+
"@esbuild-kit/esm-loader": "^2.5.1",
|
|
30
|
+
"@types/mocha": "^10.0.0",
|
|
31
|
+
"@types/sinon": "^10.0.13",
|
|
32
|
+
"coveralls": "^3.1.1",
|
|
33
|
+
"husky": "^8.0.2",
|
|
34
|
+
"jsdoc": "^3.6.10",
|
|
35
|
+
"lint-staged": "^13.0.3",
|
|
36
|
+
"mem-fs": "^2.2.1",
|
|
37
|
+
"mocha": "^10.1.0",
|
|
38
|
+
"mocha-expect-snapshot": "^7.0.0",
|
|
31
39
|
"prettier": "^2.2.1",
|
|
40
|
+
"prettier-plugin-packagejson": "^2.3.0",
|
|
32
41
|
"tui-jsdoc-template": "^1.2.2",
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"yeoman-
|
|
42
|
+
"typescript": "^4.9.3",
|
|
43
|
+
"xo": "^0.53.1",
|
|
44
|
+
"yeoman-environment": "^3.13.0",
|
|
45
|
+
"yeoman-generator": "^5.7.0"
|
|
36
46
|
},
|
|
37
47
|
"dependencies": {
|
|
38
|
-
"inquirer": "^8.
|
|
48
|
+
"@types/inquirer": "^8.2.5",
|
|
49
|
+
"@types/mem-fs-editor": "^7.0.2",
|
|
50
|
+
"@types/yeoman-environment": "^2.10.8",
|
|
51
|
+
"@types/yeoman-generator": "^5.2.11",
|
|
52
|
+
"inquirer": "^8.2.5",
|
|
39
53
|
"lodash": "^4.17.21",
|
|
40
|
-
"mem-fs-editor": "^9.
|
|
41
|
-
"sinon": "^
|
|
42
|
-
"temp-dir": "^
|
|
54
|
+
"mem-fs-editor": "^9.5.0",
|
|
55
|
+
"sinon": "^14.0.2",
|
|
56
|
+
"temp-dir": "^3.0.0"
|
|
43
57
|
},
|
|
44
58
|
"peerDependencies": {
|
|
45
|
-
"mem-fs": "^2.1
|
|
46
|
-
"yeoman-environment": "^3.
|
|
59
|
+
"mem-fs": "^2.2.1",
|
|
60
|
+
"yeoman-environment": "^3.13.0",
|
|
47
61
|
"yeoman-generator": "*"
|
|
48
62
|
},
|
|
49
63
|
"scripts": {
|
|
50
|
-
"test": "
|
|
64
|
+
"test": "mocha",
|
|
65
|
+
"build": "tsc",
|
|
66
|
+
"prepare": "npm run build",
|
|
51
67
|
"pretest": "xo",
|
|
52
68
|
"precommit": "lint-staged",
|
|
53
69
|
"doc": "npm run doc:generate && npm run doc:fix && npm run doc:prettier",
|
package/lib/adapter.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/* eslint-disable max-params */
|
|
2
|
-
'use strict';
|
|
3
|
-
const events = require('events');
|
|
4
|
-
const inquirer = require('inquirer');
|
|
5
|
-
const sinon = require('sinon');
|
|
6
|
-
const {PassThrough} = require('stream');
|
|
7
|
-
|
|
8
|
-
function DummyPrompt(mockedAnswers, options, question, _rl, answers) {
|
|
9
|
-
this.answers = {...answers, ...mockedAnswers};
|
|
10
|
-
this.question = question;
|
|
11
|
-
|
|
12
|
-
if (typeof options === 'function') {
|
|
13
|
-
this.callback = options;
|
|
14
|
-
} else if (options) {
|
|
15
|
-
this.callback = options.callback;
|
|
16
|
-
this.throwOnMissingAnswer = options.throwOnMissingAnswer;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
this.callback = this.callback || ((answers) => answers);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
DummyPrompt.prototype.run = function () {
|
|
23
|
-
let answer = this.answers[this.question.name];
|
|
24
|
-
let isSet;
|
|
25
|
-
|
|
26
|
-
switch (this.question.type) {
|
|
27
|
-
case 'list':
|
|
28
|
-
// List prompt accepts any answer value including null
|
|
29
|
-
isSet = answer !== undefined;
|
|
30
|
-
break;
|
|
31
|
-
case 'confirm':
|
|
32
|
-
// Ensure that we don't replace `false` with default `true`
|
|
33
|
-
isSet = answer || answer === false;
|
|
34
|
-
break;
|
|
35
|
-
default:
|
|
36
|
-
// Other prompts treat all falsy values to default
|
|
37
|
-
isSet = Boolean(answer);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (!isSet) {
|
|
41
|
-
if (answer === undefined && this.question.default === undefined) {
|
|
42
|
-
const missingAnswerMessage = `yeoman-test: question ${this.question.name} was asked but answer was not provided`;
|
|
43
|
-
console.warn(missingAnswerMessage);
|
|
44
|
-
if (this.throwOnMissingAnswer) {
|
|
45
|
-
return Promise.reject(new Error(missingAnswerMessage));
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
answer = this.question.default;
|
|
50
|
-
|
|
51
|
-
if (answer === undefined && this.question.type === 'confirm') {
|
|
52
|
-
answer = true;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return Promise.resolve(this.callback(answer));
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
function TestAdapter(mockedAnswers) {
|
|
60
|
-
this.promptModule = inquirer.createPromptModule({
|
|
61
|
-
input: new PassThrough(),
|
|
62
|
-
output: new PassThrough(),
|
|
63
|
-
skipTTYChecks: true
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
Object.keys(this.promptModule.prompts).forEach(function (promptName) {
|
|
67
|
-
this.promptModule.registerPrompt(
|
|
68
|
-
promptName,
|
|
69
|
-
class CustomDummyPrompt extends DummyPrompt {
|
|
70
|
-
constructor(question, rl, answers) {
|
|
71
|
-
super(mockedAnswers, undefined, question, rl, answers);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
);
|
|
75
|
-
}, this);
|
|
76
|
-
|
|
77
|
-
this.diff = sinon.spy();
|
|
78
|
-
this.log = sinon.spy();
|
|
79
|
-
Object.assign(this.log, events.EventEmitter.prototype);
|
|
80
|
-
|
|
81
|
-
// Make sure all log methods are defined
|
|
82
|
-
[
|
|
83
|
-
'write',
|
|
84
|
-
'writeln',
|
|
85
|
-
'ok',
|
|
86
|
-
'error',
|
|
87
|
-
'skip',
|
|
88
|
-
'force',
|
|
89
|
-
'create',
|
|
90
|
-
'invoke',
|
|
91
|
-
'conflict',
|
|
92
|
-
'identical',
|
|
93
|
-
'info',
|
|
94
|
-
'table'
|
|
95
|
-
].forEach(function (methodName) {
|
|
96
|
-
this.log[methodName] = sinon.stub().returns(this.log);
|
|
97
|
-
}, this);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
TestAdapter.prototype.prompt = function (questions, prefilledAnswers) {
|
|
101
|
-
return this.promptModule(questions, prefilledAnswers);
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
module.exports = {
|
|
105
|
-
DummyPrompt,
|
|
106
|
-
TestAdapter
|
|
107
|
-
};
|