1/*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16const { spawn } = require('child_process');
17const path = require('path');
18const {
19    recursiveCreateFolders,
20    copyFile,
21    isExistFile,
22    writeFile,
23    readDir
24} = require("../utils/file.js");
25
26
27const { writeJsonFile } = require("../utils/file");
28
29
30module.exports = { test, runHvigor };
31let origin = 40001;
32
33async function test(sdkPath, testFile, resultPath, casePath, ohpmBat, nodePath, hvigorPath) {
34    return new Promise(async (resolve, reject) => {
35        const testCasePath = `${casePath}\\test\\component_test\\test_cases\\components\\${testFile[0]}`;
36        const previewerExePath = `${sdkPath}\\previewer\\common\\bin`;
37        const jParam = `${testCasePath}\\entry\\.preview\\default\\intermediates\\loader_out\\default\\ets`;
38        const ljPathParam = `${testCasePath}\\entry\\.preview\\default\\intermediates\\loader\\default\\loader.json`;
39        const fParam = `${testCasePath}\\.idea\\previewer\\default\\defaultSettingConfig_Default.json`;
40        const arpParam = `${testCasePath}\\entry\\.preview\\default\\intermediates\\res\\default`;
41        const urlWithets = `"pages/${testFile[1]}/${testFile[2]}"`;
42        const urlParam = urlWithets.split(".ets")[0] + "\"";
43        let lwsParam = ++origin;
44        const page = `${testFile[0]}\\${testFile[1]}`.replaceAll("\\", "\\\\");
45        const out = `${resultPath}\\${testFile[1]}\\${testFile[2]}.json`.replaceAll("\\", "\\\\");
46        const componentTestParam = `{\\\"page\\\":\\\"${page}\\\",\\\"out\\\":\\\"${out}\\\"}`;
47        runPreviewer(previewerExePath, jParam, ljPathParam, fParam, urlParam, arpParam,
48            lwsParam, componentTestParam)
49            .then((isOver, error) => {
50                if (error) {
51                    reject(error);
52                } else {
53                    resolve(testFile);
54                }
55            }).catch((err) => {
56                if (err) {
57                    throw err;
58                }
59            });
60    });
61}
62
63const runCommand = (command, args, options) => {
64    return new Promise((resolve, reject) => {
65        const child = spawn(command, args, { shell: true, ...options });
66        if (!child) {
67            reject(new Error("Failed to create child process"));
68            return;
69        }
70        let stdoutData = "";
71        let stderrData = "";
72        child.stdout.on('data', data => {
73            stdoutData += data.toString();
74        });
75        child.stderr.on('data', (data) => {
76            stderrData += data.toString();
77            if (data.toString().includes("ERROR")) {
78                resolve(false)
79            }
80        });
81        child.on('close', code => {
82            if (code === 0) {
83                resolve(true);
84            } else {
85                resolve(false);
86            }
87        });
88    });
89};
90
91async function runHvigor(sdkPath, testFile, resultPath, casePath, ohpmBat, nodePath, hvigorPath) {
92    const testCasePath = `${casePath}\\test\\component_test\\test_cases\\components\\${testFile[0]}`;
93    const fParam = `${testCasePath}\\.idea\\previewer\\default\\defaultSettingConfig_Default.json`;
94    const caseResultPath = `${resultPath}\\${testFile[2]}.json`.replaceAll("\\", "\\\\");
95    runCommand(`"${ohpmBat}"`, [
96        'install',
97        '--all',
98        '--registry',
99        'https://ohpm.openharmony.cn/ohpm/',
100        '--strict_ssl',
101        'true'
102    ], { cwd: testCasePath })
103        .then(async (isOk, err) => {
104            if (err) {
105                console.error(err);
106            }
107            if (!isOk) {
108                writeJsonFile("", caseResultPath)
109                    .catch(err => {
110                        reject(err);
111                    });
112                resolve(true);
113            }
114        });
115
116    const localProperties = path.join(testCasePath, "local.properties");
117    if (!await isExistFile(localProperties)) {
118        let sdkDir = sdkPath.replaceAll("\\", "/");
119        let removeLast = sdkDir.replace(/\/\d+$/, '');
120        let fileContext = `sdk.dir=${removeLast}`;
121        await writeFile(path.join(testCasePath, "local.properties"), fileContext);
122    }
123
124    await runCommand(`"${nodePath}"`, [
125        `"${hvigorPath}"`,
126        '--sync',
127        '-p', 'product=default',
128        '--analyze=normal',
129        '--parallel',
130        '--incremental',
131        '--daemon'
132    ], { cwd: testCasePath })
133        .then((isOk, err) => {
134            if (err) {
135                reject(err);
136            }
137            if (!isOk) {
138                writeJsonFile("", caseResultPath)
139                    .catch(err => {
140                        reject(err);
141                    });
142                resolve(true);
143            }
144        });
145
146    await runCommand(`"${nodePath}"`, [
147        `"${hvigorPath}"`,
148        '--mode', 'module',
149        '-p', 'module=entry@default',
150        '-p', 'product=default',
151        '-p', 'pageType=page',
152        '-p', 'compileResInc=true',
153        '-p', 'requiredDeviceType=default',
154        '-p', 'previewMode=true',
155        '-p', 'buildRoot=.preview',
156        'PreviewBuild',
157        '--watch',
158        '--analyze=normal',
159        '--parallel',
160        '--incremental',
161        '--daemon'
162    ], { cwd: testCasePath, shell: true })
163        .then((isOk, err) => {
164            if (err) {
165                reject(err);
166            }
167            if (!isOk) {
168                writeJsonFile("", caseResultPath)
169                    .catch(err => {
170                        reject(err);
171                    });
172                resolve(true);
173            }
174        });
175
176    await recursiveCreateFolders(fParam.split("\\defaultSettingConfig_Default.json")[0]);
177    const configFileExists = await isExistFile(fParam);
178    if (!configFileExists) {
179        await copyFile("previewer_host\\resource\\defaultSettingConfig_Default.json", fParam);
180    }
181}
182async function runPreviewer(
183    previewerExePath, jParam, ljPathParam, fParam, urlParam, arpParam, lwsParam, componentTestParam) {
184    return new Promise(async (resolve, reject) => {
185        const previewerProcess = spawn("Previewer.exe", [
186            '-refresh', 'region',
187            '-projectID', '908375455',
188            '-ts', 'trace_48336_commandPipe',
189            '-j', jParam,
190            '-s', 'default_1713408574374_1',
191            '-cpm', 'false',
192            '-device', 'phone',
193            '-shape', 'rect',
194            '-sd', '480',
195            '-ljPath', `"${ljPathParam}"`,
196            '-or', '1080', '2340',
197            '-cr', '1080', '2340',
198            '-f', `"${fParam}"`,
199            '-n', '"entry"',
200            '-av', '"ACE_2_0"',
201            '-url', `${urlParam}`,
202            '-pages', '"main_pages"',
203            '-arp', `"${arpParam}"`,
204            '-pm', '"Stage"',
205            '-l', 'zh_CN',
206            '-cm', 'light',
207            '-o', 'portrait',
208            '-lws', lwsParam,
209            '-componentTest', `"${componentTestParam}"`
210        ], { detached: true, cwd: previewerExePath, shell: true });
211        previewerProcess.on('close', (code) => {
212            resolve(true);
213        });
214        previewerProcess.on('error', (err) => {
215            reject(err);
216        });
217    });
218}