diff --git a/.github/actions/run-qunit-tests/action.yml b/.github/actions/run-qunit-tests/action.yml index c4f9134bed0c..9aa865d45a39 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' @@ -139,6 +139,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 768d19fb384e..7cf62635f2f5 100644 --- a/.github/workflows/qunit_tests-additional-renovation.yml +++ b/.github/workflows/qunit_tests-additional-renovation.yml @@ -111,24 +111,28 @@ jobs: useJQuery: 'false' useCsp: 'true' - qunit-tests-performance: - needs: build - runs-on: devextreme-shr2 - name: Performance - timeout-minutes: 25 - steps: - - name: Get sources - uses: actions/checkout@v4 - - - name: Run QUnit tests - uses: ./.github/actions/run-qunit-tests - with: - name: 'Performance' - browser: 'chrome' - isPerformance: 'true' - useJQuery: 'true' - headless: 'false' - useCsp: 'false' +# TODO Chrome133: skipped during chrome update +# We should run performance tests with non headless chrome +# It fails in headless mode + +# qunit-tests-performance: +# needs: build +# runs-on: devextreme-shr2 +# name: Performance +# timeout-minutes: 25 +# steps: +# - name: Get sources +# uses: actions/checkout@v4 +# +# - name: Run QUnit tests +# uses: ./.github/actions/run-qunit-tests +# with: +# name: 'Performance' +# browser: 'chrome' +# isPerformance: 'true' +# useJQuery: 'true' +# headless: 'true' +# useCsp: 'false' qunit-tests-mobile-and-shadow-dom: needs: build @@ -157,7 +161,6 @@ jobs: ] kind: [ 'shadow-dom', 'ios10', 'android6' ] include: - - headless: false - kind: 'shadow-dom' userAgent: '' useShadowDom: true @@ -166,10 +169,6 @@ jobs: - kind: 'android6' userAgent: 'android6' useJQuery: true - - constel: 'ui' - headless: true - - constel: 'viz' - headless: true steps: - name: Get sources @@ -184,7 +183,7 @@ jobs: useJQuery: ${{ matrix.useJquery || 'false' }} userAgent: ${{ matrix.userAgent }} useShadowDom: ${{ matrix.useShadowDom }} - headless: ${{ matrix.headless }} + headless: 'true' useCsp: 'true' qunit-tests-firefox: @@ -279,7 +278,7 @@ jobs: needs: [ build, qunit-tests-timezones, - qunit-tests-performance, + # qunit-tests-performance, qunit-tests-mobile-and-shadow-dom, qunit-tests-firefox, qunit-tests-no-csp diff --git a/.github/workflows/testcafe_tests.yml b/.github/workflows/testcafe_tests.yml index e41024c3b623..bd960856ca1a 100644 --- a/.github/workflows/testcafe_tests.yml +++ b/.github/workflows/testcafe_tests.yml @@ -79,27 +79,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' }, @@ -112,9 +118,10 @@ jobs: { componentFolder: "dataGrid/common", name: "dataGrid / common (3/5)", indices: "3/5" }, { componentFolder: "dataGrid/common", name: "dataGrid / common (4/5)", indices: "4/5" }, { componentFolder: "dataGrid/common", name: "dataGrid / common (5/5)", indices: "5/5" }, - { componentFolder: "dataGrid/stickyColumns", name: "dataGrid / sticky (1/3)", indices: "1/3" }, - { componentFolder: "dataGrid/stickyColumns", name: "dataGrid / sticky (2/3)", indices: "2/3" }, - { componentFolder: "dataGrid/stickyColumns", name: "dataGrid / sticky (3/3)", indices: "3/3" }, + { componentFolder: "dataGrid/sticky/common", name: "dataGrid / sticky common" }, + { componentFolder: "dataGrid/sticky/fixed", name: "dataGrid / sticky (1/3)", indices: "1/3" }, + { componentFolder: "dataGrid/sticky/fixed", name: "dataGrid / sticky (2/3)", indices: "2/3" }, + { componentFolder: "dataGrid/sticky/fixed", name: "dataGrid / sticky (3/3)", indices: "3/3" }, { componentFolder: "pivotGrid", name: "pivotGrid", concurrency: 1 }, { componentFolder: "pivotGrid", name: "pivotGrid - material", theme: 'material.blue.light', concurrency: 1 }, { componentFolder: "pivotGrid", name: "pivotGrid - fluent", theme: 'fluent.blue.light', concurrency: 1 }, diff --git a/e2e/testcafe-devextreme/runner.js b/e2e/testcafe-devextreme/runner.js index 64702551f4ec..b1d719a1be4c 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 95864472d735..c24939d87420 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 b9a9f6d52294..c3429af65b3e 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) {