@aiot-toolkit/parser 2.0.6-beta.20 → 2.0.6-beta.22

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,8 @@
1
+ import { PluginObj, PluginPass } from '@babel/core';
2
+ /**
3
+ * 用于添加应用自动化测试代码
4
+ * 分为两种情况
5
+ * 1. app文件
6
+ * 2. page 文件
7
+ */
8
+ export default function e2e(): PluginObj<PluginPass>;
@@ -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.20",
3
+ "version": "2.0.6-beta.22",
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.20",
23
+ "@aiot-toolkit/shared-utils": "2.0.6-beta.22",
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.20",
34
+ "file-lane": "2.0.6-beta.22",
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": "b2a85a11db9ff9e51e63bfca5643f3e6e0eeb15c"
63
+ "gitHead": "36e03348be739bca8665d981ce33d4d3f8cc4df5"
64
64
  }