diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 9600af215..56ca46bfc 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -16,32 +16,32 @@ jobs: NODE_VERSION: [10.x, 14.x, 16.x, 18.x, 19.x] NPM_SCRIPT: ["test:browserless"] include: - - NAME: "Browser tests: full build, Chrome & Firefox stable" - NODE_VERSION: "16.x" + - NAME: "Browser tests: full build, Chrome, Firefox & WebKit" + NODE_VERSION: "18.x" NPM_SCRIPT: "test:browser" - BROWSERS: "ChromeHeadless,FirefoxHeadless" - - NAME: "Browser tests: slim build, Chrome stable" - NODE_VERSION: "16.x" + BROWSERS: "ChromeHeadless,FirefoxHeadless,WebkitHeadless" + - NAME: "Browser tests: slim build, Chrome" + NODE_VERSION: "18.x" NPM_SCRIPT: "test:slim" BROWSERS: "ChromeHeadless" - - NAME: "Browser tests: no-deprecated build, Chrome stable" - NODE_VERSION: "16.x" + - NAME: "Browser tests: no-deprecated build, Chrome" + NODE_VERSION: "18.x" NPM_SCRIPT: "test:no-deprecated" BROWSERS: "ChromeHeadless" - - NAME: "Browser tests: selector-native build, Chrome stable" - NODE_VERSION: "16.x" + - NAME: "Browser tests: selector-native build, Chrome" + NODE_VERSION: "18.x" NPM_SCRIPT: "test:selector-native" BROWSERS: "ChromeHeadless" - - NAME: "Browser tests: ES modules build, Chrome stable" - NODE_VERSION: "16.x" + - NAME: "Browser tests: ES modules build, Chrome" + NODE_VERSION: "18.x" NPM_SCRIPT: "test:esmodules" BROWSERS: "ChromeHeadless" - - NAME: "Browser tests: AMD build, Chrome stable" - NODE_VERSION: "16.x" + - NAME: "Browser tests: AMD build, Chrome" + NODE_VERSION: "18.x" NPM_SCRIPT: "test:amd" BROWSERS: "ChromeHeadless" - NAME: "Browser tests: full build, Firefox ESR" - NODE_VERSION: "16.x" + NODE_VERSION: "18.x" NPM_SCRIPT: "test:browser" BROWSERS: "FirefoxHeadless" steps: @@ -71,6 +71,10 @@ jobs: run: | npm install + - name: Install Playwright dependencies + run: npx playwright-webkit install-deps + if: "matrix.NPM_SCRIPT == 'test:browser'" + - name: Run tests env: BROWSERS: ${{ matrix.BROWSERS }} diff --git a/Gruntfile.js b/Gruntfile.js index 3a56cb4e4..f24e8a448 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -2,8 +2,8 @@ module.exports = function( grunt ) { function readOptionalJSON( filepath ) { - var stripJSONComments = require( "strip-json-comments" ), - data = {}; + const stripJSONComments = require( "strip-json-comments" ); + let data = {}; try { data = JSON.parse( stripJSONComments( fs.readFileSync( filepath, { encoding: "utf8" } ) @@ -12,19 +12,23 @@ module.exports = function( grunt ) { return data; } - // Support: Node.js <12 - // Skip running tasks that dropped support for Node.js 10 + const fs = require( "fs" ); + const gzip = require( "gzip-js" ); + const nodeV14OrNewer = !/^v1[0-3]\./.test( process.version ); + const nodeV17OrNewer = !/^v1[0-6]\./.test( process.version ); + const customBrowsers = process.env.BROWSERS && process.env.BROWSERS.split( "," ); + + // Support: Node.js <14 + // Skip running tasks that dropped support for Node.js 10 or 12 // in this Node version. function runIfNewNode( task ) { - return oldNode ? "print_old_node_message:" + task : task; + return nodeV14OrNewer ? task : "print_old_node_message:" + task; } - var fs = require( "fs" ), - gzip = require( "gzip-js" ), - oldNode = /^v10\./.test( process.version ), - nodeV17OrNewer = !/^v1[0246]\./.test( process.version ), - isCi = process.env.GITHUB_ACTION, - ciBrowsers = process.env.BROWSERS && process.env.BROWSERS.split( "," ); + if ( nodeV14OrNewer ) { + const playwright = require( "playwright-webkit" ); + process.env.WEBKIT_HEADLESS_BIN = playwright.webkit.executablePath(); + } if ( !grunt.option( "filename" ) ) { grunt.option( "filename", "jquery.js" ); @@ -242,10 +246,11 @@ module.exports = function( grunt ) { singleRun: true }, main: { - browsers: isCi && ciBrowsers || [ "ChromeHeadless", "FirefoxHeadless" ] + browsers: customBrowsers || + [ "ChromeHeadless", "FirefoxHeadless", "WebkitHeadless" ] }, esmodules: { - browsers: isCi && ciBrowsers || [ "ChromeHeadless" ], + browsers: customBrowsers || [ "ChromeHeadless" ], options: { client: { qunit: { @@ -260,7 +265,7 @@ module.exports = function( grunt ) { } }, amd: { - browsers: isCi && ciBrowsers || [ "ChromeHeadless" ], + browsers: customBrowsers || [ "ChromeHeadless" ], options: { client: { qunit: { @@ -352,7 +357,7 @@ module.exports = function( grunt ) { // Load grunt tasks from NPM packages require( "load-grunt-tasks" )( grunt, { - pattern: oldNode ? [ "grunt-*", "!grunt-eslint" ] : [ "grunt-*" ] + pattern: nodeV14OrNewer ? [ "grunt-*" ] : [ "grunt-*", "!grunt-eslint" ] } ); // Integrate jQuery specific tasks diff --git a/package.json b/package.json index 3fee5c5eb..3afa4e5f1 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,6 @@ "url": "https://github.com/jquery/jquery/issues" }, "license": "MIT", - "dependencies": {}, "devDependencies": { "@babel/core": "7.10.5", "@babel/plugin-transform-for-of": "7.10.4", @@ -47,15 +46,17 @@ "gzip-js": "0.3.2", "husky": "4.2.5", "jsdom": "19.0.0", - "karma": "^6.3.17", + "karma": "6.4.1", "karma-browserstack-launcher": "1.6.0", "karma-chrome-launcher": "3.1.1", "karma-firefox-launcher": "2.1.2", "karma-ie-launcher": "1.0.0", "karma-jsdom-launcher": "12.0.0", "karma-qunit": "4.1.2", + "karma-webkit-launcher": "2.1.0", "load-grunt-tasks": "5.1.0", "native-promise-only": "0.8.1", + "playwright-webkit": "1.29.2", "promises-aplus-tests": "2.1.2", "q": "1.5.1", "qunit": "2.10.1", diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 18e36489d..166d31de0 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -2270,7 +2270,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re // beforeunload, unload, pagehide, and visibilitychange event handlers. // See https://bugs.chromium.org/p/chromium/issues/detail?id=952452 // Safari 13 did similar changes. The below check will catch them both. - if ( !/safari/i.test( navigator.userAgent ) ) { + if ( !/webkit/i.test( navigator.userAgent ) ) { testIframe( "trac-14379 - jQuery.ajax() on unload", "ajax/onunload.html", diff --git a/test/unit/css.js b/test/unit/css.js index a7a501df1..e4a11175f 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -1757,7 +1757,7 @@ QUnit.testUnlessIE( "css(--customProperty)", function( assert ) { var div = jQuery( "
" ).appendTo( "#qunit-fixture" ), $elem = jQuery( "
" ).addClass( "test__customProperties" ) .appendTo( "#qunit-fixture" ), - webkitOrBlink = /\bsafari\b/i.test( navigator.userAgent ), + webkitOrBlink = /\webkit\b/i.test( navigator.userAgent ), expected = 20; if ( webkitOrBlink ) { diff --git a/test/unit/selector.js b/test/unit/selector.js index d177ab997..649b1e225 100644 --- a/test/unit/selector.js +++ b/test/unit/selector.js @@ -1,7 +1,11 @@ QUnit.module( "selector", { beforeEach: function() { - this.safari = /\bsafari\b/i.test( navigator.userAgent ) && - !/\b(?:headless)?chrome\b/i.test( navigator.userAgent ); + + // Playwright WebKit on macOS doesn't expose `Safari` in its user agent + // string; use the "AppleWebKit" token. This token is also present + // in the Chromium UA, but it is locked to an older version there. + // Modern WebKit (Safari 13+) locks it to `605.1.15`. + this.safari = /\bapplewebkit\/605\.1\.15\b/i.test( navigator.userAgent ); }, afterEach: moduleTeardown } ); diff --git a/test/unit/support.js b/test/unit/support.js index dc50700e8..aa3386ef8 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -70,6 +70,10 @@ testIframe( cssSupportsSelector: false, reliableTrDimensions: true }, + webkit: { + cssSupportsSelector: true, + reliableTrDimensions: true + }, firefox_102: { cssSupportsSelector: false, reliableTrDimensions: false @@ -97,14 +101,26 @@ testIframe( // Catches Edge, Chrome on Android & Opera as well. expected = expectedMap.chrome; - } else if ( /\b\d+(\.\d+)+ safari/i.test( userAgent ) ) { - expected = expectedMap.safari; } else if ( /firefox\/102\./i.test( userAgent ) ) { expected = expectedMap.firefox_102; } else if ( /firefox/i.test( userAgent ) ) { expected = expectedMap.firefox; } else if ( /(?:iphone|ipad);.*(?:iphone)? os \d+_/i.test( userAgent ) ) { expected = expectedMap.ios; + } else if ( typeof URLSearchParams !== "undefined" && + + // `karma-webkit-launcher` adds `test_browser=Playwright` to the query string. + // The normal way of using user agent to detect the browser won't help + // as on macOS Playwright doesn't specify the `Safari` token but on Linux + // it does. + // See https://github.com/google/karma-webkit-launcher#detected-if-safari-or-playwright-is-used + new URLSearchParams( document.referrer || window.location.search ).get( + "test_browser" + ) === "Playwright" + ) { + expected = expectedMap.webkit; + } else if ( /\b\d+(\.\d+)+ safari/i.test( userAgent ) ) { + expected = expectedMap.safari; } QUnit.test( "Verify that support tests resolve as expected per browser", function( assert ) { @@ -134,7 +150,8 @@ testIframe( for ( i in expected ) { assert.equal( computedSupport[ i ], expected[ i ], "jQuery.support['" + i + "']: " + computedSupport[ i ] + - ", expected['" + i + "']: " + expected[ i ] ); + ", expected['" + i + "']: " + expected[ i ] + + ";\nUser Agent: " + navigator.userAgent ); } } );