# Copyright (c) Microsoft Corporation. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import sys import pytest from playwright.async_api import Page async def test_accessibility_should_work(page: Page, is_firefox: bool, is_chromium: bool) -> None: await page.set_content( """ Accessibility Test

Inputs

""" ) # autofocus happens after a delay in chrome these days await page.wait_for_function("document.activeElement.hasAttribute('autofocus')") if is_firefox: golden = { "role": "document", "name": "Accessibility Test", "children": [ {"role": "heading", "name": "Inputs", "level": 1}, {"role": "textbox", "name": "Empty input", "focused": True}, {"role": "textbox", "name": "readonly input", "readonly": True}, {"role": "textbox", "name": "disabled input", "disabled": True}, {"role": "textbox", "name": "Input with whitespace", "value": " "}, {"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", "description": "This is a description!", }, # and here ], } elif is_chromium: golden = { "role": "WebArea", "name": "Accessibility Test", "children": [ {"role": "heading", "name": "Inputs", "level": 1}, {"role": "textbox", "name": "Empty input", "focused": True}, {"role": "textbox", "name": "readonly input", "readonly": True}, {"role": "textbox", "name": "disabled input", "disabled": True}, {"role": "textbox", "name": "Input with whitespace", "value": " "}, {"role": "textbox", "name": "", "value": "value only"}, {"role": "textbox", "name": "placeholder", "value": "and a value"}, { "role": "textbox", "name": "placeholder", "value": "and a value", "description": "This is a description!", }, ], } else: golden = { "role": "WebArea", "name": "Accessibility Test", "children": [ {"role": "heading", "name": "Inputs", "level": 1}, {"role": "textbox", "name": "Empty input", "focused": True}, {"role": "textbox", "name": "readonly input", "readonly": True}, {"role": "textbox", "name": "disabled input", "disabled": True}, {"role": "textbox", "name": "Input with whitespace", "value": " "}, {"role": "textbox", "name": "", "value": "value only"}, {"role": "textbox", "name": "placeholder", "value": "and a value"}, { "role": "textbox", "name": ( "placeholder" if ( sys.platform == "darwin" and int(os.uname().release.split(".")[0]) >= 21 ) else "This is a description!" ), "value": "and a value", }, # webkit uses the description over placeholder for the name ], } assert await page.accessibility.snapshot() == golden async def test_accessibility_should_work_with_regular_text(page: Page, is_firefox: bool) -> None: await page.set_content("
Hello World
") snapshot = await page.accessibility.snapshot() assert snapshot assert snapshot["children"][0] == { "role": "text leaf" if is_firefox else "text", "name": "Hello World", } async def test_accessibility_roledescription(page: Page) -> None: await page.set_content('

Hi

') snapshot = await page.accessibility.snapshot() assert snapshot assert snapshot["children"][0]["roledescription"] == "foo" async def test_accessibility_orientation(page: Page) -> None: await page.set_content('11') snapshot = await page.accessibility.snapshot() assert snapshot assert snapshot["children"][0]["orientation"] == "vertical" async def test_accessibility_autocomplete(page: Page) -> None: await page.set_content('
hi
') snapshot = await page.accessibility.snapshot() assert snapshot assert snapshot["children"][0]["autocomplete"] == "list" async def test_accessibility_multiselectable(page: Page) -> None: await page.set_content('
hey
') snapshot = await page.accessibility.snapshot() assert snapshot assert snapshot["children"][0]["multiselectable"] async def test_accessibility_keyshortcuts(page: Page) -> None: await page.set_content('
hey
') snapshot = await page.accessibility.snapshot() assert snapshot assert snapshot["children"][0]["keyshortcuts"] == "foo" async def test_accessibility_filtering_children_of_leaf_nodes_should_not_report_text_nodes_inside_controls( page: Page, is_firefox: bool ) -> None: await page.set_content( """
Tab1
Tab2
""" ) golden = { "role": "document" if is_firefox else "WebArea", "name": "", "children": [ {"role": "tab", "name": "Tab1", "selected": True}, {"role": "tab", "name": "Tab2"}, ], } assert await page.accessibility.snapshot() == golden # Firefox does not support contenteditable="plaintext-only". # WebKit rich text accessibility is iffy @pytest.mark.only_browser("chromium") async def test_accessibility_plain_text_field_with_role_should_not_have_children( page: Page, ) -> None: await page.set_content( """
Edit this image:my fake image
""" ) snapshot = await page.accessibility.snapshot() assert snapshot assert snapshot["children"][0] == { "multiline": True, "name": "", "role": "textbox", "value": "Edit this image:", } @pytest.mark.only_browser("chromium") async def test_accessibility_plain_text_field_without_role_should_not_have_content( page: Page, ) -> None: await page.set_content( """
Edit this image:my fake image
""" ) snapshot = await page.accessibility.snapshot() assert snapshot assert snapshot["children"][0] == { "name": "", "role": "generic", "value": "Edit this image:", } @pytest.mark.only_browser("chromium") async def test_accessibility_plain_text_field_with_tabindex_and_without_role_should_not_have_content( page: Page, ) -> None: await page.set_content( """
Edit this image:my fake image
""" ) snapshot = await page.accessibility.snapshot() assert snapshot assert snapshot["children"][0] == { "name": "", "role": "generic", "value": "Edit this image:", } async def test_accessibility_non_editable_textbox_with_role_and_tabIndex_and_label_should_not_have_children( page: Page, is_chromium: bool, is_firefox: bool ) -> None: await page.set_content( """
this is the inner content yo
""" ) if is_firefox: golden = { "role": "textbox", "name": "my favorite textbox", "value": "this is the inner content yo", } elif is_chromium: golden = { "role": "textbox", "name": "my favorite textbox", "value": "this is the inner content ", } else: golden = { "role": "textbox", "name": "my favorite textbox", "value": "this is the inner content ", } snapshot = await page.accessibility.snapshot() assert snapshot assert snapshot["children"][0] == golden async def test_accessibility_checkbox_with_and_tabIndex_and_label_should_not_have_children( page: Page, ) -> None: await page.set_content( """
this is the inner content yo
""" ) golden = {"role": "checkbox", "name": "my favorite checkbox", "checked": True} snapshot = await page.accessibility.snapshot() assert snapshot assert snapshot["children"][0] == golden async def test_accessibility_checkbox_without_label_should_not_have_children( page: Page, is_firefox: bool ) -> None: await page.set_content( """
this is the inner content yo
""" ) golden = { "role": "checkbox", "name": "this is the inner content yo", "checked": True, } snapshot = await page.accessibility.snapshot() assert snapshot assert snapshot["children"][0] == golden async def test_accessibility_should_work_a_button(page: Page) -> None: await page.set_content("") button = await page.query_selector("button") assert await page.accessibility.snapshot(root=button) == { "role": "button", "name": "My Button", } async def test_accessibility_should_work_an_input(page: Page) -> None: await page.set_content('') input = await page.query_selector("input") assert await page.accessibility.snapshot(root=input) == { "role": "textbox", "name": "My Input", "value": "My Value", } async def test_accessibility_should_work_on_a_menu(page: Page) -> None: await page.set_content( """
First Item
Second Item
Third Item
""" ) menu = await page.query_selector('div[role="menu"]') golden = { "role": "menu", "name": "My Menu", "children": [ {"role": "menuitem", "name": "First Item"}, {"role": "menuitem", "name": "Second Item"}, {"role": "menuitem", "name": "Third Item"}, ], } actual = await page.accessibility.snapshot(root=menu) assert actual # Different per browser channel if "orientation" in actual: del actual["orientation"] assert actual == golden async def test_accessibility_should_return_null_when_the_element_is_no_longer_in_DOM( page: Page, ) -> None: await page.set_content("") button = await page.query_selector("button") await page.eval_on_selector("button", "button => button.remove()") assert await page.accessibility.snapshot(root=button) is None async def test_accessibility_should_show_uninteresting_nodes(page: Page) -> None: await page.set_content( """
hello
world
""" ) root = await page.query_selector("#root") snapshot = await page.accessibility.snapshot(root=root, interesting_only=False) assert snapshot assert snapshot["role"] == "textbox" assert "hello" in snapshot["value"] assert "world" in snapshot["value"] assert snapshot["children"]