Skip to content

fix(accessibility): reject unknown audit types before they reach the device - #306

Open
navin772 wants to merge 1 commit into
appium:mainfrom
navin772:fix-aa
Open

fix(accessibility): reject unknown audit types before they reach the device#306
navin772 wants to merge 1 commit into
appium:mainfrom
navin772:fix-aa

Conversation

@navin772

Copy link
Copy Markdown
Member

An audit type the daemon doesn't implement makes it return neither issues nor a completion, and that connection can never run another audit, the service looks alive (getApiVersion still works) while every runAudit times out.

runAudit now validates against getSupportedAuditTypes() and throws locally, caching the list per connection. Matching is exact: wrong case, surrounding whitespace and a bare testType prefix all wedge the daemon too. An empty list still passes through, the device reads it as "every type".

this.auditTypeNames ??= new Set(await this.getSupportedAuditTypes(options));
const unknown = auditTypes.filter((auditType) => !this.auditTypeNames?.has(auditType));
if (unknown.length > 0) {
throw new Error(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can it ever happen that this.auditTypeNames is empty?

const unknown = auditTypes.filter((auditType) => !this.auditTypeNames?.has(auditType));
if (unknown.length > 0) {
throw new Error(
`Unknown audit type(s) ${unknown.map((auditType) => JSON.stringify(auditType)).join(', ')}; ` +

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider using util.pluralize

: undefined;

try {
await this.assertKnownAuditTypes(auditTypes, options);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont forward options here...

the caller's audit-completion timeoutMs becomes the reply timeout for the deviceAllSupportedAuditTypes invoke (overriding the 15s transport default), so a long audit budget can block minutes in pre-flight and total wait approaches 2× timeoutMs.


it('rejects an unknown setting identifier instead of silently doing nothing', async function () {
it('rejects an unknown setting identifier instead of silently doing nothing', async function (t) {
if (skipWithoutSettingWrites(t)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three tests reject client side before the write selector is ever invoked, so they shouldnt be skipped behind skipWithoutSettingWrites


/** Reports why a test is being skipped, or null when it may run. */
async function skipReason(): Promise<string | null> {
if (!supportsSettingWrites) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this gates on deviceUpdateAccessibilitySetting
but 2-3 tests only use deviceUpdateAccessibilitySetting gates on reset selector.

may be add the write only for clear session override selector

];

for (const [label, auditTypes] of POISON) {
it(`rejects ${label} without contacting the device`, async function () {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on a cold cacge the first rejection doesnt contact the device here

await assert.rejects(() => service!.runAudit([types[0], 'bogusType'], {timeoutMs: 20000}), /Unknown audit type/);
});

it('still accepts an empty list, which the device reads as every type', async function () {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this duplicates above test in file "accepts an empty audit-type list without hanging"

});

it('leaves the connection usable after a rejected audit', async function (t) {
const types = await service!.getSupportedAuditTypes();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The recovery audit only needs to prove the connection still works. the purpose of test is only checks that the connection still works after a rejection, checkignf for all is a time waste

may be

it('leaves the connection usable after a rejected audit', async function () {
  await assert.rejects(
    service!.runAudit(['nopeNotAType'], {timeoutMs: 20000}),
    /Unknown audit type/,
  );
  const issues = await service!.runAudit(['testTypeContrast'], {timeoutMs: 60000});
  assert.ok(Array.isArray(issues));
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants