mac normalize stuff

This commit is contained in:
Joel Einbinder 2020-01-14 15:17:41 -08:00 committed by Joel Einbinder
parent 36b77efdc0
commit 9681b8bca3
2 changed files with 56 additions and 21 deletions

View file

@ -68,7 +68,7 @@ class WKAXNode implements accessibility.AXNode {
return this._children; return this._children;
} }
_findNeedle() : WKAXNode { _findNeedle() : WKAXNode | null {
if (this._payload.found) if (this._payload.found)
return this; return this;
for (const child of this._children) { for (const child of this._children) {
@ -108,8 +108,26 @@ class WKAXNode implements accessibility.AXNode {
} }
} }
_isTextControl() : boolean {
switch (this._payload.role) {
case 'combobox':
case 'searchfield':
case 'textbox':
case 'TextField':
return true;
}
return false;
}
_name() : string {
if (this._payload.role === 'text')
return this._payload.value || '';
return this._payload.name || '';
}
isInteresting(insideControl: boolean) : boolean { isInteresting(insideControl: boolean) : boolean {
const {role, focusable, name} = this._payload; const {role, focusable} = this._payload;
const name = this._name();
if (role === 'ScrollArea') if (role === 'ScrollArea')
return false; return false;
if (role === 'WebArea') if (role === 'WebArea')
@ -129,14 +147,29 @@ class WKAXNode implements accessibility.AXNode {
return this.isLeafNode() && !!name; return this.isLeafNode() && !!name;
} }
_hasRendundantTextChild() {
if (this._children.length !== 1)
return false;
const child = this._children[0];
return child._payload.role === 'text' && this._payload.name === child._payload.value;
}
isLeafNode() : boolean { isLeafNode() : boolean {
return !this._children.length; if (!this._children.length)
return true;
// WebKit on Linux ignores everything inside text controls, normalize this behavior
if (this._isTextControl())
return true;
// WebKit for mac has text nodes inside heading, li, menuitem, a, and p nodes
if (this._hasRendundantTextChild())
return true;
return false;
} }
serialize(): accessibility.SerializedAXNode { serialize(): accessibility.SerializedAXNode {
const node : accessibility.SerializedAXNode = { const node : accessibility.SerializedAXNode = {
role: WKRoleToARIARole.get(this._payload.role) || this._payload.role, role: WKRoleToARIARole.get(this._payload.role) || this._payload.role,
name: this._payload.name || '', name: this._name(),
}; };
if ('description' in this._payload && this._payload.description !== node.name) if ('description' in this._payload && this._payload.description !== node.name)
@ -148,13 +181,15 @@ class WKAXNode implements accessibility.AXNode {
node.roledescription = roledescription; node.roledescription = roledescription;
} }
if ('value' in this._payload && this._payload.role !== 'text')
node.value = this._payload.value;
type AXPropertyOfType<Type> = { type AXPropertyOfType<Type> = {
[Key in keyof Protocol.Page.AXNode]: [Key in keyof Protocol.Page.AXNode]:
Protocol.Page.AXNode[Key] extends Type ? Key : never Protocol.Page.AXNode[Key] extends Type ? Key : never
}[keyof Protocol.Page.AXNode]; }[keyof Protocol.Page.AXNode];
const userStringProperties: string[] = [ const userStringProperties: string[] = [
'value',
'keyshortcuts', 'keyshortcuts',
'valuetext' 'valuetext'
]; ];

View file

@ -37,10 +37,6 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
<input aria-placeholder="placeholder" value="and a value" /> <input aria-placeholder="placeholder" value="and a value" />
<div aria-hidden="true" id="desc">This is a description!</div> <div aria-hidden="true" id="desc">This is a description!</div>
<input aria-placeholder="placeholder" value="and a value" aria-describedby="desc" /> <input aria-placeholder="placeholder" value="and a value" aria-describedby="desc" />
<select>
<option>First Option</option>
<option>Second Option</option>
</select>
</body>`); </body>`);
// autofocus happens after a delay in chrome these days // autofocus happens after a delay in chrome these days
await page.waitForFunction(() => document.activeElement.hasAttribute('autofocus')); await page.waitForFunction(() => document.activeElement.hasAttribute('autofocus'));
@ -58,10 +54,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
{role: 'textbox', name: '', value: 'value only'}, {role: 'textbox', name: '', value: 'value only'},
{role: 'textbox', name: '', value: 'and a value'}, // firefox doesn't use aria-placeholder for the name {role: 'textbox', name: '', value: 'and a value'}, // firefox doesn't use aria-placeholder for the name
{role: 'textbox', name: '', value: 'and a value', description: 'This is a description!'}, // and here {role: 'textbox', name: '', value: 'and a value', description: 'This is a description!'}, // and here
{role: 'combobox', name: '', value: 'First Option', haspopup: true, children: [ ]
{role: 'combobox option', name: 'First Option', selected: true},
{role: 'combobox option', name: 'Second Option'}]
}]
} : CHROMIUM ? { } : CHROMIUM ? {
role: 'WebArea', role: 'WebArea',
name: 'Accessibility Test', name: 'Accessibility Test',
@ -75,14 +68,12 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
{role: 'textbox', name: '', value: 'value only'}, {role: 'textbox', name: '', value: 'value only'},
{role: 'textbox', name: 'placeholder', value: 'and a value'}, {role: 'textbox', name: 'placeholder', value: 'and a value'},
{role: 'textbox', name: 'placeholder', value: 'and a value', description: 'This is a description!'}, {role: 'textbox', name: 'placeholder', value: 'and a value', description: 'This is a description!'},
{role: 'combobox', name: '', value: 'First Option', children: [ ]
{role: 'menuitem', name: 'First Option', selected: true},
{role: 'menuitem', name: 'Second Option'}]
}]
} : { } : {
role: 'WebArea', role: 'WebArea',
name: 'Accessibility Test', name: 'Accessibility Test',
children: [ children: [
{role: 'text', name: 'Hello World'},
{role: 'heading', name: 'Inputs', level: 1}, {role: 'heading', name: 'Inputs', level: 1},
{role: 'textbox', name: 'Empty input', focused: true}, {role: 'textbox', name: 'Empty input', focused: true},
{role: 'textbox', name: 'readonly input', readonly: true}, {role: 'textbox', name: 'readonly input', readonly: true},
@ -91,10 +82,6 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
{role: 'textbox', name: '', value: 'value only' }, {role: 'textbox', name: '', value: 'value only' },
{role: 'textbox', name: 'placeholder',value: 'and a value'}, {role: 'textbox', name: 'placeholder',value: 'and a value'},
{role: 'textbox', name: 'This is a description!',value: 'and a value'}, // webkit uses the description over placeholder for the name {role: 'textbox', name: 'This is a description!',value: 'and a value'}, // webkit uses the description over placeholder for the name
{role: 'button', name: '', value: 'First Option', children: [
{ role: 'MenuListOption', name: '', value: 'First Option', selected: true },
{ role: 'MenuListOption', name: '', value: 'Second Option' }]
}
] ]
}; };
expect(await page.accessibility.snapshot()).toEqual(golden); expect(await page.accessibility.snapshot()).toEqual(golden);
@ -338,6 +325,19 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
await page.$eval('button', button => button.remove()); await page.$eval('button', button => button.remove());
expect(await page.accessibility.snapshot({root: button})).toEqual(null); expect(await page.accessibility.snapshot({root: button})).toEqual(null);
}); });
it('should show uninteresting nodes', async({page}) => {
await page.setContent(`
<div id="root" role="textbox">
<div>hi</div>
</div>
`);
const root = await page.$('#root');
const snapshot = await page.accessibility.snapshot({root, interestingOnly: false});
expect(snapshot.role).toBe('textbox');
expect(snapshot.value).toBe('hi');
expect(!!snapshot.children).toBe(true);
});
}); });
}); });
function findFocusedNode(node) { function findFocusedNode(node) {