diff --git a/lib/checks/mobile/css-orientation-lock-evaluate.js b/lib/checks/mobile/css-orientation-lock-evaluate.js index bb42f0a3ef..798235cacb 100644 --- a/lib/checks/mobile/css-orientation-lock-evaluate.js +++ b/lib/checks/mobile/css-orientation-lock-evaluate.js @@ -103,22 +103,15 @@ function cssOrientationLockEvaluate(node, options, virtualNode, context) { const transformStyle = style.transform || style.webkitTransform || style.msTransform || false; - if (!transformStyle) { + if (!transformStyle && !style.rotate) { return false; } - /** - * get last match/occurrence of a transformation function that can affect rotation along Z axis - */ - const matches = transformStyle.match( - /(rotate|rotateZ|rotate3d|matrix|matrix3d)\(([^)]+)\)(?!.*(rotate|rotateZ|rotate3d|matrix|matrix3d))/ - ); - if (!matches) { - return false; - } + const transformDegrees = getTransformDegrees(transformStyle); + const rotateDegrees = getRotationInDegrees('rotate', style.rotate); - const [, transformFn, transformFnValue] = matches; - let degrees = getRotationInDegrees(transformFn, transformFnValue); + // `transform: rotate` and `rotate` are additive + let degrees = transformDegrees + rotateDegrees; if (!degrees) { return false; } @@ -134,6 +127,30 @@ function cssOrientationLockEvaluate(node, options, virtualNode, context) { return Math.abs(degrees - 90) % 90 <= degreeThreshold; } + /** + * Get the degree value of a transform. + * @property {Object} cssRule.style style + * @return {Number} + */ + function getTransformDegrees(transformStyle) { + if (!transformStyle) { + return 0; + } + + /** + * get last match/occurrence of a transformation function that can affect rotation along Z axis + */ + const matches = transformStyle.match( + /(rotate|rotateZ|rotate3d|matrix|matrix3d)\(([^)]+)\)(?!.*(rotate|rotateZ|rotate3d|matrix|matrix3d))/ + ); + if (!matches) { + return 0; + } + + const [, transformFn, transformFnValue] = matches; + return getRotationInDegrees(transformFn, transformFnValue); + } + /** * Interpolate rotation along the z axis from a given value to a transform function * @param {String} transformFunction CSS transformation function @@ -158,7 +175,7 @@ function cssOrientationLockEvaluate(node, options, virtualNode, context) { case 'matrix3d': return getAngleInDegreesFromMatrixTransform(transformFnValue); default: - return; + return 0; } } @@ -170,7 +187,7 @@ function cssOrientationLockEvaluate(node, options, virtualNode, context) { function getAngleInDegrees(angleWithUnit) { const [unit] = angleWithUnit.match(/(deg|grad|rad|turn)/) || []; if (!unit) { - return; + return 0; } const angle = parseFloat(angleWithUnit.replace(unit, ``)); diff --git a/package-lock.json b/package-lock.json index 207751b012..b88e97febb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "browser-driver-manager": "1.0.4", "chai": "^4.3.7", "chalk": "^4.x", - "chromedriver": "latest", + "chromedriver": "^111.0.0", "clone": "^2.1.2", "conventional-commits-parser": "^3.2.4", "core-js": "^3.27.1", @@ -74,7 +74,7 @@ "typedarray": "^0.0.7", "typescript": "^4.9.4", "uglify-js": "^3.17.4", - "wcag-act-rules": "github:w3c/wcag-act-rules#9416ea6", + "wcag-act-rules": "github:w3c/wcag-act-rules#2341a1b", "weakmap-polyfill": "^2.0.4" }, "engines": { @@ -2578,9 +2578,9 @@ } }, "node_modules/axios": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz", - "integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz", + "integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==", "dev": true, "dependencies": { "follow-redirects": "^1.15.0", @@ -3057,14 +3057,14 @@ } }, "node_modules/chromedriver": { - "version": "107.0.3", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-107.0.3.tgz", - "integrity": "sha512-jmzpZgctCRnhYAn0l/NIjP4vYN3L8GFVbterTrRr2Ly3W5rFMb9H8EKGuM5JCViPKSit8FbE718kZTEt3Yvffg==", + "version": "111.0.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-111.0.0.tgz", + "integrity": "sha512-XavNYNBBfKIrT8Oi/ywJ0DoOOU+jHF5bQWTkqStFsAXvfCV9VzYN3J+TGAvZdrpXeoixqPRGUxQ2yZhD2iowdQ==", "dev": true, "hasInstallScript": true, "dependencies": { "@testim/chrome-version": "^1.1.3", - "axios": "^1.1.3", + "axios": "^1.2.1", "compare-versions": "^5.0.1", "extract-zip": "^2.0.1", "https-proxy-agent": "^5.0.1", @@ -11614,7 +11614,7 @@ } }, "node_modules/wcag-act-rules": { - "resolved": "git+ssh://git@github.com/w3c/wcag-act-rules.git#9416ea60714ed6c916435c7b38db76062f3ef004", + "resolved": "git+ssh://git@github.com/w3c/wcag-act-rules.git#2341a1ba4d47bc4cdccd5a3b7534e67b52c59002", "dev": true }, "node_modules/weakmap-polyfill": { @@ -13909,9 +13909,9 @@ "dev": true }, "axios": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz", - "integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz", + "integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==", "dev": true, "requires": { "follow-redirects": "^1.15.0", @@ -14273,13 +14273,13 @@ } }, "chromedriver": { - "version": "107.0.3", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-107.0.3.tgz", - "integrity": "sha512-jmzpZgctCRnhYAn0l/NIjP4vYN3L8GFVbterTrRr2Ly3W5rFMb9H8EKGuM5JCViPKSit8FbE718kZTEt3Yvffg==", + "version": "111.0.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-111.0.0.tgz", + "integrity": "sha512-XavNYNBBfKIrT8Oi/ywJ0DoOOU+jHF5bQWTkqStFsAXvfCV9VzYN3J+TGAvZdrpXeoixqPRGUxQ2yZhD2iowdQ==", "dev": true, "requires": { "@testim/chrome-version": "^1.1.3", - "axios": "^1.1.3", + "axios": "^1.2.1", "compare-versions": "^5.0.1", "extract-zip": "^2.0.1", "https-proxy-agent": "^5.0.1", @@ -20786,9 +20786,9 @@ } }, "wcag-act-rules": { - "version": "git+ssh://git@github.com/w3c/wcag-act-rules.git#9416ea60714ed6c916435c7b38db76062f3ef004", + "version": "git+ssh://git@github.com/w3c/wcag-act-rules.git#2341a1ba4d47bc4cdccd5a3b7534e67b52c59002", "dev": true, - "from": "wcag-act-rules@github:w3c/wcag-act-rules#9416ea6" + "from": "wcag-act-rules@github:w3c/wcag-act-rules#2341a1b" }, "weakmap-polyfill": { "version": "2.0.4", diff --git a/package.json b/package.json index 90c880714b..cd7120892a 100644 --- a/package.json +++ b/package.json @@ -174,7 +174,7 @@ "typedarray": "^0.0.7", "typescript": "^4.9.4", "uglify-js": "^3.17.4", - "wcag-act-rules": "github:w3c/wcag-act-rules#9416ea6", + "wcag-act-rules": "github:w3c/wcag-act-rules#2341a1b", "weakmap-polyfill": "^2.0.4" }, "lint-staged": { diff --git a/test/checks/mobile/css-orientation-lock.js b/test/checks/mobile/css-orientation-lock.js index 46aa3ba71e..62175eccc2 100644 --- a/test/checks/mobile/css-orientation-lock.js +++ b/test/checks/mobile/css-orientation-lock.js @@ -302,6 +302,51 @@ describe('css-orientation-lock tests', function () { assert.isFalse(actual); }); + it('returns false when CSSOM has Orientation CSS media features with rotate property', function () { + var actual = check.evaluate.call(checkContext, document, {}, undefined, { + cssom: [ + { + shadowId: 'a', + root: document, + sheet: getSheet( + '@media screen and (min-width: 1px) and (max-width: 3000px) and (orientation: landscape) { body { rotate: 90deg; } }' + ) + } + ] + }); + assert.isFalse(actual); + }); + + it('returns false when CSSOM has Orientation CSS media features with rotate property matrix', function () { + var actual = check.evaluate.call(checkContext, document, {}, undefined, { + cssom: [ + { + shadowId: 'a', + root: document, + sheet: getSheet( + '@media screen and (min-width: 1px) and (max-width: 3000px) and (orientation: landscape) { body { rotate: 0 0 1 1.5708rad; } }' + ) + } + ] + }); + assert.isFalse(actual); + }); + + it('returns false when CSSOM has Orientation CSS media features with transform: rotate and rotate property', function () { + var actual = check.evaluate.call(checkContext, document, {}, undefined, { + cssom: [ + { + shadowId: 'a', + root: document, + sheet: getSheet( + '@media screen and (min-width: 1px) and (max-width: 3000px) and (orientation: landscape) { body { rotate: 45deg; transform: rotate(45deg); -webkit-transform: rotate(45deg); } }' + ) + } + ] + }); + assert.isFalse(actual); + }); + // Note: // external stylesheets is tested in integration tests // shadow DOM is tested in integration tests diff --git a/test/integration/full/css-orientation-lock/violations.css b/test/integration/full/css-orientation-lock/violations.css index e5702b6deb..ebed686f25 100644 --- a/test/integration/full/css-orientation-lock/violations.css +++ b/test/integration/full/css-orientation-lock/violations.css @@ -2,6 +2,9 @@ .thatDiv { transform: rotate(90deg); } + .rotateDiv { + rotate: 90deg; + } } @media screen and (min-width: 10px) and (max-width: 3000px) and (orientation: landscape) { @@ -11,4 +14,7 @@ .someDiv { transform: matrix3d(0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + .rotateMatrix { + rotate: 0 0 1 1.5708rad; + } } diff --git a/test/integration/full/css-orientation-lock/violations.html b/test/integration/full/css-orientation-lock/violations.html index b80196b5fa..4359e17058 100644 --- a/test/integration/full/css-orientation-lock/violations.html +++ b/test/integration/full/css-orientation-lock/violations.html @@ -23,6 +23,8 @@
some div content
that div content
+
that div content
+
that div content
diff --git a/test/integration/full/css-orientation-lock/violations.js b/test/integration/full/css-orientation-lock/violations.js index d32c84c335..ff38cfd788 100644 --- a/test/integration/full/css-orientation-lock/violations.js +++ b/test/integration/full/css-orientation-lock/violations.js @@ -41,26 +41,32 @@ describe('css-orientation-lock violations test', function () { } }, function (err, res) { - assert.isNull(err); - assert.isDefined(res); + try { + assert.isNull(err); + assert.isDefined(res); - // check for violation - assert.property(res, 'violations'); - assert.lengthOf(res.violations, 1); + // check for violation + assert.property(res, 'violations'); + assert.lengthOf(res.violations, 1); - // assert the node - var checkedNode = res.violations[0].nodes[0]; - assert.isTrue(/html/i.test(checkedNode.html)); + // assert the node + var checkedNode = res.violations[0].nodes[0]; + assert.isTrue(/html/i.test(checkedNode.html)); - // assert the relatedNodes - var checkResult = checkedNode.all[0]; - assert.lengthOf(checkResult.relatedNodes, 2); - assertViolatedSelectors(checkResult.relatedNodes, [ - '.someDiv', - '.thatDiv' - ]); + // assert the relatedNodes + var checkResult = checkedNode.all[0]; + assert.lengthOf(checkResult.relatedNodes, 4); + assertViolatedSelectors(checkResult.relatedNodes, [ + '.someDiv', + '.thatDiv', + '.rotateDiv', + '.rotateMatrix' + ]); - done(); + done(); + } catch (err) { + done(err); + } } ); }); @@ -83,27 +89,33 @@ describe('css-orientation-lock violations test', function () { } }, function (err, res) { - assert.isNull(err); - assert.isDefined(res); + try { + assert.isNull(err); + assert.isDefined(res); - // check for violation - assert.property(res, 'violations'); - assert.lengthOf(res.violations, 1); + // check for violation + assert.property(res, 'violations'); + assert.lengthOf(res.violations, 1); - // assert the node - var checkedNode = res.violations[0].nodes[0]; - assert.isTrue(/html/i.test(checkedNode.html)); + // assert the node + var checkedNode = res.violations[0].nodes[0]; + assert.isTrue(/html/i.test(checkedNode.html)); - // assert the relatedNodes - var checkResult = checkedNode.all[0]; - assert.lengthOf(checkResult.relatedNodes, 3); - assertViolatedSelectors(checkResult.relatedNodes, [ - '.someDiv', - '.thatDiv', - '.shadowDiv' - ]); + // assert the relatedNodes + var checkResult = checkedNode.all[0]; + assert.lengthOf(checkResult.relatedNodes, 5); + assertViolatedSelectors(checkResult.relatedNodes, [ + '.someDiv', + '.thatDiv', + '.rotateDiv', + '.rotateMatrix', + '.shadowDiv' + ]); - done(); + done(); + } catch (err) { + done(err); + } } ); }