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]
