ui5-test-runner 6.0.0-beta.2 → 6.0.0-beta.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 +85 -15
- package/dist/browsers/factory.js +2 -2
- package/dist/browsers/puppeteer.js +2 -2
- package/dist/cli.js +2 -2
- package/dist/configuration/options.js +12 -0
- package/dist/modes/log/index.js +1 -1
- package/dist/modes/test/browser.js +1 -1
- package/dist/platform/Module.js +4 -0
- package/dist/platform/Url.js +4 -0
- package/dist/platform/index.js +2 -0
- package/dist/platform/mock.js +23 -17
- package/package.json +3 -3
package/dist/Npm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { logger, FileSystem, Http, Path, Process } from './platform/index.js';
|
|
1
|
+
import { logger, FileSystem, Http, Module, Path, Process, Url } from './platform/index.js';
|
|
2
2
|
import { memoize } from './utils/shared/memoize.js';
|
|
3
|
-
const getNpmCliPath =
|
|
3
|
+
export const getNpmCliPath = async () => {
|
|
4
4
|
const npmChildProcess = Process.spawn('npm', [], {
|
|
5
5
|
shell: true
|
|
6
6
|
});
|
|
@@ -18,9 +18,10 @@ const getNpmCliPath = memoize(async () => {
|
|
|
18
18
|
}
|
|
19
19
|
logger.debug({ source: 'npm', message: `npm@${semver} ${path}` });
|
|
20
20
|
return Path.join(path, 'bin/npm-cli.js');
|
|
21
|
-
}
|
|
21
|
+
};
|
|
22
|
+
const memoizedNpmCliPath = memoize(getNpmCliPath);
|
|
22
23
|
const npm = async (...arguments_) => {
|
|
23
|
-
const npmCliPath = await
|
|
24
|
+
const npmCliPath = await memoizedNpmCliPath();
|
|
24
25
|
return Process.spawn('node', [npmCliPath, ...arguments_], {
|
|
25
26
|
detached: true
|
|
26
27
|
});
|
|
@@ -37,8 +38,33 @@ const getRoots = memoize(async () => {
|
|
|
37
38
|
global: globalRootProcess.stdout.trim()
|
|
38
39
|
};
|
|
39
40
|
});
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
const buildInstallPlan = (strategy, moduleName, globalRoot, prefix) => {
|
|
42
|
+
if (strategy === 'global') {
|
|
43
|
+
return { installArguments: ['install', '-g', moduleName], reimportPath: globalRoot };
|
|
44
|
+
}
|
|
45
|
+
if (strategy === 'prefix') {
|
|
46
|
+
return {
|
|
47
|
+
installArguments: ['install', '--prefix', prefix, '--no-save', moduleName],
|
|
48
|
+
reimportPath: Path.join(prefix, 'node_modules')
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return { installArguments: ['install', '--no-save', moduleName], reimportPath: undefined };
|
|
52
|
+
};
|
|
53
|
+
export class Npm {
|
|
54
|
+
static dynamicImport(specifier) {
|
|
55
|
+
return import(specifier);
|
|
56
|
+
}
|
|
57
|
+
static async tryImportFromPath(configuration, moduleName, nodeModulesPath) {
|
|
58
|
+
try {
|
|
59
|
+
const require = Module.createRequire(Url.pathToFileURL(Path.join(configuration.cwd, 'package.json')).href);
|
|
60
|
+
const resolved = require.resolve(moduleName, { paths: [nodeModulesPath] });
|
|
61
|
+
return await this.dynamicImport(Url.pathToFileURL(resolved).href);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
static async getLatestVersion(moduleName) {
|
|
42
68
|
try {
|
|
43
69
|
const response = await Http.get(`https://registry.npmjs.org/${moduleName}/latest`);
|
|
44
70
|
const { version } = JSON.parse(response);
|
|
@@ -49,8 +75,8 @@ export const Npm = {
|
|
|
49
75
|
cause: error
|
|
50
76
|
});
|
|
51
77
|
}
|
|
52
|
-
}
|
|
53
|
-
async checkIfLatestVersion(moduleName, isLocal) {
|
|
78
|
+
}
|
|
79
|
+
static async checkIfLatestVersion(moduleName, isLocal) {
|
|
54
80
|
try {
|
|
55
81
|
const { local, global } = await getRoots();
|
|
56
82
|
const { version: installedVersion } = JSON.parse(await FileSystem.readFile(Path.join(isLocal ? local : global, moduleName, 'package.json'), 'utf8'));
|
|
@@ -63,18 +89,62 @@ export const Npm = {
|
|
|
63
89
|
catch (error) {
|
|
64
90
|
logger.error({ source: 'npm', message: 'Failed in checkIfLatestVersion', error });
|
|
65
91
|
}
|
|
66
|
-
}
|
|
67
|
-
async import(moduleName) {
|
|
92
|
+
}
|
|
93
|
+
static async import(configuration, moduleName) {
|
|
68
94
|
logger.debug({ source: 'npm', message: `Npm.import(${moduleName})` });
|
|
69
95
|
try {
|
|
70
|
-
const module =
|
|
96
|
+
const module = await this.dynamicImport(moduleName);
|
|
71
97
|
logger.debug({ source: 'npm', message: `Module ${moduleName} found locally` });
|
|
72
|
-
void
|
|
98
|
+
void Npm.checkIfLatestVersion(moduleName, true);
|
|
73
99
|
return module;
|
|
74
100
|
}
|
|
75
|
-
catch {
|
|
101
|
+
catch (error) {
|
|
102
|
+
const code = error.code;
|
|
103
|
+
if (code !== 'ERR_MODULE_NOT_FOUND' && code !== 'MODULE_NOT_FOUND') {
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
76
106
|
logger.warn({ source: 'npm', message: `Module ${moduleName} not found locally` });
|
|
77
107
|
}
|
|
78
|
-
|
|
108
|
+
const { global: globalRoot } = await getRoots();
|
|
109
|
+
const fromGlobal = await this.tryImportFromPath(configuration, moduleName, globalRoot);
|
|
110
|
+
if (fromGlobal !== undefined) {
|
|
111
|
+
logger.debug({ source: 'npm', message: `Module ${moduleName} found globally` });
|
|
112
|
+
void Npm.checkIfLatestVersion(moduleName, false);
|
|
113
|
+
return fromGlobal;
|
|
114
|
+
}
|
|
115
|
+
if (configuration.alternateNpmPath) {
|
|
116
|
+
const fromAlternate = await this.tryImportFromPath(configuration, moduleName, configuration.alternateNpmPath);
|
|
117
|
+
if (fromAlternate !== undefined) {
|
|
118
|
+
logger.debug({ source: 'npm', message: `Module ${moduleName} found in alternateNpmPath` });
|
|
119
|
+
return fromAlternate;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (configuration.npmInstallPrefix) {
|
|
123
|
+
const fromPrefix = await this.tryImportFromPath(configuration, moduleName, Path.join(configuration.npmInstallPrefix, 'node_modules'));
|
|
124
|
+
if (fromPrefix !== undefined) {
|
|
125
|
+
logger.debug({ source: 'npm', message: `Module ${moduleName} found in npmInstallPrefix` });
|
|
126
|
+
return fromPrefix;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (configuration.noNpmInstall) {
|
|
130
|
+
const message = `Module ${moduleName} not found and noNpmInstall is set`;
|
|
131
|
+
logger.fatal({ source: 'npm', message });
|
|
132
|
+
throw new Error(message);
|
|
133
|
+
}
|
|
134
|
+
const strategy = configuration.npmInstall;
|
|
135
|
+
logger.info({ source: 'npm', message: `Installing ${moduleName} (strategy: ${strategy})` });
|
|
136
|
+
const { installArguments, reimportPath } = buildInstallPlan(strategy, moduleName, globalRoot, configuration.npmInstallPrefix ?? '');
|
|
137
|
+
const installProcess = await npm(...installArguments);
|
|
138
|
+
await installProcess.closed;
|
|
139
|
+
if (reimportPath !== undefined) {
|
|
140
|
+
const result = await this.tryImportFromPath(configuration, moduleName, reimportPath);
|
|
141
|
+
if (result === undefined) {
|
|
142
|
+
const message = `Module ${moduleName} could not be loaded after install`;
|
|
143
|
+
logger.fatal({ source: 'npm', message });
|
|
144
|
+
throw new Error(message);
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
return await this.dynamicImport(moduleName);
|
|
79
149
|
}
|
|
80
|
-
}
|
|
150
|
+
}
|
package/dist/browsers/factory.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { logger, Exit, Process } from '../platform/index.js';
|
|
2
2
|
import { Npm } from '../Npm.js';
|
|
3
3
|
import { agentLogPrefix } from '../types/AgentState.js';
|
|
4
|
-
export const factory = async () => {
|
|
5
|
-
const puppeteer = await Npm.import('puppeteer');
|
|
4
|
+
export const factory = async (configuration) => {
|
|
5
|
+
const puppeteer = await Npm.import(configuration, 'puppeteer');
|
|
6
6
|
const { launch } = puppeteer;
|
|
7
7
|
let browser;
|
|
8
8
|
const abortController = new AbortController();
|
package/dist/cli.js
CHANGED
|
@@ -5,8 +5,8 @@ import { CommandLine } from './configuration/CommandLine.js';
|
|
|
5
5
|
import { execute } from './modes/execute.js';
|
|
6
6
|
const main = async () => {
|
|
7
7
|
const cliVersion = await version();
|
|
8
|
-
const cliName = cliVersion.split('@')[0];
|
|
9
|
-
const indexOfCli = process.argv.findIndex((value) => /[\\/]cli(\.[tj]s)?$/.exec(value) || value
|
|
8
|
+
const cliName = cliVersion.split('@')[0] ?? 'ui5-test-runner';
|
|
9
|
+
const indexOfCli = process.argv.findIndex((value) => /[\\/]cli(\.[tj]s)?$/.exec(value) || value.endsWith(cliName));
|
|
10
10
|
const configuration = await CommandLine.buildConfigurationFrom(Host.cwd(), process.argv.slice(indexOfCli + 1));
|
|
11
11
|
await execute(configuration);
|
|
12
12
|
};
|
|
@@ -106,6 +106,17 @@ export const options = [
|
|
|
106
106
|
type: 'boolean',
|
|
107
107
|
description: 'prevent any NPM install'
|
|
108
108
|
},
|
|
109
|
+
{
|
|
110
|
+
name: 'npmInstall',
|
|
111
|
+
type: 'string',
|
|
112
|
+
description: 'npm install strategy for missing packages',
|
|
113
|
+
default: 'global'
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'npmInstallPrefix',
|
|
117
|
+
type: 'fs-entry',
|
|
118
|
+
description: 'path used as --prefix when npmInstall is set to prefix'
|
|
119
|
+
},
|
|
109
120
|
{
|
|
110
121
|
name: 'outputInterval',
|
|
111
122
|
short: 'oi',
|
|
@@ -182,6 +193,7 @@ export const defaults = {
|
|
|
182
193
|
config: 'ui5-test-runner.json',
|
|
183
194
|
cwd: process.cwd(),
|
|
184
195
|
localhost: 'localhost',
|
|
196
|
+
npmInstall: 'global',
|
|
185
197
|
outputInterval: 30_000,
|
|
186
198
|
parallel: 2,
|
|
187
199
|
reportDir: 'report',
|
package/dist/modes/log/index.js
CHANGED
|
@@ -26,7 +26,7 @@ export const log = async (configuration) => {
|
|
|
26
26
|
name: 'log',
|
|
27
27
|
stop: stop
|
|
28
28
|
});
|
|
29
|
-
const browser = await BrowserFactory.build('puppeteer');
|
|
29
|
+
const browser = await BrowserFactory.build(configuration, 'puppeteer');
|
|
30
30
|
const browserReady = browser.setup({
|
|
31
31
|
visible: true
|
|
32
32
|
});
|
|
@@ -3,7 +3,7 @@ import { Exit, assert, logger } from '../../platform/index.js';
|
|
|
3
3
|
let browser;
|
|
4
4
|
export const setupBrowser = async (configuration) => {
|
|
5
5
|
assert(configuration.browser === 'puppeteer');
|
|
6
|
-
browser = await BrowserFactory.build('puppeteer');
|
|
6
|
+
browser = await BrowserFactory.build(configuration, 'puppeteer');
|
|
7
7
|
const { debugKeepBrowserOpen } = configuration;
|
|
8
8
|
const settings = {
|
|
9
9
|
visible: debugKeepBrowserOpen
|
package/dist/platform/index.js
CHANGED
|
@@ -6,8 +6,10 @@ export * from './Exit.js';
|
|
|
6
6
|
export * from './FileSystem.js';
|
|
7
7
|
export * from './Host.js';
|
|
8
8
|
export * from './Http.js';
|
|
9
|
+
export * from './Module.js';
|
|
9
10
|
export * from './Path.js';
|
|
10
11
|
export * from './Process.js';
|
|
11
12
|
export * from './Terminal.js';
|
|
12
13
|
export * from './Thread.js';
|
|
14
|
+
export * from './Url.js';
|
|
13
15
|
export * from './ZLib.js';
|
package/dist/platform/mock.js
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { vi } from 'vitest';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
const
|
|
3
|
+
const mockMethods = (object, members) => {
|
|
4
|
+
for (const member of members) {
|
|
5
|
+
if (typeof object[member] === 'function') {
|
|
6
|
+
object[member] = vi.fn();
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
const mockStaticMethodsOfExports = (actual) => {
|
|
4
11
|
const mocked = { ...actual };
|
|
5
12
|
for (const exportName in mocked) {
|
|
6
13
|
const exportValue = mocked[exportName];
|
|
7
14
|
if (typeof exportValue === 'function') {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
exportClass[staticName] = vi.fn();
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
+
mockMethods(exportValue, Object.getOwnPropertyNames(exportValue));
|
|
16
|
+
}
|
|
17
|
+
else if (typeof exportValue === 'object' && exportValue !== null) {
|
|
18
|
+
mockMethods(exportValue, Object.keys(exportValue));
|
|
15
19
|
}
|
|
16
20
|
}
|
|
17
21
|
return mocked;
|
|
@@ -26,7 +30,7 @@ vi.mock(import('./constants.js'), async (importActual) => {
|
|
|
26
30
|
export const __unregisterExitAsyncTask = vi.fn();
|
|
27
31
|
export let __lastRegisteredExitAsyncTask;
|
|
28
32
|
vi.mock(import('./Exit.js'), async (importActual) => {
|
|
29
|
-
const mocked =
|
|
33
|
+
const mocked = mockStaticMethodsOfExports(await importActual());
|
|
30
34
|
const { Exit } = mocked;
|
|
31
35
|
vi.mocked(Exit.registerAsyncTask).mockImplementation((task) => {
|
|
32
36
|
__lastRegisteredExitAsyncTask = task;
|
|
@@ -35,7 +39,7 @@ vi.mock(import('./Exit.js'), async (importActual) => {
|
|
|
35
39
|
return mocked;
|
|
36
40
|
});
|
|
37
41
|
vi.mock(import('./FileSystem.js'), async (importActual) => {
|
|
38
|
-
const mocked =
|
|
42
|
+
const mocked = mockStaticMethodsOfExports(await importActual());
|
|
39
43
|
const { FileSystem } = mocked;
|
|
40
44
|
const writeStream = {
|
|
41
45
|
write: vi.fn().mockImplementation((_, callback) => callback()),
|
|
@@ -46,8 +50,9 @@ vi.mock(import('./FileSystem.js'), async (importActual) => {
|
|
|
46
50
|
vi.mocked(FileSystem.createReadStream).mockReturnValue(readStream);
|
|
47
51
|
return mocked;
|
|
48
52
|
});
|
|
49
|
-
vi.mock(import('./Host.js'), async (importActual) =>
|
|
50
|
-
vi.mock(import('./Http.js'), async (importActual) =>
|
|
53
|
+
vi.mock(import('./Host.js'), async (importActual) => mockStaticMethodsOfExports(await importActual()));
|
|
54
|
+
vi.mock(import('./Http.js'), async (importActual) => mockStaticMethodsOfExports(await importActual()));
|
|
55
|
+
vi.mock(import('./Module.js'), async (importActual) => mockStaticMethodsOfExports(await importActual()));
|
|
51
56
|
const logger = {
|
|
52
57
|
start: vi.fn(),
|
|
53
58
|
debug: vi.fn(),
|
|
@@ -59,18 +64,18 @@ const logger = {
|
|
|
59
64
|
};
|
|
60
65
|
vi.mock(import('./logger.js'), () => ({ logger }));
|
|
61
66
|
vi.mock(import('./Path.js'), async (importActual) => {
|
|
62
|
-
const mocked =
|
|
67
|
+
const mocked = mockStaticMethodsOfExports(await importActual());
|
|
63
68
|
const { Path } = mocked;
|
|
64
69
|
vi.mocked(Path.isAbsolute).mockImplementation((path) => path.startsWith('/'));
|
|
65
70
|
vi.mocked(Path.join).mockImplementation((...arguments_) => join(...arguments_).replaceAll('\\', '/'));
|
|
66
71
|
return mocked;
|
|
67
72
|
});
|
|
68
|
-
vi.mock(import('./Process.js'), async (importActual) =>
|
|
73
|
+
vi.mock(import('./Process.js'), async (importActual) => mockStaticMethodsOfExports(await importActual()));
|
|
69
74
|
export let __lastTerminalRawModeCallback = false;
|
|
70
75
|
vi.mock(import('./Terminal.js'), async (importActual) => {
|
|
71
76
|
const actual = await importActual();
|
|
72
77
|
const originalstripVTControlCharacters = actual.Terminal.stripVTControlCharacters;
|
|
73
|
-
const mocked =
|
|
78
|
+
const mocked = mockStaticMethodsOfExports(actual);
|
|
74
79
|
const { Terminal } = mocked;
|
|
75
80
|
vi.mocked(Terminal.setRawMode).mockImplementation((callback) => {
|
|
76
81
|
__lastTerminalRawModeCallback = callback;
|
|
@@ -79,7 +84,7 @@ vi.mock(import('./Terminal.js'), async (importActual) => {
|
|
|
79
84
|
return mocked;
|
|
80
85
|
});
|
|
81
86
|
vi.mock(import('./Thread.js'), async (importActual) => {
|
|
82
|
-
const mocked =
|
|
87
|
+
const mocked = mockStaticMethodsOfExports(await importActual());
|
|
83
88
|
const { Thread } = mocked;
|
|
84
89
|
const channel = {
|
|
85
90
|
postMessage: vi.fn().mockImplementation((data) => {
|
|
@@ -101,4 +106,5 @@ vi.mock(import('./Thread.js'), async (importActual) => {
|
|
|
101
106
|
vi.mock(import('./version.js'), () => ({
|
|
102
107
|
version: vi.fn().mockResolvedValue('ui5-test-runner@1.2.3')
|
|
103
108
|
}));
|
|
104
|
-
vi.mock(import('./ZLib.js'), async (importActual) =>
|
|
109
|
+
vi.mock(import('./ZLib.js'), async (importActual) => mockStaticMethodsOfExports(await importActual()));
|
|
110
|
+
vi.mock(import('./Url.js'), async (importActual) => mockStaticMethodsOfExports(await importActual()));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ui5-test-runner",
|
|
3
|
-
"version": "6.0.0-beta.
|
|
3
|
+
"version": "6.0.0-beta.5",
|
|
4
4
|
"description": "Standalone test runner for UI5",
|
|
5
5
|
"main": "dist/cli.js",
|
|
6
6
|
"type": "module",
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"globals": "^17.6.0",
|
|
102
102
|
"jsdom": "^29.1.1",
|
|
103
103
|
"markdownlint-cli": "^0.48.0",
|
|
104
|
-
"npm-check-updates": "^22.2.
|
|
104
|
+
"npm-check-updates": "^22.2.2",
|
|
105
105
|
"puppeteer": "^25.1.0",
|
|
106
106
|
"qunit": "^2.26.0",
|
|
107
107
|
"rimraf": "^6.1.3",
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"stylelint-config-standard": "^40.0.0",
|
|
111
111
|
"terser": "^5.48.0",
|
|
112
112
|
"typescript": "^6.0.3",
|
|
113
|
-
"typescript-eslint": "^8.60.
|
|
113
|
+
"typescript-eslint": "^8.60.1",
|
|
114
114
|
"ui5-tooling-transpile": "^3.11.2",
|
|
115
115
|
"vite": "^8.0.16",
|
|
116
116
|
"vite-plugin-css-injected-by-js": "^5.0.1",
|