@lvce-editor/test-worker 6.1.0 → 6.3.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/dist/api.d.ts +32 -1
- package/dist/testWorkerMain.js +99 -54
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -1,4 +1,34 @@
|
|
|
1
1
|
|
|
2
|
+
export interface LocatorExpect {
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
negated: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
readonly checkSingleElementCondition: (fnName: string, options?: any) => Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
readonly checkMultiElementCondition: (fnName: string, options: any) => Promise<void>;
|
|
15
|
+
readonly toBeVisible: () => Promise<void>;
|
|
16
|
+
readonly toHaveText: (text: string) => Promise<void>;
|
|
17
|
+
readonly toContainText: (text: string) => Promise<void>;
|
|
18
|
+
readonly toHaveValue: (value: string) => Promise<void>;
|
|
19
|
+
readonly toBeFocused: () => Promise<void>;
|
|
20
|
+
readonly toHaveCSS: (key: string, value: string) => Promise<void>;
|
|
21
|
+
readonly toHaveAttribute: (key: string, value: string) => Promise<void>;
|
|
22
|
+
readonly toHaveJSProperty: (key: string, value: any) => Promise<void>;
|
|
23
|
+
readonly toHaveClass: (className: string) => Promise<void>;
|
|
24
|
+
readonly toHaveId: (id: string) => Promise<void>;
|
|
25
|
+
readonly toHaveCount: (count: number) => Promise<void>;
|
|
26
|
+
readonly toBeHidden: () => Promise<void>;
|
|
27
|
+
readonly not: LocatorExpect;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
2
32
|
interface LocatorClickOptions {
|
|
3
33
|
readonly button?: string;
|
|
4
34
|
}
|
|
@@ -27,6 +57,7 @@ export interface FileSystemTmpDirOptions {
|
|
|
27
57
|
|
|
28
58
|
interface Workspace {
|
|
29
59
|
readonly openTmpDir: () => Promise<string>;
|
|
60
|
+
readonly resolveFileUrl: (url: string) => string;
|
|
30
61
|
readonly setPath: (path: string) => Promise<void>;
|
|
31
62
|
}
|
|
32
63
|
|
|
@@ -513,7 +544,7 @@ export interface TestApi {
|
|
|
513
544
|
readonly TitleBarMenuBar: TitleBarMenuBar
|
|
514
545
|
readonly Url: Url
|
|
515
546
|
readonly WebView: WebView
|
|
516
|
-
readonly expect:
|
|
547
|
+
readonly expect: (locator: ILocatorExternal) => LocatorExpect
|
|
517
548
|
readonly Locator: (selector: string, option?: any) => ILocatorExternal
|
|
518
549
|
}
|
|
519
550
|
|
package/dist/testWorkerMain.js
CHANGED
|
@@ -1079,10 +1079,55 @@ const sendMessagePortToEditorWorker = async (port, rpcId) => {
|
|
|
1079
1079
|
await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToEditorWorker', port, command, rpcId);
|
|
1080
1080
|
};
|
|
1081
1081
|
|
|
1082
|
+
const callFunction = async (fn, args) => {
|
|
1083
|
+
try {
|
|
1084
|
+
await fn(args);
|
|
1085
|
+
return undefined;
|
|
1086
|
+
} catch (error) {
|
|
1087
|
+
return error;
|
|
1088
|
+
}
|
|
1089
|
+
};
|
|
1090
|
+
|
|
1082
1091
|
const formatDuration = duration => {
|
|
1083
1092
|
return duration.toFixed(2) + 'ms';
|
|
1084
1093
|
};
|
|
1085
1094
|
|
|
1095
|
+
const Fail = 'fail';
|
|
1096
|
+
const Pass = 'pass';
|
|
1097
|
+
|
|
1098
|
+
const executeTest2 = async (name, fn, globals, timestampGenerator) => {
|
|
1099
|
+
const getTimestamp = timestampGenerator;
|
|
1100
|
+
const start = getTimestamp();
|
|
1101
|
+
const error = await callFunction(fn, globals);
|
|
1102
|
+
const end = getTimestamp();
|
|
1103
|
+
const duration = end - start;
|
|
1104
|
+
const formattedDuration = formatDuration(duration);
|
|
1105
|
+
if (error) {
|
|
1106
|
+
return {
|
|
1107
|
+
error,
|
|
1108
|
+
start,
|
|
1109
|
+
end,
|
|
1110
|
+
duration,
|
|
1111
|
+
formattedDuration,
|
|
1112
|
+
name,
|
|
1113
|
+
type: Fail,
|
|
1114
|
+
background: 'red',
|
|
1115
|
+
text: `test failed: ${error}`
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
return {
|
|
1119
|
+
error: undefined,
|
|
1120
|
+
start,
|
|
1121
|
+
end,
|
|
1122
|
+
duration,
|
|
1123
|
+
formattedDuration,
|
|
1124
|
+
name,
|
|
1125
|
+
type: Pass,
|
|
1126
|
+
background: 'green',
|
|
1127
|
+
text: `test passed in ${formattedDuration}`
|
|
1128
|
+
};
|
|
1129
|
+
};
|
|
1130
|
+
|
|
1086
1131
|
const printError = error => {
|
|
1087
1132
|
if (error && error.constructor.name === 'AssertionError') {
|
|
1088
1133
|
console.error(error.message);
|
|
@@ -1096,66 +1141,26 @@ const printTestError = async error => {
|
|
|
1096
1141
|
printError(error);
|
|
1097
1142
|
};
|
|
1098
1143
|
|
|
1099
|
-
const stringifyError = error => {
|
|
1100
|
-
if (!error) {
|
|
1101
|
-
return `${error}`;
|
|
1102
|
-
}
|
|
1103
|
-
if (error && error.message && error.constructor.name && error.constructor.name !== 'Error' && error.constructor.name !== 'VError') {
|
|
1104
|
-
return `${error}`;
|
|
1105
|
-
}
|
|
1106
|
-
return `${error.message}`;
|
|
1107
|
-
};
|
|
1108
|
-
|
|
1109
|
-
const Fail = 'fail';
|
|
1110
|
-
const Pass = 'pass';
|
|
1111
|
-
|
|
1112
1144
|
const now = () => {
|
|
1113
1145
|
return performance.now();
|
|
1114
1146
|
};
|
|
1115
1147
|
|
|
1116
|
-
// TODO make this code more functional, returning a test result
|
|
1117
|
-
// and a separate function prints out the test result
|
|
1118
1148
|
const executeTest = async (name, fn, globals = {}) => {
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
_end = now();
|
|
1128
|
-
_duration = _end - _start;
|
|
1129
|
-
_formattedDuration = formatDuration(_duration);
|
|
1130
|
-
// eslint-disable-next-line no-console
|
|
1131
|
-
console.info(`PASS ${name} in ${_formattedDuration}`);
|
|
1132
|
-
} catch (error) {
|
|
1133
|
-
if (error &&
|
|
1134
|
-
// @ts-ignore
|
|
1135
|
-
error.message.startsWith('Failed to load command TestFrameWork.')) {
|
|
1136
|
-
console.error(error);
|
|
1137
|
-
return;
|
|
1138
|
-
}
|
|
1139
|
-
_error = stringifyError(error);
|
|
1140
|
-
if (!(error instanceof VError)) {
|
|
1141
|
-
error = new VError(error, `Test failed: ${name}`);
|
|
1142
|
-
}
|
|
1149
|
+
const {
|
|
1150
|
+
error,
|
|
1151
|
+
formattedDuration,
|
|
1152
|
+
background,
|
|
1153
|
+
text,
|
|
1154
|
+
type
|
|
1155
|
+
} = await executeTest2(name, fn, globals, now);
|
|
1156
|
+
if (error) {
|
|
1143
1157
|
await printTestError(error);
|
|
1144
|
-
}
|
|
1145
|
-
let state;
|
|
1146
|
-
let background;
|
|
1147
|
-
let text;
|
|
1148
|
-
if (_error) {
|
|
1149
|
-
state = Fail;
|
|
1150
|
-
background = 'red';
|
|
1151
|
-
text = `test failed: ${_error}`;
|
|
1152
1158
|
} else {
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
state = Pass;
|
|
1159
|
+
// eslint-disable-next-line no-console
|
|
1160
|
+
console.info(`PASS ${name} in ${formattedDuration}`);
|
|
1156
1161
|
}
|
|
1157
1162
|
// @ts-ignore
|
|
1158
|
-
await invoke$1('TestFrameWork.showOverlay',
|
|
1163
|
+
await invoke$1('TestFrameWork.showOverlay', type, background, text);
|
|
1159
1164
|
};
|
|
1160
1165
|
|
|
1161
1166
|
const importScript = async url => {
|
|
@@ -1240,6 +1245,20 @@ const toHaveText = async (locator, options) => {
|
|
|
1240
1245
|
}
|
|
1241
1246
|
return `expected selector ${locatorString} to have text "${text}" but was "${actual}"`;
|
|
1242
1247
|
};
|
|
1248
|
+
const toContainText = async (locator, options) => {
|
|
1249
|
+
const locatorString = printLocator(locator);
|
|
1250
|
+
const {
|
|
1251
|
+
wasFound,
|
|
1252
|
+
actual
|
|
1253
|
+
} = await locatorInvoke(locator, 'TestFrameWork.checkConditionError', 'toContainText', locator, options);
|
|
1254
|
+
const {
|
|
1255
|
+
text
|
|
1256
|
+
} = options;
|
|
1257
|
+
if (!wasFound) {
|
|
1258
|
+
return `expected selector ${locatorString} to contain text "${text}" element was not found`;
|
|
1259
|
+
}
|
|
1260
|
+
return `expected selector ${locatorString} to contain text "${text}" but was "${actual}"`;
|
|
1261
|
+
};
|
|
1243
1262
|
const toHaveAttribute = async (locator, options) => {
|
|
1244
1263
|
const locatorString = printLocator(locator);
|
|
1245
1264
|
const {
|
|
@@ -1341,6 +1360,8 @@ const getFunction = fnName => {
|
|
|
1341
1360
|
return toHaveValue;
|
|
1342
1361
|
case 'toHaveText':
|
|
1343
1362
|
return toHaveText;
|
|
1363
|
+
case 'toContainText':
|
|
1364
|
+
return toContainText;
|
|
1344
1365
|
case 'toHaveAttribute':
|
|
1345
1366
|
return toHaveAttribute;
|
|
1346
1367
|
case 'toHaveCount':
|
|
@@ -3503,6 +3524,12 @@ const setWebViewPort = async (uid, port, origin, portType) => {
|
|
|
3503
3524
|
await invokeAndTransfer('WebView.setPort', uid, port, origin, portType);
|
|
3504
3525
|
};
|
|
3505
3526
|
|
|
3527
|
+
const transferWebViewPort = async (webViewId, port) => {
|
|
3528
|
+
const info = await getWebViewInfo(webViewId);
|
|
3529
|
+
const portType = 'test';
|
|
3530
|
+
await setWebViewPort(info.uid, port, info.origin, portType);
|
|
3531
|
+
};
|
|
3532
|
+
|
|
3506
3533
|
const waitForFirstEventEvent = async port => {
|
|
3507
3534
|
const {
|
|
3508
3535
|
resolve,
|
|
@@ -3521,9 +3548,7 @@ const createPortRpc = async webViewId => {
|
|
|
3521
3548
|
} = getPortTuple();
|
|
3522
3549
|
const firstEventPromise = waitForFirstEventEvent(port1);
|
|
3523
3550
|
// TODO ask extension host worker about webview uid
|
|
3524
|
-
|
|
3525
|
-
const portType = 'test';
|
|
3526
|
-
await setWebViewPort(info.uid, port2, info.origin, portType);
|
|
3551
|
+
await transferWebViewPort(webViewId, port2);
|
|
3527
3552
|
const firstEvent = await firstEventPromise;
|
|
3528
3553
|
if (firstEvent.data !== 'ready') {
|
|
3529
3554
|
throw new Error('unexpected first message');
|
|
@@ -3554,6 +3579,16 @@ const TestFrameWorkComponentWebView = {
|
|
|
3554
3579
|
fromId
|
|
3555
3580
|
};
|
|
3556
3581
|
|
|
3582
|
+
const toFileUrl = url => {
|
|
3583
|
+
const urlObject = new URL(url);
|
|
3584
|
+
const pathName = urlObject.pathname;
|
|
3585
|
+
if (!pathName.startsWith('/remote')) {
|
|
3586
|
+
throw new Error(`url must start with /remote`);
|
|
3587
|
+
}
|
|
3588
|
+
const rest = pathName.slice('/remote'.length);
|
|
3589
|
+
return `file://${rest}`;
|
|
3590
|
+
};
|
|
3591
|
+
|
|
3557
3592
|
const setPath = async path => {
|
|
3558
3593
|
await invoke$1('Workspace.setPath', path);
|
|
3559
3594
|
};
|
|
@@ -3562,10 +3597,20 @@ const openTmpDir = async () => {
|
|
|
3562
3597
|
await setPath(tmpDir);
|
|
3563
3598
|
return tmpDir;
|
|
3564
3599
|
};
|
|
3600
|
+
const resolveFileUrl = url => {
|
|
3601
|
+
// TODO in web, convert to memfs or fetch url
|
|
3602
|
+
// TODO on web: read filemap for that fixture
|
|
3603
|
+
// else, use filesystem to read the files
|
|
3604
|
+
// TODO covert remote url to file url
|
|
3605
|
+
// then set that as workspace path
|
|
3606
|
+
|
|
3607
|
+
return toFileUrl(url);
|
|
3608
|
+
};
|
|
3565
3609
|
|
|
3566
3610
|
const TestFrameWorkComponentWorkspace = {
|
|
3567
3611
|
__proto__: null,
|
|
3568
3612
|
openTmpDir,
|
|
3613
|
+
resolveFileUrl,
|
|
3569
3614
|
setPath
|
|
3570
3615
|
};
|
|
3571
3616
|
|