@aiot-toolkit/parser 2.0.6-beta.20 → 2.0.6-beta.21
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.
|
@@ -68,8 +68,11 @@ class ScriptToTypescript {
|
|
|
68
68
|
compilerOption: this.compilerOption
|
|
69
69
|
}]];
|
|
70
70
|
const pluginList = [{
|
|
71
|
-
enable: this.compilerOption.enableE2e,
|
|
71
|
+
enable: this.compilerOption.enableE2e && this.compilerOption.e2eConfigPath,
|
|
72
72
|
path: _path.default.resolve(__dirname, './plugins/e2e.js')
|
|
73
|
+
}, {
|
|
74
|
+
enable: this.compilerOption.enableE2e && !this.compilerOption.e2eConfigPath,
|
|
75
|
+
path: _path.default.resolve(__dirname, './plugins/e2e1.js')
|
|
73
76
|
}, {
|
|
74
77
|
enable: this.compilerOption.startPage && this.options.fileType === 'app',
|
|
75
78
|
path: _path.default.resolve(__dirname, './plugins/startPage.js')
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = e2e;
|
|
7
|
+
var t = _interopRequireWildcard(require("@babel/types"));
|
|
8
|
+
var parser = _interopRequireWildcard(require("@babel/parser"));
|
|
9
|
+
var _path = _interopRequireDefault(require("path"));
|
|
10
|
+
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
11
|
+
var _sharedUtils = require("@aiot-toolkit/shared-utils");
|
|
12
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
14
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
15
|
+
/**
|
|
16
|
+
* 用于添加应用自动化测试代码
|
|
17
|
+
* 分为两种情况
|
|
18
|
+
* 1. app文件
|
|
19
|
+
* 2. page 文件
|
|
20
|
+
*/
|
|
21
|
+
function e2e() {
|
|
22
|
+
return {
|
|
23
|
+
visitor: {
|
|
24
|
+
ExportDefaultDeclaration(path, _ref) {
|
|
25
|
+
let {
|
|
26
|
+
opts
|
|
27
|
+
} = _ref;
|
|
28
|
+
const opts2 = opts;
|
|
29
|
+
const options = opts2.options;
|
|
30
|
+
switch (options.fileType) {
|
|
31
|
+
case 'page':
|
|
32
|
+
addPageTestCode(path, opts2);
|
|
33
|
+
break;
|
|
34
|
+
case 'app':
|
|
35
|
+
addAppTestCode(path);
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 添加 app 的测试代码
|
|
45
|
+
*
|
|
46
|
+
* 引入测试框架文件
|
|
47
|
+
* @param path
|
|
48
|
+
* @param opts
|
|
49
|
+
*/
|
|
50
|
+
function addAppTestCode(path) {
|
|
51
|
+
const runtimePath = _path.default.join(__dirname, '../runtime/velaTestLibrary.js');
|
|
52
|
+
const appImport = t.importDeclaration([], t.stringLiteral(runtimePath));
|
|
53
|
+
if (path.parent.type === 'Program') {
|
|
54
|
+
path.parent.body.unshift(appImport);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 添加页面的测试代码
|
|
60
|
+
* 1. 如果测试文件存在,则
|
|
61
|
+
* a. import 测试文件
|
|
62
|
+
* b. 设置测试函数: 如果 onTestStart 方法已存在,则在其内部添加测试代码;否则,添加 onTestStart方法
|
|
63
|
+
*
|
|
64
|
+
*
|
|
65
|
+
* 2. 如果启用自动路由,且当前页面是首页
|
|
66
|
+
* a. 从routerList 中过滤出有测试文件的路由
|
|
67
|
+
* b. 在末尾添加 $generateAutoRunTest
|
|
68
|
+
* c. 在onShow 方法中调用 $generateAutoRunTest
|
|
69
|
+
*
|
|
70
|
+
*
|
|
71
|
+
* @description 示例
|
|
72
|
+
*
|
|
73
|
+
* 源码 `src/home/myHome.ux`
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* export default {}
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* 产物
|
|
80
|
+
* ```
|
|
81
|
+
* import fnTestCase from 'test/home/myHome.js'
|
|
82
|
+
*
|
|
83
|
+
* export default {
|
|
84
|
+
* onTestStart: (){
|
|
85
|
+
* // code
|
|
86
|
+
* }
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* @param path
|
|
91
|
+
* @param opts
|
|
92
|
+
*/
|
|
93
|
+
function addPageTestCode(path, opts) {
|
|
94
|
+
const e2eConfig = getE2eConfig(opts);
|
|
95
|
+
const testFilePath = getTestFilePath(opts.options.filePath, opts, e2eConfig);
|
|
96
|
+
// 1
|
|
97
|
+
if (_fsExtra.default.existsSync(testFilePath)) {
|
|
98
|
+
// 1.a
|
|
99
|
+
const relativePath = _path.default.relative(_path.default.dirname(opts.options.filePath), testFilePath);
|
|
100
|
+
const vmImport = t.importDeclaration([t.importDefaultSpecifier(t.identifier('fnTestCase'))], t.stringLiteral(relativePath));
|
|
101
|
+
if (path.parent.type === 'Program') {
|
|
102
|
+
path.parent.body.unshift(vmImport);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 1.b
|
|
106
|
+
if (path.node.declaration.type === 'ObjectExpression') {
|
|
107
|
+
const properties = path.node.declaration.properties;
|
|
108
|
+
insertFun('onTestStart', generateTestFn(), properties);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 2
|
|
113
|
+
if (isIndexPage(opts) && e2eConfig.autoRoute) {
|
|
114
|
+
let {
|
|
115
|
+
routerList,
|
|
116
|
+
pageSleep
|
|
117
|
+
} = e2eConfig.autoRoute;
|
|
118
|
+
routerList = routerList?.filter(item => hasTestFile(item, opts, e2eConfig));
|
|
119
|
+
if (!routerList?.length) {
|
|
120
|
+
opts.options.onLog({
|
|
121
|
+
level: _sharedUtils.Loglevel.WARN,
|
|
122
|
+
message: 'missing autoRoute.routerList'
|
|
123
|
+
});
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
// 2.a
|
|
127
|
+
|
|
128
|
+
if (path.node.declaration.type === 'ObjectExpression') {
|
|
129
|
+
const properties = path.node.declaration.properties;
|
|
130
|
+
|
|
131
|
+
// 2.b
|
|
132
|
+
insertFun('$generateAutoRunTest', generateAutoRouterFn(pageSleep, routerList), properties);
|
|
133
|
+
// 2.c
|
|
134
|
+
insertFun('onShow', generateAutoRouterInOnShow(), properties);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* 插入函数
|
|
141
|
+
*
|
|
142
|
+
* 如果已存在,把函数体插入到指定函数末尾;不存在,则添加
|
|
143
|
+
*
|
|
144
|
+
* @param name 函数名
|
|
145
|
+
* @param body 函数体
|
|
146
|
+
*/
|
|
147
|
+
function insertFun(name, body, properties) {
|
|
148
|
+
const fun = properties.find(p => p.type === 'ObjectMethod' && p.key.name === name);
|
|
149
|
+
if (fun) {
|
|
150
|
+
fun.body.body.push(...body.body);
|
|
151
|
+
} else {
|
|
152
|
+
properties.push(t.objectMethod('method', {
|
|
153
|
+
name: name,
|
|
154
|
+
type: 'Identifier'
|
|
155
|
+
}, [], body));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function hasTestFile(router, opts, e2eConfig) {
|
|
159
|
+
const manifest = getManifest(opts);
|
|
160
|
+
if (manifest) {
|
|
161
|
+
const {
|
|
162
|
+
pages
|
|
163
|
+
} = manifest.router;
|
|
164
|
+
const pageRouter = pages[router];
|
|
165
|
+
if (!pageRouter) {
|
|
166
|
+
opts.options.onLog({
|
|
167
|
+
level: _sharedUtils.Loglevel.WARN,
|
|
168
|
+
message: [{
|
|
169
|
+
word: router
|
|
170
|
+
}, `missing router in manifest.json`]
|
|
171
|
+
});
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
const pagePath = `${opts.compilerOption.sourceRoot}/${router}/${pageRouter.component}`;
|
|
175
|
+
const testFilePath = getTestFilePath(pagePath, opts, e2eConfig);
|
|
176
|
+
return _fsExtra.default.existsSync(testFilePath);
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
function isIndexPage(opts) {
|
|
181
|
+
const manifest = getManifest(opts);
|
|
182
|
+
if (manifest) {
|
|
183
|
+
const {
|
|
184
|
+
entry,
|
|
185
|
+
pages
|
|
186
|
+
} = manifest.router;
|
|
187
|
+
const entryItem = pages[entry];
|
|
188
|
+
const entryPath = `${entry}/${entryItem.component}`;
|
|
189
|
+
const sourcePath = _path.default.join(opts.options.projectPath, opts.compilerOption.sourceRoot);
|
|
190
|
+
const filePath = _path.default.relative(sourcePath, opts.options.filePath);
|
|
191
|
+
const filePathParsed = _path.default.parse(filePath);
|
|
192
|
+
return entryPath === `${filePathParsed.dir}/${filePathParsed.name}`;
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
function getManifest(opts) {
|
|
197
|
+
const manifestPath = _path.default.resolve(opts.options.projectPath, opts.compilerOption.sourceRoot, 'manifest.json');
|
|
198
|
+
if (manifestPath) {
|
|
199
|
+
return _fsExtra.default.readJSONSync(manifestPath);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function getE2eConfig(opts) {
|
|
203
|
+
const defaultTestDir = 'test';
|
|
204
|
+
let result = {
|
|
205
|
+
testDir: _path.default.join(opts.options.projectPath, defaultTestDir)
|
|
206
|
+
};
|
|
207
|
+
const {
|
|
208
|
+
projectPath
|
|
209
|
+
} = opts.options;
|
|
210
|
+
const {
|
|
211
|
+
e2eConfigPath
|
|
212
|
+
} = opts.compilerOption;
|
|
213
|
+
if (e2eConfigPath) {
|
|
214
|
+
const configFilePath = _path.default.resolve(projectPath, e2eConfigPath);
|
|
215
|
+
const configFileDir = _path.default.dirname(configFilePath);
|
|
216
|
+
if (_fsExtra.default.existsSync(configFilePath)) {
|
|
217
|
+
result = _fsExtra.default.readJSONSync(configFilePath, 'utf-8');
|
|
218
|
+
|
|
219
|
+
// 目录转换为绝对路径
|
|
220
|
+
if (result) {
|
|
221
|
+
result.testDir = _path.default.resolve(configFileDir, result.testDir || defaultTestDir);
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
throw new Error(`e2e Configuration file does not exist: ${configFilePath}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* 获取源文件对应的测试文件地址
|
|
232
|
+
* @param sourceFile 源文件
|
|
233
|
+
* @param opts
|
|
234
|
+
* @param e2eConfig
|
|
235
|
+
* @returns
|
|
236
|
+
*/
|
|
237
|
+
function getTestFilePath(sourceFile, opts, e2eConfig) {
|
|
238
|
+
const {
|
|
239
|
+
projectPath
|
|
240
|
+
} = opts.options;
|
|
241
|
+
const {
|
|
242
|
+
sourceRoot
|
|
243
|
+
} = opts.compilerOption;
|
|
244
|
+
const relativeSrc = _path.default.relative(_path.default.join(projectPath, sourceRoot || ''), sourceFile);
|
|
245
|
+
const parsed = _path.default.parse(relativeSrc);
|
|
246
|
+
return _path.default.join(e2eConfig.testDir, parsed.dir, `${parsed.name}.js`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* 获取测试函数的函数体
|
|
251
|
+
* @returns
|
|
252
|
+
*/
|
|
253
|
+
function generateTestFn() {
|
|
254
|
+
const fn = `function(){
|
|
255
|
+
this.$options = this._options || this.$options;
|
|
256
|
+
if (this.$options._descriptor) {
|
|
257
|
+
this.$options._descriptor["back"] = {
|
|
258
|
+
access: "public",
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
global.CASE_TEST_START = global.CASE_TEST_START || 1000;
|
|
262
|
+
global.qat = new VelaQuickappTest();
|
|
263
|
+
setTimeout(() => {
|
|
264
|
+
typeof fnTestCase === 'function' && fnTestCase(this)
|
|
265
|
+
qat.run(() => {
|
|
266
|
+
if (this.back !== "false") {
|
|
267
|
+
console.info("拥有关联测试用例,测试完毕,返回到之前的页面");
|
|
268
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
269
|
+
var _system = _interopRequireDefault($app_require$('@app-module/system.router'));
|
|
270
|
+
_system.default.back();
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
}, global.CASE_TEST_START);
|
|
274
|
+
}`;
|
|
275
|
+
return parser.parseExpression(fn).body;
|
|
276
|
+
}
|
|
277
|
+
function generateAutoRouterFn() {
|
|
278
|
+
let sleep = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 3000;
|
|
279
|
+
let routerList = arguments.length > 1 ? arguments[1] : undefined;
|
|
280
|
+
const fn = `function(){
|
|
281
|
+
const routerList = ${JSON.stringify(routerList)}
|
|
282
|
+
if (!routerList) {
|
|
283
|
+
console.log('missing routerList');
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
if (this.autoTestPageIndex === undefined) {
|
|
287
|
+
this.autoTestPageIndex = -1;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
setTimeout(() => {
|
|
291
|
+
if (++this.autoTestPageIndex < routerList.length) {
|
|
292
|
+
const uri = routerList[this.autoTestPageIndex];
|
|
293
|
+
console.log(\`auto test page=\${uri}, index=\${this.autoTestPageIndex}\`);
|
|
294
|
+
router.push({ uri });
|
|
295
|
+
} else {
|
|
296
|
+
console.log('auto test finish');
|
|
297
|
+
}
|
|
298
|
+
}, ${sleep});
|
|
299
|
+
}`;
|
|
300
|
+
return parser.parseExpression(fn).body;
|
|
301
|
+
}
|
|
302
|
+
function generateAutoRouterInOnShow() {
|
|
303
|
+
const fn = `function(){
|
|
304
|
+
this.$generateAutoRunTest();
|
|
305
|
+
}`;
|
|
306
|
+
return parser.parseExpression(fn).body;
|
|
307
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiot-toolkit/parser",
|
|
3
|
-
"version": "2.0.6-beta.
|
|
3
|
+
"version": "2.0.6-beta.21",
|
|
4
4
|
"description": "Parse the source code of aiot and convert it to the AST (Abstract Syntax Tree) of the target code.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"aiot",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"test": "node ./__tests__/parser.test.js"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@aiot-toolkit/shared-utils": "2.0.6-beta.
|
|
23
|
+
"@aiot-toolkit/shared-utils": "2.0.6-beta.21",
|
|
24
24
|
"@babel/core": "^7.23.6",
|
|
25
25
|
"@babel/generator": "^7.24.10",
|
|
26
26
|
"@babel/parser": "^7.24.8",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"css-tree": "npm:aiot-css-tree@^2.3.1",
|
|
32
32
|
"csstree-validator": "^3.0.0",
|
|
33
33
|
"eslint": "^8.46.0",
|
|
34
|
-
"file-lane": "2.0.6-beta.
|
|
34
|
+
"file-lane": "2.0.6-beta.21",
|
|
35
35
|
"fs-extra": "^11.2.0",
|
|
36
36
|
"google-protobuf": "^3.21.2",
|
|
37
37
|
"less": "^4.2.0",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"@types/tinycolor2": "^1.4.6",
|
|
61
61
|
"babel-plugin-tester": "^11.0.4"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "9294502171d727985c7a28a4a6f0c4a291623309"
|
|
64
64
|
}
|