This is an automated email from the ASF dual-hosted git repository.

sushuang pushed a commit to branch fix/contain-label-name
in repository https://gitbox.apache.org/repos/asf/echarts.git

commit 4a42f512257502d8e177a051c6982839a523ffba
Author: 100pah <[email protected]>
AuthorDate: Thu Apr 10 22:20:01 2025 +0800

    test: Manually sync test utilities.
---
 test/lib/reset.css                     |  6 +++++
 test/lib/testHelper.js                 |  1 +
 test/runTest/cli.js                    | 42 ++++++++++++++++++++++++++--------
 test/runTest/compareScreenshot.js      |  6 ++++-
 test/runTest/runtime/ActionPlayback.js | 30 ++++++++++++++++++++----
 test/runTest/runtime/main.js           | 24 ++++++++++++++++++-
 6 files changed, 93 insertions(+), 16 deletions(-)

diff --git a/test/lib/reset.css b/test/lib/reset.css
index d17312f5a..f1666779c 100644
--- a/test/lib/reset.css
+++ b/test/lib/reset.css
@@ -52,6 +52,12 @@ body > .main {
     padding-right: 2px;
 }
 
+/*
+ * [ CAUTION ]
+ *  The existing CSS class names below MUST NOT be modified;
+ *  otherwise, some recorded visual test cases may fail.
+ */
+
 .test-inputs button {
     margin: 10px 5px;
 }
diff --git a/test/lib/testHelper.js b/test/lib/testHelper.js
index ae58e64ff..224c2a133 100644
--- a/test/lib/testHelper.js
+++ b/test/lib/testHelper.js
@@ -191,6 +191,7 @@
 
         inputsContainer.className = [
             'test-inputs',
+            'test-buttons', // deprecated but backward compat.
             'test-inputs-style-' + (opt.inputsStyle || opt.buttonsStyle || 
'normal'),
             (inputsHeight != null ? 'test-inputs-fix-height' : '')
         ].join(' ');
diff --git a/test/runTest/cli.js b/test/runTest/cli.js
index cd9360ce3..cbc40ac5a 100644
--- a/test/runTest/cli.js
+++ b/test/runTest/cli.js
@@ -173,7 +173,7 @@ async function runTestPage(browser, testOpt, source, 
version, runtimeCode, isExp
     const fileUrl = testOpt.fileUrl;
     const screenshots = [];
     const logs = [];
-    const errors = [];
+    const errors = []; // string[]
 
     const page = await browser.newPage();
     page.setRequestInterception(true);
@@ -207,14 +207,36 @@ async function runTestPage(browser, testOpt, source, 
version, runtimeCode, isExp
     await page.exposeFunction('__VRT_MOUSE_MOVE__', async (x, y) =>  {
         await page.mouse.move(x, y);
     });
-    await page.exposeFunction('__VRT_MOUSE_DOWN__', async () =>  {
-        await page.mouse.down();
+    await page.exposeFunction('__VRT_MOUSE_DOWN__', async (errMsgPart) =>  {
+        try {
+            await page.mouse.down();
+        }
+        catch (err) {
+            // e.g., if double mousedown without a mouseup, error "'left' is 
already pressed." will be thrown.
+            // Report to users to re-record the test case.
+            if (errMsgPart) {
+                if ((err.message + '').indexOf('already pressed') >= 0) {
+                    errMsgPart += ' May be caused by duplicated mousedowns 
without a mouseup.'
+                        + ' Please re-record the test case.';
+                }
+                err.message = err.message + ' ' + errMsgPart;
+            }
+            throw err;
+        }
     });
-    await page.exposeFunction('__VRT_MOUSE_UP__', async () =>  {
-        await page.mouse.up();
+    await page.exposeFunction('__VRT_MOUSE_UP__', async (errMsgPart) =>  {
+        try {
+            await page.mouse.up();
+        }
+        catch (err) {
+            if (errMsgPart) {
+                err.message = err.message + ' ' + errMsgPart;
+            }
+            throw err;
+        }
     });
-    await page.exposeFunction('__VRT_LOAD_ERROR__', async (err) =>  {
-        errors.push(err);
+    await page.exposeFunction('__VRT_LOAD_ERROR__', async (errStr) =>  {
+        errors.push(errStr);
     });
     // await page.exposeFunction('__VRT_WAIT_FOR_NETWORK_IDLE__', async () =>  
{
     //     await waitForNetworkIdle();
@@ -234,8 +256,8 @@ async function runTestPage(browser, testOpt, source, 
version, runtimeCode, isExp
         });
     });
 
-    page.exposeFunction('__VRT_LOG_ERRORS__', (err) =>  {
-        errors.push(err);
+    page.exposeFunction('__VRT_LOG_ERRORS__', (errStr) =>  {
+        errors.push(errStr);
     });
 
     let actionScreenshotCount = {};
@@ -276,7 +298,7 @@ async function runTestPage(browser, testOpt, source, 
version, runtimeCode, isExp
     try {
         await page.setViewport({
             width: 800,
-            height: 600
+            height: 600,
         });
         await 
page.goto(`${origin}/test/${fileUrl}?__RENDERER__=${program.renderer}&__COARSE__POINTER__=${program.useCoarsePointer}`,
 {
             waitUntil: 'networkidle2',
diff --git a/test/runTest/compareScreenshot.js 
b/test/runTest/compareScreenshot.js
index dc239666b..769c1b739 100644
--- a/test/runTest/compareScreenshot.js
+++ b/test/runTest/compareScreenshot.js
@@ -47,7 +47,11 @@ module.exports = function (expectedShotPath, actualShotPath, 
threshold = 0.01) {
             (width !== actualImg.width)
           || (height !== actualImg.height)
         ) {
-            throw new Error('Image size not match');
+            throw new Error(
+                'Image size not match. '
+                + ' expect: ' + width + 'x' + height
+                + ' actual: ' + actualImg.width + 'x' + actualImg.height
+            );
         }
         const diffPNG = new PNG({width, height});
         let diffPixelsCount = pixelmatch(expectedImg.data, actualImg.data, 
diffPNG.data, width, height, {threshold});
diff --git a/test/runTest/runtime/ActionPlayback.js 
b/test/runTest/runtime/ActionPlayback.js
index aa50caa67..cad29497c 100644
--- a/test/runTest/runtime/ActionPlayback.js
+++ b/test/runTest/runtime/ActionPlayback.js
@@ -37,6 +37,8 @@ export class ActionPlayback {
         this._currentOpIndex = 0;
 
         this._isLastOpMousewheel = false;
+
+        this._isMouseDown = false;
     }
 
     getContext() {
@@ -52,6 +54,7 @@ export class ActionPlayback {
         this._current = Date.now();
         this._elapsedTime = 0;
         this._isLastOpMousewheel = false;
+        this._isMouseDown = false;
     }
 
     _restoreContext(ctx) {
@@ -103,7 +106,7 @@ export class ActionPlayback {
                 try {
                     // Execute all if there are multiple ops in one frame.
                     do {
-                        const executed = await self._update(takeScreenshot);
+                        const executed = await self._update(takeScreenshot, 
action.name);
                         if (!executed) {
                             break;
                         }
@@ -117,6 +120,14 @@ export class ActionPlayback {
 
                 if (self._currentOpIndex >= self._ops.length) {
                     // Finished
+                    if (self._isMouseDown) {
+                        reject(new Error(
+                            action.name + ' has finished, but the page remains 
in mousedown state.'
+                            + ' A mouseup is needed; otherwise the subsequent 
test case may be affected.'
+                            + ' Please re-record this test case.'
+                        ));
+                        return;
+                    }
                     resolve();
                 }
                 else {
@@ -135,7 +146,7 @@ export class ActionPlayback {
         }
     }
 
-    async _update(takeScreenshot) {
+    async _update(takeScreenshot, actionName) {
         let op = this._ops[this._currentOpIndex];
 
         if (!op || (op.time > this._elapsedTime)) {
@@ -144,18 +155,23 @@ export class ActionPlayback {
         }
 
         let screenshotTaken = false;
+        let errMsgPart;
         switch (op.type) {
             case 'mousedown':
+                errMsgPart = actionName + ' ' + op.type + ' (' + op.x + ',' + 
op.y + ')';
                 // Pause timeline to avoid frame not sync.
                 timeline.pause();
                 await __VRT_MOUSE_MOVE__(op.x, op.y);
-                await __VRT_MOUSE_DOWN__();
+                await __VRT_MOUSE_DOWN__(errMsgPart);
+                this._isMouseDown = true;
                 timeline.resume();
                 break;
             case 'mouseup':
+                errMsgPart = actionName + ' ' + op.type + ' (' + op.x + ',' + 
op.y + ')';
                 timeline.pause();
                 await __VRT_MOUSE_MOVE__(op.x, op.y);
-                await __VRT_MOUSE_UP__();
+                await __VRT_MOUSE_UP__(errMsgPart);
+                this._isMouseDown = false;
                 if (window.__VRT_RELOAD_TRIGGERED__) {
                     return;
                 }
@@ -187,6 +203,12 @@ export class ActionPlayback {
                 break;
             case 'valuechange':
                 const selector = document.querySelector(op.selector);
+                if (!selector) {
+                    throw new Error(
+                        '[Test Case Error] (' + actionName + ') Selector not 
found: ' + op.selector
+                        + '. It may be caused by test case changes.'
+                    );
+                }
                 selector.value = op.value;
                 // changing value via js won't trigger `change` event, so 
trigger it manually
                 selector.dispatchEvent(new Event('change'));
diff --git a/test/runTest/runtime/main.js b/test/runTest/runtime/main.js
index 633911d32..c83bd6640 100644
--- a/test/runTest/runtime/main.js
+++ b/test/runTest/runtime/main.js
@@ -103,7 +103,16 @@ window.__VRT_RUN_ACTIONS__ = async function (actions, 
restoredActionIndex, resto
             continue;
         }
         window.scrollTo(action.scrollX, action.scrollY);
-        await actionPlayback.runAction(action, index === restoredActionIndex ? 
restoredActionContext : null);
+        try {
+            await actionPlayback.runAction(action, index === 
restoredActionIndex ? restoredActionContext : null);
+        }
+        catch (err) {
+            // Any error in this JS task must be handled; otherwise 
__VRT_FINISH_ACTIONS__
+            // can not be called and the entire test execution will be blocked.
+            const errStr = errToStr(err);
+            // console.error(errStr);
+            __VRT_LOG_ERRORS__(errStr);
+        }
 
     }
     actionPlayback.stop();
@@ -111,6 +120,19 @@ window.__VRT_RUN_ACTIONS__ = async function (actions, 
restoredActionIndex, resto
     __VRT_FINISH_ACTIONS__();
 }
 
+function errToStr(err) {
+    if (typeof err === 'string') {
+        return err;
+    }
+    if (err && err.message != null) {
+        return err.message + (err.stack ? ' ' + err.stack : '');
+    }
+    if (err && err.toString) {
+        return err.toString();
+    }
+    return '[error] ' + err;
+}
+
 
 window.addEventListener('DOMContentLoaded', () => {
     let style = document.createElement('style');


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to