diff --git a/package-lock.json b/package-lock.json index 20ff52745..22e95a5a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "cross-var": "^1.1.0", "csv-parser": "^3.0.0", + "csv-writer": "^1.6.0", "fs-extra": "^11.1.0", "json-beautify": "^1.1.1", "minimist": "^1.2.8", @@ -1501,6 +1502,11 @@ "node": ">= 10" } }, + "node_modules/csv-writer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/csv-writer/-/csv-writer-1.6.0.tgz", + "integrity": "sha512-NOx7YDFWEsM/fTRAJjRpPp8t+MKRVvniAg9wQlUKx20MFrPs73WLJhFf5iteqrxNYnsy924K3Iroh3yNHeYd2g==" + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -6006,6 +6012,11 @@ "minimist": "^1.2.0" } }, + "csv-writer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/csv-writer/-/csv-writer-1.6.0.tgz", + "integrity": "sha512-NOx7YDFWEsM/fTRAJjRpPp8t+MKRVvniAg9wQlUKx20MFrPs73WLJhFf5iteqrxNYnsy924K3Iroh3yNHeYd2g==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", diff --git a/package.json b/package.json index d99ee89d5..3f41e5e66 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,13 @@ "create-all-tests": "cross-var node scripts/create-all-tests.js --testplan=$npm_config_testplan", "review-tests": "cross-var node --experimental-modules scripts/test-reviewer.mjs --testplan=$npm_config_testplan", "update-reference": "node scripts/update-reference.js", + "make-v2": "node scripts/v2maker.js", "prepare": "husky install" }, "dependencies": { "cross-var": "^1.1.0", "csv-parser": "^3.0.0", + "csv-writer": "^1.6.0", "fs-extra": "^11.1.0", "json-beautify": "^1.1.1", "minimist": "^1.2.8", diff --git a/scripts/v2maker.js b/scripts/v2maker.js new file mode 100644 index 000000000..c7a91505f --- /dev/null +++ b/scripts/v2maker.js @@ -0,0 +1,595 @@ +const fs = require('fs'); +const path = require('path'); +const csv = require('csv-parser'); +const createCsvWriter = require('csv-writer').createObjectCsvWriter; +const util = require(path.join(__dirname, 'v2makerUtil.js')); +const v2json = require(path.join(__dirname, 'v2maker.json')); + +// inputs +const csvInputFiles = new Map([ + ['v1tests', 'testsV1.csv'], + ['v1commands', 'commands.csv'], + ['v1references', 'referencesV1.csv'], + ['assertionSubstitutions', path.join(__dirname, 'v2substitutionsForAssertionIds.csv')], + ['testSubstitutions', path.join(__dirname, 'v2substitutionsForTestIds.csv')], + ['commandSubstitutions', path.join(__dirname, 'v2substitutionsForCommands.csv')], +]); + +// outputs +let testsFile = 'tests.csv'; +let assertionsFile = 'assertions.csv'; +let jawsCommandsFile = 'jaws-commands.csv'; +let nvdaCommandsFile = 'nvda-commands.csv'; +let voCommandsFile = 'voiceover_macos-commands.csv'; +let scriptsFile = 'scripts.csv'; +let referencesFile = 'references.csv'; + +const args = require('minimist')(process.argv.slice(2), { + alias: { + h: 'help', + }, +}); + +if (args.help) { + console.log(` + v2maker requires one argument: the name of the test plan directory. + The data subdirectory of the test plan directory must contain: + test.csv + commands.csv + references.csv + + If backup copies of the original V1 format tests.csv and references.csv have not been created by a prior run, the tests.csv and references.csv will be copied to testsV1.csv and referencesV1.csv before their content is replaced with the new V2 formatted content. + + Arguments: + -h, --help + Show this message. + `); + process.exit(); +} + +if (args._.length !== 1) { + console.log( + `Name of a test plan directory that is a subdirectory of the 'tests' directory is required.` + ); + process.exit(); +} + +main(); + +async function main() { + try { + const testPlan = args._[0]; + testDataPath = path.join(__dirname, '..', 'tests', testPlan, 'data'); + await util.startLoggingTo(path.join(testDataPath, 'log.txt'), 'both'); + await setupFilePaths(testDataPath); + const csvData = await readCsvFiles(); + let assertionRows = await makeAssertionsCsvData(csvData); + const v1ToV2testIdMap = await makeTestsCsvData(csvData, assertionRows); + await makeCommandsCsvData(csvData, v1ToV2testIdMap); + await makeScriptsCsvData(csvData); + await makeReferencesCsvData(csvData); + await util.logMessage(`\nFinished conversion at ${new Date().toISOString()}`); + } catch (error) { + console.error('Error!', error); + } +} + +async function setupFilePaths(testDataPath) { + // Set absolute file paths for all inputs and outputs. + // Also, if the v1 tests and references files have not been copied to preserve their content, perform the copy operation. + + // Configure file paths for the files that are in the test plan data directory. + // inputs + csvInputFiles.set('v1tests', path.join(testDataPath, csvInputFiles.get('v1tests'))); + csvInputFiles.set('v1commands', path.join(testDataPath, csvInputFiles.get('v1commands'))); + csvInputFiles.set('v1references', path.join(testDataPath, csvInputFiles.get('v1references'))); + + // outputs + testsFile = path.join(testDataPath, testsFile); + assertionsFile = path.join(testDataPath, assertionsFile); + jawsCommandsFile = path.join(testDataPath, jawsCommandsFile); + nvdaCommandsFile = path.join(testDataPath, nvdaCommandsFile); + voCommandsFile = path.join(testDataPath, voCommandsFile); + scriptsFile = path.join(testDataPath, scriptsFile); + referencesFile = path.join(testDataPath, referencesFile); + + // If the tests and references files have not yet been copied to testsV1.csv and referencesV1.csv, copy them. + // The content of the original v1 files will be overwritten with the new v2 content when making the v2 conversion. + if (!fs.existsSync(csvInputFiles.get('v1tests'))) { + try { + await fs.promises.copyFile(testsFile, csvInputFiles.get('v1tests')); + const logMsg = `Copied ${path.basename(testsFile)} to ${path.basename( + csvInputFiles.get('v1tests') + )}`; + await util.logMessage(logMsg); + } catch (copyErr) { + throw new Error(`Error copying ${testsFile} to ${csvInputFiles.get('v1tests')}: ${copyErr}`); + } + } + if (!fs.existsSync(csvInputFiles.get('v1references'))) { + try { + await fs.promises.copyFile(referencesFile, csvInputFiles.get('v1references')); + const logMsg = `Copied ${path.basename(referencesFile)} to ${path.basename( + csvInputFiles.get('v1references') + )}`; + await util.logMessage(logMsg); + } catch (copyErr) { + throw new Error( + `Error copying ${referencesFile} to ${csvInputFiles('v1references')}: ${copyErr}` + ); + } + } +} + +async function readCsvFiles() { + const csvData = {}; + const filePromises = Array.from(csvInputFiles.entries()).map( + async ([fileDescriptor, fileName]) => { + const stream = fs.createReadStream(fileName, 'utf8'); + const rows = []; + return new Promise((resolve, reject) => { + stream + .pipe(csv()) + .on('data', row => { + rows.push(row); + }) + .on('end', () => { + csvData[fileDescriptor] = rows; + resolve(); + }) + .on('error', error => { + reject(error); + }); + }); + } + ); + + await Promise.all(filePromises); + return csvData; +} + +async function makeAssertionsCsvData(allInputCsvData) { + await util.logMessage(`\nCreating ${path.basename(assertionsFile)}`); + + // pull data from the assertion1 through assertionN columns of the v1tests array in allInputCsvData. + let assertions = []; + for (const row of allInputCsvData.v1tests) { + // properties in the row objects match columns in the input file: + // testId,title,appliesTo,mode,task,setupScript,setupScriptDescription,refs,instructions,assertion1,assertion2,assertion3,assertion4,assertion5,assertion6,assertion7 + const colNames = Object.keys(row); + for (const colName of colNames) { + if (colName.startsWith('assertion')) { + if (row[colName].trim() !== '') { + assertions.push(row[colName]); + } + } + } + } + + // Separate p1 and p2 assertions. + let p1assertions = assertions.filter(assertion => !assertion.includes('2:')); + let p2assertions = assertions.filter(assertion => assertion.includes('2:')); + // Remove the prefixes from the p2 assertions. + p2assertions = p2assertions.map(assertion => assertion.replace('2:', '')); + // Get rid of duplicates. + p1assertions = [...new Set(p1assertions)]; + p2assertions = [...new Set(p2assertions)]; + // Remove p1 assertions that are the same as a p2 assertion. + for (const p2assertion of p2assertions) { + if (p1assertions.includes(p2assertion)) { + await util.logMessage( + `P1 and P2 priorities found for assertion '${p2assertion}. Keeping only the P2 priority.` + ); + p1assertions = p1assertions.filter(p1assertion => p1assertion !== p2assertion); + } + } + + // to make assertionIds, we need the substitutions and deletions data. + const { deletions, substitutions } = util.getSubstitutionsAndDeletions( + 'assertionSubstitutions', + allInputCsvData, + 'oldWords', + 'newWords' + ); + + // Start making rows for the output CSV file. + let assertionRows = []; + for (const assertion of p1assertions) { + let newRow = {}; + newRow.assertionId = util.makeId(util.trimQuotes(assertion), substitutions, deletions); + newRow.priority = '1'; + newRow.assertionStatement = util.sentenceCase(assertion); + const phrase = assertion.replace( + /("?)(\w)((?:.*?),?(?:.*?))((?:,\s+is|\s+is)\s+conveyed)("?)/g, + '$1Convey $2$3$5' + ); + newRow.assertionPhrase = util.phraseCase(phrase); + newRow.refIds = ''; + assertionRows.push(newRow); + } + for (const assertion of p2assertions) { + let newRow = {}; + newRow.assertionId = util.makeId(util.trimQuotes(assertion), substitutions, deletions); + newRow.priority = '2'; + newRow.assertionStatement = util.sentenceCase(assertion); + const phrase = assertion.replace( + /("?)(\w)((?:.*?),?(?:.*?))((?:,\s+is|\s+is)\s+conveyed)("?)/g, + '$1Convey $2$3$5' + ); + newRow.assertionPhrase = util.phraseCase(phrase); + newRow.refIds = ''; + assertionRows.push(newRow); + } + + // Sort rows by assertionId ascending + assertionRows.sort((a, b) => { + const valueA = a.assertionId; + const valueB = b.assertionId; + if (valueA < valueB) { + return -1; + } + if (valueA > valueB) { + return 1; + } + return 0; + }); + + // Write rows to CSV file + const rowWriter = createCsvWriter({ + path: assertionsFile, + header: Object.keys(assertionRows[0]).map(column => ({ id: column, title: column })), + }); + await rowWriter.writeRecords(assertionRows); + await util.logMessage( + `Wrote ${assertionRows.length} assertion statements to ${path.basename(assertionsFile)}` + ); + + return assertionRows; +} + +async function makeTestsCsvData(allInputCsvData, assertionRows) { + await util.logMessage(`\nCreating ${path.basename(testsFile)}.`); + + // to make testIds, we will need the substitutions and deletions data. + const { deletions, substitutions } = util.getSubstitutionsAndDeletions( + 'testSubstitutions', + allInputCsvData, + 'oldWords', + 'newWords' + ); + + // To convert assertions to assertionIds, we will need a map of assertionStatements to assertionIds. So comparisons can be case insensitive, we'll lowercase the keys. + const assertionStatementsToIds = new Map(); + for (row of assertionRows) { + assertionStatementsToIds.set(row.assertionStatement.toLowerCase(), row.assertionId); + } + + // pull the data for the rows of the new tests file from the columns of the v1tests array in allInputCsvData. + let v2testRows = []; + for (const row of allInputCsvData.v1tests) { + // properties in the row objects match columns in the input file: + // testId,title,appliesTo,mode,task,setupScript,setupScriptDescription,refs,instructions,assertion1,assertion2,assertion3,assertion4,assertion5,assertion6,assertion7 + let newRow = {}; + // Add properties to newRow in the order that the columns will appear in the new tests.csv file. + newRow.testId = util.makeId(util.trimQuotes(row.title), substitutions, deletions); + newRow.title = util.sentenceCase( + row.title.replace(/read\s+information\s+about/i, 'Request information about') + ); + newRow.presentationNumber = row.testId; + newRow.setupScript = row.setupScript; + newRow.instructions = row.instructions; + let assertions = ''; + // Loop through the assertion columns, get the assertionId for each, and join them with spaces. + const colNames = Object.keys(row); + for (const colName of colNames) { + if (colName.startsWith('assertion')) { + if (row[colName].trim() !== '') { + // Remove priority prefix if present. + const v1assertion = row[colName].replace('2:', ''); + // get the v2 assertion Id and add it to the assertions string. Do lookups and comparisons using lowercase. Keeping the original case for the log in the event the assertion is not found. + if (assertionStatementsToIds.has(v1assertion.toLowerCase())) { + assertions += ` ${assertionStatementsToIds.get(v1assertion.toLowerCase())}`; + } else + await util.logMessage( + `assertionId not found for '${v1assertion} when processing testId ${row.testId}.` + ); + } + } + } + newRow.assertions = assertions.trim(); + v2testRows.push(newRow); + } + + // Sort rows by presentationNumber ascending + v2testRows.sort((a, b) => { + const valueA = Number(a.presentationNumber); + const valueB = Number(b.presentationNumber); + if (valueA < valueB) { + return -1; + } + if (valueA > valueB) { + return 1; + } + return 0; + }); + + /* + We will be filtering testRows to keep only the rows for the VoiceOver tests. We want to get rid of all the tests that specify reading mode or interaction mode. + However, before removing those obsolete tests, there is some data we need to collect from them: + 1. A map of all the v1 testIds to v2 testIds to use during conversion of commands.csv. + 2. Determine whether there are test tasks where JAWS and NVDA have assertions that are not specified for VoiceOver. + If there are tests where JAWS and NVDA have assertions that are not specified for VoiceOver, we'll log a warning for each task/assertion pair specified for JAWS and NVDA that is not specified for VoiceOver. + + Note: It's better to log a warning than combine all the assertions that appear to be different because they might not actually be different in meaning. + Sometimes there are two different wordings of the same assertion. + */ + // Build a map that specifies which new v2testId to use in place of a v1testId in commands.csv. + const v1ToV2testIds = new Map(); + for (row of v2testRows) { + v1ToV2testIds.set(row.presentationNumber, row.testId); + } + + // Get a set containing all the tasks in the test plan. + const v1tasks = new Set(allInputCsvData.v1tests.map(row => row.task)); + // iterate through the tasks and compare the VoiceOver assertions to the the JAWS and NVDA assertions. + for (const task of v1tasks) { + // Find the v1testId for the VoiceOver test for this task in the v1testRows array. + const voiceOverV1TestId = allInputCsvData.v1tests.find( + row => row.task === task && row.appliesTo.toLowerCase().includes('voiceover') + ).testId; + // Use the v1testId to extract the VoiceOver assertions column for this task from the v2testRows. It contains a space-delimited set of assertionIds. + // Note that the v1testId was stored in the presentationNumber property in v2testRows. + const voiceOverAssertions = v2testRows.find( + row => row.presentationNumber === voiceOverV1TestId + ).assertions; + // Get array of v1testIds for JAWS and NVDA for this task. + const jawsAndNvdaV1testIds = allInputCsvData.v1tests + .filter(row => row.task === task && row.appliesTo.toLowerCase().search(/jaws|nvda/) >= 0) + .map(row => row.testId); + for (const v1testId of jawsAndNvdaV1testIds) { + const jawsAndNvdaAssertions = v2testRows + .find(row => row.presentationNumber === v1testId) + .assertions.split(' '); + let loggedWarnings = ''; + for (const assertion of jawsAndNvdaAssertions) { + if (!voiceOverAssertions.includes(assertion)) { + if (!loggedWarnings.includes(assertion)) { + const v2testId = v2testRows.find(row => row.presentationNumber === v1testId).testId; + const msg = + `Warning! In ${csvInputFiles.get( + 'v1tests' + )}, task ${task} specified assertionId ${assertion} for JAWS and NVDA but not VoiceOver.\n` + + `${assertion} has been left out of ${testsFile} for testId ${v2testId}. Make sure ${assertion} has the same meaning as another assertion that is specified for ${v2testId}.`; + await util.logMessage(msg); + } + } + } + } + } + + // Now filter v2testRows down to just the VoiceOver rows. + // First, get an array of just the voiceOver rows from v1tests. + const v1voiceOverRows = allInputCsvData.v1tests.filter(row => + row.appliesTo.toLowerCase().includes('voiceover') + ); + // Build a set of the v1 testIds for the VoiceOver tests. + const voiceOverV1testIds = new Set(v1voiceOverRows.map(row => row.testId)); + // Filter v2testRows. Note that the presentationNumber property contains the v1testId. + v2testRows = v2testRows.filter(row => voiceOverV1testIds.has(row.presentationNumber)); + + // Write rows to CSV file + const rowWriter = createCsvWriter({ + path: testsFile, + header: Object.keys(v2testRows[0]).map(column => ({ id: column, title: column })), + }); + await rowWriter.writeRecords(v2testRows); + await util.logMessage(`Wrote ${v2testRows.length} tests to ${path.basename(testsFile)}`); + + return v1ToV2testIds; +} + +async function makeCommandsCsvData(allInputCsvData, v1ToV2testIds) { + /* + The V1 columns are: + testId,task,mode,at,commandA,commandB,commandC... + The V2 columns are: + testId,command,settings,assertionExceptions,presentationNumber + */ + + const v1commandRows = allInputCsvData['v1commands']; + const screenReaders = ['jaws', 'nvda', 'voiceover']; + for (const screenReader of screenReaders) { + // set output file + let outputFile = ''; + let readingModeSetting = ''; + let interactionModeSetting = ''; + switch (screenReader) { + case 'jaws': + outputFile = jawsCommandsFile; + readingModeSetting = 'virtualCursor'; + interactionModeSetting = 'pcCursor'; + break; + case 'nvda': + outputFile = nvdaCommandsFile; + readingModeSetting = 'browseMode'; + interactionModeSetting = 'focusMode'; + break; + case 'voiceover': + outputFile = voCommandsFile; + readingModeSetting = 'quickNavOn'; + break; + } + await util.logMessage(`\nCreating ${path.basename(outputFile)}.`); + + // Get the set of v1commandRows for this screenReader. + let screenReaderV1commandRows = v1commandRows.filter(row => + row.at.toLowerCase().includes(screenReader) + ); + let v2commandRows = []; + for (const row of screenReaderV1commandRows) { + // Make an array of the commands from the columns for commandA, commandB, etc. + let commands = []; + const colNames = Object.keys(row); + for (const colName of colNames) { + if (colName.toLowerCase().startsWith('command')) { + if (row[colName].trim() !== '') commands.push(row[colName]); + } + } + + // Make a new row for each command. + for (const [index, command] of commands.entries()) { + let newRow = {}; + newRow.testId = v1ToV2testIds.get(row.testId); + const { commandSequence, commandSettings } = util.translateCommand( + screenReader, + command, + allInputCsvData.commandSubstitutions + ); + newRow.command = commandSequence; + if (commandSettings.trim() !== '') newRow.settings = commandSettings; + else if (row.mode.toLowerCase().includes('reading')) newRow.settings = readingModeSetting; + else if (row.mode.toLowerCase().includes('interaction')) + newRow.settings = interactionModeSetting; + else newRow.settings = ''; + newRow.assertionExceptions = ''; + newRow.presentationNumber = (Number(row.testId) + 0.1 * index).toFixed(1); + v2commandRows.push(newRow); + } + } + + // Write rows to CSV file + const rowWriter = createCsvWriter({ + path: outputFile, + header: Object.keys(v2commandRows[0]).map(column => ({ id: column, title: column })), + }); + await rowWriter.writeRecords(v2commandRows); + await util.logMessage(`Wrote ${v2commandRows.length} commands to ${path.basename(outputFile)}`); + } +} + +async function makeScriptsCsvData(allInputCsvData) { + await util.logMessage(`\nCreating ${path.basename(scriptsFile)}.`); + + // pull data from the setupScript and setupScriptDescription columns of the v1tests array in allInputCsvData. + let scriptRows = []; + for (const row of allInputCsvData.v1tests) { + // properties in the row objects match columns in the input file: + // testId,title,appliesTo,mode,task,setupScript,setupScriptDescription,refs,instructions,assertion1,assertion2,assertion3,assertion4,assertion5,assertion6,assertion7 + let newRow = {}; + newRow.setupScript = row.setupScript; + newRow.setupScriptDescription = row.setupScriptDescription; + scriptRows.push(newRow); + } + + // Get rid of duplicates. + scriptRows = util.removeDuplicateAndBlankRows(scriptRows); + + // Sort rows by script ascending + scriptRows.sort((a, b) => { + const valueA = a.setupScript; + const valueB = b.setupScript; + if (valueA < valueB) { + return -1; + } + if (valueA > valueB) { + return 1; + } + return 0; + }); + + // Write rows to CSV file + const rowWriter = createCsvWriter({ + path: scriptsFile, + header: Object.keys(scriptRows[0]).map(column => ({ id: column, title: column })), + }); + await rowWriter.writeRecords(scriptRows); + await util.logMessage( + `Wrote ${scriptRows.length} script names and descriptions to ${path.basename(scriptsFile)}` + ); +} + +async function makeReferencesCsvData(allInputCsvData) { + await util.logMessage(`\nCreating ${path.basename(referencesFile)}.`); + + // pull data from the refId and value columns of the v1references aray. + let refRows = []; + for (const row of allInputCsvData.v1references) { + // properties in the row objects match columns in the input file: + // refId, value + let newRow = {}; + newRow.refId = row.refId; + if (row.refId.trim().search(/^author$/i) >= 0) { + newRow.type = 'metadata'; + newRow.value = row.value; + newRow.linkText = ''; + } else if (row.refId.trim().search(/^authorEmail$/i) >= 0) { + newRow.type = 'metadata'; + newRow.value = row.value; + newRow.linkText = ''; + } else if (row.refId.trim().search(/^title$/i) >= 0) { + newRow.type = 'metadata'; + newRow.value = row.value; + newRow.linkText = ''; + } else if (row.refId.trim().search(/^reference$/i) >= 0) { + newRow.type = 'metadata'; + newRow.value = row.value; + const planTitle = allInputCsvData.v1references.find( + row => row.refId.trim().search(/^title$/i) >= 0 + ).value; + newRow.linkText = `Test Case Page for ${planTitle}`; + } else if (row.refId.trim().search(/^example$/i) >= 0) { + newRow.type = 'metadata'; + newRow.value = row.value; + newRow.linkText = ''; + // See if we can update value and link text to represent new APG + if (row.value.toLowerCase().includes('github')) { + let newValue = 'New URL is Required'; + const indexOfDotIo = row.value.toLowerCase().indexOf('.io'); + if (indexOfDotIo >= 0) { + const oldUrlPath = row.value.substring(indexOfDotIo + 3); + newRow.value = v2json.oldToNewAPGExamples[oldUrlPath]; + const indexOfSlashApg = newRow.value.indexOf('/apg'); + if (indexOfSlashApg >= 0) { + const newUrlPath = newRow.value.substring(indexOfSlashApg + 4); + newRow.linkText = `APG Example: ${v2json.apgExamples[newUrlPath]}`; + } + } + } + } else if (row.refId.trim().search(/^designPattern$/i) >= 0) { + newRow.type = 'metadata'; + newRow.value = row.value; + newRow.linkText = 'APG Design Pattern'; + // See if we can update value and link text to represent new APG + if (row.value.toLowerCase().includes('github')) { + let newValue = 'New URL is Required'; + const indexOfHash = row.value.toLowerCase().indexOf('#'); + if (indexOfHash >= 0) { + const oldUrlPath = row.value.substring(indexOfHash); + newRow.value = v2json.oldToNewAPGPatterns[oldUrlPath]; + const indexOfSlashApg = newRow.value.indexOf('/apg'); + if (indexOfSlashApg >= 0) { + const newUrlPath = newRow.value.substring(indexOfSlashApg + 4); + newRow.linkText = v2json.apgPatterns[newUrlPath]; + } + } + } + } else if (row.refId.trim().search(/^developmentDocumentation$/i) >= 0) { + newRow.type = 'metadata'; + newRow.value = row.value; + newRow.linkText = `Development Documentation for ${row.title} Test Plan`; + } else { + newRow.type = 'aria'; + newRow.value = row.refId; + newRow.linkText = row.refId; + } + refRows.push(newRow); + } + + // Write rows to CSV file + const rowWriter = createCsvWriter({ + path: referencesFile, + header: Object.keys(refRows[0]).map(column => ({ id: column, title: column })), + }); + await rowWriter.writeRecords(refRows); + await util.logMessage(`Wrote ${refRows.length} references to ${path.basename(referencesFile)}`); +} diff --git a/scripts/v2maker.json b/scripts/v2maker.json new file mode 100644 index 000000000..f23670121 --- /dev/null +++ b/scripts/v2maker.json @@ -0,0 +1,158 @@ +{ + "oldToNewAPGExamples": { + "/aria-practices/examples/alert/alert.html": "https://www.w3.org/WAI/ARIA/apg/patterns/alert/examples/alert/", + "/aria-practices/examples/breadcrumb/index.html": "https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/examples/breadcrumb/", + "/aria-practices/examples/button/button.html": "https://www.w3.org/WAI/ARIA/apg/patterns/button/examples/button/", + "/aria-practices/examples/checkbox/checkbox-1/checkbox-1.html": "https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/examples/checkbox/", + "/aria-practices/examples/checkbox/checkbox-mixed.html": "https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/examples/checkbox-mixed/", + "/aria-practices/examples/combobox/combobox-autocomplete-both.html": "https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-both/", + "/aria-practices/examples/combobox/combobox-select-only.html": "https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-select-only/", + "/aria-practices/examples/dialog-modal/dialog.html": "https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/examples/dialog/", + "/aria-practices/examples/disclosure/disclosure-faq.html": "https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/examples/disclosure-faq/", + "/aria-practices/examples/disclosure/disclosure-navigation.html": "https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/examples/disclosure-navigation/", + "/aria-practices/examples/grid/dataGrids.html": "https://www.w3.org/WAI/ARIA/apg/patterns/grid/examples/data-grids/", + "/aria-practices/examples/landmarks/banner.html": "https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/examples/banner.html", + "/aria-practices/examples/landmarks/complementary.html": "https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/examples/complementary.html", + "/aria-practices/examples/landmarks/contentinfo.html": "https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/examples/contentinfo.html", + "/aria-practices/examples/landmarks/form.html": "https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/examples/form.html", + "/aria-practices/examples/landmarks/main.html": "https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/examples/main.html", + "/aria-practices/examples/link/link.html": "https://www.w3.org/WAI/ARIA/apg/patterns/link/examples/link/", + "/aria-practices/examples/menubar/menubar-editor.html": "https://www.w3.org/WAI/ARIA/apg/patterns/menubar/examples/menubar-editor/", + "/aria-practices/examples/menu-button/menu-button-actions.html": "https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/examples/menu-button-actions/", + "/aria-practices/examples/menu-button/menu-button-actions-active-descendant.html": "https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-descendant/", + "/aria-practices/examples/menu-button/menu-button-links.html": "https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/examples/menu-button-links/", + "/aria-practices/examples/meter/meter.html": "https://www.w3.org/WAI/ARIA/apg/patterns/meter/examples/meter/", + "/aria-practices/examples/radio/radio.html": "https://www.w3.org/WAI/ARIA/apg/patterns/radio/examples/radio/", + "/aria-practices/examples/radio/radio-activedescendant.html": "https://www.w3.org/WAI/ARIA/apg/patterns/radio/examples/radio-activedescendant/", + "/aria-practices/examples/slider/slider-color-viewer.html": "https://www.w3.org/WAI/ARIA/apg/patterns/slider/examples/slider-color-viewer/", + "/aria-practices/examples/slider/slider-rating.html": "https://www.w3.org/WAI/ARIA/apg/patterns/slider/examples/slider-rating/", + "/aria-practices/examples/slider/slider-seek.html": "https://www.w3.org/WAI/ARIA/apg/patterns/slider/examples/slider-seek/", + "/aria-practices/examples/slider/slider-temperature.html": "https://www.w3.org/WAI/ARIA/apg/patterns/slider/examples/slider-temperature/", + "/aria-practices/examples/spinbutton/datepicker-spinbuttons.html": "https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/examples/datepicker-spinbuttons/", + "/aria-practices/examples/switch/switch.html": "https://www.w3.org/WAI/ARIA/apg/patterns/switch/examples/switch/", + "/aria-practices/examples/tabs/tabs-2/tabs.html": "https://www.w3.org/WAI/ARIA/apg/patterns/tabs/examples/tabs-manual/" + }, + "apgExamples": { + "/patterns/accordion/examples/accordion/": "Accordion", + "/patterns/alert/examples/alert/": "Alert", + "/patterns/alertdialog/examples/alertdialog/": "Alert Dialog", + "/patterns/breadcrumb/examples/breadcrumb/": "Breadcrumb", + "/patterns/button/examples/button_idl/": "Button (IDL Version)", + "/patterns/button/examples/button/": "Button", + "/patterns/carousel/examples/carousel-1-prev-next/": "Auto-Rotating Image Carousel with Buttons for Slide Control", + "/patterns/carousel/examples/carousel-2-tablist/": "Auto-Rotating Image Carousel with Tabs for Slide Control", + "/patterns/checkbox/examples/checkbox-mixed/": "Checkbox (Mixed-State)", + "/patterns/checkbox/examples/checkbox/": "Checkbox (Two State)", + "/patterns/combobox/examples/combobox-autocomplete-both/": "Editable Combobox With Both List and Inline Autocomplete", + "/patterns/combobox/examples/combobox-autocomplete-list/": "Editable Combobox With List Autocomplete", + "/patterns/combobox/examples/combobox-autocomplete-none/": "Editable Combobox without Autocomplete", + "/patterns/combobox/examples/combobox-datepicker/": "Date Picker Combobox", + "/patterns/combobox/examples/combobox-select-only/": "Select-Only Combobox", + "/patterns/combobox/examples/grid-combo/": "Editable Combobox with Grid Popup", + "/patterns/dialog-modal/examples/datepicker-dialog/": "Date Picker Dialog", + "/patterns/dialog-modal/examples/dialog/": "Modal Dialog", + "/patterns/disclosure/examples/disclosure-faq/": "Disclosure (Show/Hide) for Answers to Frequently Asked Questions", + "/patterns/disclosure/examples/disclosure-image-description/": "Disclosure (Show/Hide) for Image Description", + "/patterns/disclosure/examples/disclosure-navigation-hybrid/": "Disclosure Navigation Menu with Top-Level Links", + "/patterns/disclosure/examples/disclosure-navigation/": "Disclosure Navigation Menu", + "/patterns/feed/examples/feed/": "Feed", + "/patterns/grid/examples/data-grids/": "Data Grid", + "/patterns/grid/examples/layout-grids/": "Layout Grid", + "/patterns/landmarks/examples/banner.html": "Banner Landmark", + "/patterns/landmarks/examples/complementary.html": "Complementary Landmark", + "/patterns/landmarks/examples/contentinfo.html": "Contentinfo Landmark", + "/patterns/landmarks/examples/form.html": "Form Landmark", + "/patterns/landmarks/examples/main.html": "Main Landmark", + "/patterns/landmarks/examples/navigation.html": "Navigation Landmark", + "/patterns/landmarks/examples/region.html": "Region Landmark", + "/patterns/landmarks/examples/search.html": "Search Landmark", + "/patterns/link/examples/link/": "Link", + "/patterns/listbox/examples/listbox-collapsible/": "(Deprecated) Collapsible Dropdown Listbox", + "/patterns/listbox/examples/listbox-grouped/": "Listbox with Grouped Options", + "/patterns/listbox/examples/listbox-rearrangeable/": "Listboxes with Rearrangeable Options", + "/patterns/listbox/examples/listbox-scrollable/": "Scrollable Listbox", + "/patterns/menu-button/examples/menu-button-actions-active-descendant/": "Actions Menu Button Using aria-activedescendant", + "/patterns/menu-button/examples/menu-button-actions/": "Actions Menu Button Using element.focus()", + "/patterns/menu-button/examples/menu-button-links/": "Navigation Menu Button", + "/patterns/menubar/examples/menubar-editor/": "Editor Menubar", + "/patterns/menubar/examples/menubar-navigation/": "Navigation Menubar", + "/patterns/meter/examples/meter/": "Meter", + "/patterns/radio/examples/radio-activedescendant/": "Radio Group Using aria-activedescendant", + "/patterns/radio/examples/radio-rating/": "Rating Radio Group", + "/patterns/radio/examples/radio/": "Radio Group Using Roving tabindex", + "/patterns/slider-multithumb/examples/slider-multithumb/": "Horizontal Multi-Thumb Slider", + "/patterns/slider/examples/slider-color-viewer/": "Color Viewer Slider", + "/patterns/slider/examples/slider-rating/": "Rating Slider", + "/patterns/slider/examples/slider-seek/": "Media Seek Slider", + "/patterns/slider/examples/slider-temperature/": "Vertical Temperature Slider", + "/patterns/spinbutton/examples/datepicker-spinbuttons/": "Date Picker Spin Button", + "/patterns/switch/examples/switch-button/": "Switch Using HTML Button", + "/patterns/switch/examples/switch-checkbox/": "Switch Using HTML Checkbox Input", + "/patterns/switch/examples/switch/": "Switch", + "/patterns/table/examples/sortable-table/": "Sortable Table", + "/patterns/table/examples/table/": "Table", + "/patterns/tabs/examples/tabs-automatic/": "Tabs with Automatic Activation", + "/patterns/tabs/examples/tabs-manual/": "Tabs with Manual Activation", + "/patterns/toolbar/examples/toolbar/": "Toolbar", + "/patterns/treegrid/examples/treegrid-1/": "Treegrid Email Inbox", + "/patterns/treeview/examples/treeview-1a/": "File Directory Treeview Using Computed Properties", + "/patterns/treeview/examples/treeview-1b/": "File Directory Treeview Using Declared Properties", + "/patterns/treeview/examples/treeview-navigation/": "Navigation Treeview" + }, + "oldToNewAPGPatterns": { + "#alert": "https://www.w3.org/WAI/ARIA/apg/patterns/alert/", + "#aria_lh_banner": "https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/", + "#aria_lh_complementary": "https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/", + "#aria_lh_contentinfo": "https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/", + "#aria_lh_form": "https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/", + "#aria_lh_main": "https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/", + "#breadcrumb": "https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/", + "#button": "https://www.w3.org/WAI/ARIA/apg/patterns/button/", + "#checkbox": "https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/", + "#combobox": "https://www.w3.org/WAI/ARIA/apg/patterns/combobox/", + "#dialog_modal": "https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/", + "#disclosure": "https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/", + "#grid": "https://www.w3.org/WAI/ARIA/apg/patterns/grid/", + "#link": "https://www.w3.org/WAI/ARIA/apg/patterns/link/", + "#menu": "https://www.w3.org/WAI/ARIA/apg/patterns/menubar/", + "#menubutton": "https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/", + "#meter": "https://www.w3.org/WAI/ARIA/apg/patterns/meter/", + "#radiobutton": "https://www.w3.org/WAI/ARIA/apg/patterns/radio/", + "#slider": "https://www.w3.org/WAI/ARIA/apg/patterns/slider/", + "#spinbutton": "https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/", + "#switch": "https://www.w3.org/WAI/ARIA/apg/patterns/switch/", + "#tabpanel": "https://www.w3.org/WAI/ARIA/apg/patterns/tabs/" + }, + "apgPatterns": { + "/patterns/accordion/": "APG Pattern: Accordion (Sections With Show/Hide Functionality)", + "/patterns/alert/": "APG Pattern: Alert", + "/patterns/alertdialog/": "APG Pattern: Alert and Message Dialogs", + "/patterns/breadcrumb/": "APG Pattern: Breadcrumb", + "/patterns/button/": "APG Pattern: Button", + "/patterns/carousel/": "APG Pattern: Carousel (Slide Show or Image Rotator)", + "/patterns/checkbox/": "APG Pattern: Checkbox", + "/patterns/combobox/": "APG Pattern: Combobox", + "/patterns/dialog-modal/": "APG Pattern: Dialog (Modal)", + "/patterns/disclosure/": "APG Pattern: Disclosure (Show/Hide)", + "/patterns/feed/": "APG Pattern: Feed", + "/patterns/grid/": "APG Pattern: Grid (Interactive Tabular Data and Layout Containers)", + "/patterns/landmarks/": "APG Pattern: Landmarks", + "/patterns/link/": "APG Pattern: Link", + "/patterns/listbox/": "APG Pattern: Listbox", + "/patterns/menubar/": "APG Pattern: Menu and Menubar", + "/patterns/menu-button/": "APG Pattern: Menu Button", + "/patterns/meter/": "APG Pattern: Meter", + "/patterns/radio/": "APG Pattern: Radio Group", + "/patterns/slider/": "APG Pattern: Slider", + "/patterns/slider-multithumb/": "APG Pattern: Slider (Multi-Thumb)", + "/patterns/spinbutton/": "APG Pattern: Spinbutton", + "/patterns/switch/": "APG Pattern: Switch", + "/patterns/table/": "APG Pattern: Table", + "/patterns/tabs/": "APG Pattern: Tabs", + "/patterns/toolbar/": "APG Pattern: Toolbar", + "/patterns/tooltip/": "APG Pattern: Tooltip", + "/patterns/treeview/": "APG Pattern: Tree View", + "/patterns/treegrid/": "APG Pattern: Treegrid", + "/patterns/windowsplitter/": "APG Pattern: Window Splitter" + } +} \ No newline at end of file diff --git a/scripts/v2makerUtil.js b/scripts/v2makerUtil.js new file mode 100644 index 000000000..00742de8b --- /dev/null +++ b/scripts/v2makerUtil.js @@ -0,0 +1,271 @@ +const fs = require('fs'); +let logFile = null; +const validLogBehaviors = ['none', 'console', 'file', 'both']; +let logBehavior = 'both'; + +const escapeRegExp = string => { + return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // Escape special characters +}; + +async function deleteFile(filePath) { + if (fs.existsSync(filePath)) { + await fs.unlinkSync(filePath); + } +} + +async function startLoggingTo(name, behavior) { + if (behavior === undefined) logBehavior = 'both'; + if (validLogBehaviors.includes(behavior)) logBehavior = behavior; + else + throw new Error( + `'${behavior}' is not a valid log behavior. Valid behaviors are ${validLogBehaviors}` + ); + if (name === undefined) logFile = './log.txt'; + else logFile = name; + if (logBehavior !== 'none') { + if (logBehavior === 'file' || logBehavior === 'both') await deleteFile(logFile); + const timestamp = new Date().toISOString(); + await logMessage(`Starting format conversion at ${timestamp}`); + } +} + +async function logMessage(message) { + if (logBehavior === 'console' || logBehavior === 'both') console.log(message); + if (logBehavior === 'file' || logBehavior === 'both') { + const logEntry = `${message}\n`; + await fs.appendFile(logFile, logEntry, err => { + if (err) { + throw new Error(`Error writing to ${logFilePath}: ${err}`); + } + }); + } +} + +function setLogBehavior(behavior) { + if (validLogBehaviors.includes(behavior)) logBehavior = behavior; + else + throw new Error( + `'${behavior}' is not a valid log behavior. Valid behaviors are ${validLogBehaviors}` + ); +} + +function getSubstitutionsAndDeletions( + substitutionsFileDescriptor, + csvData, + searchStringsColName, + replacementStringsColName +) { + const substitutionsCsvData = csvData[substitutionsFileDescriptor]; + const substitutions = new Map(); + const deletions = new Set(); + + let headersChecked = false; + for (const row of substitutionsCsvData) { + if (!headersChecked) { + if (!(searchStringsColName in row) || !(replacementStringsColName in row)) { + throw new Error( + `Columns '${searchStringsColName}' and '${replacementStringsColName}' do not exist in the CSV file for ${substitutionsFileDescriptor}.` + ); + } + headersChecked = true; + } + + const oldWords = row[searchStringsColName] || ''; + const newWords = row[replacementStringsColName] || ''; + if (newWords.trim() === '') { + deletions.add(oldWords); + } else { + substitutions.set(oldWords, newWords); + } + } + return { deletions: deletions, substitutions: substitutions }; +} + +function makeId(id, substitutions, deletions) { + // First step is to make substitutions specified in the substitutions file. + + // Make substitutions that replace multiple words + substitutions.forEach((newWord, oldWords) => { + if (oldWords.includes(' ')) { + const regex = new RegExp(`\\b${escapeRegExp(oldWords)}\\b`, 'g'); + id = id.replace(regex, newWord); + } + }); + + // Make substitutions that delete multiple words + deletions.forEach(wordToDelete => { + if (wordToDelete.includes(' ')) { + const regex = new RegExp(`\\b${escapeRegExp(wordToDelete)}\\b`, 'g'); + id = id.replace(regex, ''); + } + }); + + // Make substitutions that replace single words + substitutions.forEach((newWord, oldWords) => { + if (!oldWords.includes(' ')) { + const regex = new RegExp(`\\b${escapeRegExp(oldWords)}\\b`, 'g'); + id = id.replace(regex, newWord); + } + }); + + // Make substitutions that delete single words + deletions.forEach(wordToDelete => { + if (!wordToDelete.includes(' ')) { + const regex = new RegExp(`\\b${escapeRegExp(wordToDelete)}\\b`, 'g'); + id = id.replace(regex, ''); + } + }); + + // step 2 is to Transform to single camel case word by upper casing first letters, removing spaces, and lowercasing start of string. + id = id + .toLowerCase() + .replace(/[^a-z0-9]/g, ' ') + .replace(/\s+/g, ' ') + .split(' ') + .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .join(''); + id = id.charAt(0).toLowerCase() + id.slice(1); + + return id; +} + +function translateCommand(screenReader, commandSequence, substitutions) { + commandSequence = commandSequence.replaceAll(',', ' ').toLowerCase(); + let commandSettings = ''; + // Get substitutions for this screenReader + substitutions = substitutions.filter( + row => row.screenReader.toLowerCase().trim() === screenReader.toLowerCase().trim() + ); + if (substitutions.length > 0) { + const oldCommands = commandSequence.split(' '); + let newCommandSequence = []; + let newCommandSettings = []; + for (const oldCommand of oldCommands) { + let newCommand = oldCommand; + for (const substitution of substitutions) { + oldCommandRegex = new RegExp(`^${substitution.oldCommand}$`, 'i'); + if (oldCommand.match(oldCommandRegex)) { + newCommand = oldCommand.replace(oldCommandRegex, substitution.newCommand); + const newSetting = substitution.settings.trim(); + if (newSetting !== '' && !newCommandSettings.includes(newSetting)) + newCommandSettings.push(newSetting); + break; + } + } + newCommandSequence.push(newCommand); + } + commandSequence = newCommandSequence.join(' '); + if (newCommandSettings.length > 0) commandSettings = newCommandSettings.join(' '); + } + commandSequence = commandSequence.replaceAll('_', '+'); + return { commandSequence, commandSettings }; +} + +function fixCase(input, isSentence) { + let entireInputWrappedInSingleQuotes = false; + let entireInputWrappedInDoubleQuotes = false; + let charInsideSingleQuotes = false; + let charInsideDoubleQuotes = false; + let isStartOfFirstWord = true; + + const result = input.split('').map((char, index, arr) => { + // If the entire string is quoted, ignore the leading and trailing quotes, i.e., continue to change case in the string. + if (index === 0) { + if (char === '"' && arr[arr.length - 1] === '"') { + entireInputWrappedInDoubleQuotes = true; + return char; + } + if (char === "'" && arr[arr.length - 1] === "'") { + entireInputWrappedInSingleQuotes = true; + return char; + } + } + if (index === arr.length - 1) { + if (entireInputWrappedInDoubleQuotes) return char; + if (entireInputWrappedInSingleQuotes) return char; + } + // If the entire string is wrapped in double quotes, only pay attention to single quotes on the inside and vice versa. + if (char === '"') { + if (!entireInputWrappedInDoubleQuotes) charInsideDoubleQuotes = !charInsideDoubleQuotes; + return char; + } + if (char === "'") { + if (!entireInputWrappedInSingleQuotes) charInsideSingleQuotes = !charInsideSingleQuotes; + return char; + } + // now process non-quote characters + // Return any white space + if (char.match(/\s/)) { + isStartOfFirstWord = false; + return char; + } + // Change case for any character not inside of quotes + if (!charInsideSingleQuotes && !charInsideDoubleQuotes) { + if (isStartOfFirstWord && isSentence) { + isStartOfFirstWord = false; + return char.toUpperCase(); + } else { + isStartOfFirstWord = false; + return char.toLowerCase(); + } + } else { + return char; + } + }); + + return result.join(''); +} + +function sentenceCase(input) { + return fixCase(input, true); +} + +function phraseCase(input) { + return fixCase(input, false); +} + +function removeDuplicateAndBlankRows(rows) { + // Find and remove rows where all values in all columns are equivalent. + // Also remove blank rows. + const uniqueNonBlankRows = []; + const seenRows = new Set(); + for (const row of rows) { + let blankCellCount = 0; + const rowString = JSON.stringify(row); + if (!seenRows.has(rowString)) { + seenRows.add(rowString); + for (const [key, value] of Object.entries(row)) { + if (value.trim() === '') blankCellCount++; + else break; + } + if (blankCellCount < Object.keys(row).length) { + uniqueNonBlankRows.push(row); + } + } + } + return uniqueNonBlankRows; +} + +function trimQuotes(input) { + // Trim leading and/or trailing double quotes from a string + if (input.length >= 2 && input.charAt(0) === '"') { + input = input.slice(1); + } + if (input.length >= 1 && input.charAt(input.length - 1) === '"') { + input = input.slice(0, -1); + } + return input; +} + +module.exports = { + deleteFile, + startLoggingTo, + logMessage, + getSubstitutionsAndDeletions, + makeId, + translateCommand, + phraseCase, + sentenceCase, + removeDuplicateAndBlankRows, + trimQuotes, +}; diff --git a/scripts/v2substitutionsForAssertionIds.csv b/scripts/v2substitutionsForAssertionIds.csv new file mode 100644 index 000000000..725a33d7e --- /dev/null +++ b/scripts/v2substitutionsForAssertionIds.csv @@ -0,0 +1,12 @@ +oldWords,newWords +a, +an, +backwards,back +Change in state,state change +in, +information,info +is conveyed, +of, +previous,prev +radio button,radio +the, diff --git a/scripts/v2substitutionsForCommands.csv b/scripts/v2substitutionsForCommands.csv new file mode 100644 index 000000000..8d9660b66 --- /dev/null +++ b/scripts/v2substitutionsForCommands.csv @@ -0,0 +1,7 @@ +screenReader,oldCommand,newCommand,settings +VoiceOver,CTRL_OPT_CMD_(\w),$1 ,quickNavOn +VoiceOver,SHIFT_CTRL_OPT_CMD_(\w),$1 ,quickNavOn +VoiceOver,LEFT,LEFT,quickNavOff +VoiceOver,RIGHT,RIGHT,quickNavOff +VoiceOver,DOWN,DOWN,quickNavOff +VoiceOver,UP,UP,quickNavOff diff --git a/scripts/v2substitutionsForTestIds.csv b/scripts/v2substitutionsForTestIds.csv new file mode 100644 index 000000000..1d53a156d --- /dev/null +++ b/scripts/v2substitutionsForTestIds.csv @@ -0,0 +1,17 @@ +oldWords,newWords +a, +an, +backwards,back +in, +in a group, +information,info +interaction, +is conveyed, +mode, +Navigate,nav +of, +previous,prev +radio button,radio +Read,req +reading, +the, diff --git a/tests/commands.json b/tests/commands.json new file mode 100644 index 000000000..9f5e3cf94 --- /dev/null +++ b/tests/commands.json @@ -0,0 +1,115 @@ +{ + "modifiers": { + "alt": "Alt", + "opt": "Option", + "shift": "Shift", + "ctrl": "Control", + "cmd": "Command", + "win": "Windows", + "ins": "Insert" + }, + "modifierAliases": { + "jaws": "ins", + "nvda": "ins", + "vo": "ctrl+opt" + }, + "keys": { + "a": "a", + "b": "b", + "c": "c", + "d": "d", + "e": "e", + "f": "f", + "g": "g", + "h": "h", + "i": "i", + "j": "j", + "k": "k", + "l": "l", + "m": "m", + "n": "n", + "o": "o", + "p": "p", + "q": "q", + "r": "r", + "s": "s", + "t": "t", + "u": "u", + "v": "v", + "w": "w", + "x": "x", + "y": "y", + "z": "z", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7", + "8": "8", + "9": "9", + "0": "0", + "dash": "Dash", + "equals": "Equals", + "grave": "Grave", + "leftBracket": "Left Bracket", + "rightBracket": "Right Bracket", + "backslash": "Backslash", + "semicolon": "Semicolon", + "apostrophe": "Apostrophe", + "comma": "Comma", + "period": "Period", + "slash": "Slash", + "esc": "Escape", + "backspace": "Backspace", + "tab": "Tab", + "capsLock": "Caps Lock", + "enter": "Enter", + "space": "Space", + "f1": "F1", + "f2": "F2", + "f3": "F3", + "f4": "F4", + "f5": "F5", + "f6": "F6", + "f7": "F7", + "f8": "F8", + "f9": "F9", + "f10": "F10", + "f11": "F11", + "f12": "F12", + "scrollLock": "Scroll Lock", + "pause": "Pause", + "home": "Home", + "end": "End", + "pageUp": "Page Up", + "pageDown": "Page Down", + "del": "Delete", + "left": "Left Arrow", + "right": "Right Arrow", + "up": "Up Arrow", + "down": "Down Arrow", + "numLock": "Num Lock", + "numpadSlash": "Numpad Slash", + "numpadAsterisk": "Numpad Asterisk", + "numpadMinus": "Numpad Minus", + "numpadPlus": "Numpad Plus", + "numpadEnter": "Numpad Enter", + "numpad1": "Numpad 1", + "numpad2": "Numpad 2", + "numpad3": "Numpad 3", + "numpad4": "Numpad 4", + "numpad5": "Numpad 5", + "numpad6": "Numpad 6", + "numpad7": "Numpad 7", + "numpad8": "Numpad 8", + "numpad9": "Numpad 9", + "numpad0": "Numpad 0", + "numpadPeriod": "Numpad Period" + }, + "keyAliases": { + "delete": "del", + "escape": "esc" + } +} \ No newline at end of file diff --git a/tests/radiogroup-aria-activedescendant/data/assertions.csv b/tests/radiogroup-aria-activedescendant/data/assertions.csv new file mode 100644 index 000000000..5446d1c89 --- /dev/null +++ b/tests/radiogroup-aria-activedescendant/data/assertions.csv @@ -0,0 +1,22 @@ +assertionId,priority,assertionStatement,assertionPhrase,refIds +groupBoundary,1,Group boundary is conveyed,convey group boundary, +nameDeepDish,1,Name 'Deep dish' is conveyed,convey name 'Deep dish', +nameGroupPizzaCrust,1,"Name of the group, 'Pizza Crust', is conveyed","convey name of the group, 'Pizza Crust'", +nameNavigateBackFromHere,1,Name 'Navigate backwards from here' is conveyed,convey name 'Navigate backwards from here', +nameNavigateForwardsFromHere,1,Name 'Navigate forwards from here' is conveyed,convey name 'Navigate forwards from here', +nameRadioRegularCrust,1,"Name of the radio button, 'Regular crust', is conveyed","convey name of the radio button, 'Regular crust'", +nameRadioThinCrust,1,"Name of the radio button, 'Thin crust', is conveyed","convey name of the radio button, 'Thin crust'", +nameRegularCrust,1,Name 'Regular crust' is conveyed,convey name 'Regular crust', +nameThinCrust,1,Name 'Thin crust' is conveyed,convey name 'Thin crust', +numberRadioButtonsGroup3,2,"Number of radio buttons in the group, 3, is conveyed","convey number of radio buttons in the group, 3", +positionRadio1,2,"Position of the radio button, 1, is conveyed","convey position of the radio button, 1", +positionRadio2,2,"Position of the radio button, 2, is conveyed","convey position of the radio button, 2", +positionRadio3,2,"Position of the radio button, 3, is conveyed","convey position of the radio button, 3", +roleGroup,1,Role 'group' is conveyed,convey role 'group', +roleLink,1,Role 'link' is conveyed,convey role 'link', +roleRadio,1,Role 'radio button' is conveyed,convey role 'radio button', +stateChangeToChecked,1,"Change in state, to 'checked', is conveyed","convey change in state, to 'checked'", +stateChecked,1,State 'checked' is conveyed,convey state 'checked', +stateRadioChecked,1,"State of the radio button, 'checked', is conveyed","convey state of the radio button, 'checked'", +stateRadioUnchecked,1,"State of the radio button, 'unchecked', is conveyed","convey state of the radio button, 'unchecked'", +stateUnchecked,1,State 'unchecked' is conveyed,convey state 'unchecked', diff --git a/tests/radiogroup-aria-activedescendant/data/jaws-commands.csv b/tests/radiogroup-aria-activedescendant/data/jaws-commands.csv new file mode 100644 index 000000000..aa974bdfc --- /dev/null +++ b/tests/radiogroup-aria-activedescendant/data/jaws-commands.csv @@ -0,0 +1,51 @@ +testId,command,settings,assertionExceptions,presentationNumber +navToFirstUncheckedRadio,f,virtualCursor,,1.0 +navToFirstUncheckedRadio,a,virtualCursor,,1.1 +navToFirstUncheckedRadio,down down,virtualCursor,,1.2 +navToLastUncheckedRadio,shift+f,virtualCursor,,3.0 +navToLastUncheckedRadio,shift+a,virtualCursor,,3.1 +navToLastUncheckedRadio,up up,virtualCursor,,3.2 +navToFirstCheckedRadio,f,virtualCursor,,5.0 +navToFirstCheckedRadio,a,virtualCursor,,5.1 +navToFirstCheckedRadio,down down,virtualCursor,,5.2 +navToLastCheckedRadio,shift+f,virtualCursor,,7.0 +navToLastCheckedRadio,shift+a,virtualCursor,,7.1 +navToLastCheckedRadio,up up,virtualCursor,,7.2 +navForwardsToUncheckedRadio,tab,pcCursor,,9.0 +navBackToUncheckedRadio,shift+tab,pcCursor,,11.0 +navForwardsToCheckedRadio,tab,pcCursor,,13.0 +navBackToCheckedRadio,shift+tab,pcCursor,,15.0 +navOutStartRadioGroup,up up,virtualCursor,,17.0 +navOutStartRadioGroup,shift+tab,pcCursor,,18.0 +navOutEndRadioGroup,down down,virtualCursor,,20.0 +navOutEndRadioGroup,tab,pcCursor,,21.0 +reqInfoAboutUncheckedRadio,ins+tab,virtualCursor,,23.0 +reqInfoAboutUncheckedRadio,ins+up,virtualCursor,,23.1 +reqInfoAboutUncheckedRadio,ins+tab,pcCursor,,24.0 +reqInfoAboutUncheckedRadio,ins+up,pcCursor,,24.1 +reqInfoAboutCheckedRadio,ins+tab,virtualCursor,,26.0 +reqInfoAboutCheckedRadio,ins+up,virtualCursor,,26.1 +reqInfoAboutCheckedRadio,ins+tab,pcCursor,,27.0 +reqInfoAboutCheckedRadio,ins+up,pcCursor,,27.1 +navToNextUncheckedRadio,f,virtualCursor,,29.0 +navToNextUncheckedRadio,a,virtualCursor,,29.1 +navToNextUncheckedRadio,down,virtualCursor,,29.2 +navToPrevUncheckedRadio,shift+f,virtualCursor,,31.0 +navToPrevUncheckedRadio,shift+a,virtualCursor,,31.1 +navToPrevUncheckedRadio,up,virtualCursor,,31.2 +navToNextCheckedRadio,f,virtualCursor,,33.0 +navToNextCheckedRadio,a,virtualCursor,,33.1 +navToNextCheckedRadio,down,virtualCursor,,33.2 +navToPrevCheckedRadio,shift+f,virtualCursor,,35.0 +navToPrevCheckedRadio,shift+a,virtualCursor,,35.1 +navToPrevCheckedRadio,up,virtualCursor,,35.2 +navToNextRadio,down,pcCursor,,37.0 +navToNextRadio,right,pcCursor,,37.1 +navToPrevRadio,up,pcCursor,,39.0 +navToPrevRadio,left,pcCursor,,39.1 +navToFirstRadio,down,pcCursor,,41.0 +navToFirstRadio,right,pcCursor,,41.1 +navToLastRadio,up,pcCursor,,43.0 +navToLastRadio,left,pcCursor,,43.1 +checkRadio,space,virtualCursor,,45.0 +checkRadio,space,pcCursor,,46.0 diff --git a/tests/radiogroup-aria-activedescendant/data/nvda-commands.csv b/tests/radiogroup-aria-activedescendant/data/nvda-commands.csv new file mode 100644 index 000000000..0637822ad --- /dev/null +++ b/tests/radiogroup-aria-activedescendant/data/nvda-commands.csv @@ -0,0 +1,41 @@ +testId,command,settings,assertionExceptions,presentationNumber +navToFirstUncheckedRadio,f,browseMode,,1.0 +navToFirstUncheckedRadio,r,browseMode,,1.1 +navToLastUncheckedRadio,shift+f,browseMode,,3.0 +navToLastUncheckedRadio,shift+r,browseMode,,3.1 +navToFirstCheckedRadio,f,browseMode,,5.0 +navToFirstCheckedRadio,r,browseMode,,5.1 +navToLastCheckedRadio,shift+f,browseMode,,7.0 +navToLastCheckedRadio,shift+r,browseMode,,7.1 +navForwardsToUncheckedRadio,tab,focusMode,,9.0 +navBackToUncheckedRadio,shift+tab,focusMode,,11.0 +navForwardsToCheckedRadio,tab,focusMode,,13.0 +navBackToCheckedRadio,shift+tab,focusMode,,15.0 +navOutStartRadioGroup,up,browseMode,,17.0 +navOutStartRadioGroup,shift+tab,focusMode,,18.0 +navOutEndRadioGroup,down,browseMode,,20.0 +navOutEndRadioGroup,tab,focusMode,,21.0 +reqInfoAboutUncheckedRadio,ins+tab,browseMode,,23.0 +reqInfoAboutUncheckedRadio,ins+tab,focusMode,,24.0 +reqInfoAboutUncheckedRadio,ins+up,focusMode,,24.1 +reqInfoAboutCheckedRadio,ins+tab,browseMode,,26.0 +reqInfoAboutCheckedRadio,ins+tab,focusMode,,27.0 +reqInfoAboutCheckedRadio,ins+up,focusMode,,27.1 +navToNextUncheckedRadio,f,browseMode,,29.0 +navToNextUncheckedRadio,r,browseMode,,29.1 +navToPrevUncheckedRadio,shift+f,browseMode,,31.0 +navToPrevUncheckedRadio,shift+r,browseMode,,31.1 +navToNextCheckedRadio,f,browseMode,,33.0 +navToNextCheckedRadio,r,browseMode,,33.1 +navToPrevCheckedRadio,shift+f,browseMode,,35.0 +navToPrevCheckedRadio,shift+r,browseMode,,35.1 +navToNextRadio,down,focusMode,,37.0 +navToNextRadio,right,focusMode,,37.1 +navToPrevRadio,up,focusMode,,39.0 +navToPrevRadio,left,focusMode,,39.1 +navToFirstRadio,down,focusMode,,41.0 +navToFirstRadio,right,focusMode,,41.1 +navToLastRadio,up,focusMode,,43.0 +navToLastRadio,left,focusMode,,43.1 +checkRadio,space,browseMode,,45.0 +checkRadio,space,focusMode,,46.0 diff --git a/tests/radiogroup-aria-activedescendant/data/references.csv b/tests/radiogroup-aria-activedescendant/data/references.csv index cd9c1c65e..42873cfd4 100644 --- a/tests/radiogroup-aria-activedescendant/data/references.csv +++ b/tests/radiogroup-aria-activedescendant/data/references.csv @@ -1,12 +1,12 @@ -refId,value -author,Isabel Del Castillo -authorEmail,isa.delcastillo5@gmail.com -title,Radio Group Example Using aria-activedescendant -reference,reference/2022-4-7_113015/radio-activedescendant.html -designPattern,https://w3c.github.io/aria-practices/#radiobutton -example,https://w3c.github.io/aria-practices/examples/radio/radio-activedescendant.html -radiogroup,https://w3c.github.io/aria/#radiogroup -radio,https://w3c.github.io/aria/#radio -aria-activedescendant,https://w3c.github.io/aria/#aria-activedescendant -aria-labelledby,https://w3c.github.io/aria/#aria-labelledby -aria-checked,https://w3c.github.io/aria/#aria-checked +refId,type,value,linkText +author,metadata,Isabel Del Castillo, +authorEmail,metadata,isa.delcastillo5@gmail.com, +title,metadata,Radio Group Example Using aria-activedescendant, +reference,metadata,reference/2022-4-7_113015/radio-activedescendant.html,Test Case Page for Radio Group Example Using aria-activedescendant +designPattern,metadata,https://www.w3.org/WAI/ARIA/apg/patterns/radio/,APG Pattern: Radio Group +example,metadata,https://www.w3.org/WAI/ARIA/apg/patterns/radio/examples/radio-activedescendant/,APG Example: Radio Group Using aria-activedescendant +radiogroup,aria,radiogroup,radiogroup +radio,aria,radio,radio +aria-activedescendant,aria,aria-activedescendant,aria-activedescendant +aria-labelledby,aria,aria-labelledby,aria-labelledby +aria-checked,aria,aria-checked,aria-checked diff --git a/tests/radiogroup-aria-activedescendant/data/referencesV1.csv b/tests/radiogroup-aria-activedescendant/data/referencesV1.csv new file mode 100644 index 000000000..cd9c1c65e --- /dev/null +++ b/tests/radiogroup-aria-activedescendant/data/referencesV1.csv @@ -0,0 +1,12 @@ +refId,value +author,Isabel Del Castillo +authorEmail,isa.delcastillo5@gmail.com +title,Radio Group Example Using aria-activedescendant +reference,reference/2022-4-7_113015/radio-activedescendant.html +designPattern,https://w3c.github.io/aria-practices/#radiobutton +example,https://w3c.github.io/aria-practices/examples/radio/radio-activedescendant.html +radiogroup,https://w3c.github.io/aria/#radiogroup +radio,https://w3c.github.io/aria/#radio +aria-activedescendant,https://w3c.github.io/aria/#aria-activedescendant +aria-labelledby,https://w3c.github.io/aria/#aria-labelledby +aria-checked,https://w3c.github.io/aria/#aria-checked diff --git a/tests/radiogroup-aria-activedescendant/data/scripts.csv b/tests/radiogroup-aria-activedescendant/data/scripts.csv new file mode 100644 index 000000000..ff2b30f2c --- /dev/null +++ b/tests/radiogroup-aria-activedescendant/data/scripts.csv @@ -0,0 +1,12 @@ +setupScript,setupScriptDescription +checkFirstRadioButtonAndSetFocusAfterRadioGroup,"sets the state of the first radio button to checked, and sets focus on a link after the radio group" +checkFirstRadioButtonAndSetFocusBeforeRadioGroup,"sets the state of the first radio button to checked, sets focus on a link before the radio group, and hides the group heading" +checkThirdRadioButtonAndSetFocusAfterRadioGroup,"sets the state of the third radio button to checked, and sets focus on a link after the radio group" +setFocusAfterRadioGroup,sets focus on a link after the radio group +setFocusBeforeRadioGroup,"sets focus on a link before the radio group, and hides the group heading" +setFocusOnAndCheckFirstRadioButton,"sets focus on the first radio button, and sets its state to checked" +setFocusOnFirstRadioButton,sets focus on the first radio button +setFocusOnFirstRadioButtonAndCheckSecondRadioButton,"sets focus on the first radio button, and checks the second radio button" +setFocusOnSecondRadioButton,sets focus on the second radio button +setFocusOnSecondRadioButtonAndCheckFirstRadioButton,"sets focus on the second radio button, and checks the first radio button" +setFocusOnThirdRadioButton,sets focus on the third radio button diff --git a/tests/radiogroup-aria-activedescendant/data/tests.csv b/tests/radiogroup-aria-activedescendant/data/tests.csv index fbc720e2f..f61dec144 100644 --- a/tests/radiogroup-aria-activedescendant/data/tests.csv +++ b/tests/radiogroup-aria-activedescendant/data/tests.csv @@ -1,48 +1,22 @@ -testId,title,appliesTo,mode,task,setupScript,setupScriptDescription,refs,instructions,assertion1,assertion2,assertion3,assertion4,assertion5,assertion6,assertion7 -1,Navigate to the first unchecked radio button in a group in reading mode,"JAWS,NVDA",READING,Navigate to the first unchecked radio button in a group,setFocusBeforeRadioGroup,"sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With the reading cursor on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'unchecked', is conveyed","2:Position of the radio button, 1, is conveyed","2:Number of radio buttons in the group, 3, is conveyed" -2,Navigate to the first unchecked radio button in a group,VOICEOVER_MACOS,INTERACTION,Navigate to the first unchecked radio button in a group,setFocusBeforeRadioGroup,"sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'unchecked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" -3,Navigate to the last unchecked radio button in a group in reading mode,"JAWS,NVDA",READING,Navigate to the last unchecked radio button in a group,setFocusAfterRadioGroup,sets focus on a link after the radio group,radiogroup aria-labelledby radio aria-checked,"With the reading cursor on the 'Navigate backwards from here' link, navigate to the 'Thin crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Thin crust', is conveyed","State of the radio button, 'unchecked', is conveyed","2:Position of the radio button, 3, is conveyed","2:Number of radio buttons in the group, 3, is conveyed" -4,Navigate to the last unchecked radio button in a group,VOICEOVER_MACOS,INTERACTION,Navigate to the last unchecked radio button in a group,setFocusAfterRadioGroup,sets focus on a link after the radio group,radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate backwards from here' link, navigate to the 'Thin crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Thin crust', is conveyed","State of the radio button, 'unchecked', is conveyed","Position of the radio button, 3, is conveyed","Number of radio buttons in the group, 3, is conveyed" -5,Navigate to the first checked radio button in a group in reading mode,"JAWS,NVDA",READING,Navigate to the first checked radio button in a group,checkFirstRadioButtonAndSetFocusBeforeRadioGroup,"sets the state of the first radio button to checked, sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With the reading cursor on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'checked', is conveyed","2:Position of the radio button, 1, is conveyed","2:Number of radio buttons in the group, 3, is conveyed" -6,Navigate to the first checked radio button in a group,VOICEOVER_MACOS,INTERACTION,Navigate to the first checked radio button in a group,checkFirstRadioButtonAndSetFocusBeforeRadioGroup,"sets the state of the first radio button to checked, sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'checked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" -7,Navigate to the last checked radio button in a group in reading mode,"JAWS,NVDA",READING,Navigate to the last checked radio button in a group,checkThirdRadioButtonAndSetFocusAfterRadioGroup,"sets the state of the third radio button to checked, and sets focus on a link after the radio group",radiogroup aria-labelledby radio aria-checked,"With the reading cursor on the 'Navigate backwards from here' link, navigate to the 'Thin crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Thin crust', is conveyed","State of the radio button, 'checked', is conveyed","2:Position of the radio button, 3, is conveyed","2:Number of radio buttons in the group, 3, is conveyed" -8,Navigate to the last checked radio button in a group,VOICEOVER_MACOS,INTERACTION,Navigate to the last checked radio button in a group,checkThirdRadioButtonAndSetFocusAfterRadioGroup,"sets the state of the third radio button to checked, and sets focus on a link after the radio group",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate backwards from here' link, navigate to the 'Thin crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Thin crust', is conveyed","State of the radio button, 'checked', is conveyed","Position of the radio button, 3, is conveyed","Number of radio buttons in the group, 3, is conveyed" -9,Navigate forwards to an unchecked radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate forwards to an unchecked radio button,setFocusBeforeRadioGroup,"sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'unchecked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" -10,Navigate forwards to an unchecked radio button,VOICEOVER_MACOS,INTERACTION,Navigate forwards to an unchecked radio button,setFocusBeforeRadioGroup,"sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'unchecked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" -11,Navigate backwards to an unchecked radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate backwards to an unchecked radio button,setFocusAfterRadioGroup,sets focus on a link after the radio group,radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate backwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'unchecked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" -12,Navigate backwards to an unchecked radio button,VOICEOVER_MACOS,INTERACTION,Navigate backwards to an unchecked radio button,setFocusAfterRadioGroup,sets focus on a link after the radio group,radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate backwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'unchecked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" -13,Navigate forwards to a checked radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate forwards to a checked radio button,checkFirstRadioButtonAndSetFocusBeforeRadioGroup,"sets the state of the first radio button to checked, sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'checked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" -14,Navigate forwards to a checked radio button,VOICEOVER_MACOS,INTERACTION,Navigate forwards to a checked radio button,checkFirstRadioButtonAndSetFocusBeforeRadioGroup,"sets the state of the first radio button to checked, sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'checked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" -15,Navigate backwards to a checked radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate backwards to a checked radio button,checkFirstRadioButtonAndSetFocusAfterRadioGroup,"sets the state of the first radio button to checked, and sets focus on a link after the radio group",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate backwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'checked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" -16,Navigate backwards to a checked radio button,VOICEOVER_MACOS,INTERACTION,Navigate backwards to a checked radio button,checkFirstRadioButtonAndSetFocusAfterRadioGroup,"sets the state of the first radio button to checked, and sets focus on a link after the radio group",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate backwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'checked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" -17,Navigate out of the start of a radio group in reading mode,"JAWS,NVDA",READING,Navigate out of the start of a radio group,setFocusOnFirstRadioButton,sets focus on the first radio button,radiogroup aria-labelledby,"With the reading cursor on the 'Regular crust' radio button, navigate to the 'Navigate forwards from here' link.",Group boundary is conveyed,Role 'link' is conveyed,name 'Navigate forwards from here' is conveyed,,,, -18,Navigate out of the start of a radio group in interaction mode,"JAWS,NVDA",INTERACTION,Navigate out of the start of a radio group,setFocusOnFirstRadioButton,sets focus on the first radio button,radiogroup aria-labelledby,"With focus on the 'Regular crust' radio button, navigate to the 'Navigate forwards from here' link.",Role 'link' is conveyed,name 'Navigate forwards from here' is conveyed,,,,, -19,Navigate out of the start of a radio group,VOICEOVER_MACOS,INTERACTION,Navigate out of the start of a radio group,setFocusOnFirstRadioButton,sets focus on the first radio button,radiogroup aria-labelledby,"With focus on the 'Regular crust' radio button, navigate to the 'Navigate forwards from here' link.",Group boundary is conveyed,Role 'link' is conveyed,name 'Navigate forwards from here' is conveyed,,,, -20,Navigate out of the end of a radio group in reading mode,"JAWS,NVDA",READING,Navigate out of the end of a radio group,setFocusOnThirdRadioButton,sets focus on the third radio button,radiogroup aria-labelledby,"With the reading cursor on the 'Thin crust' radio button, navigate to the 'Navigate backwards from here' link.",Group boundary is conveyed,Role 'link' is conveyed,name 'Navigate backwards from here' is conveyed,,,, -21,Navigate out of the end of a radio group in interaction mode,"JAWS,NVDA",INTERACTION,Navigate out of the end of a radio group,setFocusOnThirdRadioButton,sets focus on the third radio button,radiogroup aria-labelledby,"With focus on the 'Thin crust' radio button, navigate to the 'Navigate backwards from here' link.",Role 'link' is conveyed,name 'Navigate backwards from here' is conveyed,,,,, -22,Navigate out of the end of a radio group,VOICEOVER_MACOS,INTERACTION,Navigate out of the end of a radio group,setFocusOnThirdRadioButton,sets focus on the third radio button,radiogroup aria-labelledby,"With focus on the 'Thin crust' radio button, navigate to the 'Navigate backwards from here' link.",Group boundary is conveyed,Role 'link' is conveyed,name 'Navigate backwards from here' is conveyed,,,, -23,Read information about an unchecked radio button in reading mode,"JAWS,NVDA",READING,Read information about an unchecked radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With the reading cursor on the 'Regular crust' radio button, read information about the radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'unchecked' is conveyed,"2:Position of the radio button, 1, is conveyed","2:Number of radio buttons in the group, 3, is conveyed",, -24,Read information about an unchecked radio button in interaction mode,"JAWS,NVDA",INTERACTION,Read information about an unchecked radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, read information about the radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'unchecked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -25,Read information about an unchecked radio button,VOICEOVER_MACOS,INTERACTION,Read information about an unchecked radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, read information about the radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'unchecked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -26,Read information about a checked radio button in reading mode,"JAWS,NVDA",READING,Read information about a checked radio button,setFocusOnAndCheckFirstRadioButton,"sets focus on the first radio button, and sets its state to checked",radio aria-activedescendant aria-checked,"With the reading cursor on the 'Regular crust' radio button, read information about the radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"2:Position of the radio button, 1, is conveyed","2:Number of radio buttons in the group, 3, is conveyed",, -27,Read information about a checked radio button in interaction mode,"JAWS,NVDA",INTERACTION,Read information about a checked radio button,setFocusOnAndCheckFirstRadioButton,"sets focus on the first radio button, and sets its state to checked",radio aria-activedescendant aria-checked,"With the reading cursor on the 'Regular crust' radio button, read information about the radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -28,Read information about a checked radio button,VOICEOVER_MACOS,INTERACTION,Read information about a checked radio button,setFocusOnAndCheckFirstRadioButton,"sets focus on the first radio button, and sets its state to checked",radio aria-activedescendant aria-checked,"With the reading cursor on the 'Regular crust' radio button, read information about the radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -29,Navigate to the next unchecked radio button in reading mode,"JAWS,NVDA",READING,Navigate to the next unchecked radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With the reading cursor on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",Role 'radio button' is conveyed,Name 'Deep dish' is conveyed,State 'unchecked' is conveyed,"2:Position of the radio button, 2, is conveyed","2:Number of radio buttons in the group, 3, is conveyed",, -30,Navigate to the next unchecked radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the next unchecked radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",Role 'radio button' is conveyed,Name 'Deep dish' is conveyed,State 'unchecked' is conveyed,"Position of the radio button, 2, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -31,Navigate to the previous unchecked radio button in reading mode,"JAWS,NVDA",READING,Navigate to the previous unchecked radio button,setFocusOnSecondRadioButton,sets focus on the second radio button,radio aria-activedescendant aria-checked,"With the reading cursor on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'unchecked' is conveyed,"2:Position of the radio button, 1, is conveyed","2:Number of radio buttons in the group, 3, is conveyed",, -32,Navigate to the previous unchecked radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the previous unchecked radio button,setFocusOnSecondRadioButton,sets focus on the second radio button,radio aria-activedescendant aria-checked,"With focus on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'unchecked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -33,Navigate to the next checked radio button in reading mode,"JAWS,NVDA",READING,Navigate to the next checked radio button,setFocusOnFirstRadioButtonAndCheckSecondRadioButton,"sets focus on the first radio button, and checks the second radio button",radio aria-activedescendant aria-checked,"With the reading cursor on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",Role 'radio button' is conveyed,Name 'Deep dish' is conveyed,State 'checked' is conveyed,"2:Position of the radio button, 2, is conveyed","2:Number of radio buttons in the group, 3, is conveyed",, -34,Navigate to the next checked radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the next checked radio button,setFocusOnFirstRadioButtonAndCheckSecondRadioButton,"sets focus on the first radio button, and checks the second radio button",radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",Role 'radio button' is conveyed,Name 'Deep dish' is conveyed,State 'checked' is conveyed,"Position of the radio button, 2, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -35,Navigate to the previous checked radio button in reading mode,"JAWS,NVDA",READING,Navigate to the previous checked radio button,setFocusOnSecondRadioButtonAndCheckFirstRadioButton,"sets focus on the second radio button, and checks the first radio button",radio aria-activedescendant aria-checked,"With the reading cursor on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"2:Position of the radio button, 1, is conveyed","2:Number of radio buttons in the group, 3, is conveyed",, -36,Navigate to the previous checked radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the previous checked radio button,setFocusOnSecondRadioButtonAndCheckFirstRadioButton,"sets focus on the second radio button, and checks the first radio button",radio aria-activedescendant aria-checked,"With focus on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -37,Navigate to the next radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate to the next radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",Role 'radio button' is conveyed,Name 'Deep dish' is conveyed,State 'checked' is conveyed,"Position of the radio button, 2, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -38,Navigate to the next radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the next radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",Role 'radio button' is conveyed,Name 'Deep dish' is conveyed,State 'checked' is conveyed,"Position of the radio button, 2, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -39,Navigate to the previous radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate to the previous radio button,setFocusOnSecondRadioButton,sets focus on the second radio button,radio aria-activedescendant aria-checked,"With focus on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -40,Navigate to the previous radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the previous radio button,setFocusOnSecondRadioButton,sets focus on the second radio button,radio aria-activedescendant aria-checked,"With focus on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -41,Navigate to the first radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate to the first radio button,setFocusOnThirdRadioButton,sets focus on the third radio button,radio aria-activedescendant aria-checked,"With focus on the 'Thin crust' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -42,Navigate to the first radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the first radio button,setFocusOnThirdRadioButton,sets focus on the third radio button,radio aria-activedescendant aria-checked,"With focus on the 'Thin crust' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -43,Navigate to the last radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate to the last radio button ,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, navigate to the 'Thin crust' radio button.",Role 'radio button' is conveyed,Name 'Thin crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 3, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -44,Navigate to the last radio button ,VOICEOVER_MACOS,INTERACTION,Navigate to the last radio button ,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, navigate to the 'Thin crust' radio button.",Role 'radio button' is conveyed,Name 'Thin crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 3, is conveyed","Number of radio buttons in the group, 3, is conveyed",, -45,Check a radio button in reading mode,"JAWS,NVDA",READING,Check a radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,aria-checked,"With the reading cursor on the 'Regular crust' radio button, check the radio button.","Change in state, to 'checked', is conveyed",,,,,, -46,Check a radio button in interaction mode,"JAWS,NVDA",INTERACTION,Check a radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,aria-checked,"With focus on the 'Regular crust' radio button, check the radio button.","Change in state, to 'checked', is conveyed",,,,,, -47,Check a radio button,VOICEOVER_MACOS,INTERACTION,Check a radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,aria-checked,"With focus on the 'Regular crust' radio button, check the radio button.","Change in state, to 'checked', is conveyed",,,,,, +testId,title,presentationNumber,setupScript,instructions,assertions +navToFirstUncheckedRadio,Navigate to the first unchecked radio button in a group,2,setFocusBeforeRadioGroup,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",roleGroup nameGroupPizzaCrust roleRadio nameRadioRegularCrust stateRadioUnchecked positionRadio1 numberRadioButtonsGroup3 +navToLastUncheckedRadio,Navigate to the last unchecked radio button in a group,4,setFocusAfterRadioGroup,"With focus on the 'Navigate backwards from here' link, navigate to the 'Thin crust' radio button.",roleGroup nameGroupPizzaCrust roleRadio nameRadioThinCrust stateRadioUnchecked positionRadio3 numberRadioButtonsGroup3 +navToFirstCheckedRadio,Navigate to the first checked radio button in a group,6,checkFirstRadioButtonAndSetFocusBeforeRadioGroup,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",roleGroup nameGroupPizzaCrust roleRadio nameRadioRegularCrust stateRadioChecked positionRadio1 numberRadioButtonsGroup3 +navToLastCheckedRadio,Navigate to the last checked radio button in a group,8,checkThirdRadioButtonAndSetFocusAfterRadioGroup,"With focus on the 'Navigate backwards from here' link, navigate to the 'Thin crust' radio button.",roleGroup nameGroupPizzaCrust roleRadio nameRadioThinCrust stateRadioChecked positionRadio3 numberRadioButtonsGroup3 +navForwardsToUncheckedRadio,Navigate forwards to an unchecked radio button,10,setFocusBeforeRadioGroup,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",roleGroup nameGroupPizzaCrust roleRadio nameRadioRegularCrust stateRadioUnchecked positionRadio1 numberRadioButtonsGroup3 +navBackToUncheckedRadio,Navigate backwards to an unchecked radio button,12,setFocusAfterRadioGroup,"With focus on the 'Navigate backwards from here' link, navigate to the 'Regular crust' radio button.",roleGroup nameGroupPizzaCrust roleRadio nameRadioRegularCrust stateRadioUnchecked positionRadio1 numberRadioButtonsGroup3 +navForwardsToCheckedRadio,Navigate forwards to a checked radio button,14,checkFirstRadioButtonAndSetFocusBeforeRadioGroup,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",roleGroup nameGroupPizzaCrust roleRadio nameRadioRegularCrust stateRadioChecked positionRadio1 numberRadioButtonsGroup3 +navBackToCheckedRadio,Navigate backwards to a checked radio button,16,checkFirstRadioButtonAndSetFocusAfterRadioGroup,"With focus on the 'Navigate backwards from here' link, navigate to the 'Regular crust' radio button.",roleGroup nameGroupPizzaCrust roleRadio nameRadioRegularCrust stateRadioChecked positionRadio1 numberRadioButtonsGroup3 +navOutStartRadioGroup,Navigate out of the start of a radio group,19,setFocusOnFirstRadioButton,"With focus on the 'Regular crust' radio button, navigate to the 'Navigate forwards from here' link.",groupBoundary roleLink nameNavigateForwardsFromHere +navOutEndRadioGroup,Navigate out of the end of a radio group,22,setFocusOnThirdRadioButton,"With focus on the 'Thin crust' radio button, navigate to the 'Navigate backwards from here' link.",groupBoundary roleLink nameNavigateBackFromHere +reqInfoAboutUncheckedRadio,Request information about an unchecked radio button,25,setFocusOnFirstRadioButton,"With focus on the 'Regular crust' radio button, read information about the radio button.",roleRadio nameRegularCrust stateUnchecked positionRadio1 numberRadioButtonsGroup3 +reqInfoAboutCheckedRadio,Request information about a checked radio button,28,setFocusOnAndCheckFirstRadioButton,"With the reading cursor on the 'Regular crust' radio button, read information about the radio button.",roleRadio nameRegularCrust stateChecked positionRadio1 numberRadioButtonsGroup3 +navToNextUncheckedRadio,Navigate to the next unchecked radio button,30,setFocusOnFirstRadioButton,"With focus on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",roleRadio nameDeepDish stateUnchecked positionRadio2 numberRadioButtonsGroup3 +navToPrevUncheckedRadio,Navigate to the previous unchecked radio button,32,setFocusOnSecondRadioButton,"With focus on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",roleRadio nameRegularCrust stateUnchecked positionRadio1 numberRadioButtonsGroup3 +navToNextCheckedRadio,Navigate to the next checked radio button,34,setFocusOnFirstRadioButtonAndCheckSecondRadioButton,"With focus on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",roleRadio nameDeepDish stateChecked positionRadio2 numberRadioButtonsGroup3 +navToPrevCheckedRadio,Navigate to the previous checked radio button,36,setFocusOnSecondRadioButtonAndCheckFirstRadioButton,"With focus on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",roleRadio nameRegularCrust stateChecked positionRadio1 numberRadioButtonsGroup3 +navToNextRadio,Navigate to the next radio button,38,setFocusOnFirstRadioButton,"With focus on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",roleRadio nameDeepDish stateChecked positionRadio2 numberRadioButtonsGroup3 +navToPrevRadio,Navigate to the previous radio button,40,setFocusOnSecondRadioButton,"With focus on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",roleRadio nameRegularCrust stateChecked positionRadio1 numberRadioButtonsGroup3 +navToFirstRadio,Navigate to the first radio button,42,setFocusOnThirdRadioButton,"With focus on the 'Thin crust' radio button, navigate to the 'Regular crust' radio button.",roleRadio nameRegularCrust stateChecked positionRadio1 numberRadioButtonsGroup3 +navToLastRadio,Navigate to the last radio button ,44,setFocusOnFirstRadioButton,"With focus on the 'Regular crust' radio button, navigate to the 'Thin crust' radio button.",roleRadio nameThinCrust stateChecked positionRadio3 numberRadioButtonsGroup3 +checkRadio,Check a radio button,47,setFocusOnFirstRadioButton,"With focus on the 'Regular crust' radio button, check the radio button.",stateChangeToChecked diff --git a/tests/radiogroup-aria-activedescendant/data/testsV1.csv b/tests/radiogroup-aria-activedescendant/data/testsV1.csv new file mode 100644 index 000000000..fbc720e2f --- /dev/null +++ b/tests/radiogroup-aria-activedescendant/data/testsV1.csv @@ -0,0 +1,48 @@ +testId,title,appliesTo,mode,task,setupScript,setupScriptDescription,refs,instructions,assertion1,assertion2,assertion3,assertion4,assertion5,assertion6,assertion7 +1,Navigate to the first unchecked radio button in a group in reading mode,"JAWS,NVDA",READING,Navigate to the first unchecked radio button in a group,setFocusBeforeRadioGroup,"sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With the reading cursor on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'unchecked', is conveyed","2:Position of the radio button, 1, is conveyed","2:Number of radio buttons in the group, 3, is conveyed" +2,Navigate to the first unchecked radio button in a group,VOICEOVER_MACOS,INTERACTION,Navigate to the first unchecked radio button in a group,setFocusBeforeRadioGroup,"sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'unchecked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" +3,Navigate to the last unchecked radio button in a group in reading mode,"JAWS,NVDA",READING,Navigate to the last unchecked radio button in a group,setFocusAfterRadioGroup,sets focus on a link after the radio group,radiogroup aria-labelledby radio aria-checked,"With the reading cursor on the 'Navigate backwards from here' link, navigate to the 'Thin crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Thin crust', is conveyed","State of the radio button, 'unchecked', is conveyed","2:Position of the radio button, 3, is conveyed","2:Number of radio buttons in the group, 3, is conveyed" +4,Navigate to the last unchecked radio button in a group,VOICEOVER_MACOS,INTERACTION,Navigate to the last unchecked radio button in a group,setFocusAfterRadioGroup,sets focus on a link after the radio group,radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate backwards from here' link, navigate to the 'Thin crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Thin crust', is conveyed","State of the radio button, 'unchecked', is conveyed","Position of the radio button, 3, is conveyed","Number of radio buttons in the group, 3, is conveyed" +5,Navigate to the first checked radio button in a group in reading mode,"JAWS,NVDA",READING,Navigate to the first checked radio button in a group,checkFirstRadioButtonAndSetFocusBeforeRadioGroup,"sets the state of the first radio button to checked, sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With the reading cursor on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'checked', is conveyed","2:Position of the radio button, 1, is conveyed","2:Number of radio buttons in the group, 3, is conveyed" +6,Navigate to the first checked radio button in a group,VOICEOVER_MACOS,INTERACTION,Navigate to the first checked radio button in a group,checkFirstRadioButtonAndSetFocusBeforeRadioGroup,"sets the state of the first radio button to checked, sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'checked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" +7,Navigate to the last checked radio button in a group in reading mode,"JAWS,NVDA",READING,Navigate to the last checked radio button in a group,checkThirdRadioButtonAndSetFocusAfterRadioGroup,"sets the state of the third radio button to checked, and sets focus on a link after the radio group",radiogroup aria-labelledby radio aria-checked,"With the reading cursor on the 'Navigate backwards from here' link, navigate to the 'Thin crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Thin crust', is conveyed","State of the radio button, 'checked', is conveyed","2:Position of the radio button, 3, is conveyed","2:Number of radio buttons in the group, 3, is conveyed" +8,Navigate to the last checked radio button in a group,VOICEOVER_MACOS,INTERACTION,Navigate to the last checked radio button in a group,checkThirdRadioButtonAndSetFocusAfterRadioGroup,"sets the state of the third radio button to checked, and sets focus on a link after the radio group",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate backwards from here' link, navigate to the 'Thin crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Thin crust', is conveyed","State of the radio button, 'checked', is conveyed","Position of the radio button, 3, is conveyed","Number of radio buttons in the group, 3, is conveyed" +9,Navigate forwards to an unchecked radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate forwards to an unchecked radio button,setFocusBeforeRadioGroup,"sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'unchecked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" +10,Navigate forwards to an unchecked radio button,VOICEOVER_MACOS,INTERACTION,Navigate forwards to an unchecked radio button,setFocusBeforeRadioGroup,"sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'unchecked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" +11,Navigate backwards to an unchecked radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate backwards to an unchecked radio button,setFocusAfterRadioGroup,sets focus on a link after the radio group,radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate backwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'unchecked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" +12,Navigate backwards to an unchecked radio button,VOICEOVER_MACOS,INTERACTION,Navigate backwards to an unchecked radio button,setFocusAfterRadioGroup,sets focus on a link after the radio group,radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate backwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'unchecked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" +13,Navigate forwards to a checked radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate forwards to a checked radio button,checkFirstRadioButtonAndSetFocusBeforeRadioGroup,"sets the state of the first radio button to checked, sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'checked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" +14,Navigate forwards to a checked radio button,VOICEOVER_MACOS,INTERACTION,Navigate forwards to a checked radio button,checkFirstRadioButtonAndSetFocusBeforeRadioGroup,"sets the state of the first radio button to checked, sets focus on a link before the radio group, and hides the group heading",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate forwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'checked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" +15,Navigate backwards to a checked radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate backwards to a checked radio button,checkFirstRadioButtonAndSetFocusAfterRadioGroup,"sets the state of the first radio button to checked, and sets focus on a link after the radio group",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate backwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'checked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" +16,Navigate backwards to a checked radio button,VOICEOVER_MACOS,INTERACTION,Navigate backwards to a checked radio button,checkFirstRadioButtonAndSetFocusAfterRadioGroup,"sets the state of the first radio button to checked, and sets focus on a link after the radio group",radiogroup aria-labelledby radio aria-checked,"With focus on the 'Navigate backwards from here' link, navigate to the 'Regular crust' radio button.",Role 'group' is conveyed,"Name of the group, 'Pizza Crust', is conveyed",Role 'radio button' is conveyed,"Name of the radio button, 'Regular crust', is conveyed","State of the radio button, 'checked', is conveyed","Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed" +17,Navigate out of the start of a radio group in reading mode,"JAWS,NVDA",READING,Navigate out of the start of a radio group,setFocusOnFirstRadioButton,sets focus on the first radio button,radiogroup aria-labelledby,"With the reading cursor on the 'Regular crust' radio button, navigate to the 'Navigate forwards from here' link.",Group boundary is conveyed,Role 'link' is conveyed,name 'Navigate forwards from here' is conveyed,,,, +18,Navigate out of the start of a radio group in interaction mode,"JAWS,NVDA",INTERACTION,Navigate out of the start of a radio group,setFocusOnFirstRadioButton,sets focus on the first radio button,radiogroup aria-labelledby,"With focus on the 'Regular crust' radio button, navigate to the 'Navigate forwards from here' link.",Role 'link' is conveyed,name 'Navigate forwards from here' is conveyed,,,,, +19,Navigate out of the start of a radio group,VOICEOVER_MACOS,INTERACTION,Navigate out of the start of a radio group,setFocusOnFirstRadioButton,sets focus on the first radio button,radiogroup aria-labelledby,"With focus on the 'Regular crust' radio button, navigate to the 'Navigate forwards from here' link.",Group boundary is conveyed,Role 'link' is conveyed,name 'Navigate forwards from here' is conveyed,,,, +20,Navigate out of the end of a radio group in reading mode,"JAWS,NVDA",READING,Navigate out of the end of a radio group,setFocusOnThirdRadioButton,sets focus on the third radio button,radiogroup aria-labelledby,"With the reading cursor on the 'Thin crust' radio button, navigate to the 'Navigate backwards from here' link.",Group boundary is conveyed,Role 'link' is conveyed,name 'Navigate backwards from here' is conveyed,,,, +21,Navigate out of the end of a radio group in interaction mode,"JAWS,NVDA",INTERACTION,Navigate out of the end of a radio group,setFocusOnThirdRadioButton,sets focus on the third radio button,radiogroup aria-labelledby,"With focus on the 'Thin crust' radio button, navigate to the 'Navigate backwards from here' link.",Role 'link' is conveyed,name 'Navigate backwards from here' is conveyed,,,,, +22,Navigate out of the end of a radio group,VOICEOVER_MACOS,INTERACTION,Navigate out of the end of a radio group,setFocusOnThirdRadioButton,sets focus on the third radio button,radiogroup aria-labelledby,"With focus on the 'Thin crust' radio button, navigate to the 'Navigate backwards from here' link.",Group boundary is conveyed,Role 'link' is conveyed,name 'Navigate backwards from here' is conveyed,,,, +23,Read information about an unchecked radio button in reading mode,"JAWS,NVDA",READING,Read information about an unchecked radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With the reading cursor on the 'Regular crust' radio button, read information about the radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'unchecked' is conveyed,"2:Position of the radio button, 1, is conveyed","2:Number of radio buttons in the group, 3, is conveyed",, +24,Read information about an unchecked radio button in interaction mode,"JAWS,NVDA",INTERACTION,Read information about an unchecked radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, read information about the radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'unchecked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +25,Read information about an unchecked radio button,VOICEOVER_MACOS,INTERACTION,Read information about an unchecked radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, read information about the radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'unchecked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +26,Read information about a checked radio button in reading mode,"JAWS,NVDA",READING,Read information about a checked radio button,setFocusOnAndCheckFirstRadioButton,"sets focus on the first radio button, and sets its state to checked",radio aria-activedescendant aria-checked,"With the reading cursor on the 'Regular crust' radio button, read information about the radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"2:Position of the radio button, 1, is conveyed","2:Number of radio buttons in the group, 3, is conveyed",, +27,Read information about a checked radio button in interaction mode,"JAWS,NVDA",INTERACTION,Read information about a checked radio button,setFocusOnAndCheckFirstRadioButton,"sets focus on the first radio button, and sets its state to checked",radio aria-activedescendant aria-checked,"With the reading cursor on the 'Regular crust' radio button, read information about the radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +28,Read information about a checked radio button,VOICEOVER_MACOS,INTERACTION,Read information about a checked radio button,setFocusOnAndCheckFirstRadioButton,"sets focus on the first radio button, and sets its state to checked",radio aria-activedescendant aria-checked,"With the reading cursor on the 'Regular crust' radio button, read information about the radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +29,Navigate to the next unchecked radio button in reading mode,"JAWS,NVDA",READING,Navigate to the next unchecked radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With the reading cursor on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",Role 'radio button' is conveyed,Name 'Deep dish' is conveyed,State 'unchecked' is conveyed,"2:Position of the radio button, 2, is conveyed","2:Number of radio buttons in the group, 3, is conveyed",, +30,Navigate to the next unchecked radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the next unchecked radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",Role 'radio button' is conveyed,Name 'Deep dish' is conveyed,State 'unchecked' is conveyed,"Position of the radio button, 2, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +31,Navigate to the previous unchecked radio button in reading mode,"JAWS,NVDA",READING,Navigate to the previous unchecked radio button,setFocusOnSecondRadioButton,sets focus on the second radio button,radio aria-activedescendant aria-checked,"With the reading cursor on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'unchecked' is conveyed,"2:Position of the radio button, 1, is conveyed","2:Number of radio buttons in the group, 3, is conveyed",, +32,Navigate to the previous unchecked radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the previous unchecked radio button,setFocusOnSecondRadioButton,sets focus on the second radio button,radio aria-activedescendant aria-checked,"With focus on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'unchecked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +33,Navigate to the next checked radio button in reading mode,"JAWS,NVDA",READING,Navigate to the next checked radio button,setFocusOnFirstRadioButtonAndCheckSecondRadioButton,"sets focus on the first radio button, and checks the second radio button",radio aria-activedescendant aria-checked,"With the reading cursor on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",Role 'radio button' is conveyed,Name 'Deep dish' is conveyed,State 'checked' is conveyed,"2:Position of the radio button, 2, is conveyed","2:Number of radio buttons in the group, 3, is conveyed",, +34,Navigate to the next checked radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the next checked radio button,setFocusOnFirstRadioButtonAndCheckSecondRadioButton,"sets focus on the first radio button, and checks the second radio button",radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",Role 'radio button' is conveyed,Name 'Deep dish' is conveyed,State 'checked' is conveyed,"Position of the radio button, 2, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +35,Navigate to the previous checked radio button in reading mode,"JAWS,NVDA",READING,Navigate to the previous checked radio button,setFocusOnSecondRadioButtonAndCheckFirstRadioButton,"sets focus on the second radio button, and checks the first radio button",radio aria-activedescendant aria-checked,"With the reading cursor on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"2:Position of the radio button, 1, is conveyed","2:Number of radio buttons in the group, 3, is conveyed",, +36,Navigate to the previous checked radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the previous checked radio button,setFocusOnSecondRadioButtonAndCheckFirstRadioButton,"sets focus on the second radio button, and checks the first radio button",radio aria-activedescendant aria-checked,"With focus on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +37,Navigate to the next radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate to the next radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",Role 'radio button' is conveyed,Name 'Deep dish' is conveyed,State 'checked' is conveyed,"Position of the radio button, 2, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +38,Navigate to the next radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the next radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, navigate to the 'Deep dish' radio button.",Role 'radio button' is conveyed,Name 'Deep dish' is conveyed,State 'checked' is conveyed,"Position of the radio button, 2, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +39,Navigate to the previous radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate to the previous radio button,setFocusOnSecondRadioButton,sets focus on the second radio button,radio aria-activedescendant aria-checked,"With focus on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +40,Navigate to the previous radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the previous radio button,setFocusOnSecondRadioButton,sets focus on the second radio button,radio aria-activedescendant aria-checked,"With focus on the 'Deep dish' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +41,Navigate to the first radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate to the first radio button,setFocusOnThirdRadioButton,sets focus on the third radio button,radio aria-activedescendant aria-checked,"With focus on the 'Thin crust' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +42,Navigate to the first radio button,VOICEOVER_MACOS,INTERACTION,Navigate to the first radio button,setFocusOnThirdRadioButton,sets focus on the third radio button,radio aria-activedescendant aria-checked,"With focus on the 'Thin crust' radio button, navigate to the 'Regular crust' radio button.",Role 'radio button' is conveyed,Name 'Regular crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 1, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +43,Navigate to the last radio button in interaction mode,"JAWS,NVDA",INTERACTION,Navigate to the last radio button ,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, navigate to the 'Thin crust' radio button.",Role 'radio button' is conveyed,Name 'Thin crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 3, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +44,Navigate to the last radio button ,VOICEOVER_MACOS,INTERACTION,Navigate to the last radio button ,setFocusOnFirstRadioButton,sets focus on the first radio button,radio aria-activedescendant aria-checked,"With focus on the 'Regular crust' radio button, navigate to the 'Thin crust' radio button.",Role 'radio button' is conveyed,Name 'Thin crust' is conveyed,State 'checked' is conveyed,"Position of the radio button, 3, is conveyed","Number of radio buttons in the group, 3, is conveyed",, +45,Check a radio button in reading mode,"JAWS,NVDA",READING,Check a radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,aria-checked,"With the reading cursor on the 'Regular crust' radio button, check the radio button.","Change in state, to 'checked', is conveyed",,,,,, +46,Check a radio button in interaction mode,"JAWS,NVDA",INTERACTION,Check a radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,aria-checked,"With focus on the 'Regular crust' radio button, check the radio button.","Change in state, to 'checked', is conveyed",,,,,, +47,Check a radio button,VOICEOVER_MACOS,INTERACTION,Check a radio button,setFocusOnFirstRadioButton,sets focus on the first radio button,aria-checked,"With focus on the 'Regular crust' radio button, check the radio button.","Change in state, to 'checked', is conveyed",,,,,, diff --git a/tests/radiogroup-aria-activedescendant/data/voiceover_macos-commands.csv b/tests/radiogroup-aria-activedescendant/data/voiceover_macos-commands.csv new file mode 100644 index 000000000..e27db589f --- /dev/null +++ b/tests/radiogroup-aria-activedescendant/data/voiceover_macos-commands.csv @@ -0,0 +1,33 @@ +testId,command,settings,assertionExceptions,presentationNumber +navToFirstUncheckedRadio,ctrl+opt+right ctrl+opt+right,,,2.0 +navToFirstUncheckedRadio,j ,quickNavOn,,2.1 +navToLastUncheckedRadio,ctrl+opt+left ctrl+opt+left,,,4.0 +navToLastUncheckedRadio,j ,quickNavOn,,4.1 +navToFirstCheckedRadio,ctrl+opt+right ctrl+opt+right,,,6.0 +navToFirstCheckedRadio,j ,quickNavOn,,6.1 +navToLastCheckedRadio,ctrl+opt+left ctrl+opt+left,,,8.0 +navToLastCheckedRadio,j ,quickNavOn,,8.1 +navForwardsToUncheckedRadio,tab,,,10.0 +navBackToUncheckedRadio,shift+tab,,,12.0 +navForwardsToCheckedRadio,tab,,,14.0 +navBackToCheckedRadio,shift+tab,,,16.0 +navOutStartRadioGroup,ctrl+opt+left ctrl+opt+left,,,19.0 +navOutEndRadioGroup,ctrl+opt+right ctrl+opt+right,,,22.0 +reqInfoAboutUncheckedRadio,ctrl+opt+f3,,,25.0 +reqInfoAboutUncheckedRadio,ctrl+opt+f4,,,25.1 +reqInfoAboutCheckedRadio,ctrl+opt+f3,,,28.0 +reqInfoAboutCheckedRadio,ctrl+opt+f4,,,28.1 +navToNextUncheckedRadio,ctrl+opt+right,,,30.0 +navToPrevUncheckedRadio,ctrl+opt+left,,,32.0 +navToNextCheckedRadio,ctrl+opt+right,,,34.0 +navToPrevCheckedRadio,ctrl+opt+left,,,36.0 +navToNextRadio,DOWN,quickNavOff,,38.0 +navToNextRadio,RIGHT,quickNavOff,,38.1 +navToPrevRadio,UP,quickNavOff,,40.0 +navToPrevRadio,LEFT,quickNavOff,,40.1 +navToFirstRadio,DOWN,quickNavOff,,42.0 +navToFirstRadio,RIGHT,quickNavOff,,42.1 +navToLastRadio,UP,quickNavOff,,44.0 +navToLastRadio,LEFT,quickNavOff,,44.1 +checkRadio,space,,,47.0 +checkRadio,ctrl+opt+space,,,47.1 diff --git a/tests/support.json b/tests/support.json index e7e5c08a2..417222160 100644 --- a/tests/support.json +++ b/tests/support.json @@ -2,15 +2,76 @@ "ats": [ { "name": "JAWS", - "key": "jaws" + "key": "jaws", + "defaultConfigurationInstructionsHTML": "Configure JAWS with default settings. For help, read <a href="https://github.com/w3c/aria-at/wiki/Configuring-Screen-Readers-for-Testing">Configuring Screen Readers for Testing</a>.", + "assertionTokens": { + "screenReader": "JAWS", + "readingMode": "virtual cursor active", + "interactionMode": "PC cursor active" + }, + "settings": { + "virtualCursor": { + "screenText": "virtual cursor active", + "instructions": [ + "Press <kbd>Alt</kbd>+<kbd>Delete </kbd> to determine which cursor is active.", + "If the PC cursor is active, press <kbd>Escape</kbd> to activate the virtual cursor." + ] + }, + "pcCursor": { + "screenText": "PC cursor active", + "instructions": [ + "Press <kbd>Alt</kbd>+<kbd>Delete</kbd> to determine which cursor is active.", + "If the virtual cursor is active, press <kbd>Insert</kbd>+<kbd>z</kbd> to disable the virtual cursor." + ] + } + } }, { "name": "NVDA", - "key": "nvda" + "key": "nvda", + "defaultConfigurationInstructionsHTML": "Configure NVDA with default settings. For help, read <a href="https://github.com/w3c/aria-at/wiki/Configuring-Screen-Readers-for-Testing">Configuring Screen Readers for Testing</a>.", + "assertionTokens": { + "screenReader": "NVDA", + "readingMode": "browse mode", + "interactionMode": "focus mode" + }, + "settings": { + "browseMode": { + "screenText": "browse mode on", + "instructions": [ + "Press <kbd>insert</kbd>+<kbd>Space</kbd>.", + "If NVDA made the focus mode sound , press <kbd>Insert</kbd>+<kbd>Space</kbd> again to turn browse mode back on." + ] + }, + "focusMode": { + "screenText": "focus mode on", + "instructions": [ + "Press <kbd>insert</kbd>+<kbd>Space</kbd>.", + "If NVDA made the browse mode sound , press <kbd>Insert</kbd>+<kbd>Space</kbd> again to turn focus mode back on." + ] + } + } }, { "name": "VoiceOver for macOS", - "key": "voiceover_macos" + "key": "voiceover_macos", + "defaultConfigurationInstructionsHTML": "Configure VoiceOver with default settings. For help, read <a href="https://github.com/w3c/aria-at/wiki/Configuring-Screen-Readers-for-Testing">Configuring Screen Readers for Testing</a>.", + "settings": { + "quickNavOn": { + "screenText": "quick nav on", + "instructions": [ + "Simultaneously press <kbd>Left Arrow</kbd> and <kbd>Right Arrow</kbd>.", + "If VoiceOver said 'quick nav off', press <kbd>Left Arrow</kbd> and <kbd>Right Arrow</kbd> again to turn it back on." + ] + }, + "quickNavOff": { + "screenText": "quick nav off", + "instructions": [ + "Simultaneously press <kbd>Left Arrow</kbd> and <kbd>Right Arrow</kbd>.", + "If VoiceOver said 'quick nav on', press <kbd>Left Arrow</kbd> and <kbd>Right Arrow</kbd> again to turn it back off." + ] + } + } } ], "applies_to": { @@ -24,5 +85,326 @@ "NVDA", "JAWS" ] + }, + "testPlanStrings": { + "ariaSpecsPreface": "Tested ARIA features:", + "openExampleInstruction": "Activate the "Open test page" button, which opens the example to test in a new window and runs a script that", + "commandListPreface": "Do this with each of the following commands or command sequences.", + "commandListSettingsPreface": "If any settings are specified in parentheses, ensure the settings are active before executing the command or command sequence.", + "settingInstructionsPreface": "To perform a task with", + "assertionResponseQuestion": "Which statements are true about the response to" + }, + "references": { + "aria": { + "baseUrl": "https://www.w3.org/TR/wai-aria/", + "linkText": "ARIA Specification", + "fragmentIds": { + "alert": "#alert", + "alertdialog": "#alertdialog", + "application": "#application", + "article": "#article", + "associationlist": "#associationlist", + "associationlistitemkey": "#associationlistitemkey", + "associationlistitemvalue": "#associationlistitemvalue", + "banner": "#banner", + "blockquote": "#blockquote", + "button": "#button", + "caption": "#caption", + "cell": "#cell", + "checkbox": "#checkbox", + "code": "#code", + "columnheader": "#columnheader", + "combobox": "#combobox", + "command": "#command", + "comment": "#comment", + "complementary": "#complementary", + "composite": "#composite", + "contentinfo": "#contentinfo", + "definition": "#definition", + "deletion": "#deletion", + "dialog": "#dialog", + "directory": "#directory", + "document": "#document", + "emphasis": "#emphasis", + "feed": "#feed", + "figure": "#figure", + "form": "#form", + "generic": "#generic", + "grid": "#grid", + "gridcell": "#gridcell", + "group": "#group", + "heading": "#heading", + "image": "#image", + "img": "#img", + "input": "#input", + "insertion": "#insertion", + "landmark": "#landmark", + "link": "#link", + "list": "#list", + "listbox": "#listbox", + "listitem": "#listitem", + "log": "#log", + "main": "#main", + "mark": "#mark", + "marquee": "#marquee", + "math": "#math", + "menu": "#menu", + "menubar": "#menubar", + "menuitem": "#menuitem", + "menuitemcheckbox": "#menuitemcheckbox", + "menuitemradio": "#menuitemradio", + "meter": "#meter", + "navigation": "#navigation", + "none": "#none", + "note": "#note", + "option": "#option", + "paragraph": "#paragraph", + "presentation": "#presentation", + "progressbar": "#progressbar", + "radio": "#radio", + "radiogroup": "#radiogroup", + "range": "#range", + "region": "#region", + "roletype": "#roletype", + "row": "#row", + "rowgroup": "#rowgroup", + "rowheader": "#rowheader", + "scrollbar": "#scrollbar", + "search": "#search", + "searchbox": "#searchbox", + "section": "#section", + "sectionhead": "#sectionhead", + "select": "#select", + "separator": "#separator", + "slider": "#slider", + "spinbutton": "#spinbutton", + "status": "#status", + "strong": "#strong", + "structure": "#structure", + "subscript": "#subscript", + "suggestion": "#suggestion", + "superscript": "#superscript", + "switch": "#switch", + "tab": "#tab", + "table": "#table", + "tablist": "#tablist", + "tabpanel": "#tabpanel", + "term": "#term", + "textbox": "#textbox", + "time": "#time", + "timer": "#timer", + "toolbar": "#toolbar", + "tooltip": "#tooltip", + "tree": "#tree", + "treegrid": "#treegrid", + "treeitem": "#treeitem", + "widget": "#widget", + "window": "#window", + "aria-activedescendant": "#aria-activedescendant", + "aria-atomic": "#aria-atomic", + "aria-autocomplete": "#aria-autocomplete", + "aria-braillelabel": "#aria-braillelabel", + "aria-brailleroledescription": "#aria-brailleroledescription", + "aria-busy": "#aria-busy", + "aria-checked": "#aria-checked", + "aria-colcount": "#aria-colcount", + "aria-colindex": "#aria-colindex", + "aria-colindextext": "#aria-colindextext", + "aria-colspan": "#aria-colspan", + "aria-controls": "#aria-controls", + "aria-current": "#aria-current", + "aria-describedby": "#aria-describedby", + "aria-description": "#aria-description", + "aria-details": "#aria-details", + "aria-disabled": "#aria-disabled", + "aria-errormessage": "#aria-errormessage", + "aria-expanded": "#aria-expanded", + "aria-flowto": "#aria-flowto", + "aria-haspopup": "#aria-haspopup", + "aria-hidden": "#aria-hidden", + "aria-invalid": "#aria-invalid", + "aria-keyshortcuts": "#aria-keyshortcuts", + "aria-label": "#aria-label", + "aria-labelledby": "#aria-labelledby", + "aria-level": "#aria-level", + "aria-live": "#aria-live", + "aria-modal": "#aria-modal", + "aria-multiline": "#aria-multiline", + "aria-multiselectable": "#aria-multiselectable", + "aria-orientation": "#aria-orientation", + "aria-owns": "#aria-owns", + "aria-placeholder": "#aria-placeholder", + "aria-posinset": "#aria-posinset", + "aria-pressed": "#aria-pressed", + "aria-readonly": "#aria-readonly", + "aria-relevant": "#aria-relevant", + "aria-required": "#aria-required", + "aria-roledescription": "#aria-roledescription", + "aria-rowcount": "#aria-rowcount", + "aria-rowindex": "#aria-rowindex", + "aria-rowindextext": "#aria-rowindextext", + "aria-rowspan": "#aria-rowspan", + "aria-selected": "#aria-selected", + "aria-setsize": "#aria-setsize", + "aria-sort": "#aria-sort", + "aria-valuemax": "#aria-valuemax", + "aria-valuemin": "#aria-valuemin", + "aria-valuenow": "#aria-valuenow", + "aria-valuetext": "#aria-valuetext" + } + }, + "htmlAam": { + "baseUrl": "https://www.w3.org/TR/html-aam-1.0/", + "linkText": "Accessibility API Mapping", + "fragmentIds": { + "a": "#el-a", + "aNoHref": "#el-a-no-href", + "abbr": "#el-abbr", + "address": "#el-address", + "area": "#el-area", + "areaNoHref": "#el-area-no-href", + "article": "#el-article", + "asideBodyOrMainScope": "#el-aside-ancestorbodymain", + "asideSectionScope": "#el-aside", + "audio": "#el-audio", + "autonomous custom element": "#el-autonomous-custom-element", + "b": "#el-b", + "base": "#el-base", + "bdi": "#el-bdi", + "bdo": "#el-bdo", + "blockquote": "#el-blockquote", + "body": "#el-body", + "br": "#el-br", + "button": "#el-button", + "canvas": "#el-canvas", + "caption": "#el-caption", + "cite": "#el-cite", + "code": "#el-code", + "col": "#el-col", + "colgroup": "#el-colgroup", + "data": "#el-data", + "datalist": "#el-datalist", + "dd": "#el-dd", + "del": "#el-del", + "details": "#el-details", + "dfn": "#el-dfn", + "dialog": "#el-dialog", + "div": "#el-div", + "dl": "#el-dl", + "dt": "#el-dt", + "em": "#el-em", + "embed": "#el-embed", + "fieldset": "#el-fieldset", + "figcaption": "#el-figcaption", + "figure": "#el-figure", + "footerBodyScope": "#el-footer-ancestorbody", + "footerMainScope": "#el-footer", + "form": "#el-form", + "formAssociatedCustomElement": "#el-form-associated-custom-element", + "heading": "#el-h1-h6", + "head": "#el-head", + "headerBodyScope": "#el-header-ancestorbody", + "headerMainScope": "#el-header", + "hgroup": "#el-hgroup", + "hr": "#el-hr", + "html": "#el-html", + "i": "#el-i", + "iframe": "#el-iframe", + "img": "#el-img", + "imgEmptyAlt": "#el-img-empty-alt", + "inputTypeButton": "#el-input-button", + "inputTypeCheckbox": "#el-input-checkbox", + "inputTypeColor": "#el-input-color", + "inputTypeDate": "#el-input-date", + "inputTypeDateTime": "#el-input-datetime-local", + "inputTypeEmail": "#el-input-email", + "inputTypeFile": "#el-input-file", + "inputTypeHidden": "#el-input-hidden", + "inputTypeImage": "#el-input-image", + "inputTypeMonth": "#el-input-month", + "inputTypeNumber": "#el-input-number", + "inputTypePassword": "#el-input-password", + "inputTypeRadio": "#el-input-radio", + "inputTypeRange": "#el-input-range", + "inputTypeReset": "#el-input-reset", + "inputTypeSearch": "#el-input-search", + "inputTypeSubmit": "#el-input-submit", + "inputTypeTelephone": "#el-input-tel", + "inputTypeText": "#el-input-text", + "inputTypeTextAutocomplete": "#el-input-textetc-autocomplete", + "inputTypeTime": "#el-input-time", + "inputTypeUrl": "#el-input-url", + "inputTypeWeek": "#el-input-week", + "ins": "#el-ins", + "kbd": "#el-kbd", + "label": "#el-label", + "legend": "#el-legend", + "li": "#el-li", + "link": "#el-link", + "main": "#el-main", + "map": "#el-map", + "mark": "#el-mark", + "math": "#el-math", + "menu": "#el-menu", + "meta": "#el-meta", + "meter": "#el-meter", + "nav": "#el-nav", + "noscript": "#el-noscript", + "object": "#el-object", + "ol": "#el-ol", + "optgroup": "#el-optgroup", + "option": "#el-option", + "output": "#el-output", + "p": "#el-p", + "param": "#el-param", + "picture": "#el-picture", + "pre": "#el-pre", + "progress": "#el-progress", + "q": "#el-q", + "rb": "#el-rb", + "rp": "#el-rp", + "rt": "#el-rt", + "rtc": "#el-rtc", + "ruby": "#el-ruby", + "s": "#el-s", + "samp": "#el-samp", + "script": "#el-script", + "search": "#el-search", + "section": "#el-section", + "select": "#el-select-listbox", + "selectSize1": "#el-select-combobox", + "slot": "#el-slot", + "small": "#el-small", + "source": "#el-source", + "span": "#el-span", + "strong": "#el-strong", + "style": "#el-style", + "sub": "#el-sub", + "summary": "#el-summary", + "sup": "#el-sup", + "svg": "#el-svg", + "table": "#el-table", + "tbody": "#el-tbody", + "td": "#el-td", + "tdGridcell": "#el-td-gridcell", + "template": "#el-template", + "textarea": "#el-textarea", + "tfoot": "#el-tfoot", + "th": "#el-th", + "thGridcell": "#el-th-gridcell", + "thColgroupHeader": "#el-th-columnheader", + "thRowgroupHeader": "#el-th-rowheader", + "thead": "#el-thead", + "time": "#el-time", + "title": "#el-title", + "tr": "#el-tr", + "track": "#el-track", + "u": "#el-u", + "ul": "#el-ul", + "var": "#el-var", + "video": "#el-video", + "wbr": "#el-wbr" + } + } } -} +} \ No newline at end of file