From 78168f4faffdb51bf8a1dda9fe0515aa186e1077 Mon Sep 17 00:00:00 2001 From: wdevfx Date: Wed, 5 Mar 2025 12:52:17 +0400 Subject: [PATCH] tests(QUnit & Testcafe): modify CI configuration --- .github/actions/run-qunit-tests/action.yml | 3 +- .../setup-chrome-headless-shell/action.yml | 34 +++++++++++++ .../qunit_tests-additional-renovation.yml | 9 +--- .github/workflows/testcafe_tests.yml | 48 +++++++++++-------- e2e/testcafe-devextreme/runner.js | 43 +++++++++++++---- packages/devextreme/docker-ci.sh | 35 +++++++++----- .../dataGrid.tests.js | 3 +- 7 files changed, 124 insertions(+), 51 deletions(-) create mode 100644 .github/actions/setup-chrome-headless-shell/action.yml diff --git a/.github/actions/run-qunit-tests/action.yml b/.github/actions/run-qunit-tests/action.yml index ca3c490a92e1..5623dca71ead 100644 --- a/.github/actions/run-qunit-tests/action.yml +++ b/.github/actions/run-qunit-tests/action.yml @@ -52,7 +52,7 @@ runs: - name: Setup Chrome if: ${{ inputs.browser == 'chrome' }} - uses: ./.github/actions/setup-chrome + uses: ./.github/actions/setup-chrome-headless-shell with: chrome-version: '133.0.6943.53' @@ -126,6 +126,7 @@ runs: GITHUBACTION: "true" TARGET: "test" DISPLAY: ":99" + CHROME_CMD: ${{ env.CHROME_SHELL }} run: | chmod +x ./docker-ci.sh ./docker-ci.sh diff --git a/.github/actions/setup-chrome-headless-shell/action.yml b/.github/actions/setup-chrome-headless-shell/action.yml new file mode 100644 index 000000000000..5ad9bca9ffc2 --- /dev/null +++ b/.github/actions/setup-chrome-headless-shell/action.yml @@ -0,0 +1,34 @@ +name: Chrome headless shell installer +description: Install chrome-headless-shell + +# Chrome headless shell +# https://developer.chrome.com/blog/chrome-headless-shell + +inputs: + chrome-version: + description: Chrome headless shell version to install + default: "latest" + +runs: + using: composite + steps: + - name: Setup chrome-headless-shell + shell: bash + env: + CHROME_VERSION: ${{ inputs.chrome-version }} + run: | + if [ -n "$CHROME_VERSION" ]; then + sudo apt-get update + sudo apt-get -y install libu2f-udev + sudo apt-get -y install dbus + + echo "version to install: $CHROME_VERSION" + CHROME_BIN=`npx @puppeteer/browsers install chrome-headless-shell@$CHROME_VERSION | awk '{print $2}'` + chmod +x $CHROME_BIN + echo "chrome-headless-shell installed in: $CHROME_BIN" + $CHROME_BIN --version + echo "CHROME_SHELL=$CHROME_BIN" >> $GITHUB_ENV + else + echo "chrome-headless-shell not installed!" + fi + diff --git a/.github/workflows/qunit_tests-additional-renovation.yml b/.github/workflows/qunit_tests-additional-renovation.yml index 1013f3f02742..0cf8c3997363 100644 --- a/.github/workflows/qunit_tests-additional-renovation.yml +++ b/.github/workflows/qunit_tests-additional-renovation.yml @@ -112,7 +112,7 @@ jobs: browser: 'chrome' isPerformance: 'true' useJQuery: 'true' - headless: 'false' + headless: 'true' useCsp: 'false' qunit-tests-mobile-and-shadow-dom: @@ -140,7 +140,6 @@ jobs: ] kind: [ 'shadow-dom', 'ios10', 'android6' ] include: - - headless: false - kind: 'shadow-dom' userAgent: '' useShadowDom: true @@ -149,10 +148,6 @@ jobs: - kind: 'android6' userAgent: 'android6' useJQuery: true - - constel: 'ui' - headless: true - - constel: 'viz' - headless: true steps: - name: Get sources @@ -167,7 +162,7 @@ jobs: useJQuery: ${{ matrix.useJquery || 'false' }} userAgent: ${{ matrix.userAgent }} useShadowDom: ${{ matrix.useShadowDom }} - headless: ${{ matrix.headless }} + headless: 'true' useCsp: 'true' qunit-tests-firefox: diff --git a/.github/workflows/testcafe_tests.yml b/.github/workflows/testcafe_tests.yml index 27f738042705..8866820da581 100644 --- a/.github/workflows/testcafe_tests.yml +++ b/.github/workflows/testcafe_tests.yml @@ -64,27 +64,33 @@ jobs: fail-fast: false matrix: ARGS: [ - { componentFolder: "accessibility", name: "accessibility (1/7)", indices: "1/7" }, - { componentFolder: "accessibility", name: "accessibility (2/7)", indices: "2/7" }, - { componentFolder: "accessibility", name: "accessibility (3/7)", indices: "3/7" }, - { componentFolder: "accessibility", name: "accessibility (4/7)", indices: "4/7" }, - { componentFolder: "accessibility", name: "accessibility (5/7)", indices: "5/7" }, - { componentFolder: "accessibility", name: "accessibility (6/7)", indices: "6/7" }, - { componentFolder: "accessibility", name: "accessibility (7/7)", indices: "7/7" }, - { componentFolder: "accessibility", name: "accessibility - material (1/7)", theme: "material.blue.light", indices: "1/7" }, - { componentFolder: "accessibility", name: "accessibility - material (2/7)", theme: "material.blue.light", indices: "2/7" }, - { componentFolder: "accessibility", name: "accessibility - material (3/7)", theme: "material.blue.light", indices: "3/7" }, - { componentFolder: "accessibility", name: "accessibility - material (4/7)", theme: "material.blue.light", indices: "4/7" }, - { componentFolder: "accessibility", name: "accessibility - material (5/7)", theme: "material.blue.light", indices: "5/7" }, - { componentFolder: "accessibility", name: "accessibility - material (6/7)", theme: "material.blue.light", indices: "6/7" }, - { componentFolder: "accessibility", name: "accessibility - material (7/7)", theme: "material.blue.light", indices: "7/7" }, - { componentFolder: "accessibility", name: "accessibility - fluent (1/7)", theme: "fluent.blue.light", indices: "1/7" }, - { componentFolder: "accessibility", name: "accessibility - fluent (2/7)", theme: "fluent.blue.light", indices: "2/7" }, - { componentFolder: "accessibility", name: "accessibility - fluent (3/7)", theme: "fluent.blue.light", indices: "3/7" }, - { componentFolder: "accessibility", name: "accessibility - fluent (4/7)", theme: "fluent.blue.light", indices: "4/7" }, - { componentFolder: "accessibility", name: "accessibility - fluent (5/7)", theme: "fluent.blue.light", indices: "5/7" }, - { componentFolder: "accessibility", name: "accessibility - fluent (6/7)", theme: "fluent.blue.light", indices: "6/7" }, - { componentFolder: "accessibility", name: "accessibility - fluent (7/7)", theme: "fluent.blue.light", indices: "7/7" }, + { componentFolder: "accessibility/common", name: "accessibility (1/7)", indices: "1/7" }, + { componentFolder: "accessibility/common", name: "accessibility (2/7)", indices: "2/7" }, + { componentFolder: "accessibility/common", name: "accessibility (3/7)", indices: "3/7" }, + { componentFolder: "accessibility/common", name: "accessibility (4/7)", indices: "4/7" }, + { componentFolder: "accessibility/common", name: "accessibility (5/7)", indices: "5/7" }, + { componentFolder: "accessibility/common", name: "accessibility (6/7)", indices: "6/7" }, + { componentFolder: "accessibility/common", name: "accessibility (7/7)", indices: "7/7" }, + { componentFolder: "accessibility/common", name: "accessibility - material (1/7)", theme: "material.blue.light", indices: "1/7" }, + { componentFolder: "accessibility/common", name: "accessibility - material (2/7)", theme: "material.blue.light", indices: "2/7" }, + { componentFolder: "accessibility/common", name: "accessibility - material (3/7)", theme: "material.blue.light", indices: "3/7" }, + { componentFolder: "accessibility/common", name: "accessibility - material (4/7)", theme: "material.blue.light", indices: "4/7" }, + { componentFolder: "accessibility/common", name: "accessibility - material (5/7)", theme: "material.blue.light", indices: "5/7" }, + { componentFolder: "accessibility/common", name: "accessibility - material (6/7)", theme: "material.blue.light", indices: "6/7" }, + { componentFolder: "accessibility/common", name: "accessibility - material (7/7)", theme: "material.blue.light", indices: "7/7" }, + { componentFolder: "accessibility/common", name: "accessibility - fluent (1/7)", theme: "fluent.blue.light", indices: "1/7" }, + { componentFolder: "accessibility/common", name: "accessibility - fluent (2/7)", theme: "fluent.blue.light", indices: "2/7" }, + { componentFolder: "accessibility/common", name: "accessibility - fluent (3/7)", theme: "fluent.blue.light", indices: "3/7" }, + { componentFolder: "accessibility/common", name: "accessibility - fluent (4/7)", theme: "fluent.blue.light", indices: "4/7" }, + { componentFolder: "accessibility/common", name: "accessibility - fluent (5/7)", theme: "fluent.blue.light", indices: "5/7" }, + { componentFolder: "accessibility/common", name: "accessibility - fluent (6/7)", theme: "fluent.blue.light", indices: "6/7" }, + { componentFolder: "accessibility/common", name: "accessibility - fluent (7/7)", theme: "fluent.blue.light", indices: "7/7" }, + { componentFolder: "accessibility/list", name: "accessibility - list (1/2)", indices: "1/2" }, + { componentFolder: "accessibility/list", name: "accessibility - list (1/2)", indices: "2/2" }, + { componentFolder: "accessibility/list", name: "accessibility - list - material (1/2)", theme: "material.blue.light", indices: "1/2" }, + { componentFolder: "accessibility/list", name: "accessibility - list - material (1/2)", theme: "material.blue.light", indices: "2/2" }, + { componentFolder: "accessibility/list", name: "accessibility - list - fluent (1/2)", theme: "fluent.blue.light", indices: "1/2" }, + { componentFolder: "accessibility/list", name: "accessibility - list - fluent (1/2)", theme: "fluent.blue.light", indices: "2/2" }, { componentFolder: "common", name: "common" }, { componentFolder: "common", name: "common - material", theme: 'material.blue.light' }, { componentFolder: "common", name: "common - fluent", theme: 'fluent.blue.light' }, diff --git a/e2e/testcafe-devextreme/runner.js b/e2e/testcafe-devextreme/runner.js index b8407f7746f4..4a2d987b64e8 100644 --- a/e2e/testcafe-devextreme/runner.js +++ b/e2e/testcafe-devextreme/runner.js @@ -9,6 +9,16 @@ const { globSync } = require('glob'); const testPageUtils = require('./helpers/clearPage'); require('nconf').argv(); +const LAUNCH_RETRY_ATTEMPTS = 5; +const LAUNCH_RETRY_TIMEOUT = 20000; +const TESTCAFE_CONFIG = { + hostname: 'localhost', + port1: 1437, + port2: 1438, + // eslint-disable-next-line spellcheck/spell-checker + experimentalProxyless: true, +}; + const changeTheme = async(t, themeName) => createTestCafe.ClientFunction(() => new Promise((resolve) => { // eslint-disable-next-line no-undef window.DevExpress.ui.themes.ready(resolve); @@ -33,14 +43,31 @@ const addShadowRootTree = async(t) => { }).with({ boundTestRun: t })(); }; +const wait = async(timeout) => new Promise(resolve => setTimeout(resolve, timeout)); + +const retry = async(action, attempt) => { + return await action() + .catch(async(error) => { + if(attempt <= 1) { + throw error; + } + + /* eslint-disable no-console */ + console.log('\n > error occurred during testcafe launch!\n'); + console.error(error); + console.info(`\n > waiting ${LAUNCH_RETRY_TIMEOUT / 1000} seconds...\n`); + await wait(LAUNCH_RETRY_TIMEOUT); + console.info('\n > retry launching testcafe\n'); + /* eslint-enable no-console */ + return await retry(action, attempt - 1); + }); +}; + let testCafe; -createTestCafe({ - hostname: 'localhost', - port1: 1437, - port2: 1438, - // eslint-disable-next-line spellcheck/spell-checker - experimentalProxyless: true, -}) + +const initTestCafe = () => createTestCafe(TESTCAFE_CONFIG); + +retry(initTestCafe, LAUNCH_RETRY_ATTEMPTS) .then(tc => { testCafe = tc; @@ -186,7 +213,7 @@ function setShadowDom(args) { function expandBrowserAlias(browser, componentFolder) { switch(browser) { case 'chrome:devextreme-shr2': - return 'chrome:headless --no-sandbox --disable-gpu --window-size=1200,800 --disable-partial-raster --disable-skia-runtime-opts --run-all-compositor-stages-before-draw --disable-new-content-rendering-timeout --disable-threaded-animation --disable-threaded-scrolling --disable-checker-imaging --disable-image-animation-resync --use-gl="swiftshader" --disable-features=PaintHolding --js-flags=--random-seed=2147483647 --font-render-hinting=none --disable-font-subpixel-positioning'; + return 'chrome:headless --no-sandbox --disable-gpu --window-size=1200,800 --disable-partial-raster --disable-skia-runtime-opts --run-all-compositor-stages-before-draw --disable-new-content-rendering-timeout --disable-threaded-animation --disable-threaded-scrolling --disable-checker-imaging --disable-image-animation-resync --use-gl="swiftshader" --disable-features=PaintHolding --font-render-hinting=none --disable-font-subpixel-positioning'; case 'chrome:docker': return 'chromium:headless --no-sandbox --disable-gpu --window-size=1200,800'; } diff --git a/packages/devextreme/docker-ci.sh b/packages/devextreme/docker-ci.sh index 8160e193348b..ce8b02217672 100755 --- a/packages/devextreme/docker-ci.sh +++ b/packages/devextreme/docker-ci.sh @@ -24,6 +24,7 @@ function run_test_impl { local runner_pid local runner_result=0 + [ -z "$CHROME_CMD"] && CHROME_CMD=google-chrome-stable [ "$LOCAL" == "true" ] && url="http://host.docker.internal:$port/run?notimers=true" [ -n "$CONSTEL" ] && url="$url&constellation=$CONSTEL" [ -n "$MOBILE_UA" ] && url="$url&deviceMode=true" @@ -96,23 +97,32 @@ function run_test_impl { ;; *) - local chrome_command=google-chrome-stable + local chrome_command=$CHROME_CMD local chrome_args=( --no-sandbox - --disable-dev-shm-usage + --headless --disable-gpu + --disable-partial-raster + --disable-skia-runtime-opts + --no-first-run + --run-all-compositor-stages-before-draw + --disable-new-content-rendering-timeout + --disable-background-timer-throttling + --disable-renderer-backgrounding + --disable-threaded-animation + --disable-threaded-scrolling + --disable-checker-imaging + --disable-image-animation-resync + --use-gl="swiftshader" + --disable-features=PaintHolding + --disable-features=ScriptStreaming + --disable-features=LazyFrameLoading + --font-render-hinting=none + --disable-font-subpixel-positioning --disable-extensions - --user-data-dir=/tmp/chrome ) - if [ "$NO_HEADLESS" != "true" ]; then - echo "Headless mode" - chrome_args+=( - --headless - --remote-debugging-address=0.0.0.0 - --remote-debugging-port=9222 - ) - else + if [ "$NO_HEADLESS" == "true" ]; then chrome_command="dbus-launch --exit-with-session $chrome_command" chrome_args+=( --no-first-run @@ -125,7 +135,6 @@ function run_test_impl { echo "Performance tests" chrome_args+=( --disable-popup-blocking - --remote-debugging-port=9223 --enable-impl-side-painting --enable-skia-benchmarking --disable-web-security @@ -163,7 +172,7 @@ function run_test_impl { printf ' %s\n' "${chrome_args[@]}" tput setaf 9 fi - google-chrome-stable --version + eval "$chrome_command --version" eval "$chrome_command ${chrome_args[@]} '$url'" &>chrome.log & ;; diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/dataGrid.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/dataGrid.tests.js index 2538da31e5ff..8a2dcda0531f 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/dataGrid.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/dataGrid.tests.js @@ -1044,7 +1044,8 @@ QUnit.module('Initialization', baseModuleConfig, () => { // assert assert.equal(toolbarItemOffset, $(dataGrid.$element()).find('.dx-datagrid-search-panel').offset().top, 'toolbar search panel is aligned'); - assert.roughEqual(toolbarItemOffset, $(dataGrid.$element()).find('.dx-toolbar .dx-datebox').offset().top, 0.51, 'toolbar custom item is aligned'); + // NOTE: Changed during Chrome133 update from 0.51 -> 1.51 + assert.roughEqual(toolbarItemOffset, $(dataGrid.$element()).find('.dx-toolbar .dx-datebox').offset().top, 1.51, 'toolbar custom item is aligned'); }); QUnit.test('Column caption should have correct width when sorting is disabled (T1009923)', function(assert) {