diff --git a/package-lock.json b/package-lock.json index c8ade355b5..3202d16151 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "browser-driver-manager": "1.0.4", "chai": "~4.3.6", "chalk": "^4.x", - "chromedriver": "latest", + "chromedriver": "^105.0.1", "clone": "^2.1.2", "conventional-commits-parser": "^3.2.4", "core-js": "^3.23.5", @@ -66,6 +66,7 @@ "proxyquire": "^2.1.3", "revalidator": "~0.3.1", "selenium-webdriver": "^4.5.0", + "serve-handler": "^6.1.3", "sinon": "^11.1.2", "sri-toolbox": "^0.2.0", "standard-version": "^9.5.0", @@ -3305,6 +3306,15 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -5382,6 +5392,21 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "dev": true, + "dependencies": { + "punycode": "^1.3.2" + } + }, + "node_modules/fast-url-parser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + }, "node_modules/fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -9470,6 +9495,12 @@ "node": ">=0.10.0" } }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -10462,6 +10493,79 @@ "randombytes": "^2.1.0" } }, + "node_modules/serve-handler": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", + "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==", + "dev": true, + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.0.4", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-handler/node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-handler/node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-handler/node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/serve-handler/node_modules/path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==", + "dev": true + }, + "node_modules/serve-handler/node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -14510,6 +14614,12 @@ } } }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "dev": true + }, "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -16000,6 +16110,23 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "dev": true, + "requires": { + "punycode": "^1.3.2" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + } + } + }, "fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -19060,6 +19187,12 @@ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -19815,6 +19948,66 @@ "randombytes": "^2.1.0" } }, + "serve-handler": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", + "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.0.4", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "requires": { + "mime-db": "~1.33.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==", + "dev": true + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "dev": true + } + } + }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", diff --git a/package.json b/package.json index 6a8d76baab..32ebfde2c8 100644 --- a/package.json +++ b/package.json @@ -84,15 +84,13 @@ "test:unit:virtual-rules": "npm run test:unit -- testDirs=virtual-rules", "integration": "node test/integration/full/test-webdriver.js", "integration:apg": "mocha test/aria-practices/*.spec.js", - "integration:act": "mocha test/act-rules/*.spec.js", "integration:chrome": "npm run integration -- browser=Chrome", "integration:firefox": "npm run integration -- browser=Firefox", "test:integration": "npm run test:integration:chrome", "test:integration:chrome": "start-server-and-test 9876 integration:chrome", "test:integration:firefox": "start-server-and-test 9876 integration:firefox", "test:examples": "node ./doc/examples/test-examples", - "test:act": "start-server-and-test 9876 integration:act", - "test:act:debug": "npm run test:act -- --no-single-run --browsers=Chrome", + "test:act": "mocha test/act-rules/*.spec.js", "test:apg": "start-server-and-test 9876 integration:apg", "test:locales": "mocha test/test-locales.js", "test:virtual-rules": "mocha test/test-virtual-rules.js", @@ -168,6 +166,7 @@ "proxyquire": "^2.1.3", "revalidator": "~0.3.1", "selenium-webdriver": "^4.5.0", + "serve-handler": "^6.1.3", "sinon": "^11.1.2", "sri-toolbox": "^0.2.0", "standard-version": "^9.5.0", diff --git a/test/act-mapping/valid-lang.json b/test/act-mapping/valid-lang.json deleted file mode 100644 index f11a1956e6..0000000000 --- a/test/act-mapping/valid-lang.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "de46e4", - "title": "Element with lang attribute has valid language tag", - "axeRules": ["valid-lang"] -} diff --git a/test/act-rules/README.md b/test/act-rules/README.md index be0cc19c83..eb4b2a32fb 100644 --- a/test/act-rules/README.md +++ b/test/act-rules/README.md @@ -2,4 +2,4 @@ Each ACT rule that axe-core is consistent with has a test file in this directory named [after the ACT rule](https://github.com/act-rules/act-rules.github.io/tree/develop/_rules). These tests use the `act-runner.js` script, which loads the test cases from `node_modules/wcag-act-rules`. The ACT runner accepts a `id` and `title` from the ACT rule, and an array of `axeRules` that map to this ACT rule. -To run all tests, use `npm run test:act`. This starts both the local server, and the test runner. To test individual files, you'll need to run the local server in a separate process (`npm start`), and call `npm run integration:act`. This can use the mocha `--grep` flag to filter. For example: `npm run integration:act --grep="afw4f7"`. +To run all tests, use `npm run test:act`. To test individual files, you can use Mocha's --grep argument: `npm run test:act -- --grep=afw4f7`. diff --git a/test/act-rules/act-runner.js b/test/act-rules/act-runner.js index 5a0168edb4..3da9e18507 100644 --- a/test/act-rules/act-runner.js +++ b/test/act-rules/act-runner.js @@ -1,5 +1,7 @@ const path = require('path'); const fs = require('fs'); +const http = require('http'); +const handler = require('serve-handler'); const chromedriver = require('chromedriver'); const AxeBuilder = require('@axe-core/webdriverjs'); const { @@ -8,7 +10,8 @@ const { } = require('../aria-practices/run-server'); const { assert } = require('chai'); -const port = 9515; +const driverPort = 9515; +const serverPort = 9898; const axePath = require.resolve('../../axe.js'); const axeSource = fs.readFileSync(axePath, 'utf8'); const actPath = path.resolve(__dirname, '../../node_modules/wcag-act-rules/'); @@ -16,34 +19,55 @@ const testCaseJsonPath = path.resolve( actPath, './content-assets/wcag-act-rules/testcases.json' ); -const addr = `http://localhost:9876/node_modules/wcag-act-rules/content-assets/wcag-act-rules/`; + +const addr = `http://localhost:${serverPort}/WAI/content-assets/wcag-act-rules/`; const testCaseJson = require(testCaseJsonPath); module.exports = ({ id, title, axeRules }) => { describe(`${title} (${id})`, function () { + let driver, server; const testcases = testCaseJson.testcases.filter( ({ ruleId }) => ruleId === id ); + this.timeout(50000); this.retries(3); - let driver; before(async () => { - chromedriver.start([`--port=${port}`]); + chromedriver.start([`--port=${driverPort}`]); await new Promise(r => setTimeout(r, 500)); - await connectToChromeDriver(port); + await connectToChromeDriver(driverPort); driver = getWebdriver(); }); + before(done => { + server = http.createServer((request, response) => { + return handler(request, response, { + cleanUrls: false, + rewrites: [ + { + source: + '/WAI/content-assets/wcag-act-rules/:dir?/:subDir?/:file?', + destination: + '/node_modules/wcag-act-rules/content-assets/wcag-act-rules/:dir?/:subDir?/:file?' + } + ] + }); + }); + server.listen(serverPort, done); + }); + after(async () => { await driver.close(); chromedriver.stop(); + await new Promise(r => server.close(r)); }); testcases.forEach(testcase => { const shouldRun = testcase.relativePath.match(/\.(xhtml|html?)$/); (shouldRun ? it : xit)(testcase.testcaseTitle, async () => { await driver.get(`${addr}/${testcase.relativePath}`); + const builder = new AxeBuilder(driver, axeSource); builder.withRules(axeRules); const results = await builder.analyze(); diff --git a/test/act-rules/element-lang-valid-de46e4.spec.js b/test/act-rules/element-lang-valid-de46e4.spec.js new file mode 100644 index 0000000000..9cc15e9c68 --- /dev/null +++ b/test/act-rules/element-lang-valid-de46e4.spec.js @@ -0,0 +1,5 @@ +require('./act-runner.js')({ + id: 'de46e4', + title: 'Element with lang attribute has valid language tag', + axeRules: ['valid-lang'] +}); diff --git a/test/act-rules/object-has-acessible-name-8fc3b6.spec.js b/test/act-rules/object-has-acessible-name-8fc3b6.spec.js new file mode 100644 index 0000000000..7a3b9c9297 --- /dev/null +++ b/test/act-rules/object-has-acessible-name-8fc3b6.spec.js @@ -0,0 +1,6 @@ +require('./act-runner.js')({ + id: '8fc3b6', + title: + 'Object element rendering non-text content has non-empty accessible name', + axeRules: ['object-alt'] +});