ui5-test-runner 6.0.4 → 6.0.5
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/dist/Npm.js
CHANGED
|
@@ -19,7 +19,7 @@ const npm = async (...arguments_) => {
|
|
|
19
19
|
detached: true
|
|
20
20
|
});
|
|
21
21
|
};
|
|
22
|
-
const validateRoot = async (proc, label) => {
|
|
22
|
+
const validateRoot = async (proc, label, requiresExistence) => {
|
|
23
23
|
if (proc.code !== 0) {
|
|
24
24
|
logger.fatal({ source: 'npm', message: `npm root ${label} failed with code ${proc.code}` });
|
|
25
25
|
}
|
|
@@ -30,8 +30,11 @@ const validateRoot = async (proc, label) => {
|
|
|
30
30
|
try {
|
|
31
31
|
await FileSystem.access(value, FileSystem.constants.R_OK);
|
|
32
32
|
}
|
|
33
|
-
catch {
|
|
34
|
-
|
|
33
|
+
catch (error) {
|
|
34
|
+
const code = error.code;
|
|
35
|
+
if (requiresExistence || code !== 'ENOENT') {
|
|
36
|
+
logger.fatal({ source: 'npm', message: `npm root ${label} directory is not accessible: "${value}"` });
|
|
37
|
+
}
|
|
35
38
|
}
|
|
36
39
|
return value;
|
|
37
40
|
};
|
|
@@ -39,8 +42,8 @@ const getRoots = memoize(async () => {
|
|
|
39
42
|
const localRootProcess = await npm('root');
|
|
40
43
|
const globalRootProcess = await npm('root', '--global');
|
|
41
44
|
await Promise.all([localRootProcess.closed, globalRootProcess.closed]);
|
|
42
|
-
const local = await validateRoot(localRootProcess, '(local)');
|
|
43
|
-
const global = await validateRoot(globalRootProcess, '(global)');
|
|
45
|
+
const local = await validateRoot(localRootProcess, '(local)', false);
|
|
46
|
+
const global = await validateRoot(globalRootProcess, '(global)', true);
|
|
44
47
|
logger.debug({ source: 'npm', message: 'roots', data: { local, global } });
|
|
45
48
|
return { local, global };
|
|
46
49
|
});
|
|
@@ -63,6 +66,17 @@ export class Npm {
|
|
|
63
66
|
static dynamicImport(specifier) {
|
|
64
67
|
return import(specifier);
|
|
65
68
|
}
|
|
69
|
+
static resolveSpecifier(specifier) {
|
|
70
|
+
return import.meta.resolve(specifier);
|
|
71
|
+
}
|
|
72
|
+
static tryResolveSpecifier(specifier) {
|
|
73
|
+
try {
|
|
74
|
+
return this.resolveSpecifier(specifier);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return 'unknown location';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
66
80
|
static tryResolvePackageDir(moduleName, nodeModulesPath) {
|
|
67
81
|
try {
|
|
68
82
|
const packageJsonPath = Module.findPackageJSON(moduleName, `${nodeModulesPath}/`);
|
|
@@ -79,7 +93,7 @@ export class Npm {
|
|
|
79
93
|
try {
|
|
80
94
|
const require = Module.createRequire(`${Url.pathToFileURL(configuration.cwd).href}/`);
|
|
81
95
|
const resolved = require.resolve(moduleName, { paths: [nodeModulesPath] });
|
|
82
|
-
return await this.dynamicImport(Url.pathToFileURL(resolved).href);
|
|
96
|
+
return { module: await this.dynamicImport(Url.pathToFileURL(resolved).href), resolved };
|
|
83
97
|
}
|
|
84
98
|
catch {
|
|
85
99
|
return undefined;
|
|
@@ -89,19 +103,24 @@ export class Npm {
|
|
|
89
103
|
for (const { path, label, checkVersion } of roots) {
|
|
90
104
|
const result = await this.tryImportFromPath(configuration, moduleName, path);
|
|
91
105
|
if (result !== undefined) {
|
|
92
|
-
logger.debug({ source: 'npm', message: `Module ${moduleName} ${label}` });
|
|
106
|
+
logger.debug({ source: 'npm', message: `Module ${moduleName} ${label} (${result.resolved})` });
|
|
93
107
|
if (checkVersion)
|
|
94
108
|
void this.checkIfLatestVersion(configuration, moduleName);
|
|
95
|
-
return result;
|
|
109
|
+
return result.module;
|
|
96
110
|
}
|
|
97
111
|
}
|
|
98
112
|
return undefined;
|
|
99
113
|
}
|
|
100
|
-
static async
|
|
101
|
-
|
|
114
|
+
static async tryImportLocally(configuration, moduleName) {
|
|
115
|
+
if (configuration.debugNpmNoLocal) {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
102
118
|
try {
|
|
103
119
|
const module = await this.dynamicImport(moduleName);
|
|
104
|
-
logger.debug({
|
|
120
|
+
logger.debug({
|
|
121
|
+
source: 'npm',
|
|
122
|
+
message: `Module ${moduleName} found locally (${this.tryResolveSpecifier(moduleName)})`
|
|
123
|
+
});
|
|
105
124
|
void this.checkIfLatestVersion(configuration, moduleName);
|
|
106
125
|
return module;
|
|
107
126
|
}
|
|
@@ -113,7 +132,14 @@ export class Npm {
|
|
|
113
132
|
if (moduleName === this.packageNameOf(moduleName)) {
|
|
114
133
|
logger.warn({ source: 'npm', message: `Module ${moduleName} not found locally` });
|
|
115
134
|
}
|
|
135
|
+
return undefined;
|
|
116
136
|
}
|
|
137
|
+
}
|
|
138
|
+
static async import(configuration, moduleName) {
|
|
139
|
+
logger.debug({ source: 'npm', message: `Importing module: ${moduleName}` });
|
|
140
|
+
const local = await this.tryImportLocally(configuration, moduleName);
|
|
141
|
+
if (local !== undefined)
|
|
142
|
+
return local;
|
|
117
143
|
const { local: localRoot, global: globalRoot } = await getRoots();
|
|
118
144
|
const extraRoots = [
|
|
119
145
|
...(configuration.alternateNpmPath
|
|
@@ -124,7 +150,9 @@ export class Npm {
|
|
|
124
150
|
: [])
|
|
125
151
|
];
|
|
126
152
|
const found = await this.tryImportFromRoots(configuration, moduleName, [
|
|
127
|
-
|
|
153
|
+
...(configuration.debugNpmNoLocal
|
|
154
|
+
? []
|
|
155
|
+
: [{ path: localRoot, label: 'found in local node_modules', checkVersion: true }]),
|
|
128
156
|
{ path: globalRoot, label: 'found globally', checkVersion: true },
|
|
129
157
|
...extraRoots
|
|
130
158
|
]);
|
|
@@ -147,18 +175,20 @@ export class Npm {
|
|
|
147
175
|
if (reimportPath !== undefined) {
|
|
148
176
|
const result = await this.tryImportFromPath(configuration, moduleName, reimportPath);
|
|
149
177
|
if (result === undefined) {
|
|
150
|
-
|
|
151
|
-
logger.fatal({ source: 'npm', message });
|
|
178
|
+
return logger.fatal({ source: 'npm', message: `Module ${moduleName} could not be loaded after install` });
|
|
152
179
|
}
|
|
153
|
-
|
|
180
|
+
logger.debug({ source: 'npm', message: `Module ${moduleName} loaded after install (${result.resolved})` });
|
|
181
|
+
return result.module;
|
|
154
182
|
}
|
|
155
183
|
return await this.dynamicImport(moduleName);
|
|
156
184
|
}
|
|
157
185
|
static async resolvePackageDir(configuration, moduleName) {
|
|
158
186
|
const { local, global: globalRoot } = await getRoots();
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
187
|
+
if (!configuration.debugNpmNoLocal) {
|
|
188
|
+
const fromLocal = this.tryResolvePackageDir(moduleName, local);
|
|
189
|
+
if (fromLocal)
|
|
190
|
+
return fromLocal;
|
|
191
|
+
}
|
|
162
192
|
const fromGlobal = this.tryResolvePackageDir(moduleName, globalRoot);
|
|
163
193
|
if (fromGlobal)
|
|
164
194
|
return fromGlobal;
|
|
@@ -174,6 +204,17 @@ export class Npm {
|
|
|
174
204
|
}
|
|
175
205
|
throw new Error(`Cannot locate package directory for ${moduleName}`);
|
|
176
206
|
}
|
|
207
|
+
static async resolvePackageBinCommand(configuration, moduleName, command) {
|
|
208
|
+
const packageDirectory = await this.resolvePackageDir(configuration, moduleName);
|
|
209
|
+
const { bin } = JSON.parse(await FileSystem.readFile(Path.join(packageDirectory, 'package.json'), 'utf8'));
|
|
210
|
+
const binRelativePath = typeof bin === 'string' ? bin : bin?.[command];
|
|
211
|
+
return binRelativePath
|
|
212
|
+
? Path.join(packageDirectory, binRelativePath)
|
|
213
|
+
: logger.fatal({
|
|
214
|
+
source: 'npm',
|
|
215
|
+
message: `Unable to locate command "${command}" in ${moduleName} package.json "bin"`
|
|
216
|
+
});
|
|
217
|
+
}
|
|
177
218
|
static packageNameOf(moduleName) {
|
|
178
219
|
if (moduleName.startsWith('@')) {
|
|
179
220
|
const [scope, package_] = moduleName.split('/', 2);
|
|
@@ -35,8 +35,8 @@ export const factory = async (configuration, signal) => {
|
|
|
35
35
|
max: 0
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
|
-
await
|
|
39
|
-
|
|
38
|
+
const cliPath = await Npm.resolvePackageBinCommand(configuration, 'playwright', 'playwright');
|
|
39
|
+
await Process.spawn('node', [cliPath, 'install', 'chromium'], {
|
|
40
40
|
signal
|
|
41
41
|
}).closed;
|
|
42
42
|
browser = await chromium.launch(launchOptions);
|
|
@@ -45,8 +45,8 @@ export const factory = async (configuration, signal) => {
|
|
|
45
45
|
max: 0
|
|
46
46
|
}
|
|
47
47
|
});
|
|
48
|
-
await
|
|
49
|
-
|
|
48
|
+
const cliPath = await Npm.resolvePackageBinCommand(configuration, 'puppeteer', 'puppeteer');
|
|
49
|
+
await Process.spawn('node', [cliPath, 'browsers', 'install', target], {
|
|
50
50
|
signal
|
|
51
51
|
}).closed;
|
|
52
52
|
browser = await launch(launchOptions);
|
|
@@ -91,6 +91,17 @@ const extractConfigEntries = (parsed, configDirectory) => {
|
|
|
91
91
|
}
|
|
92
92
|
return { forcedKeys, configFileKeys, configFileObject };
|
|
93
93
|
};
|
|
94
|
+
const substitutePlaceholder = async (merged, searchToken, valueToReplace) => {
|
|
95
|
+
for (const option of options) {
|
|
96
|
+
if (!(option.type === 'fs-entry' &&
|
|
97
|
+
typeof merged[option.name] === 'string' &&
|
|
98
|
+
merged[option.name].includes(searchToken))) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const substituted = Path.join(valueToReplace, merged[option.name].split(searchToken, 2)[1]);
|
|
102
|
+
Object.assign(merged, { [option.name]: await validateValue(option, { ...merged, [option.name]: substituted }) });
|
|
103
|
+
}
|
|
104
|
+
};
|
|
94
105
|
const finalizeConfiguration = async (merged) => {
|
|
95
106
|
const hasExplicitReportDirectory = Object.hasOwn(merged, 'reportDir');
|
|
96
107
|
for (const option of options) {
|
|
@@ -108,15 +119,8 @@ const finalizeConfiguration = async (merged) => {
|
|
|
108
119
|
reportDir: await validateValue(reportDirectoryOption, { ...merged, reportDir: batchReportDirectory })
|
|
109
120
|
});
|
|
110
121
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
typeof merged[option.name] === 'string' &&
|
|
114
|
-
merged[option.name].includes('{{reportDir}}'))) {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
const substituted = Path.join(merged.reportDir, merged[option.name].split('{{reportDir}}', 2)[1]);
|
|
118
|
-
Object.assign(merged, { [option.name]: await validateValue(option, { ...merged, [option.name]: substituted }) });
|
|
119
|
-
}
|
|
122
|
+
await substitutePlaceholder(merged, '{{reportDir}}', merged.reportDir);
|
|
123
|
+
await substitutePlaceholder(merged, '{{tmpDir}}', Host.tmpdir());
|
|
120
124
|
for (const derive of derivations) {
|
|
121
125
|
derive(merged);
|
|
122
126
|
}
|
|
@@ -249,6 +249,11 @@ export const options = [
|
|
|
249
249
|
type: 'boolean',
|
|
250
250
|
description: 'use local docs/ directory instead of fetching from GitHub (development only)'
|
|
251
251
|
},
|
|
252
|
+
{
|
|
253
|
+
name: 'debugNpmNoLocal',
|
|
254
|
+
type: 'boolean',
|
|
255
|
+
description: 'Simulates a locally-absent package so the runner falls back to global or prefix resolution (development/testing only)'
|
|
256
|
+
},
|
|
252
257
|
{
|
|
253
258
|
name: 'driver',
|
|
254
259
|
short: 'd',
|
|
@@ -378,7 +383,8 @@ export const options = [
|
|
|
378
383
|
{
|
|
379
384
|
name: 'npmInstallPrefix',
|
|
380
385
|
type: 'fs-entry',
|
|
381
|
-
|
|
386
|
+
typeModifiers: new Set(['overwrite']),
|
|
387
|
+
description: 'Directory used as the npm --prefix install target when --npm-install is set to prefix'
|
|
382
388
|
},
|
|
383
389
|
{
|
|
384
390
|
name: 'outputInterval',
|