From 419bd7e3695dee083a68c91e7d4c1433e1a0b0b7 Mon Sep 17 00:00:00 2001 From: Stalgia Grigg Date: Wed, 15 Oct 2025 16:30:56 -0700 Subject: [PATCH 1/8] Spike on DB automation supporting AT version --- server/controllers/AutomationController.js | 11 +++ ...14111422-add-atversion-automation-flags.js | 42 ++++++++++ ...617-backfill-atversion-automation-flags.js | 61 +++++++++++++++ server/models/AtVersion.js | 9 ++- server/models/services/AtVersionService.js | 76 ++++++++++++++----- .../populate-test-data/pg_dump_test_data.sql | 6 +- server/util/constants.js | 14 +--- server/util/getAtVersionWithRequirements.js | 27 +++---- 8 files changed, 191 insertions(+), 55 deletions(-) create mode 100644 server/migrations/20251014111422-add-atversion-automation-flags.js create mode 100644 server/migrations/20251015111617-backfill-atversion-automation-flags.js diff --git a/server/controllers/AutomationController.js b/server/controllers/AutomationController.js index ad091f960..91870260e 100644 --- a/server/controllers/AutomationController.js +++ b/server/controllers/AutomationController.js @@ -12,6 +12,9 @@ const saveTestResultCommon = require('../resolvers/TestResultOperations/saveTest const { findOrCreateAtVersion } = require('../models/services/AtVersionService'); +const { + promoteAutomationSupportedVersion +} = require('../models/services/AtVersionService'); const { getAts } = require('../models/services/AtService'); const { getBrowsers, @@ -421,6 +424,14 @@ const updateJobResults = async (req, res) => { }) ]); + const isVoiceOver = at.id === 3; + if (isVoiceOver) { + await promoteAutomationSupportedVersion({ + atVersionId: atVersion.id, + transaction + }); + } + const processedResponses = convertEmptyStringsToNoOutputMessages(responses); diff --git a/server/migrations/20251014111422-add-atversion-automation-flags.js b/server/migrations/20251014111422-add-atversion-automation-flags.js new file mode 100644 index 000000000..55ea47217 --- /dev/null +++ b/server/migrations/20251014111422-add-atversion-automation-flags.js @@ -0,0 +1,42 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + const table = await queryInterface.describeTable('AtVersion'); + if (!table.supportedByAutomation) { + await queryInterface.addColumn('AtVersion', 'supportedByAutomation', { + type: Sequelize.BOOLEAN, + allowNull: false, + defaultValue: false + }); + } + if (!table.latestAutomationSupporting) { + await queryInterface.addColumn( + 'AtVersion', + 'latestAutomationSupporting', + { + type: Sequelize.BOOLEAN, + allowNull: false, + defaultValue: false + } + ); + } + }, + + async down(queryInterface) { + try { + await queryInterface.removeColumn( + 'AtVersion', + 'latestAutomationSupporting' + ); + } catch (e) { + console.error(e); + } + try { + await queryInterface.removeColumn('AtVersion', 'supportedByAutomation'); + } catch (e) { + console.error(e); + } + } +}; diff --git a/server/migrations/20251015111617-backfill-atversion-automation-flags.js b/server/migrations/20251015111617-backfill-atversion-automation-flags.js new file mode 100644 index 000000000..85cc72538 --- /dev/null +++ b/server/migrations/20251015111617-backfill-atversion-automation-flags.js @@ -0,0 +1,61 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface) { + const transaction = await queryInterface.sequelize.transaction(); + try { + const [ats] = await queryInterface.sequelize.query( + 'select id, name from "At"', + { transaction } + ); + + const supported = { + 'VoiceOver for macOS': ['13.0', '14.0', '15.0'], + NVDA: ['2025.2', '2024.4.1', '2024.1', '2023.3.3', '2023.3'], + JAWS: ['2025.2508.120'] + }; + + for (const at of ats) { + const names = supported[at.name] || []; + if (!names.length) continue; + await queryInterface.sequelize.query( + `update "AtVersion" + set "supportedByAutomation" = true + where "atId" = :atId and name in (:names)`, + { replacements: { atId: at.id, names }, transaction } + ); + + // latestAutomationSupporting should be the most recent supported version by releasedAt + const [rows] = await queryInterface.sequelize.query( + `select id from "AtVersion" + where "atId" = :atId and "supportedByAutomation" = true + order by "releasedAt" desc`, + { replacements: { atId: at.id }, transaction } + ); + if (rows.length) { + const latestId = rows[0].id; + await queryInterface.sequelize.query( + `update "AtVersion" set "latestAutomationSupporting" = false where "atId" = :atId`, + { replacements: { atId: at.id }, transaction } + ); + await queryInterface.sequelize.query( + `update "AtVersion" set "latestAutomationSupporting" = true where id = :id`, + { replacements: { id: latestId }, transaction } + ); + } + } + + await transaction.commit(); + } catch (e) { + await transaction.rollback(); + throw e; + } + }, + + async down(queryInterface) { + await queryInterface.sequelize.query( + 'update "AtVersion" set "supportedByAutomation" = false, "latestAutomationSupporting" = false' + ); + } +}; diff --git a/server/models/AtVersion.js b/server/models/AtVersion.js index c40bd599d..f9faa82df 100644 --- a/server/models/AtVersion.js +++ b/server/models/AtVersion.js @@ -28,7 +28,14 @@ module.exports = function (sequelize, DataTypes) { defaultValue: new Date() }, supportedByAutomation: { - type: DataTypes.VIRTUAL + type: DataTypes.BOOLEAN, + allowNull: false, + defaultValue: false + }, + latestAutomationSupporting: { + type: DataTypes.BOOLEAN, + allowNull: false, + defaultValue: false } }, { diff --git a/server/models/services/AtVersionService.js b/server/models/services/AtVersionService.js index f242ff4c1..32fb55631 100644 --- a/server/models/services/AtVersionService.js +++ b/server/models/services/AtVersionService.js @@ -2,9 +2,6 @@ const ModelService = require('./ModelService'); const { AtVersion, TestPlanReport } = require('..'); const { Op } = require('sequelize'); const { AT_VERSION_ATTRIBUTES, AT_ATTRIBUTES } = require('./helpers'); -const { - AT_VERSIONS_SUPPORTED_BY_COLLECTION_JOBS -} = require('../../util/constants'); /** * @param atAttributes - At attributes to be returned in the result @@ -82,6 +79,7 @@ const getAtVersionWithRequirements = async ( const matchingAtVersions = await getAtVersions({ where: { atId, + supportedByAutomation: true, releasedAt: { [Op.gte]: minimumAtVersion.releasedAt } }, pagination: { @@ -90,15 +88,8 @@ const getAtVersionWithRequirements = async ( transaction }); - const supportedVersions = - AT_VERSIONS_SUPPORTED_BY_COLLECTION_JOBS[ - matchingAtVersions[0]?.at?.name - ] || []; - const latestSupportedAtVersion = matchingAtVersions.find( - atv => - supportedVersions.includes(atv.name) && - new Date(atv.releasedAt) >= new Date(minimumAtVersion.releasedAt) + atv => new Date(atv.releasedAt) >= new Date(minimumAtVersion.releasedAt) ); if (!latestSupportedAtVersion) { @@ -123,17 +114,17 @@ const getAtVersionWithRequirements = async ( */ const getLatestAutomationSupportedAtVersion = async (atId, transaction) => { const versions = await getAtVersions({ - where: { atId }, - pagination: { order: [['releasedAt', 'ASC']] }, + where: { + atId, + supportedByAutomation: true, + latestAutomationSupporting: true + }, transaction }); - const atName = versions[0]?.at?.name; - const supportedNames = AT_VERSIONS_SUPPORTED_BY_COLLECTION_JOBS[atName] || []; - const supported = versions.filter(v => supportedNames.includes(v.name)); - if (!supported.length) { + if (!versions.length) { throw new Error(`No automation-supported versions found for AT ${atId}`); } - return supported[supported.length - 1]; + return versions[0]; }; /** @@ -304,6 +295,50 @@ const removeAtVersionById = async ({ id, truncate = false, transaction }) => { }); }; +/** + * Promote an AT version to be automation-supported, and mark it latest for that AT. + * Demotes any other versions for the same AT from latestAutomationSupporting. + * @param {object} params + * @param {number} params.atVersionId + * @param {*} transaction + */ +const promoteAutomationSupportedVersion = async ({ + atVersionId, + transaction +}) => { + const version = await ModelService.getById(AtVersion, { + id: atVersionId, + attributes: AT_VERSION_ATTRIBUTES, + transaction + }); + if (!version) return null; + + if (version.supportedByAutomation && version.latestAutomationSupporting) { + return version; + } + + await ModelService.update(AtVersion, { + where: { id: atVersionId }, + values: { supportedByAutomation: true, latestAutomationSupporting: true }, + transaction + }); + await ModelService.update(AtVersion, { + where: { + atId: version.atId, + id: { [Op.ne]: atVersionId }, + latestAutomationSupporting: true + }, + values: { latestAutomationSupporting: false }, + transaction + }); + + return ModelService.getById(AtVersion, { + id: atVersionId, + attributes: AT_VERSION_ATTRIBUTES, + transaction + }); +}; + /** * Returns all the unique AT Versions used when collecting results from testers * for a Test Plan Report @@ -404,9 +439,7 @@ const getRerunnableTestPlanReportsForVersion = async ({ } // Check if version is supported by automation - const supportedVersionNames = - AT_VERSIONS_SUPPORTED_BY_COLLECTION_JOBS[currentVersion.at.name] || []; - if (!supportedVersionNames.includes(currentVersion.name)) { + if (!currentVersion.supportedByAutomation) { return { currentVersion, previousVersionGroups: [] }; } @@ -637,6 +670,7 @@ module.exports = { updateAtVersionByQuery, removeAtVersionByQuery, removeAtVersionById, + promoteAutomationSupportedVersion, findOrCreateAtVersion, getUniqueAtVersionsForReport, getRerunnableTestPlanReportsForVersion, diff --git a/server/scripts/populate-test-data/pg_dump_test_data.sql b/server/scripts/populate-test-data/pg_dump_test_data.sql index 65092a6b0..b451969f1 100644 --- a/server/scripts/populate-test-data/pg_dump_test_data.sql +++ b/server/scripts/populate-test-data/pg_dump_test_data.sql @@ -47,9 +47,9 @@ $$; -- Data for Name: AtVersion; Type: TABLE DATA; Schema: public; Owner: atr -- -INSERT INTO "AtVersion" ("atId", "name", "releasedAt") VALUES (2, '2023.3.3', '2023-12-02'); -INSERT INTO "AtVersion" ("atId", "name", "releasedAt") VALUES (3, '13.0', '2023-12-02'); -INSERT INTO "AtVersion" ("atId", "name", "releasedAt") VALUES (3, '14.0', '2024-09-23'); +INSERT INTO "AtVersion" ("atId", "name", "releasedAt", "supportedByAutomation", "latestAutomationSupporting") VALUES (2, '2023.3.3', '2023-12-02', true, true); +INSERT INTO "AtVersion" ("atId", "name", "releasedAt", "supportedByAutomation", "latestAutomationSupporting") VALUES (3, '13.0', '2023-12-02', true, false); +INSERT INTO "AtVersion" ("atId", "name", "releasedAt", "supportedByAutomation", "latestAutomationSupporting") VALUES (3, '14.0', '2024-09-23', true, true); -- INSERT INTO "AtVersion" ("atId", "name", "releasedAt") VALUES (2, '2019.3', '2022-05-02'); diff --git a/server/util/constants.js b/server/util/constants.js index 949075a93..44ff5924c 100644 --- a/server/util/constants.js +++ b/server/util/constants.js @@ -1,18 +1,8 @@ // Mirror of constant in /client/components/TestRenderer/OutputTextArea/constants.js const NO_OUTPUT_STRING = 'No output was detected.'; -const AT_VERSIONS_SUPPORTED_BY_COLLECTION_JOBS = { - // These are tracked with the available versions in the github workflow file - // https://github.com/bocoup/aria-at-gh-actions-helper/blob/main/.github/workflows/voiceover-test.yml#L39 - // Separate workflow exists for supporting macOS 15 on self-hosted runner - // https://github.com/bocoup/aria-at-gh-actions-helper/blob/main/.github/workflows/self-hosted-macos-15.yml - 'VoiceOver for macOS': ['13.0', '14.0', '15.0'], - // These are tracked with the https://github.com/bocoup/aria-at-automation-nvda-builds/releases - NVDA: ['2025.2', '2024.4.1', '2024.1', '2023.3.3', '2023.3'], - // These are tracked and assigned URLs in - // https://github.com/bocoup/aria-at-gh-actions-helper/blob/main/JAWS/InstallJAWSUnattended.ps1 - JAWS: ['2025.2508.120'] -}; +// Deprecated: AT versions supported by jobs now stored in DB on AtVersion +const AT_VERSIONS_SUPPORTED_BY_COLLECTION_JOBS = {}; const VENDOR_NAME_TO_AT_MAPPING = { vispero: ['JAWS'], diff --git a/server/util/getAtVersionWithRequirements.js b/server/util/getAtVersionWithRequirements.js index e34f3439a..a2867a450 100644 --- a/server/util/getAtVersionWithRequirements.js +++ b/server/util/getAtVersionWithRequirements.js @@ -1,6 +1,4 @@ const { getAtVersions } = require('../models/services/AtService'); -const { AT_VERSIONS_SUPPORTED_BY_COLLECTION_JOBS } = require('./constants'); -const { utils } = require('shared'); const getAtVersionWithRequirements = async ( atId, @@ -19,31 +17,24 @@ const getAtVersionWithRequirements = async ( ); } - // Get all versions for this AT without date filtering - const matchingAtVersions = await getAtVersions({ - where: { atId }, + // Get the latest automation-supported version directly + const latestSupportedAtVersions = await getAtVersions({ + where: { + atId, + supportedByAutomation: true, + latestAutomationSupporting: true + }, transaction }); - // Sort versions by semantic version and date - const sortedVersions = utils.sortAtVersions(matchingAtVersions); - - const supportedVersions = - AT_VERSIONS_SUPPORTED_BY_COLLECTION_JOBS[sortedVersions[0]?.at?.name] || - []; - - const latestSupportedAtVersion = sortedVersions.find(atv => - supportedVersions.includes(atv.name.trim()) - ); - - if (!latestSupportedAtVersion) { + if (!latestSupportedAtVersions.length) { throw new Error( `No suitable AT version found for automation for AT ${atId} ` + `with minimumAtVersion ${minimumAtVersion?.name}` ); } - return latestSupportedAtVersion; + return latestSupportedAtVersions[0]; } catch (error) { console.error('Error while determining AT version:', error); throw error; From d3b84fce33e486483d9ba4a46236b0449b4c0981 Mon Sep 17 00:00:00 2001 From: Stalgia Grigg Date: Thu, 16 Oct 2025 08:49:59 -0700 Subject: [PATCH 2/8] Cleanup, update snaps --- .../common/AtAndBrowserDetailsModal/index.jsx | 78 ++++++++--------- client/tests/e2e/snapshots/saved/_.html | 10 +-- .../snapshots/saved/_account_settings.html | 2 +- .../e2e/snapshots/saved/_data-management.html | 87 ++++++++++++++++--- server/graphql-schema.js | 1 + .../supportedByAutomationResolver.js | 7 +- server/util/isSupportedByAutomation.js | 30 ------- 7 files changed, 116 insertions(+), 99 deletions(-) delete mode 100644 server/util/isSupportedByAutomation.js diff --git a/client/components/common/AtAndBrowserDetailsModal/index.jsx b/client/components/common/AtAndBrowserDetailsModal/index.jsx index 0fea2aa91..763d22589 100644 --- a/client/components/common/AtAndBrowserDetailsModal/index.jsx +++ b/client/components/common/AtAndBrowserDetailsModal/index.jsx @@ -365,47 +365,43 @@ const AtAndBrowserDetailsModal = ({ )} {/* Tester Scenario 3 */} - {!isFirstLoad && - !isAdmin && - forceBrowserVersionUpdateMessage && ( - - - - We have automatically detected you are using a different - version of {uaBrowser} and we have updated it - below. The previous version you were using was{' '} - {browserVersion}. -
-
- This change doesn't affect results that have - already been submitted for this plan. However, results - you submit during this session will be recorded with the - versions specified in this form. -
-
- )} - {isFirstLoad && - uaBrowser !== browserName && - uaMajor !== '0' && ( - - - - We have automatically detected you are using{' '} - - {uaBrowser} {uaMajor} - - . This test plan requires {browserName}. If you - are recording results on behalf of someone else, please - provide the Browser version below. - - - )} + {!isFirstLoad && !isAdmin && forceBrowserVersionUpdateMessage && ( + + + + We have automatically detected you are using a different + version of {uaBrowser} and we have updated it + below. The previous version you were using was{' '} + {browserVersion}. +
+
+ This change doesn't affect results that have already + been submitted for this plan. However, results you submit + during this session will be recorded with the versions + specified in this form. +
+
+ )} + {isFirstLoad && uaBrowser !== browserName && uaMajor !== '0' && ( + + + + We have automatically detected you are using{' '} + + {uaBrowser} {uaMajor} + + . This test plan requires {browserName}. If you are + recording results on behalf of someone else, please + provide the Browser version below. + + + )} {/* Tester Scenario 4 */} {!isAdmin && !isFirstLoad && diff --git a/client/tests/e2e/snapshots/saved/_.html b/client/tests/e2e/snapshots/saved/_.html index 38b5b3948..ddab7781e 100644 --- a/client/tests/e2e/snapshots/saved/_.html +++ b/client/tests/e2e/snapshots/saved/_.html @@ -84,13 +84,9 @@
- +

Enabling Interoperability for Assistive Technology Users

diff --git a/client/tests/e2e/snapshots/saved/_account_settings.html b/client/tests/e2e/snapshots/saved/_account_settings.html index d908fdbcc..baa68460e 100644 --- a/client/tests/e2e/snapshots/saved/_account_settings.html +++ b/client/tests/e2e/snapshots/saved/_account_settings.html @@ -98,7 +98,7 @@

Admin Actions

-

Date of latest test plan version: October 1, 2025 21:37 UTC

+

Date of latest test plan version: October 6, 2025 22:33 UTC

diff --git a/client/tests/e2e/snapshots/saved/_data-management.html b/client/tests/e2e/snapshots/saved/_data-management.html index 02b95d023..2cbf77858 100644 --- a/client/tests/e2e/snapshots/saved/_data-management.html +++ b/client/tests/e2e/snapshots/saved/_data-management.html @@ -276,15 +276,20 @@

- + - - - - + + + + +
@@ -384,7 +389,7 @@

Test Plans Status Summary

data-testid="filter-all" aria-pressed="true" class="filter-button btn active btn-secondary"> - All Plans (39) + All Plans (40)
  • @@ -393,7 +398,7 @@

    Test Plans Status Summary

    data-testid="filter-rd" aria-pressed="false" class="filter-button btn btn-secondary"> - R&D Complete (35) + R&D Complete (36)
  • @@ -427,7 +432,7 @@

    Test Plans Status Summary

    @@ -1197,7 +1202,7 @@

    Test Plans Status Summary

    + + + + + + + + + - + - +
    + Switch Example Using HTML Checkbox Input + +
    + JAWS, NVDA and VoiceOver for macOS +
    +
    +
    + R&D +

    Complete Oct 6, 2025

    +
    +
    +
    + V25.10.06 +
    +
    + Not Started + + Not Started + None Yet
    Tabs with Automatic ActivationTest Plans Status Summary None Yet
    Tabs with Manual ActivationTest Plans Status Summary None Yet
    Vertical Temperature SliderTest Plans Status Summary
    - +

    Enabling Interoperability for Assistive Technology Users

    diff --git a/server/graphql-schema.js b/server/graphql-schema.js index 54770442a..c7e1a6eb4 100644 --- a/server/graphql-schema.js +++ b/server/graphql-schema.js @@ -1270,8 +1270,7 @@ const graphqlSchema = gql` } """ - - """ + Records information about the review of a TestPlanReport by a vendor representative. type ReviewerStatus { """ The vendor representative who reviewed the test. From 0a1128901ca65b8de4c514634f3214d319146053 Mon Sep 17 00:00:00 2001 From: Stalgia Grigg Date: Thu, 16 Oct 2025 11:26:50 -0700 Subject: [PATCH 4/8] Fix quoting mistake in schema --- server/graphql-schema.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/graphql-schema.js b/server/graphql-schema.js index c7e1a6eb4..908af4e17 100644 --- a/server/graphql-schema.js +++ b/server/graphql-schema.js @@ -1271,6 +1271,7 @@ const graphqlSchema = gql` """ Records information about the review of a TestPlanReport by a vendor representative. + """ type ReviewerStatus { """ The vendor representative who reviewed the test. From 53d00bae94c5367bcee06577b2491ee93934382b Mon Sep 17 00:00:00 2001 From: Stalgia Grigg Date: Thu, 16 Oct 2025 11:44:47 -0700 Subject: [PATCH 5/8] AtAndBrowserDetailsModal prettier bug --- .../common/AtAndBrowserDetailsModal/index.jsx | 78 ++++++++++--------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/client/components/common/AtAndBrowserDetailsModal/index.jsx b/client/components/common/AtAndBrowserDetailsModal/index.jsx index 763d22589..0fea2aa91 100644 --- a/client/components/common/AtAndBrowserDetailsModal/index.jsx +++ b/client/components/common/AtAndBrowserDetailsModal/index.jsx @@ -365,43 +365,47 @@ const AtAndBrowserDetailsModal = ({ )} {/* Tester Scenario 3 */} - {!isFirstLoad && !isAdmin && forceBrowserVersionUpdateMessage && ( - - - - We have automatically detected you are using a different - version of {uaBrowser} and we have updated it - below. The previous version you were using was{' '} - {browserVersion}. -
    -
    - This change doesn't affect results that have already - been submitted for this plan. However, results you submit - during this session will be recorded with the versions - specified in this form. -
    -
    - )} - {isFirstLoad && uaBrowser !== browserName && uaMajor !== '0' && ( - - - - We have automatically detected you are using{' '} - - {uaBrowser} {uaMajor} - - . This test plan requires {browserName}. If you are - recording results on behalf of someone else, please - provide the Browser version below. - - - )} + {!isFirstLoad && + !isAdmin && + forceBrowserVersionUpdateMessage && ( + + + + We have automatically detected you are using a different + version of {uaBrowser} and we have updated it + below. The previous version you were using was{' '} + {browserVersion}. +
    +
    + This change doesn't affect results that have + already been submitted for this plan. However, results + you submit during this session will be recorded with the + versions specified in this form. +
    +
    + )} + {isFirstLoad && + uaBrowser !== browserName && + uaMajor !== '0' && ( + + + + We have automatically detected you are using{' '} + + {uaBrowser} {uaMajor} + + . This test plan requires {browserName}. If you + are recording results on behalf of someone else, please + provide the Browser version below. + + + )} {/* Tester Scenario 4 */} {!isAdmin && !isFirstLoad && From 538829eaedcafecae14934b7838ff5a3abe4e06c Mon Sep 17 00:00:00 2001 From: Stalgia Grigg Date: Thu, 16 Oct 2025 13:26:56 -0700 Subject: [PATCH 6/8] Add tests --- server/models/services/AtVersionService.js | 16 +- server/tests/models/AtVersion.spec.js | 9 +- .../tests/models/services/AtService.test.js | 155 ++++++++++++++++++ 3 files changed, 177 insertions(+), 3 deletions(-) diff --git a/server/models/services/AtVersionService.js b/server/models/services/AtVersionService.js index 32fb55631..61e4ce6be 100644 --- a/server/models/services/AtVersionService.js +++ b/server/models/services/AtVersionService.js @@ -186,13 +186,25 @@ const getAtVersionByQuery = async ({ * @returns {Promise<*>} */ const createAtVersion = async ({ - values: { atId, name, releasedAt }, + values: { + atId, + name, + releasedAt, + supportedByAutomation = false, + latestAutomationSupporting = false + }, atVersionAttributes = AT_VERSION_ATTRIBUTES, atAttributes = AT_ATTRIBUTES, transaction }) => { await ModelService.create(AtVersion, { - values: { atId, name, releasedAt }, + values: { + atId, + name, + releasedAt, + supportedByAutomation, + latestAutomationSupporting + }, transaction }); return ModelService.getByQuery(AtVersion, { diff --git a/server/tests/models/AtVersion.spec.js b/server/tests/models/AtVersion.spec.js index c4725f3c7..b639e0675 100644 --- a/server/tests/models/AtVersion.spec.js +++ b/server/tests/models/AtVersion.spec.js @@ -18,7 +18,14 @@ describe('AtVersionModel', () => { describe('properties', () => { // A3 - ['id', 'atId', 'name'].forEach(checkPropertyExists(modelInstance)); + [ + 'id', + 'atId', + 'name', + 'releasedAt', + 'supportedByAutomation', + 'latestAutomationSupporting' + ].forEach(checkPropertyExists(modelInstance)); }); describe('associations', () => { diff --git a/server/tests/models/services/AtService.test.js b/server/tests/models/services/AtService.test.js index 92b0d313f..4a4500d50 100644 --- a/server/tests/models/services/AtService.test.js +++ b/server/tests/models/services/AtService.test.js @@ -564,4 +564,159 @@ describe('AtVersionModel Data Checks', () => { }) ); }); + + it('should have supportedByAutomation and latestAutomationSupporting flags', async () => { + // A1 + const _id = 1; + + // A2 + const atVersion = await AtVersionService.getAtVersionById({ + id: _id, + transaction: false + }); + + // A3 + expect(atVersion).toHaveProperty('supportedByAutomation'); + expect(atVersion).toHaveProperty('latestAutomationSupporting'); + expect(typeof atVersion.supportedByAutomation).toBe('boolean'); + expect(typeof atVersion.latestAutomationSupporting).toBe('boolean'); + }); + + it('should promote an atVersion to automation supported', async () => { + await dbCleaner(async transaction => { + // A1 + const _atId = 1; + const _atVersion = randomStringGenerator(); + const _releasedAt = new Date('2022-05-01 20:00:00-04'); + + // A2 + const atVersionInstance = await AtVersionService.createAtVersion({ + values: { + atId: _atId, + name: _atVersion, + releasedAt: _releasedAt + }, + transaction + }); + const { id } = atVersionInstance; + + // A3 + const promoted = await AtVersionService.promoteAutomationSupportedVersion( + { + atVersionId: id, + transaction + } + ); + + // A4 + expect(promoted).not.toBeNull(); + expect(promoted.supportedByAutomation).toBe(true); + expect(promoted.latestAutomationSupporting).toBe(true); + }); + }); + + it('should handle promoting an already-promoted atVersion', async () => { + await dbCleaner(async transaction => { + // A1 + const _atId = 1; + const _atVersion = randomStringGenerator(); + const _releasedAt = new Date('2022-05-01 20:00:00-04'); + + // A2 + const atVersionInstance = await AtVersionService.createAtVersion({ + values: { + atId: _atId, + name: _atVersion, + releasedAt: _releasedAt, + supportedByAutomation: true, + latestAutomationSupporting: true + }, + transaction + }); + const { id } = atVersionInstance; + + // A3 + const promoted = await AtVersionService.promoteAutomationSupportedVersion( + { + atVersionId: id, + transaction + } + ); + + // A4 + expect(promoted).not.toBeNull(); + expect(promoted.supportedByAutomation).toBe(true); + expect(promoted.latestAutomationSupporting).toBe(true); + }); + }); + + it('should demote other versions when promoting a new latest', async () => { + await dbCleaner(async transaction => { + // A1 + const _atId = 1; + const _firstVersion = randomStringGenerator(); + const _secondVersion = randomStringGenerator(); + const _releasedAt1 = new Date('2022-05-01 20:00:00-04'); + const _releasedAt2 = new Date('2022-06-01 20:00:00-04'); + + // A2 + const firstVersion = await AtVersionService.createAtVersion({ + values: { + atId: _atId, + name: _firstVersion, + releasedAt: _releasedAt1, + supportedByAutomation: true, + latestAutomationSupporting: true + }, + transaction + }); + + const secondVersion = await AtVersionService.createAtVersion({ + values: { + atId: _atId, + name: _secondVersion, + releasedAt: _releasedAt2, + supportedByAutomation: false, + latestAutomationSupporting: false + }, + transaction + }); + + // A3 + const promoted = await AtVersionService.promoteAutomationSupportedVersion( + { + atVersionId: secondVersion.id, + transaction + } + ); + + // A4 + const demoted = await AtVersionService.getAtVersionById({ + id: firstVersion.id, + transaction + }); + + expect(promoted.latestAutomationSupporting).toBe(true); + expect(demoted.latestAutomationSupporting).toBe(false); + expect(demoted.supportedByAutomation).toBe(true); + }); + }); + + it('should return null when promoting non-existent atVersion', async () => { + await dbCleaner(async transaction => { + // A1 + const nonExistentId = 999999; + + // A2 + const promoted = await AtVersionService.promoteAutomationSupportedVersion( + { + atVersionId: nonExistentId, + transaction + } + ); + + // A3 + expect(promoted).toBeNull(); + }); + }); }); From 088b9e49cca38ff1b81d7c15a1717abbab1e74be Mon Sep 17 00:00:00 2001 From: Stalgia Grigg Date: Thu, 16 Oct 2025 13:46:22 -0700 Subject: [PATCH 7/8] Update documentation --- docs/adding-at-automation-version.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/adding-at-automation-version.md b/docs/adding-at-automation-version.md index 50d1d2f19..ba4a295dc 100644 --- a/docs/adding-at-automation-version.md +++ b/docs/adding-at-automation-version.md @@ -61,18 +61,19 @@ This document describes the process for adding a new version of an AT to the ARI ## Update Aria-AT App -Note that these steps are required for both NVDA and VoiceOver - -1. Update the supported versions constant in the aria-at-app: - - `AT_VERSIONS_SUPPORTED_BY_COLLECTION_JOBS` in [server/util/constants.js](https://github.com/w3c/aria-at-app/blob/development/server/util/constants.js#L4) -2. Update the relevant deployment -3. Create and deploy a new release of the aria-at-app to production -4. Log in to the ARIA-AT App as an administrator -5. Navigate to the "Test Queue" page -6. Click "Manage Assistive Technology Versions" -7. If the new AT version is not listed: - 1. Click "Add New AT Version" - 2. Enter the version number and available date - 3. Save the new version +There are two ways to add a new automation-supported AT version to the ARIA-AT App. + +Note that these steps are required for NVDA and JAWS. VoiceOver will automatically be marked as latest and automation-supported when the first bot run completes with the new version. + +### Option A: Add a seeder\*\* + +- Create a new seeder file in `server/seeders/` to mark the version as supported +- Go through the process of deploying the changes to the ARIA-AT App + +### Option B: Use GraphQL Playground\*\* + +1. Navigate to the GraphQL playground in your deployed environment +2. Use the `createAtVersion` mutation to add the new version +3. Use the `promoteAutomationSupportedVersion` mutation to mark the version as latest automation-supported The new AT version is now fully configured and ready for use in ARIA-AT App. From 3f6a7a0796b1f8c1a1ff9e409ac1245dad959ad7 Mon Sep 17 00:00:00 2001 From: Stalgia Grigg Date: Thu, 16 Oct 2025 13:51:08 -0700 Subject: [PATCH 8/8] Remove deprecated const --- server/util/constants.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/server/util/constants.js b/server/util/constants.js index 44ff5924c..410e7e630 100644 --- a/server/util/constants.js +++ b/server/util/constants.js @@ -1,9 +1,6 @@ // Mirror of constant in /client/components/TestRenderer/OutputTextArea/constants.js const NO_OUTPUT_STRING = 'No output was detected.'; -// Deprecated: AT versions supported by jobs now stored in DB on AtVersion -const AT_VERSIONS_SUPPORTED_BY_COLLECTION_JOBS = {}; - const VENDOR_NAME_TO_AT_MAPPING = { vispero: ['JAWS'], nvAccess: ['NVDA'], @@ -12,6 +9,5 @@ const VENDOR_NAME_TO_AT_MAPPING = { module.exports = { NO_OUTPUT_STRING, - AT_VERSIONS_SUPPORTED_BY_COLLECTION_JOBS, VENDOR_NAME_TO_AT_MAPPING };