From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- accessible/tests/browser/.eslintrc.js | 218 ++ accessible/tests/browser/browser.ini | 17 + .../browser/browser_shutdown_multi_reference.js | 48 + .../browser_shutdown_parent_own_reference.js | 72 + .../browser_shutdown_remote_no_reference.js | 48 + .../tests/browser/browser_shutdown_remote_only.js | 40 + .../browser_shutdown_remote_own_reference.js | 75 + .../browser/browser_shutdown_scope_lifecycle.js | 21 + .../browser/browser_shutdown_start_restart.js | 41 + accessible/tests/browser/e10s/browser.ini | 51 + .../browser/e10s/browser_caching_attributes.js | 117 + .../browser/e10s/browser_caching_description.js | 164 ++ .../tests/browser/e10s/browser_caching_name.js | 434 ++++ .../browser/e10s/browser_caching_relations.js | 86 + .../tests/browser/e10s/browser_caching_states.js | 120 + .../tests/browser/e10s/browser_caching_value.js | 155 ++ .../tests/browser/e10s/browser_events_caretmove.js | 21 + .../tests/browser/e10s/browser_events_hide.js | 35 + .../tests/browser/e10s/browser_events_show.js | 17 + .../browser/e10s/browser_events_statechange.js | 62 + .../browser/e10s/browser_events_textchange.js | 74 + .../browser/e10s/browser_treeupdate_ariadialog.js | 43 + .../browser/e10s/browser_treeupdate_ariaowns.js | 318 +++ .../browser/e10s/browser_treeupdate_canvas.js | 25 + .../browser/e10s/browser_treeupdate_cssoverflow.js | 64 + .../tests/browser/e10s/browser_treeupdate_doc.js | 312 +++ .../browser/e10s/browser_treeupdate_gencontent.js | 78 + .../browser/e10s/browser_treeupdate_hidden.js | 30 + .../browser/e10s/browser_treeupdate_imagemap.js | 176 ++ .../tests/browser/e10s/browser_treeupdate_list.js | 43 + .../e10s/browser_treeupdate_list_editabledoc.js | 39 + .../browser/e10s/browser_treeupdate_listener.js | 29 + .../browser/e10s/browser_treeupdate_optgroup.js | 91 + .../browser/e10s/browser_treeupdate_removal.js | 39 + .../tests/browser/e10s/browser_treeupdate_table.js | 51 + .../browser/e10s/browser_treeupdate_textleaf.js | 35 + .../browser/e10s/browser_treeupdate_visibility.js | 196 ++ .../browser/e10s/browser_treeupdate_whitespace.js | 71 + .../browser/e10s/doc_treeupdate_ariadialog.html | 23 + .../browser/e10s/doc_treeupdate_ariaowns.html | 44 + .../browser/e10s/doc_treeupdate_imagemap.html | 21 + .../browser/e10s/doc_treeupdate_removal.xhtml | 11 + .../browser/e10s/doc_treeupdate_visibility.html | 78 + .../browser/e10s/doc_treeupdate_whitespace.html | 10 + accessible/tests/browser/e10s/events.js | 127 ++ accessible/tests/browser/e10s/head.js | 84 + accessible/tests/browser/head.js | 116 + accessible/tests/browser/shared-head.js | 229 ++ accessible/tests/crashtests/448064.xhtml | 73 + accessible/tests/crashtests/471493.xul | 35 + accessible/tests/crashtests/crashtests.list | 3 + accessible/tests/mochitest/a11y.ini | 17 + accessible/tests/mochitest/actions.js | 187 ++ accessible/tests/mochitest/actions/a11y.ini | 18 + .../tests/mochitest/actions/test_anchors.html | 150 ++ accessible/tests/mochitest/actions/test_aria.html | 202 ++ .../tests/mochitest/actions/test_controls.html | 109 + .../tests/mochitest/actions/test_general.html | 107 + .../tests/mochitest/actions/test_general.xul | 145 ++ accessible/tests/mochitest/actions/test_keys.html | 60 + .../tests/mochitest/actions/test_keys_menu.xul | 99 + accessible/tests/mochitest/actions/test_link.html | 147 ++ accessible/tests/mochitest/actions/test_media.html | 121 + .../tests/mochitest/actions/test_select.html | 105 + accessible/tests/mochitest/actions/test_tree.xul | 128 ++ .../tests/mochitest/actions/test_treegrid.xul | 197 ++ accessible/tests/mochitest/aom/a11y.ini | 3 + accessible/tests/mochitest/aom/test_general.html | 55 + accessible/tests/mochitest/attributes.js | 382 ++++ accessible/tests/mochitest/attributes/a11y.ini | 12 + .../tests/mochitest/attributes/test_obj.html | 278 +++ .../tests/mochitest/attributes/test_obj_css.html | 231 ++ .../tests/mochitest/attributes/test_obj_css.xul | 73 + .../tests/mochitest/attributes/test_obj_group.html | 469 ++++ .../tests/mochitest/attributes/test_obj_group.xul | 216 ++ .../mochitest/attributes/test_obj_group_tree.xul | 85 + .../tests/mochitest/attributes/test_tag.html | 82 + .../tests/mochitest/attributes/test_xml-roles.html | 251 +++ accessible/tests/mochitest/autocomplete.js | 221 ++ accessible/tests/mochitest/bounds/a11y.ini | 8 + accessible/tests/mochitest/bounds/test_list.html | 81 + accessible/tests/mochitest/bounds/test_select.html | 85 + accessible/tests/mochitest/bounds/test_zoom.html | 96 + .../tests/mochitest/bounds/test_zoom_text.html | 77 + accessible/tests/mochitest/browser.js | 153 ++ accessible/tests/mochitest/common.js | 952 ++++++++ accessible/tests/mochitest/dumbfile.zip | Bin 0 -> 22 bytes accessible/tests/mochitest/editabletext/a11y.ini | 7 + .../tests/mochitest/editabletext/editabletext.js | 353 +++ .../tests/mochitest/editabletext/test_1.html | 144 ++ .../tests/mochitest/editabletext/test_2.html | 63 + accessible/tests/mochitest/elm/a11y.ini | 16 + accessible/tests/mochitest/elm/test_HTMLSpec.html | 1671 ++++++++++++++ .../tests/mochitest/elm/test_MathMLSpec.html | 620 ++++++ accessible/tests/mochitest/elm/test_canvas.html | 58 + accessible/tests/mochitest/elm/test_figure.html | 62 + accessible/tests/mochitest/elm/test_listbox.xul | 74 + .../tests/mochitest/elm/test_nsApplicationAcc.html | 75 + accessible/tests/mochitest/elm/test_plugin.html | 79 + .../tests/mochitest/elm/test_shadowroot.html | 60 + accessible/tests/mochitest/events.js | 2329 ++++++++++++++++++++ accessible/tests/mochitest/events/a11y.ini | 67 + accessible/tests/mochitest/events/docload_wnd.html | 39 + accessible/tests/mochitest/events/focus.html | 10 + accessible/tests/mochitest/events/scroll.html | 181 ++ .../tests/mochitest/events/test_aria_alert.html | 92 + .../tests/mochitest/events/test_aria_menu.html | 285 +++ .../tests/mochitest/events/test_aria_objattr.html | 118 + .../tests/mochitest/events/test_aria_owns.html | 129 ++ .../mochitest/events/test_aria_statechange.html | 208 ++ accessible/tests/mochitest/events/test_attrs.html | 90 + .../tests/mochitest/events/test_bug1322593-2.html | 83 + .../tests/mochitest/events/test_bug1322593.html | 80 + .../tests/mochitest/events/test_caretmove.html | 140 ++ .../tests/mochitest/events/test_caretmove.xul | 72 + .../tests/mochitest/events/test_coalescence.html | 864 ++++++++ .../tests/mochitest/events/test_contextmenu.html | 139 ++ .../tests/mochitest/events/test_descrchange.html | 85 + .../tests/mochitest/events/test_docload.html | 360 +++ accessible/tests/mochitest/events/test_docload.xul | 243 ++ .../tests/mochitest/events/test_docload_aria.html | 83 + .../tests/mochitest/events/test_dragndrop.html | 110 + accessible/tests/mochitest/events/test_flush.html | 77 + .../events/test_focus_aria_activedescendant.html | 120 + .../mochitest/events/test_focus_autocomplete.xul | 518 +++++ .../mochitest/events/test_focus_browserui.xul | 149 ++ .../tests/mochitest/events/test_focus_canvas.html | 61 + .../mochitest/events/test_focus_contextmenu.xul | 99 + .../mochitest/events/test_focus_controls.html | 75 + .../tests/mochitest/events/test_focus_dialog.html | 164 ++ .../tests/mochitest/events/test_focus_doc.html | 95 + .../tests/mochitest/events/test_focus_general.html | 179 ++ .../tests/mochitest/events/test_focus_general.xul | 179 ++ .../mochitest/events/test_focus_listcontrols.xul | 189 ++ .../tests/mochitest/events/test_focus_menu.xul | 119 + .../tests/mochitest/events/test_focus_name.html | 122 + .../tests/mochitest/events/test_focus_selects.html | 118 + .../tests/mochitest/events/test_focus_tabbox.xul | 103 + .../tests/mochitest/events/test_focus_tree.xul | 122 + .../tests/mochitest/events/test_fromUserInput.html | 127 ++ accessible/tests/mochitest/events/test_label.xul | 177 ++ accessible/tests/mochitest/events/test_menu.xul | 202 ++ .../tests/mochitest/events/test_mutation.html | 632 ++++++ .../tests/mochitest/events/test_mutation.xhtml | 97 + .../tests/mochitest/events/test_namechange.html | 123 ++ .../tests/mochitest/events/test_namechange.xul | 92 + accessible/tests/mochitest/events/test_scroll.xul | 131 ++ .../tests/mochitest/events/test_scroll_caret.xul | 91 + .../tests/mochitest/events/test_selection.html | 118 + .../tests/mochitest/events/test_selection.xul | 255 +++ .../mochitest/events/test_selection_aria.html | 127 ++ .../tests/mochitest/events/test_statechange.html | 287 +++ accessible/tests/mochitest/events/test_text.html | 339 +++ .../tests/mochitest/events/test_text_alg.html | 249 +++ .../mochitest/events/test_textattrchange.html | 115 + .../tests/mochitest/events/test_textselchange.html | 86 + accessible/tests/mochitest/events/test_tree.xul | 348 +++ .../tests/mochitest/events/test_valuechange.html | 255 +++ accessible/tests/mochitest/focus/a11y.ini | 9 + .../tests/mochitest/focus/test_focusedChild.html | 87 + .../tests/mochitest/focus/test_takeFocus.html | 128 ++ .../tests/mochitest/focus/test_takeFocus.xul | 106 + accessible/tests/mochitest/formimage.png | Bin 0 -> 20105 bytes accessible/tests/mochitest/grid.js | 149 ++ accessible/tests/mochitest/hittest/a11y.ini | 14 + .../tests/mochitest/hittest/test_browser.html | 63 + .../mochitest/hittest/test_canvas_hitregion.html | 88 + .../tests/mochitest/hittest/test_general.html | 115 + accessible/tests/mochitest/hittest/test_menu.xul | 134 ++ .../tests/mochitest/hittest/test_shadowroot.html | 72 + accessible/tests/mochitest/hittest/test_zoom.html | 61 + .../tests/mochitest/hittest/test_zoom_text.html | 57 + .../tests/mochitest/hittest/test_zoom_tree.xul | 100 + accessible/tests/mochitest/hittest/zoom_tree.xul | 18 + accessible/tests/mochitest/hyperlink/a11y.ini | 7 + accessible/tests/mochitest/hyperlink/hyperlink.js | 42 + .../tests/mochitest/hyperlink/test_general.html | 279 +++ .../tests/mochitest/hyperlink/test_general.xul | 97 + accessible/tests/mochitest/hypertext/a11y.ini | 7 + .../tests/mochitest/hypertext/test_general.html | 156 ++ .../tests/mochitest/hypertext/test_update.html | 236 ++ accessible/tests/mochitest/jsat/a11y.ini | 30 + .../mochitest/jsat/doc_content_integration.html | 115 + .../tests/mochitest/jsat/doc_content_text.html | 15 + accessible/tests/mochitest/jsat/doc_traversal.html | 164 ++ accessible/tests/mochitest/jsat/dom_helper.js | 209 ++ accessible/tests/mochitest/jsat/gestures.json | 352 +++ accessible/tests/mochitest/jsat/jsatcommon.js | 739 +++++++ accessible/tests/mochitest/jsat/output.js | 114 + accessible/tests/mochitest/jsat/test_alive.html | 81 + .../mochitest/jsat/test_content_integration.html | 343 +++ .../tests/mochitest/jsat/test_content_text.html | 292 +++ .../tests/mochitest/jsat/test_explicit_names.html | 191 ++ .../tests/mochitest/jsat/test_gesture_tracker.html | 51 + accessible/tests/mochitest/jsat/test_hints.html | 89 + .../tests/mochitest/jsat/test_landmarks.html | 183 ++ .../tests/mochitest/jsat/test_live_regions.html | 472 ++++ accessible/tests/mochitest/jsat/test_output.html | 673 ++++++ .../tests/mochitest/jsat/test_output_mathml.html | 313 +++ .../tests/mochitest/jsat/test_pointer_relay.html | 95 + .../tests/mochitest/jsat/test_quicknav_modes.html | 107 + accessible/tests/mochitest/jsat/test_tables.html | 579 +++++ .../tests/mochitest/jsat/test_traversal.html | 167 ++ .../mochitest/jsat/test_traversal_helper.html | 113 + accessible/tests/mochitest/layout.js | 258 +++ accessible/tests/mochitest/letters.gif | Bin 0 -> 5596 bytes accessible/tests/mochitest/longdesc_src.html | 8 + accessible/tests/mochitest/moz.build | 37 + accessible/tests/mochitest/moz.png | Bin 0 -> 1991 bytes accessible/tests/mochitest/name.js | 33 + accessible/tests/mochitest/name/a11y.ini | 20 + accessible/tests/mochitest/name/general.css | 11 + accessible/tests/mochitest/name/general.xbl | 32 + accessible/tests/mochitest/name/markup.js | 382 ++++ accessible/tests/mochitest/name/markuprules.xml | 373 ++++ accessible/tests/mochitest/name/test_browserui.xul | 107 + .../tests/mochitest/name/test_counterstyle.html | 153 ++ accessible/tests/mochitest/name/test_general.html | 631 ++++++ accessible/tests/mochitest/name/test_general.xul | 382 ++++ accessible/tests/mochitest/name/test_link.html | 89 + accessible/tests/mochitest/name/test_list.html | 89 + accessible/tests/mochitest/name/test_markup.html | 60 + accessible/tests/mochitest/name/test_svg.html | 55 + .../tests/mochitest/name/test_toolbaritem.xul | 84 + accessible/tests/mochitest/name/test_tree.xul | 211 ++ accessible/tests/mochitest/pivot.js | 551 +++++ accessible/tests/mochitest/pivot/a11y.ini | 8 + .../tests/mochitest/pivot/doc_virtualcursor.html | 38 + .../mochitest/pivot/doc_virtualcursor_text.html | 29 + .../tests/mochitest/pivot/test_virtualcursor.html | 129 ++ .../mochitest/pivot/test_virtualcursor_text.html | 241 ++ accessible/tests/mochitest/relations.js | 192 ++ accessible/tests/mochitest/relations/a11y.ini | 12 + .../tests/mochitest/relations/test_bindings.xhtml | 103 + .../tests/mochitest/relations/test_embeds.xul | 122 + .../tests/mochitest/relations/test_general.html | 406 ++++ .../tests/mochitest/relations/test_general.xul | 238 ++ .../tests/mochitest/relations/test_tabbrowser.xul | 103 + accessible/tests/mochitest/relations/test_tree.xul | 106 + .../mochitest/relations/test_ui_modalprompt.html | 107 + .../tests/mochitest/relations/test_update.html | 225 ++ accessible/tests/mochitest/role.js | 178 ++ accessible/tests/mochitest/role/a11y.ini | 10 + accessible/tests/mochitest/role/test_aria.html | 345 +++ accessible/tests/mochitest/role/test_aria.xul | 72 + accessible/tests/mochitest/role/test_general.html | 186 ++ accessible/tests/mochitest/role/test_general.xul | 57 + accessible/tests/mochitest/role/test_svg.html | 70 + accessible/tests/mochitest/scroll/a11y.ini | 6 + accessible/tests/mochitest/scroll/test_zoom.html | 148 ++ .../tests/mochitest/scroll/test_zoom_text.html | 158 ++ accessible/tests/mochitest/selectable.js | 80 + accessible/tests/mochitest/selectable/a11y.ini | 11 + .../tests/mochitest/selectable/test_aria.html | 225 ++ .../tests/mochitest/selectable/test_listbox.xul | 152 ++ .../tests/mochitest/selectable/test_menu.xul | 78 + .../tests/mochitest/selectable/test_menulist.xul | 96 + .../tests/mochitest/selectable/test_select.html | 243 ++ .../tests/mochitest/selectable/test_tree.xul | 188 ++ accessible/tests/mochitest/states.js | 266 +++ accessible/tests/mochitest/states/a11y.ini | 37 + accessible/tests/mochitest/states/test_aria.html | 629 ++++++ accessible/tests/mochitest/states/test_aria.xul | 60 + .../tests/mochitest/states/test_aria_imgmap.html | 79 + .../mochitest/states/test_aria_widgetitems.html | 162 ++ .../tests/mochitest/states/test_buttons.html | 85 + .../tests/mochitest/states/test_controls.html | 53 + .../tests/mochitest/states/test_controls.xul | 182 ++ accessible/tests/mochitest/states/test_doc.html | 89 + .../tests/mochitest/states/test_doc_busy.html | 79 + .../tests/mochitest/states/test_docarticle.html | 80 + .../tests/mochitest/states/test_editablebody.html | 46 + .../tests/mochitest/states/test_expandable.xul | 118 + accessible/tests/mochitest/states/test_frames.html | 95 + accessible/tests/mochitest/states/test_inputs.html | 271 +++ accessible/tests/mochitest/states/test_link.html | 144 ++ accessible/tests/mochitest/states/test_popup.xul | 55 + .../tests/mochitest/states/test_selects.html | 203 ++ accessible/tests/mochitest/states/test_stale.html | 115 + accessible/tests/mochitest/states/test_tabs.xul | 70 + accessible/tests/mochitest/states/test_textbox.xul | 153 ++ accessible/tests/mochitest/states/test_tree.xul | 152 ++ .../tests/mochitest/states/test_visibility.html | 175 ++ .../tests/mochitest/states/test_visibility.xul | 152 ++ accessible/tests/mochitest/states/z_frames.html | 11 + .../tests/mochitest/states/z_frames_article.html | 11 + .../tests/mochitest/states/z_frames_checkbox.html | 11 + .../tests/mochitest/states/z_frames_textbox.html | 11 + .../tests/mochitest/states/z_frames_update.html | 22 + accessible/tests/mochitest/table.js | 778 +++++++ accessible/tests/mochitest/table/a11y.ini | 27 + .../tests/mochitest/table/test_css_tables.html | 116 + .../mochitest/table/test_headers_ariagrid.html | 185 ++ .../mochitest/table/test_headers_ariatable.html | 96 + .../tests/mochitest/table/test_headers_listbox.xul | 194 ++ .../tests/mochitest/table/test_headers_table.html | 713 ++++++ .../tests/mochitest/table/test_headers_tree.xul | 101 + .../mochitest/table/test_indexes_ariagrid.html | 139 ++ .../tests/mochitest/table/test_indexes_listbox.xul | 85 + .../tests/mochitest/table/test_indexes_table.html | 410 ++++ .../tests/mochitest/table/test_indexes_tree.xul | 71 + .../tests/mochitest/table/test_layoutguess.html | 506 +++++ accessible/tests/mochitest/table/test_mtable.html | 128 ++ .../tests/mochitest/table/test_sels_ariagrid.html | 161 ++ .../tests/mochitest/table/test_sels_listbox.xul | 247 +++ .../tests/mochitest/table/test_sels_table.html | 180 ++ .../tests/mochitest/table/test_sels_tree.xul | 79 + .../mochitest/table/test_struct_ariagrid.html | 149 ++ .../mochitest/table/test_struct_ariatreegrid.html | 76 + .../tests/mochitest/table/test_struct_listbox.xul | 117 + .../tests/mochitest/table/test_struct_table.html | 203 ++ .../tests/mochitest/table/test_struct_tree.xul | 74 + accessible/tests/mochitest/table/test_table_1.html | 105 + accessible/tests/mochitest/table/test_table_2.html | 89 + .../tests/mochitest/test_OuterDocAccessible.html | 89 + .../tests/mochitest/test_aria_token_attrs.html | 329 +++ accessible/tests/mochitest/test_bug420863.html | 103 + accessible/tests/mochitest/test_descr.html | 121 + .../mochitest/test_nsIAccessibleDocument.html | 96 + .../tests/mochitest/test_nsIAccessibleImage.html | 202 ++ accessible/tests/mochitest/text.js | 634 ++++++ accessible/tests/mochitest/text/a11y.ini | 16 + accessible/tests/mochitest/text/doc.html | 9 + .../tests/mochitest/text/test_atcaretoffset.html | 455 ++++ .../tests/mochitest/text/test_charboundary.html | 140 ++ accessible/tests/mochitest/text/test_doc.html | 42 + accessible/tests/mochitest/text/test_dynamic.html | 88 + accessible/tests/mochitest/text/test_general.xul | 80 + accessible/tests/mochitest/text/test_gettext.html | 112 + .../tests/mochitest/text/test_hypertext.html | 147 ++ .../tests/mochitest/text/test_lineboundary.html | 265 +++ .../tests/mochitest/text/test_passwords.html | 60 + .../tests/mochitest/text/test_selection.html | 101 + .../tests/mochitest/text/test_wordboundary.html | 291 +++ accessible/tests/mochitest/text/test_words.html | 133 ++ accessible/tests/mochitest/textattrs/a11y.ini | 7 + .../tests/mochitest/textattrs/test_general.html | 735 ++++++ .../tests/mochitest/textattrs/test_invalid.html | 62 + accessible/tests/mochitest/textcaret/a11y.ini | 6 + .../tests/mochitest/textcaret/test_browserui.xul | 67 + .../tests/mochitest/textcaret/test_general.html | 183 ++ accessible/tests/mochitest/textrange/a11y.ini | 7 + .../tests/mochitest/textrange/test_general.html | 108 + .../tests/mochitest/textrange/test_selection.html | 120 + accessible/tests/mochitest/textselection/a11y.ini | 6 + .../mochitest/textselection/test_general.html | 221 ++ .../mochitest/textselection/test_userinput.html | 95 + accessible/tests/mochitest/tree/a11y.ini | 51 + accessible/tests/mochitest/tree/dockids.html | 30 + .../tests/mochitest/tree/test_applicationacc.xul | 74 + .../tests/mochitest/tree/test_aria_globals.html | 129 ++ .../tests/mochitest/tree/test_aria_grid.html | 279 +++ .../tests/mochitest/tree/test_aria_imgmap.html | 108 + .../tests/mochitest/tree/test_aria_list.html | 92 + .../tests/mochitest/tree/test_aria_menu.html | 93 + .../tests/mochitest/tree/test_aria_owns.html | 187 ++ .../mochitest/tree/test_aria_presentation.html | 179 ++ .../tests/mochitest/tree/test_aria_table.html | 63 + .../tests/mochitest/tree/test_brokencontext.html | 265 +++ accessible/tests/mochitest/tree/test_button.xul | 73 + accessible/tests/mochitest/tree/test_canvas.html | 55 + accessible/tests/mochitest/tree/test_combobox.xul | 291 +++ .../tests/mochitest/tree/test_cssflexbox.html | 80 + .../tests/mochitest/tree/test_cssoverflow.html | 146 ++ .../tests/mochitest/tree/test_dochierarchy.html | 86 + accessible/tests/mochitest/tree/test_dockids.html | 65 + accessible/tests/mochitest/tree/test_filectrl.html | 58 + accessible/tests/mochitest/tree/test_formctrl.html | 132 ++ accessible/tests/mochitest/tree/test_formctrl.xul | 130 ++ .../tests/mochitest/tree/test_gencontent.html | 71 + accessible/tests/mochitest/tree/test_groupbox.xul | 64 + accessible/tests/mochitest/tree/test_iframe.html | 52 + accessible/tests/mochitest/tree/test_img.html | 88 + .../tests/mochitest/tree/test_invalid_img.xhtml | 50 + .../mochitest/tree/test_invalidationlist.html | 57 + accessible/tests/mochitest/tree/test_list.html | 247 +++ accessible/tests/mochitest/tree/test_map.html | 83 + accessible/tests/mochitest/tree/test_media.html | 84 + accessible/tests/mochitest/tree/test_select.html | 139 ++ accessible/tests/mochitest/tree/test_tabbox.xul | 99 + .../tests/mochitest/tree/test_tabbrowser.xul | 255 +++ accessible/tests/mochitest/tree/test_table.html | 282 +++ accessible/tests/mochitest/tree/test_tree.xul | 182 ++ accessible/tests/mochitest/tree/test_txtcntr.html | 234 ++ accessible/tests/mochitest/tree/test_txtctrl.html | 173 ++ accessible/tests/mochitest/tree/test_txtctrl.xul | 219 ++ accessible/tests/mochitest/tree/wnd.xul | 8 + accessible/tests/mochitest/treeupdate/a11y.ini | 41 + .../mochitest/treeupdate/test_ariadialog.html | 119 + .../tests/mochitest/treeupdate/test_ariaowns.html | 693 ++++++ .../mochitest/treeupdate/test_bug1040735.html | 42 + .../mochitest/treeupdate/test_bug1100602.html | 114 + .../mochitest/treeupdate/test_bug1175913.html | 105 + .../mochitest/treeupdate/test_bug1189277.html | 86 + .../mochitest/treeupdate/test_bug1276857.html | 143 ++ .../mochitest/treeupdate/test_bug852150.xhtml | 59 + .../mochitest/treeupdate/test_bug883708.xhtml | 33 + .../mochitest/treeupdate/test_bug884251.xhtml | 21 + .../tests/mochitest/treeupdate/test_bug895082.html | 51 + .../tests/mochitest/treeupdate/test_canvas.html | 92 + .../mochitest/treeupdate/test_colorpicker.xul | 150 ++ .../mochitest/treeupdate/test_contextmenu.xul | 317 +++ .../mochitest/treeupdate/test_cssoverflow.html | 143 ++ .../tests/mochitest/treeupdate/test_deck.xul | 109 + .../tests/mochitest/treeupdate/test_doc.html | 466 ++++ .../mochitest/treeupdate/test_gencontent.html | 160 ++ .../tests/mochitest/treeupdate/test_general.html | 150 ++ .../tests/mochitest/treeupdate/test_hidden.html | 135 ++ .../tests/mochitest/treeupdate/test_imagemap.html | 442 ++++ .../tests/mochitest/treeupdate/test_list.html | 152 ++ .../treeupdate/test_list_editabledoc.html | 106 + .../tests/mochitest/treeupdate/test_listbox.xul | 180 ++ .../tests/mochitest/treeupdate/test_menu.xul | 128 ++ .../tests/mochitest/treeupdate/test_menubutton.xul | 198 ++ .../tests/mochitest/treeupdate/test_optgroup.html | 137 ++ .../mochitest/treeupdate/test_recreation.html | 155 ++ .../tests/mochitest/treeupdate/test_select.html | 130 ++ .../tests/mochitest/treeupdate/test_shutdown.xul | 132 ++ .../tests/mochitest/treeupdate/test_table.html | 81 + .../tests/mochitest/treeupdate/test_textleaf.html | 180 ++ .../mochitest/treeupdate/test_visibility.html | 437 ++++ .../mochitest/treeupdate/test_whitespace.html | 187 ++ accessible/tests/mochitest/treeview.css | 15 + accessible/tests/mochitest/treeview.js | 289 +++ accessible/tests/mochitest/value.js | 32 + accessible/tests/mochitest/value/a11y.ini | 9 + accessible/tests/mochitest/value/test_general.html | 159 ++ accessible/tests/mochitest/value/test_number.html | 59 + .../tests/mochitest/value/test_progress.html | 61 + accessible/tests/mochitest/value/test_progress.xul | 72 + accessible/tests/mochitest/value/test_range.html | 59 + 431 files changed, 66338 insertions(+) create mode 100644 accessible/tests/browser/.eslintrc.js create mode 100644 accessible/tests/browser/browser.ini create mode 100644 accessible/tests/browser/browser_shutdown_multi_reference.js create mode 100644 accessible/tests/browser/browser_shutdown_parent_own_reference.js create mode 100644 accessible/tests/browser/browser_shutdown_remote_no_reference.js create mode 100644 accessible/tests/browser/browser_shutdown_remote_only.js create mode 100644 accessible/tests/browser/browser_shutdown_remote_own_reference.js create mode 100644 accessible/tests/browser/browser_shutdown_scope_lifecycle.js create mode 100644 accessible/tests/browser/browser_shutdown_start_restart.js create mode 100644 accessible/tests/browser/e10s/browser.ini create mode 100644 accessible/tests/browser/e10s/browser_caching_attributes.js create mode 100644 accessible/tests/browser/e10s/browser_caching_description.js create mode 100644 accessible/tests/browser/e10s/browser_caching_name.js create mode 100644 accessible/tests/browser/e10s/browser_caching_relations.js create mode 100644 accessible/tests/browser/e10s/browser_caching_states.js create mode 100644 accessible/tests/browser/e10s/browser_caching_value.js create mode 100644 accessible/tests/browser/e10s/browser_events_caretmove.js create mode 100644 accessible/tests/browser/e10s/browser_events_hide.js create mode 100644 accessible/tests/browser/e10s/browser_events_show.js create mode 100644 accessible/tests/browser/e10s/browser_events_statechange.js create mode 100644 accessible/tests/browser/e10s/browser_events_textchange.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_ariadialog.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_canvas.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_cssoverflow.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_doc.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_gencontent.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_hidden.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_imagemap.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_list.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_list_editabledoc.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_listener.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_optgroup.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_removal.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_table.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_textleaf.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_visibility.js create mode 100644 accessible/tests/browser/e10s/browser_treeupdate_whitespace.js create mode 100644 accessible/tests/browser/e10s/doc_treeupdate_ariadialog.html create mode 100644 accessible/tests/browser/e10s/doc_treeupdate_ariaowns.html create mode 100644 accessible/tests/browser/e10s/doc_treeupdate_imagemap.html create mode 100644 accessible/tests/browser/e10s/doc_treeupdate_removal.xhtml create mode 100644 accessible/tests/browser/e10s/doc_treeupdate_visibility.html create mode 100644 accessible/tests/browser/e10s/doc_treeupdate_whitespace.html create mode 100644 accessible/tests/browser/e10s/events.js create mode 100644 accessible/tests/browser/e10s/head.js create mode 100644 accessible/tests/browser/head.js create mode 100644 accessible/tests/browser/shared-head.js create mode 100644 accessible/tests/crashtests/448064.xhtml create mode 100644 accessible/tests/crashtests/471493.xul create mode 100644 accessible/tests/crashtests/crashtests.list create mode 100644 accessible/tests/mochitest/a11y.ini create mode 100644 accessible/tests/mochitest/actions.js create mode 100644 accessible/tests/mochitest/actions/a11y.ini create mode 100644 accessible/tests/mochitest/actions/test_anchors.html create mode 100644 accessible/tests/mochitest/actions/test_aria.html create mode 100644 accessible/tests/mochitest/actions/test_controls.html create mode 100644 accessible/tests/mochitest/actions/test_general.html create mode 100644 accessible/tests/mochitest/actions/test_general.xul create mode 100644 accessible/tests/mochitest/actions/test_keys.html create mode 100644 accessible/tests/mochitest/actions/test_keys_menu.xul create mode 100644 accessible/tests/mochitest/actions/test_link.html create mode 100644 accessible/tests/mochitest/actions/test_media.html create mode 100644 accessible/tests/mochitest/actions/test_select.html create mode 100644 accessible/tests/mochitest/actions/test_tree.xul create mode 100644 accessible/tests/mochitest/actions/test_treegrid.xul create mode 100644 accessible/tests/mochitest/aom/a11y.ini create mode 100644 accessible/tests/mochitest/aom/test_general.html create mode 100644 accessible/tests/mochitest/attributes.js create mode 100644 accessible/tests/mochitest/attributes/a11y.ini create mode 100644 accessible/tests/mochitest/attributes/test_obj.html create mode 100644 accessible/tests/mochitest/attributes/test_obj_css.html create mode 100644 accessible/tests/mochitest/attributes/test_obj_css.xul create mode 100644 accessible/tests/mochitest/attributes/test_obj_group.html create mode 100644 accessible/tests/mochitest/attributes/test_obj_group.xul create mode 100644 accessible/tests/mochitest/attributes/test_obj_group_tree.xul create mode 100644 accessible/tests/mochitest/attributes/test_tag.html create mode 100644 accessible/tests/mochitest/attributes/test_xml-roles.html create mode 100644 accessible/tests/mochitest/autocomplete.js create mode 100644 accessible/tests/mochitest/bounds/a11y.ini create mode 100644 accessible/tests/mochitest/bounds/test_list.html create mode 100644 accessible/tests/mochitest/bounds/test_select.html create mode 100644 accessible/tests/mochitest/bounds/test_zoom.html create mode 100644 accessible/tests/mochitest/bounds/test_zoom_text.html create mode 100644 accessible/tests/mochitest/browser.js create mode 100644 accessible/tests/mochitest/common.js create mode 100644 accessible/tests/mochitest/dumbfile.zip create mode 100644 accessible/tests/mochitest/editabletext/a11y.ini create mode 100644 accessible/tests/mochitest/editabletext/editabletext.js create mode 100644 accessible/tests/mochitest/editabletext/test_1.html create mode 100644 accessible/tests/mochitest/editabletext/test_2.html create mode 100644 accessible/tests/mochitest/elm/a11y.ini create mode 100644 accessible/tests/mochitest/elm/test_HTMLSpec.html create mode 100644 accessible/tests/mochitest/elm/test_MathMLSpec.html create mode 100644 accessible/tests/mochitest/elm/test_canvas.html create mode 100644 accessible/tests/mochitest/elm/test_figure.html create mode 100644 accessible/tests/mochitest/elm/test_listbox.xul create mode 100644 accessible/tests/mochitest/elm/test_nsApplicationAcc.html create mode 100644 accessible/tests/mochitest/elm/test_plugin.html create mode 100644 accessible/tests/mochitest/elm/test_shadowroot.html create mode 100644 accessible/tests/mochitest/events.js create mode 100644 accessible/tests/mochitest/events/a11y.ini create mode 100644 accessible/tests/mochitest/events/docload_wnd.html create mode 100644 accessible/tests/mochitest/events/focus.html create mode 100644 accessible/tests/mochitest/events/scroll.html create mode 100644 accessible/tests/mochitest/events/test_aria_alert.html create mode 100644 accessible/tests/mochitest/events/test_aria_menu.html create mode 100644 accessible/tests/mochitest/events/test_aria_objattr.html create mode 100644 accessible/tests/mochitest/events/test_aria_owns.html create mode 100644 accessible/tests/mochitest/events/test_aria_statechange.html create mode 100644 accessible/tests/mochitest/events/test_attrs.html create mode 100644 accessible/tests/mochitest/events/test_bug1322593-2.html create mode 100644 accessible/tests/mochitest/events/test_bug1322593.html create mode 100644 accessible/tests/mochitest/events/test_caretmove.html create mode 100644 accessible/tests/mochitest/events/test_caretmove.xul create mode 100644 accessible/tests/mochitest/events/test_coalescence.html create mode 100644 accessible/tests/mochitest/events/test_contextmenu.html create mode 100644 accessible/tests/mochitest/events/test_descrchange.html create mode 100644 accessible/tests/mochitest/events/test_docload.html create mode 100644 accessible/tests/mochitest/events/test_docload.xul create mode 100644 accessible/tests/mochitest/events/test_docload_aria.html create mode 100644 accessible/tests/mochitest/events/test_dragndrop.html create mode 100644 accessible/tests/mochitest/events/test_flush.html create mode 100644 accessible/tests/mochitest/events/test_focus_aria_activedescendant.html create mode 100644 accessible/tests/mochitest/events/test_focus_autocomplete.xul create mode 100644 accessible/tests/mochitest/events/test_focus_browserui.xul create mode 100644 accessible/tests/mochitest/events/test_focus_canvas.html create mode 100644 accessible/tests/mochitest/events/test_focus_contextmenu.xul create mode 100644 accessible/tests/mochitest/events/test_focus_controls.html create mode 100644 accessible/tests/mochitest/events/test_focus_dialog.html create mode 100644 accessible/tests/mochitest/events/test_focus_doc.html create mode 100644 accessible/tests/mochitest/events/test_focus_general.html create mode 100644 accessible/tests/mochitest/events/test_focus_general.xul create mode 100644 accessible/tests/mochitest/events/test_focus_listcontrols.xul create mode 100644 accessible/tests/mochitest/events/test_focus_menu.xul create mode 100644 accessible/tests/mochitest/events/test_focus_name.html create mode 100644 accessible/tests/mochitest/events/test_focus_selects.html create mode 100644 accessible/tests/mochitest/events/test_focus_tabbox.xul create mode 100644 accessible/tests/mochitest/events/test_focus_tree.xul create mode 100644 accessible/tests/mochitest/events/test_fromUserInput.html create mode 100644 accessible/tests/mochitest/events/test_label.xul create mode 100644 accessible/tests/mochitest/events/test_menu.xul create mode 100644 accessible/tests/mochitest/events/test_mutation.html create mode 100644 accessible/tests/mochitest/events/test_mutation.xhtml create mode 100644 accessible/tests/mochitest/events/test_namechange.html create mode 100644 accessible/tests/mochitest/events/test_namechange.xul create mode 100644 accessible/tests/mochitest/events/test_scroll.xul create mode 100644 accessible/tests/mochitest/events/test_scroll_caret.xul create mode 100644 accessible/tests/mochitest/events/test_selection.html create mode 100644 accessible/tests/mochitest/events/test_selection.xul create mode 100644 accessible/tests/mochitest/events/test_selection_aria.html create mode 100644 accessible/tests/mochitest/events/test_statechange.html create mode 100644 accessible/tests/mochitest/events/test_text.html create mode 100644 accessible/tests/mochitest/events/test_text_alg.html create mode 100644 accessible/tests/mochitest/events/test_textattrchange.html create mode 100644 accessible/tests/mochitest/events/test_textselchange.html create mode 100644 accessible/tests/mochitest/events/test_tree.xul create mode 100644 accessible/tests/mochitest/events/test_valuechange.html create mode 100644 accessible/tests/mochitest/focus/a11y.ini create mode 100644 accessible/tests/mochitest/focus/test_focusedChild.html create mode 100644 accessible/tests/mochitest/focus/test_takeFocus.html create mode 100644 accessible/tests/mochitest/focus/test_takeFocus.xul create mode 100644 accessible/tests/mochitest/formimage.png create mode 100644 accessible/tests/mochitest/grid.js create mode 100644 accessible/tests/mochitest/hittest/a11y.ini create mode 100644 accessible/tests/mochitest/hittest/test_browser.html create mode 100644 accessible/tests/mochitest/hittest/test_canvas_hitregion.html create mode 100644 accessible/tests/mochitest/hittest/test_general.html create mode 100644 accessible/tests/mochitest/hittest/test_menu.xul create mode 100644 accessible/tests/mochitest/hittest/test_shadowroot.html create mode 100644 accessible/tests/mochitest/hittest/test_zoom.html create mode 100644 accessible/tests/mochitest/hittest/test_zoom_text.html create mode 100644 accessible/tests/mochitest/hittest/test_zoom_tree.xul create mode 100644 accessible/tests/mochitest/hittest/zoom_tree.xul create mode 100644 accessible/tests/mochitest/hyperlink/a11y.ini create mode 100644 accessible/tests/mochitest/hyperlink/hyperlink.js create mode 100644 accessible/tests/mochitest/hyperlink/test_general.html create mode 100644 accessible/tests/mochitest/hyperlink/test_general.xul create mode 100644 accessible/tests/mochitest/hypertext/a11y.ini create mode 100644 accessible/tests/mochitest/hypertext/test_general.html create mode 100644 accessible/tests/mochitest/hypertext/test_update.html create mode 100644 accessible/tests/mochitest/jsat/a11y.ini create mode 100644 accessible/tests/mochitest/jsat/doc_content_integration.html create mode 100644 accessible/tests/mochitest/jsat/doc_content_text.html create mode 100644 accessible/tests/mochitest/jsat/doc_traversal.html create mode 100644 accessible/tests/mochitest/jsat/dom_helper.js create mode 100644 accessible/tests/mochitest/jsat/gestures.json create mode 100644 accessible/tests/mochitest/jsat/jsatcommon.js create mode 100644 accessible/tests/mochitest/jsat/output.js create mode 100644 accessible/tests/mochitest/jsat/test_alive.html create mode 100644 accessible/tests/mochitest/jsat/test_content_integration.html create mode 100644 accessible/tests/mochitest/jsat/test_content_text.html create mode 100644 accessible/tests/mochitest/jsat/test_explicit_names.html create mode 100644 accessible/tests/mochitest/jsat/test_gesture_tracker.html create mode 100644 accessible/tests/mochitest/jsat/test_hints.html create mode 100644 accessible/tests/mochitest/jsat/test_landmarks.html create mode 100644 accessible/tests/mochitest/jsat/test_live_regions.html create mode 100644 accessible/tests/mochitest/jsat/test_output.html create mode 100644 accessible/tests/mochitest/jsat/test_output_mathml.html create mode 100644 accessible/tests/mochitest/jsat/test_pointer_relay.html create mode 100644 accessible/tests/mochitest/jsat/test_quicknav_modes.html create mode 100644 accessible/tests/mochitest/jsat/test_tables.html create mode 100644 accessible/tests/mochitest/jsat/test_traversal.html create mode 100644 accessible/tests/mochitest/jsat/test_traversal_helper.html create mode 100644 accessible/tests/mochitest/layout.js create mode 100644 accessible/tests/mochitest/letters.gif create mode 100644 accessible/tests/mochitest/longdesc_src.html create mode 100644 accessible/tests/mochitest/moz.build create mode 100644 accessible/tests/mochitest/moz.png create mode 100644 accessible/tests/mochitest/name.js create mode 100644 accessible/tests/mochitest/name/a11y.ini create mode 100644 accessible/tests/mochitest/name/general.css create mode 100644 accessible/tests/mochitest/name/general.xbl create mode 100644 accessible/tests/mochitest/name/markup.js create mode 100644 accessible/tests/mochitest/name/markuprules.xml create mode 100644 accessible/tests/mochitest/name/test_browserui.xul create mode 100644 accessible/tests/mochitest/name/test_counterstyle.html create mode 100644 accessible/tests/mochitest/name/test_general.html create mode 100644 accessible/tests/mochitest/name/test_general.xul create mode 100644 accessible/tests/mochitest/name/test_link.html create mode 100644 accessible/tests/mochitest/name/test_list.html create mode 100644 accessible/tests/mochitest/name/test_markup.html create mode 100644 accessible/tests/mochitest/name/test_svg.html create mode 100644 accessible/tests/mochitest/name/test_toolbaritem.xul create mode 100644 accessible/tests/mochitest/name/test_tree.xul create mode 100644 accessible/tests/mochitest/pivot.js create mode 100644 accessible/tests/mochitest/pivot/a11y.ini create mode 100644 accessible/tests/mochitest/pivot/doc_virtualcursor.html create mode 100644 accessible/tests/mochitest/pivot/doc_virtualcursor_text.html create mode 100644 accessible/tests/mochitest/pivot/test_virtualcursor.html create mode 100644 accessible/tests/mochitest/pivot/test_virtualcursor_text.html create mode 100644 accessible/tests/mochitest/relations.js create mode 100644 accessible/tests/mochitest/relations/a11y.ini create mode 100644 accessible/tests/mochitest/relations/test_bindings.xhtml create mode 100644 accessible/tests/mochitest/relations/test_embeds.xul create mode 100644 accessible/tests/mochitest/relations/test_general.html create mode 100644 accessible/tests/mochitest/relations/test_general.xul create mode 100644 accessible/tests/mochitest/relations/test_tabbrowser.xul create mode 100644 accessible/tests/mochitest/relations/test_tree.xul create mode 100644 accessible/tests/mochitest/relations/test_ui_modalprompt.html create mode 100644 accessible/tests/mochitest/relations/test_update.html create mode 100644 accessible/tests/mochitest/role.js create mode 100644 accessible/tests/mochitest/role/a11y.ini create mode 100644 accessible/tests/mochitest/role/test_aria.html create mode 100644 accessible/tests/mochitest/role/test_aria.xul create mode 100644 accessible/tests/mochitest/role/test_general.html create mode 100644 accessible/tests/mochitest/role/test_general.xul create mode 100644 accessible/tests/mochitest/role/test_svg.html create mode 100644 accessible/tests/mochitest/scroll/a11y.ini create mode 100644 accessible/tests/mochitest/scroll/test_zoom.html create mode 100644 accessible/tests/mochitest/scroll/test_zoom_text.html create mode 100644 accessible/tests/mochitest/selectable.js create mode 100644 accessible/tests/mochitest/selectable/a11y.ini create mode 100644 accessible/tests/mochitest/selectable/test_aria.html create mode 100644 accessible/tests/mochitest/selectable/test_listbox.xul create mode 100644 accessible/tests/mochitest/selectable/test_menu.xul create mode 100644 accessible/tests/mochitest/selectable/test_menulist.xul create mode 100644 accessible/tests/mochitest/selectable/test_select.html create mode 100644 accessible/tests/mochitest/selectable/test_tree.xul create mode 100644 accessible/tests/mochitest/states.js create mode 100644 accessible/tests/mochitest/states/a11y.ini create mode 100644 accessible/tests/mochitest/states/test_aria.html create mode 100644 accessible/tests/mochitest/states/test_aria.xul create mode 100644 accessible/tests/mochitest/states/test_aria_imgmap.html create mode 100644 accessible/tests/mochitest/states/test_aria_widgetitems.html create mode 100644 accessible/tests/mochitest/states/test_buttons.html create mode 100644 accessible/tests/mochitest/states/test_controls.html create mode 100644 accessible/tests/mochitest/states/test_controls.xul create mode 100644 accessible/tests/mochitest/states/test_doc.html create mode 100644 accessible/tests/mochitest/states/test_doc_busy.html create mode 100644 accessible/tests/mochitest/states/test_docarticle.html create mode 100644 accessible/tests/mochitest/states/test_editablebody.html create mode 100644 accessible/tests/mochitest/states/test_expandable.xul create mode 100644 accessible/tests/mochitest/states/test_frames.html create mode 100644 accessible/tests/mochitest/states/test_inputs.html create mode 100644 accessible/tests/mochitest/states/test_link.html create mode 100644 accessible/tests/mochitest/states/test_popup.xul create mode 100644 accessible/tests/mochitest/states/test_selects.html create mode 100644 accessible/tests/mochitest/states/test_stale.html create mode 100644 accessible/tests/mochitest/states/test_tabs.xul create mode 100644 accessible/tests/mochitest/states/test_textbox.xul create mode 100644 accessible/tests/mochitest/states/test_tree.xul create mode 100644 accessible/tests/mochitest/states/test_visibility.html create mode 100644 accessible/tests/mochitest/states/test_visibility.xul create mode 100644 accessible/tests/mochitest/states/z_frames.html create mode 100644 accessible/tests/mochitest/states/z_frames_article.html create mode 100644 accessible/tests/mochitest/states/z_frames_checkbox.html create mode 100644 accessible/tests/mochitest/states/z_frames_textbox.html create mode 100644 accessible/tests/mochitest/states/z_frames_update.html create mode 100644 accessible/tests/mochitest/table.js create mode 100644 accessible/tests/mochitest/table/a11y.ini create mode 100644 accessible/tests/mochitest/table/test_css_tables.html create mode 100644 accessible/tests/mochitest/table/test_headers_ariagrid.html create mode 100644 accessible/tests/mochitest/table/test_headers_ariatable.html create mode 100644 accessible/tests/mochitest/table/test_headers_listbox.xul create mode 100644 accessible/tests/mochitest/table/test_headers_table.html create mode 100644 accessible/tests/mochitest/table/test_headers_tree.xul create mode 100644 accessible/tests/mochitest/table/test_indexes_ariagrid.html create mode 100644 accessible/tests/mochitest/table/test_indexes_listbox.xul create mode 100644 accessible/tests/mochitest/table/test_indexes_table.html create mode 100644 accessible/tests/mochitest/table/test_indexes_tree.xul create mode 100644 accessible/tests/mochitest/table/test_layoutguess.html create mode 100644 accessible/tests/mochitest/table/test_mtable.html create mode 100644 accessible/tests/mochitest/table/test_sels_ariagrid.html create mode 100644 accessible/tests/mochitest/table/test_sels_listbox.xul create mode 100644 accessible/tests/mochitest/table/test_sels_table.html create mode 100644 accessible/tests/mochitest/table/test_sels_tree.xul create mode 100644 accessible/tests/mochitest/table/test_struct_ariagrid.html create mode 100644 accessible/tests/mochitest/table/test_struct_ariatreegrid.html create mode 100644 accessible/tests/mochitest/table/test_struct_listbox.xul create mode 100644 accessible/tests/mochitest/table/test_struct_table.html create mode 100644 accessible/tests/mochitest/table/test_struct_tree.xul create mode 100644 accessible/tests/mochitest/table/test_table_1.html create mode 100644 accessible/tests/mochitest/table/test_table_2.html create mode 100644 accessible/tests/mochitest/test_OuterDocAccessible.html create mode 100644 accessible/tests/mochitest/test_aria_token_attrs.html create mode 100644 accessible/tests/mochitest/test_bug420863.html create mode 100644 accessible/tests/mochitest/test_descr.html create mode 100644 accessible/tests/mochitest/test_nsIAccessibleDocument.html create mode 100644 accessible/tests/mochitest/test_nsIAccessibleImage.html create mode 100644 accessible/tests/mochitest/text.js create mode 100644 accessible/tests/mochitest/text/a11y.ini create mode 100644 accessible/tests/mochitest/text/doc.html create mode 100644 accessible/tests/mochitest/text/test_atcaretoffset.html create mode 100644 accessible/tests/mochitest/text/test_charboundary.html create mode 100644 accessible/tests/mochitest/text/test_doc.html create mode 100644 accessible/tests/mochitest/text/test_dynamic.html create mode 100644 accessible/tests/mochitest/text/test_general.xul create mode 100644 accessible/tests/mochitest/text/test_gettext.html create mode 100644 accessible/tests/mochitest/text/test_hypertext.html create mode 100644 accessible/tests/mochitest/text/test_lineboundary.html create mode 100644 accessible/tests/mochitest/text/test_passwords.html create mode 100644 accessible/tests/mochitest/text/test_selection.html create mode 100644 accessible/tests/mochitest/text/test_wordboundary.html create mode 100644 accessible/tests/mochitest/text/test_words.html create mode 100644 accessible/tests/mochitest/textattrs/a11y.ini create mode 100644 accessible/tests/mochitest/textattrs/test_general.html create mode 100644 accessible/tests/mochitest/textattrs/test_invalid.html create mode 100644 accessible/tests/mochitest/textcaret/a11y.ini create mode 100644 accessible/tests/mochitest/textcaret/test_browserui.xul create mode 100644 accessible/tests/mochitest/textcaret/test_general.html create mode 100644 accessible/tests/mochitest/textrange/a11y.ini create mode 100644 accessible/tests/mochitest/textrange/test_general.html create mode 100644 accessible/tests/mochitest/textrange/test_selection.html create mode 100644 accessible/tests/mochitest/textselection/a11y.ini create mode 100644 accessible/tests/mochitest/textselection/test_general.html create mode 100644 accessible/tests/mochitest/textselection/test_userinput.html create mode 100644 accessible/tests/mochitest/tree/a11y.ini create mode 100644 accessible/tests/mochitest/tree/dockids.html create mode 100644 accessible/tests/mochitest/tree/test_applicationacc.xul create mode 100644 accessible/tests/mochitest/tree/test_aria_globals.html create mode 100644 accessible/tests/mochitest/tree/test_aria_grid.html create mode 100644 accessible/tests/mochitest/tree/test_aria_imgmap.html create mode 100644 accessible/tests/mochitest/tree/test_aria_list.html create mode 100644 accessible/tests/mochitest/tree/test_aria_menu.html create mode 100644 accessible/tests/mochitest/tree/test_aria_owns.html create mode 100644 accessible/tests/mochitest/tree/test_aria_presentation.html create mode 100644 accessible/tests/mochitest/tree/test_aria_table.html create mode 100644 accessible/tests/mochitest/tree/test_brokencontext.html create mode 100644 accessible/tests/mochitest/tree/test_button.xul create mode 100644 accessible/tests/mochitest/tree/test_canvas.html create mode 100644 accessible/tests/mochitest/tree/test_combobox.xul create mode 100644 accessible/tests/mochitest/tree/test_cssflexbox.html create mode 100644 accessible/tests/mochitest/tree/test_cssoverflow.html create mode 100644 accessible/tests/mochitest/tree/test_dochierarchy.html create mode 100644 accessible/tests/mochitest/tree/test_dockids.html create mode 100644 accessible/tests/mochitest/tree/test_filectrl.html create mode 100644 accessible/tests/mochitest/tree/test_formctrl.html create mode 100644 accessible/tests/mochitest/tree/test_formctrl.xul create mode 100644 accessible/tests/mochitest/tree/test_gencontent.html create mode 100644 accessible/tests/mochitest/tree/test_groupbox.xul create mode 100644 accessible/tests/mochitest/tree/test_iframe.html create mode 100644 accessible/tests/mochitest/tree/test_img.html create mode 100644 accessible/tests/mochitest/tree/test_invalid_img.xhtml create mode 100644 accessible/tests/mochitest/tree/test_invalidationlist.html create mode 100644 accessible/tests/mochitest/tree/test_list.html create mode 100644 accessible/tests/mochitest/tree/test_map.html create mode 100644 accessible/tests/mochitest/tree/test_media.html create mode 100644 accessible/tests/mochitest/tree/test_select.html create mode 100644 accessible/tests/mochitest/tree/test_tabbox.xul create mode 100644 accessible/tests/mochitest/tree/test_tabbrowser.xul create mode 100644 accessible/tests/mochitest/tree/test_table.html create mode 100644 accessible/tests/mochitest/tree/test_tree.xul create mode 100644 accessible/tests/mochitest/tree/test_txtcntr.html create mode 100644 accessible/tests/mochitest/tree/test_txtctrl.html create mode 100644 accessible/tests/mochitest/tree/test_txtctrl.xul create mode 100644 accessible/tests/mochitest/tree/wnd.xul create mode 100644 accessible/tests/mochitest/treeupdate/a11y.ini create mode 100644 accessible/tests/mochitest/treeupdate/test_ariadialog.html create mode 100644 accessible/tests/mochitest/treeupdate/test_ariaowns.html create mode 100644 accessible/tests/mochitest/treeupdate/test_bug1040735.html create mode 100644 accessible/tests/mochitest/treeupdate/test_bug1100602.html create mode 100644 accessible/tests/mochitest/treeupdate/test_bug1175913.html create mode 100644 accessible/tests/mochitest/treeupdate/test_bug1189277.html create mode 100644 accessible/tests/mochitest/treeupdate/test_bug1276857.html create mode 100644 accessible/tests/mochitest/treeupdate/test_bug852150.xhtml create mode 100644 accessible/tests/mochitest/treeupdate/test_bug883708.xhtml create mode 100644 accessible/tests/mochitest/treeupdate/test_bug884251.xhtml create mode 100644 accessible/tests/mochitest/treeupdate/test_bug895082.html create mode 100644 accessible/tests/mochitest/treeupdate/test_canvas.html create mode 100644 accessible/tests/mochitest/treeupdate/test_colorpicker.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_contextmenu.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_cssoverflow.html create mode 100644 accessible/tests/mochitest/treeupdate/test_deck.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_doc.html create mode 100644 accessible/tests/mochitest/treeupdate/test_gencontent.html create mode 100644 accessible/tests/mochitest/treeupdate/test_general.html create mode 100644 accessible/tests/mochitest/treeupdate/test_hidden.html create mode 100644 accessible/tests/mochitest/treeupdate/test_imagemap.html create mode 100644 accessible/tests/mochitest/treeupdate/test_list.html create mode 100644 accessible/tests/mochitest/treeupdate/test_list_editabledoc.html create mode 100644 accessible/tests/mochitest/treeupdate/test_listbox.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_menu.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_menubutton.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_optgroup.html create mode 100644 accessible/tests/mochitest/treeupdate/test_recreation.html create mode 100644 accessible/tests/mochitest/treeupdate/test_select.html create mode 100644 accessible/tests/mochitest/treeupdate/test_shutdown.xul create mode 100644 accessible/tests/mochitest/treeupdate/test_table.html create mode 100644 accessible/tests/mochitest/treeupdate/test_textleaf.html create mode 100644 accessible/tests/mochitest/treeupdate/test_visibility.html create mode 100644 accessible/tests/mochitest/treeupdate/test_whitespace.html create mode 100644 accessible/tests/mochitest/treeview.css create mode 100644 accessible/tests/mochitest/treeview.js create mode 100644 accessible/tests/mochitest/value.js create mode 100644 accessible/tests/mochitest/value/a11y.ini create mode 100644 accessible/tests/mochitest/value/test_general.html create mode 100644 accessible/tests/mochitest/value/test_number.html create mode 100644 accessible/tests/mochitest/value/test_progress.html create mode 100644 accessible/tests/mochitest/value/test_progress.xul create mode 100644 accessible/tests/mochitest/value/test_range.html (limited to 'accessible/tests') diff --git a/accessible/tests/browser/.eslintrc.js b/accessible/tests/browser/.eslintrc.js new file mode 100644 index 000000000..53425abc4 --- /dev/null +++ b/accessible/tests/browser/.eslintrc.js @@ -0,0 +1,218 @@ +"use strict"; + +module.exports = { // eslint-disable-line no-undef + "extends": [ + "../../../testing/mochitest/browser.eslintrc.js" + ], + // All globals made available in the test environment. + "globals": { + // Content scripts have global 'content' object + "content": true, + + "add_task": true, + + // Defined in accessible/tests/mochitest/ common.js, name.js, states.js + "prettyName": true, + "statesToString": true, + "eventTypeToString": true, + "testAttrs": true, + "testAbsentAttrs": true, + "testName": true, + "testDescr": true, + "testStates": true, + "testRelation": true, + "testValue": true, + "testAccessibleTree": true, + "isAccessible": true, + "getAccessibleDOMNodeID": true, + + // Defined for all top level accessibility browser tests. + "setE10sPrefs": true, + "unsetE10sPrefs": true, + "initPromise": true, + "shutdownPromise": true, + "forceGC": true, + + // Defined for all e10s accessibility browser tests. + "addAccessibleTask": true, + "BrowserTestUtils": true, + "ContentTask": true, + "gBrowser": true, + "isDefunct": true, + "loadScripts": true, + "loadFrameScripts": true, + "Logger": true, + "MOCHITESTS_DIR": true, + "waitForEvent": true, + "waitForMultipleEvents": true, + "invokeSetAttribute": true, + "invokeSetStyle": true, + "invokeFocus": true, + "findAccessibleChildByID": true + }, + "rules": { + "mozilla/no-aArgs": "warn", + "mozilla/no-cpows-in-tests": "warn", + "mozilla/reject-importGlobalProperties": "warn", + "mozilla/var-only-at-top-level": "warn", + + "block-scoped-var": "error", + "brace-style": ["error", "1tbs"], + "camelcase": "error", + "comma-dangle": ["error", "never"], + "comma-spacing": "error", + "comma-style": ["error", "last"], + "complexity": ["error", 35], + "consistent-this": "off", + "curly": ["error", "multi-line"], + "default-case": "off", + "dot-location": ["error", "property"], + "dot-notation": "error", + "eol-last": "error", + "eqeqeq": "off", + "func-names": "off", + "func-style": "off", + "generator-star": "off", + "global-strict": "off", + "handle-callback-err": ["error", "er"], + "indent": ["error", 2, {"SwitchCase": 1}], + "key-spacing": ["error", {"beforeColon": false, "afterColon": true}], + "linebreak-style": "off", + "max-depth": "off", + "max-nested-callbacks": ["error", 4], + "max-params": "off", + "max-statements": "off", + "new-cap": ["error", {"capIsNew": false}], + "new-parens": "error", + "no-array-constructor": "error", + "no-bitwise": "off", + "no-caller": "error", + "no-catch-shadow": "error", + "no-comma-dangle": "off", + "no-cond-assign": "error", + "no-console": "off", + "no-constant-condition": "off", + "no-continue": "off", + "no-control-regex": "error", + "no-debugger": "error", + "no-delete-var": "error", + "no-div-regex": "off", + "no-dupe-args": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-else-return": "error", + "no-empty": "error", + "no-empty-character-class": "error", + "no-eval": "error", + "no-ex-assign": "error", + "no-extend-native": "error", + "no-extra-bind": "error", + "no-extra-boolean-cast": "error", + "no-extra-parens": "off", + "no-extra-semi": "error", + "no-extra-strict": "off", + "no-fallthrough": "error", + "no-floating-decimal": "off", + "no-inline-comments": "off", + "no-lonely-if": "error", + "no-mixed-requires": "off", + "no-mixed-spaces-and-tabs": "error", + "no-multi-spaces": "error", + "no-multi-str": "error", + "no-multiple-empty-lines": ["error", {"max": 1}], + "no-native-reassign": "error", + "no-nested-ternary": "error", + "no-new-require": "off", + "no-octal": "error", + "no-param-reassign": "off", + "no-path-concat": "off", + "no-plusplus": "off", + "no-process-env": "off", + "no-process-exit": "off", + "no-proto": "error", + "no-redeclare": "error", + "no-regex-spaces": "error", + "no-reserved-keys": "off", + "no-restricted-modules": "off", + "no-return-assign": "error", + "no-script-url": "off", + "no-self-compare": "error", + "no-sequences": "error", + "no-shadow": "error", + "no-shadow-restricted-names": "error", + "no-space-before-semi": "off", + "no-spaced-func": "error", + "no-sparse-arrays": "error", + "no-sync": "off", + "no-ternary": "off", + "no-throw-literal": "error", + "no-trailing-spaces": "error", + "no-undef": "error", + "no-underscore-dangle": "off", + "no-undefined": "off", + "no-unneeded-ternary": "error", + "no-unreachable": "error", + "no-unused-vars": ["error", {"vars": "all", "args": "none"}], + "no-use-before-define": "off", + "no-var": "off", + "no-warning-comments": "off", + "no-with": "error", + "object-shorthand": "off", + "one-var": ["error", "never"], + "padded-blocks": ["error", "never"], + "quote-props": "off", + "radix": "error", + "semi": ["error", "always"], + "semi-spacing": ["error", {"before": false, "after": true}], + "sort-vars": "off", + "space-after-function-name": "off", + "keyword-spacing": "error", + "space-before-blocks": "error", + "space-before-function-parentheses": "off", + "space-before-function-paren": ["error", "never"], + "space-in-brackets": "off", + "space-in-parens": ["error", "never"], + "space-infix-ops": ["error", {"int32Hint": true}], + "space-unary-ops": ["error", { "words": true, "nonwords": false }], + "space-unary-word-ops": "off", + "spaced-comment": ["error", "always"], + "strict": ["error", "global"], + "use-isnan": "error", + "valid-jsdoc": "off", + "valid-typeof": "error", + "vars-on-top": "off", + "wrap-iife": "off", + "wrap-regex": "off", + "yoda": "error", + + "guard-for-in": "off", + "newline-after-var": "off", + "no-alert": "off", + "no-eq-null": "off", + "no-func-assign": "off", + "no-implied-eval": "off", + "no-inner-declarations": "off", + "no-invalid-regexp": "off", + "no-irregular-whitespace": "off", + "no-iterator": "off", + "no-label-var": "off", + "no-labels": "error", + "no-lone-blocks": "off", + "no-loop-func": "off", + "no-negated-in-lhs": "off", + "no-new": "off", + "no-new-func": "off", + "no-new-object": "off", + "no-new-wrappers": "off", + "no-obj-calls": "off", + "no-octal-escape": "off", + "no-undef-init": "error", + "no-unexpected-multiline": "error", + "object-curly-spacing": "off", + "no-unused-expressions": "off", + "no-void": "off", + "no-wrap-func": "off", + "operator-assignment": "off", + "operator-linebreak": ["error", "after"] + } +}; diff --git a/accessible/tests/browser/browser.ini b/accessible/tests/browser/browser.ini new file mode 100644 index 000000000..402deda24 --- /dev/null +++ b/accessible/tests/browser/browser.ini @@ -0,0 +1,17 @@ +[DEFAULT] + +support-files = + head.js + shared-head.js + +[browser_shutdown_multi_reference.js] +[browser_shutdown_parent_own_reference.js] +skip-if = !e10s # e10s specific test for a11y start/shutdown between parent and content. +[browser_shutdown_remote_no_reference.js] +skip-if = !e10s # e10s specific test for a11y start/shutdown between parent and content. +[browser_shutdown_remote_only.js] +skip-if = !e10s # e10s specific test for a11y start/shutdown between parent and content. +[browser_shutdown_remote_own_reference.js] +skip-if = !e10s # e10s specific test for a11y start/shutdown between parent and content. +[browser_shutdown_scope_lifecycle.js] +[browser_shutdown_start_restart.js] diff --git a/accessible/tests/browser/browser_shutdown_multi_reference.js b/accessible/tests/browser/browser_shutdown_multi_reference.js new file mode 100644 index 000000000..e0ba3ce6b --- /dev/null +++ b/accessible/tests/browser/browser_shutdown_multi_reference.js @@ -0,0 +1,48 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +add_task(function* () { + info('Creating a service'); + // Create a11y service. + let a11yInit = initPromise(); + let accService1 = Cc['@mozilla.org/accessibilityService;1'].getService( + Ci.nsIAccessibilityService); + yield a11yInit; + ok(accService1, 'Service initialized'); + + // Add another reference to a11y service. This will not trigger + // 'a11y-init-or-shutdown' event + let accService2 = Cc['@mozilla.org/accessibilityService;1'].getService( + Ci.nsIAccessibilityService); + ok(accService2, 'Service initialized'); + + info('Removing all service references'); + let canShutdown = false; + // This promise will resolve only if canShutdonw flag is set to true. If + // 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut + // down, the promise will reject. + let a11yShutdown = new Promise((resolve, reject) => + shutdownPromise().then(flag => canShutdown ? + resolve() : reject('Accessible service was shut down incorrectly'))); + // Remove first a11y service reference. + accService1 = null; + ok(!accService1, 'Service is removed'); + // Force garbage collection that should not trigger shutdown because there is + // another reference. + forceGC(); + + // Have some breathing room when removing a11y service references. + yield new Promise(resolve => executeSoon(resolve)); + + // Now allow a11y service to shutdown. + canShutdown = true; + // Remove last a11y service reference. + accService2 = null; + ok(!accService2, 'Service is removed'); + // Force garbage collection that should trigger shutdown. + forceGC(); + yield a11yShutdown; +}); diff --git a/accessible/tests/browser/browser_shutdown_parent_own_reference.js b/accessible/tests/browser/browser_shutdown_parent_own_reference.js new file mode 100644 index 000000000..9895bd2c7 --- /dev/null +++ b/accessible/tests/browser/browser_shutdown_parent_own_reference.js @@ -0,0 +1,72 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +add_task(function* () { + // Making sure that the e10s is enabled on Windows for testing. + yield setE10sPrefs(); + + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: `data:text/html, + + + + Accessibility Test + + + ` + }, function*(browser) { + info('Creating a service in parent and waiting for service to be created ' + + 'in content'); + // Create a11y service in the main process. This will trigger creating of + // the a11y service in parent as well. + let parentA11yInit = initPromise(); + let contentA11yInit = initPromise(browser); + let accService = Cc['@mozilla.org/accessibilityService;1'].getService( + Ci.nsIAccessibilityService); + ok(accService, 'Service initialized in parent'); + yield Promise.all([parentA11yInit, contentA11yInit]); + + info('Adding additional reference to accessibility service in content ' + + 'process'); + // Add a new reference to the a11y service inside the content process. + loadFrameScripts(browser, `let accService = Components.classes[ + '@mozilla.org/accessibilityService;1'].getService( + Components.interfaces.nsIAccessibilityService);`); + + info('Trying to shut down a service in content and making sure it stays ' + + 'alive as it was started by parent'); + let contentCanShutdown = false; + // This promise will resolve only if contentCanShutdown flag is set to true. + // If 'a11y-init-or-shutdown' event with '0' flag (in content) comes before + // it can be shut down, the promise will reject. + let contentA11yShutdown = new Promise((resolve, reject) => + shutdownPromise(browser).then(flag => contentCanShutdown ? + resolve() : reject('Accessible service was shut down incorrectly'))); + // Remove a11y service reference in content and force garbage collection. + // This should not trigger shutdown since a11y was originally initialized by + // the main process. + loadFrameScripts(browser, `accService = null; Components.utils.forceGC();`); + + // Have some breathing room between a11y service shutdowns. + yield new Promise(resolve => executeSoon(resolve)); + + info('Removing a service in parent'); + // Now allow a11y service to shutdown in content. + contentCanShutdown = true; + // Remove the a11y service reference in the main process. + let parentA11yShutdown = shutdownPromise(); + accService = null; + ok(!accService, 'Service is removed in parent'); + // Force garbage collection that should trigger shutdown in both parent and + // content. + forceGC(); + yield Promise.all([parentA11yShutdown, contentA11yShutdown]); + + // Unsetting e10s related preferences. + yield unsetE10sPrefs(); + }); +}); diff --git a/accessible/tests/browser/browser_shutdown_remote_no_reference.js b/accessible/tests/browser/browser_shutdown_remote_no_reference.js new file mode 100644 index 000000000..b066c2592 --- /dev/null +++ b/accessible/tests/browser/browser_shutdown_remote_no_reference.js @@ -0,0 +1,48 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +add_task(function* () { + // Making sure that the e10s is enabled on Windows for testing. + yield setE10sPrefs(); + + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: `data:text/html, + + + + Accessibility Test + + + ` + }, function*(browser) { + info('Creating a service in parent and waiting for service to be created ' + + 'in content'); + // Create a11y service in the main process. This will trigger creating of + // the a11y service in parent as well. + let parentA11yInit = initPromise(); + let contentA11yInit = initPromise(browser); + let accService = Cc['@mozilla.org/accessibilityService;1'].getService( + Ci.nsIAccessibilityService); + ok(accService, 'Service initialized in parent'); + yield Promise.all([parentA11yInit, contentA11yInit]); + + info('Removing a service in parent and waiting for service to be shut ' + + 'down in content'); + // Remove a11y service reference in the main process. + let parentA11yShutdown = shutdownPromise(); + let contentA11yShutdown = shutdownPromise(browser); + accService = null; + ok(!accService, 'Service is removed in parent'); + // Force garbage collection that should trigger shutdown in both main and + // content process. + forceGC(); + yield Promise.all([parentA11yShutdown, contentA11yShutdown]); + }); + + // Unsetting e10s related preferences. + yield unsetE10sPrefs(); +}); diff --git a/accessible/tests/browser/browser_shutdown_remote_only.js b/accessible/tests/browser/browser_shutdown_remote_only.js new file mode 100644 index 000000000..aab497678 --- /dev/null +++ b/accessible/tests/browser/browser_shutdown_remote_only.js @@ -0,0 +1,40 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +add_task(function* () { + // Making sure that the e10s is enabled on Windows for testing. + yield setE10sPrefs(); + + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: `data:text/html, + + + + Accessibility Test + + + ` + }, function*(browser) { + info('Creating a service in content'); + // Create a11y service in the content process. + let a11yInit = initPromise(browser); + loadFrameScripts(browser, `let accService = Components.classes[ + '@mozilla.org/accessibilityService;1'].getService( + Components.interfaces.nsIAccessibilityService);`); + yield a11yInit; + + info('Removing a service in content'); + // Remove a11y service reference from the content process. + let a11yShutdown = shutdownPromise(browser); + // Force garbage collection that should trigger shutdown. + loadFrameScripts(browser, `accService = null; Components.utils.forceGC();`); + yield a11yShutdown; + + // Unsetting e10s related preferences. + yield unsetE10sPrefs(); + }); +}); diff --git a/accessible/tests/browser/browser_shutdown_remote_own_reference.js b/accessible/tests/browser/browser_shutdown_remote_own_reference.js new file mode 100644 index 000000000..429737a81 --- /dev/null +++ b/accessible/tests/browser/browser_shutdown_remote_own_reference.js @@ -0,0 +1,75 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +add_task(function* () { + // Making sure that the e10s is enabled on Windows for testing. + yield setE10sPrefs(); + + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: `data:text/html, + + + + Accessibility Test + + + ` + }, function*(browser) { + info('Creating a service in parent and waiting for service to be created ' + + 'in content'); + // Create a11y service in the main process. This will trigger creating of + // the a11y service in parent as well. + let parentA11yInit = initPromise(); + let contentA11yInit = initPromise(browser); + let accService = Cc['@mozilla.org/accessibilityService;1'].getService( + Ci.nsIAccessibilityService); + ok(accService, 'Service initialized in parent'); + yield Promise.all([parentA11yInit, contentA11yInit]); + + info('Adding additional reference to accessibility service in content ' + + 'process'); + // Add a new reference to the a11y service inside the content process. + loadFrameScripts(browser, `let accService = Components.classes[ + '@mozilla.org/accessibilityService;1'].getService( + Components.interfaces.nsIAccessibilityService);`); + + info('Shutting down a service in parent and making sure the one in ' + + 'content stays alive'); + let contentCanShutdown = false; + let parentA11yShutdown = shutdownPromise(); + // This promise will resolve only if contentCanShutdown flag is set to true. + // If 'a11y-init-or-shutdown' event with '0' flag (in content) comes before + // it can be shut down, the promise will reject. + let contentA11yShutdown = new Promise((resolve, reject) => + shutdownPromise(browser).then(flag => contentCanShutdown ? + resolve() : reject('Accessible service was shut down incorrectly'))); + // Remove a11y service reference in the main process and force garbage + // collection. This should not trigger shutdown in content since a11y + // service is used by XPCOM. + accService = null; + ok(!accService, 'Service is removed in parent'); + // Force garbage collection that should not trigger shutdown because there + // is a reference in a content process. + forceGC(); + loadFrameScripts(browser, `Components.utils.forceGC();`); + yield parentA11yShutdown; + + // Have some breathing room between a11y service shutdowns. + yield new Promise(resolve => executeSoon(resolve)); + + info('Removing a service in content'); + // Now allow a11y service to shutdown in content. + contentCanShutdown = true; + // Remove last reference to a11y service in content and force garbage + // collection that should trigger shutdown. + loadFrameScripts(browser, `accService = null; Components.utils.forceGC();`); + yield contentA11yShutdown; + + // Unsetting e10s related preferences. + yield unsetE10sPrefs(); + }); +}); diff --git a/accessible/tests/browser/browser_shutdown_scope_lifecycle.js b/accessible/tests/browser/browser_shutdown_scope_lifecycle.js new file mode 100644 index 000000000..be9c63d46 --- /dev/null +++ b/accessible/tests/browser/browser_shutdown_scope_lifecycle.js @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +add_task(function* () { + // Create a11y service inside of the function scope. Its reference should be + // released once the anonimous function is called. + let a11yInitThenShutdown = initPromise().then(shutdownPromise); + + (function() { + let accService = Cc['@mozilla.org/accessibilityService;1'].getService( + Ci.nsIAccessibilityService); + ok(accService, 'Service initialized'); + })(); + + // Force garbage collection that should trigger shutdown. + forceGC(); + yield a11yInitThenShutdown; +}); diff --git a/accessible/tests/browser/browser_shutdown_start_restart.js b/accessible/tests/browser/browser_shutdown_start_restart.js new file mode 100644 index 000000000..53bd4daee --- /dev/null +++ b/accessible/tests/browser/browser_shutdown_start_restart.js @@ -0,0 +1,41 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +add_task(function* () { + info('Creating a service'); + // Create a11y service. + let a11yInit = initPromise(); + let accService = Cc['@mozilla.org/accessibilityService;1'].getService( + Ci.nsIAccessibilityService); + yield a11yInit; + ok(accService, 'Service initialized'); + + info('Removing a service'); + // Remove the only reference to an a11y service. + let a11yShutdown = shutdownPromise(); + accService = null; + ok(!accService, 'Service is removed'); + // Force garbage collection that should trigger shutdown. + forceGC(); + yield a11yShutdown; + + info('Recreating a service'); + // Re-create a11y service. + a11yInit = initPromise(); + accService = Cc['@mozilla.org/accessibilityService;1'].getService( + Ci.nsIAccessibilityService); + yield a11yInit; + ok(accService, 'Service initialized again'); + + info('Removing a service again'); + // Remove the only reference to an a11y service again. + a11yShutdown = shutdownPromise(); + accService = null; + ok(!accService, 'Service is removed again'); + // Force garbage collection that should trigger shutdown. + forceGC(); + yield a11yShutdown; +}); diff --git a/accessible/tests/browser/e10s/browser.ini b/accessible/tests/browser/e10s/browser.ini new file mode 100644 index 000000000..e0ca44dde --- /dev/null +++ b/accessible/tests/browser/e10s/browser.ini @@ -0,0 +1,51 @@ +[DEFAULT] +skip-if = (e10s && os == 'win') # Bug 1269369: Document loaded event does not fire in Windows +support-files = + events.js + head.js + doc_treeupdate_ariadialog.html + doc_treeupdate_ariaowns.html + doc_treeupdate_imagemap.html + doc_treeupdate_removal.xhtml + doc_treeupdate_visibility.html + doc_treeupdate_whitespace.html + !/accessible/tests/browser/shared-head.js + !/accessible/tests/mochitest/*.js + !/accessible/tests/mochitest/letters.gif + !/accessible/tests/mochitest/moz.png + +# Caching tests +[browser_caching_attributes.js] +[browser_caching_description.js] +[browser_caching_name.js] +[browser_caching_relations.js] +[browser_caching_states.js] +[browser_caching_value.js] + +# Events tests +[browser_events_caretmove.js] +[browser_events_hide.js] +[browser_events_show.js] +[browser_events_statechange.js] +[browser_events_textchange.js] + +# Tree update tests +[browser_treeupdate_ariadialog.js] +[browser_treeupdate_ariaowns.js] +[browser_treeupdate_canvas.js] +[browser_treeupdate_cssoverflow.js] +[browser_treeupdate_doc.js] +[browser_treeupdate_gencontent.js] +[browser_treeupdate_hidden.js] +[browser_treeupdate_imagemap.js] +skip-if = e10s # Bug 1318569 +[browser_treeupdate_list.js] +[browser_treeupdate_list_editabledoc.js] +[browser_treeupdate_listener.js] +[browser_treeupdate_optgroup.js] +[browser_treeupdate_removal.js] +[browser_treeupdate_table.js] +[browser_treeupdate_textleaf.js] +[browser_treeupdate_visibility.js] +[browser_treeupdate_whitespace.js] +skip-if = true # Failing due to incorrect index of test container children on document load. diff --git a/accessible/tests/browser/e10s/browser_caching_attributes.js b/accessible/tests/browser/e10s/browser_caching_attributes.js new file mode 100644 index 000000000..449ca9d91 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_caching_attributes.js @@ -0,0 +1,117 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_FOCUS */ + +loadScripts({ name: 'attributes.js', dir: MOCHITESTS_DIR }); + +/** + * Default textbox accessible attributes. + */ +const defaultAttributes = { + 'margin-top': '0px', + 'margin-right': '0px', + 'margin-bottom': '0px', + 'margin-left': '0px', + 'text-align': 'start', + 'text-indent': '0px', + 'id': 'textbox', + 'tag': 'input', + 'display': 'inline' +}; + +/** + * Test data has the format of: + * { + * desc {String} description for better logging + * expected {Object} expected attributes for given accessibles + * unexpected {Object} unexpected attributes for given accessibles + * + * action {?Function*} an optional action that yields a change in + * attributes + * attrs {?Array} an optional list of attributes to update + * waitFor {?Number} an optional event to wait for + * } + */ +const attributesTests = [{ + desc: 'Initiall accessible attributes', + expected: defaultAttributes, + unexpected: { + 'line-number': '1', + 'explicit-name': 'true', + 'container-live': 'polite', + 'live': 'polite' + } +}, { + desc: '@line-number attribute is present when textbox is focused', + action: function*(browser) { + yield invokeFocus(browser, 'textbox'); + }, + waitFor: EVENT_FOCUS, + expected: Object.assign({}, defaultAttributes, { 'line-number': '1' }), + unexpected: { + 'explicit-name': 'true', + 'container-live': 'polite', + 'live': 'polite' + } +}, { + desc: '@aria-live sets container-live and live attributes', + attrs: [{ + attr: 'aria-live', + value: 'polite' + }], + expected: Object.assign({}, defaultAttributes, { + 'line-number': '1', + 'container-live': 'polite', + 'live': 'polite' + }), + unexpected: { + 'explicit-name': 'true' + } +}, { + desc: '@title attribute sets explicit-name attribute to true', + attrs: [{ + attr: 'title', + value: 'textbox' + }], + expected: Object.assign({}, defaultAttributes, { + 'line-number': '1', + 'explicit-name': 'true', + 'container-live': 'polite', + 'live': 'polite' + }), + unexpected: {} +}]; + +/** + * Test caching of accessible object attributes + */ +addAccessibleTask(` + `, + function* (browser, accDoc) { + let textbox = findAccessibleChildByID(accDoc, 'textbox'); + for (let { desc, action, attrs, expected, waitFor, unexpected } of attributesTests) { + info(desc); + let onUpdate; + + if (waitFor) { + onUpdate = waitForEvent(waitFor, 'textbox'); + } + + if (action) { + yield action(browser); + } else if (attrs) { + for (let { attr, value } of attrs) { + yield invokeSetAttribute(browser, 'textbox', attr, value); + } + } + + yield onUpdate; + testAttrs(textbox, expected); + testAbsentAttrs(textbox, unexpected); + } + } +); diff --git a/accessible/tests/browser/e10s/browser_caching_description.js b/accessible/tests/browser/e10s/browser_caching_description.js new file mode 100644 index 000000000..18ee58bd0 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_caching_description.js @@ -0,0 +1,164 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_DESCRIPTION_CHANGE, EVENT_NAME_CHANGE, EVENT_REORDER */ + +loadScripts({ name: 'name.js', dir: MOCHITESTS_DIR }); + +/** + * Test data has the format of: + * { + * desc {String} description for better logging + * expected {String} expected description value for a given accessible + * attrs {?Array} an optional list of attributes to update + * waitFor {?Array} an optional list of accessible events to wait for when + * attributes are updated + * } + */ +const tests = [{ + desc: 'No description when there are no @alt, @title and @aria-describedby', + expected: '' +}, { + desc: 'Description from @aria-describedby attribute', + attrs: [{ + attr: 'aria-describedby', + value: 'description' + }], + waitFor: [{ eventType: EVENT_DESCRIPTION_CHANGE, id: 'image' }], + expected: 'aria description' +}, { + desc: 'No description from @aria-describedby since it is the same as the ' + + '@alt attribute which is used as the name', + attrs: [{ + attr: 'alt', + value: 'aria description' + }], + waitFor: [{ eventType: EVENT_REORDER, id: 'body' }], + expected: '' +}, { + desc: 'Description from @aria-describedby attribute when @alt and ' + + '@aria-describedby are not the same', + attrs: [{ + attr: 'aria-describedby', + value: 'description2' + }], + waitFor: [{ eventType: EVENT_DESCRIPTION_CHANGE, id: 'image' }], + expected: 'another description' +}, { + desc: 'Description from @aria-describedby attribute when @title (used for ' + + 'name) and @aria-describedby are not the same', + attrs: [{ + attr: 'alt' + }, { + attr: 'title', + value: 'title' + }], + waitFor: [{ eventType: EVENT_REORDER, id: 'body' }], + expected: 'another description' +}, { + desc: 'No description from @aria-describedby since it is the same as the ' + + '@title attribute which is used as the name', + attrs: [{ + attr: 'title', + value: 'another description' + }], + waitFor: [{ eventType: EVENT_NAME_CHANGE, id: 'image' }], + expected: '' +}, { + desc: 'No description with only @title attribute which is used as the name', + attrs: [{ + attr: 'aria-describedby' + }], + waitFor: [{ eventType: EVENT_DESCRIPTION_CHANGE, id: 'image' }], + expected: '' +}, { + desc: 'Description from @title attribute when @alt and @atitle are not the ' + + 'same', + attrs: [{ + attr: 'alt', + value: 'aria description' + }], + waitFor: [{ eventType: EVENT_REORDER, id: 'body' }], + expected: 'another description' +}, { + desc: 'No description from @title since it is the same as the @alt ' + + 'attribute which is used as the name', + attrs: [{ + attr: 'alt', + value: 'another description' + }], + waitFor: [{ eventType: EVENT_NAME_CHANGE, id: 'image' }], + expected: '' +}, { + desc: 'No description from @aria-describedby since it is the same as the ' + + '@alt (used for name) and @title attributes', + attrs: [{ + attr: 'aria-describedby', + value: 'description2' + }], + waitFor: [{ eventType: EVENT_DESCRIPTION_CHANGE, id: 'image' }], + expected: '' +}, { + desc: 'Description from @aria-describedby attribute when it is different ' + + 'from @alt (used for name) and @title attributes', + attrs: [{ + attr: 'aria-describedby', + value: 'description' + }], + waitFor: [{ eventType: EVENT_DESCRIPTION_CHANGE, id: 'image' }], + expected: 'aria description' +}, { + desc: 'No description from @aria-describedby since it is the same as the ' + + '@alt attribute (used for name) but different from title', + attrs: [{ + attr: 'alt', + value: 'aria description' + }], + waitFor: [{ eventType: EVENT_NAME_CHANGE, id: 'image' }], + expected: '' +}, { + desc: 'Description from @aria-describedby attribute when @alt (used for ' + + 'name) and @aria-describedby are not the same but @title and ' + + 'aria-describedby are', + attrs: [{ + attr: 'aria-describedby', + value: 'description2' + }], + waitFor: [{ eventType: EVENT_DESCRIPTION_CHANGE, id: 'image' }], + expected: 'another description' +}]; + +/** + * Test caching of accessible object description + */ +addAccessibleTask(` +

aria description

+

another description

+ `, + function*(browser, accDoc) { + let imgAcc = findAccessibleChildByID(accDoc, 'image'); + + for (let { desc, waitFor, attrs, expected } of tests) { + info(desc); + let onUpdate; + if (waitFor) { + onUpdate = waitForMultipleEvents(waitFor); + } + if (attrs) { + for (let { attr, value } of attrs) { + yield invokeSetAttribute(browser, 'image', attr, value); + } + } + yield onUpdate; + // When attribute change (alt) triggers reorder event, accessible will + // become defunct. + if (isDefunct(imgAcc)) { + imgAcc = findAccessibleChildByID(accDoc, 'image'); + } + testDescr(imgAcc, expected); + } + } +); diff --git a/accessible/tests/browser/e10s/browser_caching_name.js b/accessible/tests/browser/e10s/browser_caching_name.js new file mode 100644 index 000000000..08e635014 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_caching_name.js @@ -0,0 +1,434 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_REORDER, EVENT_TEXT_INSERTED */ + +loadScripts({ name: 'name.js', dir: MOCHITESTS_DIR }); + +/** + * Rules for name tests that are inspired by + * accessible/tests/mochitest/name/markuprules.xul + * + * Each element in the list of rules represents a name calculation rule for a + * particular test case. + * + * The rules have the following format: + * { attr } - calculated from attribute + * { elm } - calculated from another element + * { fromsubtree } - calculated from element's subtree + * + * + * Options include: + * * recreated - subrtee is recreated and the test should only continue + * after a reorder event + * * textchanged - text is inserted into a subtree and the test should only + * continue after a text inserted event + */ +const ARIARule = [{ attr: 'aria-labelledby' }, { attr: 'aria-label' }]; +const HTMLControlHeadRule = [...ARIARule, { elm: 'label', isSibling: true }]; +const rules = { + CSSContent: [{ elm: 'style', isSibling: true }, { fromsubtree: true }], + HTMLARIAGridCell: [...ARIARule, { fromsubtree: true }, { attr: 'title' }], + HTMLControl: [...HTMLControlHeadRule, { fromsubtree: true }, + { attr: 'title' }], + HTMLElm: [...ARIARule, { attr: 'title' }], + HTMLImg: [...ARIARule, { attr: 'alt', recreated: true }, { attr: 'title' }], + HTMLImgEmptyAlt: [...ARIARule, { attr: 'title' }, { attr: 'alt' }], + HTMLInputButton: [...HTMLControlHeadRule, { attr: 'value' }, + { attr: 'title' }], + HTMLInputImage: [...HTMLControlHeadRule, { attr: 'alt', recreated: true }, + { attr: 'value', recreated: true }, { attr: 'title' }], + HTMLInputImageNoValidSrc: [...HTMLControlHeadRule, + { attr: 'alt', recreated: true }, { attr: 'value', recreated: true }], + HTMLInputReset: [...HTMLControlHeadRule, + { attr: 'value', textchanged: true }], + HTMLInputSubmit: [...HTMLControlHeadRule, + { attr: 'value', textchanged: true }], + HTMLLink: [...ARIARule, { fromsubtree: true }, { attr: 'title' }], + HTMLLinkImage: [...ARIARule, { elm: 'img' }, { attr: 'title' }], + HTMLOption: [...ARIARule, { attr: 'label' }, { fromsubtree: true }, + { attr: 'title' }], + HTMLTable: [...ARIARule, { elm: 'caption' }, { attr: 'summary' }, + { attr: 'title' }] +}; + +const markupTests = [{ + id: 'btn', + ruleset: 'HTMLControl', + markup: ` + test2 + test3 + + `, + expected: ['test2 test3', 'test1', 'test4', 'press me', 'test5'] +}, { + id: 'btn', + ruleset: 'HTMLInputButton', + markup: ` + test2 + test3 + + `, + expected: ['test2 test3', 'test1', 'test4', 'name from value', + 'name from title'] +}, { + id: 'btn-submit', + ruleset: 'HTMLInputSubmit', + markup: ` + test2 + test3 + + `, + expected: ['test2 test3', 'test1', 'test4', 'name from value'] +}, { + id: 'btn-reset', + ruleset: 'HTMLInputReset', + markup: ` + test2 + test3 + + `, + expected: ['test2 test3', 'test1', 'test4', 'name from value'] +}, { + id: 'btn-image', + ruleset: 'HTMLInputImage', + markup: ` + test2 + test3 + + `, + expected: ['test2 test3', 'test1', 'test4', 'name from alt', + 'name from value', 'name from title'] +}, { + id: 'btn-image', + ruleset: 'HTMLInputImageNoValidSrc', + markup: ` + test2 + test3 + + `, + expected: ['test2 test3', 'test1', 'test4', 'name from alt', + 'name from value'] +}, { + id: 'opt', + ruleset: 'HTMLOption', + markup: ` + test2 + test3 + `, + expected: ['test2 test3', 'test1', 'test4', 'option1', 'test5'] +}, { + id: 'img', + ruleset: 'HTMLImg', + markup: ` + test2 + test3 + Mozilla logo`, + expected: ['test2 test3', 'Logo of Mozilla', 'Mozilla logo', 'This is a logo'] +}, { + id: 'imgemptyalt', + ruleset: 'HTMLImgEmptyAlt', + markup: ` + test2 + test3 + `, + expected: ['test2 test3', 'Logo of Mozilla', 'This is a logo', ''] +}, { + id: 'tc', + ruleset: 'HTMLElm', + markup: ` + test2 + test3 + + + + + +
+

This is a paragraph

+ This is a link +
    +
  • This is a list
  • +
+
`, + expected: ['test2 test3', 'test1', 'test5'] +}, { + id: 'gc', + ruleset: 'HTMLARIAGridCell', + markup: ` + test2 + test3 + + + + + +
+

This is a paragraph

+ This is a link +
    +
  • Listitem1
  • +
  • Listitem2
  • +
+
`, + expected: ['test2 test3', 'test1', 'This is a paragraph', + 'This is a paragraph This is a link This is a list'] +}, { + id: 't', + ruleset: 'HTMLTable', + markup: ` + lby_tst6_1 + lby_tst6_2 + + + + + + + +
caption_tst6
cell1cell2
`, + expected: ['lby_tst6_1 lby_tst6_2', 'arialabel_tst6', 'caption_tst6', + 'summary_tst6', 'title_tst6'] +}, { + id: 'btn', + ruleset: 'CSSContent', + markup: ` + + `, + expected: ['do not press me', 'press me'] +}, { + // TODO: uncomment when Bug-1256382 is resoved. + // id: 'li', + // ruleset: 'CSSContent', + // markup: ` + // + // `, + // expected: ['1. Listitem', `${String.fromCharCode(0x2022)} Listitem`] +// }, { + id: 'a', + ruleset: 'HTMLLink', + markup: ` + test2 + test3 + test5`, + expected: ['test2 test3', 'test1', 'test5', 'test4'] +}, { + id: 'a-img', + ruleset: 'HTMLLinkImage', + markup: ` + test2 + test3 + test5`, + expected: ['test2 test3', 'test1', 'test5', 'test4'] +}]; + +/** + * Wait for an accessible event to happen and, in case given accessible is + * defunct, update it to one that is attached to the accessible event. + * @param {Promise} onEvent accessible event promise + * @param {Object} target { acc, parent, id } structure that contains an + * accessible, its parent and its content element + * id. + */ +function* updateAccessibleIfNeeded(onEvent, target) { + let event = yield onEvent; + if (isDefunct(target.acc)) { + target.acc = findAccessibleChildByID(event.accessible, target.id); + } +} + +/** + * Test accessible name that is calculated from an attribute, remove the + * attribute before proceeding to the next name test. If attribute removal + * results in a reorder or text inserted event - wait for it. If accessible + * becomes defunct, update its reference using the one that is attached to one + * of the above events. + * @param {Object} browser current "tabbrowser" element + * @param {Object} target { acc, parent, id } structure that contains an + * accessible, its parent and its content element + * id. + * @param {Object} rule current attr rule for name calculation + * @param {[type]} expected expected name value + */ +function* testAttrRule(browser, target, rule, expected) { + testName(target.acc, expected); + let onEvent; + if (rule.recreated) { + onEvent = waitForEvent(EVENT_REORDER, target.parent); + } else if (rule.textchanged) { + onEvent = waitForEvent(EVENT_TEXT_INSERTED, target.id); + } + yield invokeSetAttribute(browser, target.id, rule.attr); + if (onEvent) { + yield updateAccessibleIfNeeded(onEvent, target); + } +} + +/** + * Test accessible name that is calculated from an element name, remove the + * element before proceeding to the next name test. If element removal results + * in a reorder event - wait for it. If accessible becomes defunct, update its + * reference using the one that is attached to a possible reorder event. + * @param {Object} browser current "tabbrowser" element + * @param {Object} target { acc, parent, id } structure that contains an + * accessible, its parent and its content element + * id. + * @param {Object} rule current elm rule for name calculation + * @param {[type]} expected expected name value + */ +function* testElmRule(browser, target, rule, expected) { + testName(target.acc, expected); + let onEvent = waitForEvent(EVENT_REORDER, rule.isSibling ? + target.parent : target.id); + yield ContentTask.spawn(browser, rule.elm, elm => + content.document.querySelector(`${elm}`).remove()); + yield updateAccessibleIfNeeded(onEvent, target); +} + +/** + * Test accessible name that is calculated from its subtree, remove the subtree + * and wait for a reorder event before proceeding to the next name test. If + * accessible becomes defunct, update its reference using the one that is + * attached to a reorder event. + * @param {Object} browser current "tabbrowser" element + * @param {Object} target { acc, parent, id } structure that contains an + * accessible, its parent and its content element + * id. + * @param {Object} rule current subtree rule for name calculation + * @param {[type]} expected expected name value + */ +function* testSubtreeRule(browser, target, rule, expected) { + testName(target.acc, expected); + let onEvent = waitForEvent(EVENT_REORDER, target.id); + yield ContentTask.spawn(browser, target.id, id => { + let elm = content.document.getElementById(id); + while (elm.firstChild) { + elm.removeChild(elm.firstChild); + } + }); + yield updateAccessibleIfNeeded(onEvent, target); +} + +/** + * Iterate over a list of rules and test accessible names for each one of the + * rules. + * @param {Object} browser current "tabbrowser" element + * @param {Object} target { acc, parent, id } structure that contains an + * accessible, its parent and its content element + * id. + * @param {Array} ruleset A list of rules to test a target with + * @param {Array} expected A list of expected name value for each rule + */ +function* testNameRule(browser, target, ruleset, expected) { + for (let i = 0; i < ruleset.length; ++i) { + let rule = ruleset[i]; + let testFn; + if (rule.attr) { + testFn = testAttrRule; + } else if (rule.elm) { + testFn = testElmRule; + } else if (rule.fromsubtree) { + testFn = testSubtreeRule; + } + yield testFn(browser, target, rule, expected[i]); + } +} + +markupTests.forEach(({ id, ruleset, markup, expected }) => + addAccessibleTask(markup, function*(browser, accDoc) { + // Find a target accessible from an accessible subtree. + let acc = findAccessibleChildByID(accDoc, id); + // Find target's parent accessible from an accessible subtree. + let parent = getAccessibleDOMNodeID(acc.parent); + let target = { id, parent, acc }; + yield testNameRule(browser, target, rules[ruleset], expected); + })); diff --git a/accessible/tests/browser/e10s/browser_caching_relations.js b/accessible/tests/browser/e10s/browser_caching_relations.js new file mode 100644 index 000000000..772aee96a --- /dev/null +++ b/accessible/tests/browser/e10s/browser_caching_relations.js @@ -0,0 +1,86 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global RELATION_LABELLED_BY, RELATION_LABEL_FOR, RELATION_DESCRIBED_BY, + RELATION_DESCRIPTION_FOR, RELATION_CONTROLLER_FOR, + RELATION_CONTROLLED_BY, RELATION_FLOWS_TO, RELATION_FLOWS_FROM */ + +loadScripts({ name: 'relations.js', dir: MOCHITESTS_DIR }); + +/** + * A test specification that has the following format: + * [ + * attr relevant aria attribute + * hostRelation corresponding host relation type + * dependantRelation corresponding dependant relation type + * ] + */ +const attrRelationsSpec = [ + ['aria-labelledby', RELATION_LABELLED_BY, RELATION_LABEL_FOR], + ['aria-describedby', RELATION_DESCRIBED_BY, RELATION_DESCRIPTION_FOR], + ['aria-controls', RELATION_CONTROLLER_FOR, RELATION_CONTROLLED_BY], + ['aria-flowto', RELATION_FLOWS_TO, RELATION_FLOWS_FROM] +]; + +function* testRelated(browser, accDoc, attr, hostRelation, dependantRelation) { + let host = findAccessibleChildByID(accDoc, 'host'); + let dependant1 = findAccessibleChildByID(accDoc, 'dependant1'); + let dependant2 = findAccessibleChildByID(accDoc, 'dependant2'); + + /** + * Test data has the format of: + * { + * desc {String} description for better logging + * attrs {?Array} an optional list of attributes to update + * expected {Array} expected relation values for dependant1, dependant2 + * and host respectively. + * } + */ + const tests = [{ + desc: 'No attribute', + expected: [ null, null, null ] + }, { + desc: 'Set attribute', + attrs: [{ key: attr, value: 'dependant1' }], + expected: [ host, null, dependant1 ] + }, { + desc: 'Change attribute', + attrs: [{ key: attr, value: 'dependant2' }], + expected: [ null, host, dependant2 ] + }, { + desc: 'Remove attribute', + attrs: [{ key: attr }], + expected: [ null, null, null ] + }]; + + for (let { desc, attrs, expected } of tests) { + info(desc); + + if (attrs) { + for (let { key, value } of attrs) { + yield invokeSetAttribute(browser, 'host', key, value); + } + } + + testRelation(dependant1, dependantRelation, expected[0]); + testRelation(dependant2, dependantRelation, expected[1]); + testRelation(host, hostRelation, expected[2]); + } +} + +/** + * Test caching of relations between accessible objects. + */ +addAccessibleTask(` +
label
+
label2
+ `, + function* (browser, accDoc) { + for (let spec of attrRelationsSpec) { + yield testRelated(browser, accDoc, ...spec); + } + } +); diff --git a/accessible/tests/browser/e10s/browser_caching_states.js b/accessible/tests/browser/e10s/browser_caching_states.js new file mode 100644 index 000000000..69e4931ea --- /dev/null +++ b/accessible/tests/browser/e10s/browser_caching_states.js @@ -0,0 +1,120 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_STATE_CHANGE, STATE_CHECKED, STATE_BUSY, STATE_REQUIRED, + STATE_INVALID, EXT_STATE_ENABLED */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }, + { name: 'states.js', dir: MOCHITESTS_DIR }); + +/** + * Test data has the format of: + * { + * desc {String} description for better logging + * expected {Array} expected states for a given accessible that have the + * following format: + * [ + * expected state, + * expected extra state, + * absent state, + * absent extra state + * ] + * attrs {?Array} an optional list of attributes to update + * } + */ + +// State caching tests for attribute changes +const attributeTests = [{ + desc: 'Checkbox with @checked attribute set to true should have checked ' + + 'state', + attrs: [{ + attr: 'checked', + value: 'true' + }], + expected: [STATE_CHECKED, 0] +}, { + desc: 'Checkbox with no @checked attribute should not have checked state', + attrs: [{ + attr: 'checked' + }], + expected: [0, 0, STATE_CHECKED] +}]; + +// State caching tests for ARIA changes +const ariaTests = [{ + desc: 'File input has busy state when @aria-busy attribute is set to true', + attrs: [{ + attr: 'aria-busy', + value: 'true' + }], + expected: [STATE_BUSY, 0, STATE_REQUIRED | STATE_INVALID] +}, { + desc: 'File input has required state when @aria-required attribute is set ' + + 'to true', + attrs: [{ + attr: 'aria-required', + value: 'true' + }], + expected: [STATE_REQUIRED, 0, STATE_INVALID] +}, { + desc: 'File input has invalid state when @aria-invalid attribute is set to ' + + 'true', + attrs: [{ + attr: 'aria-invalid', + value: 'true' + }], + expected: [STATE_INVALID, 0] +}]; + +// Extra state caching tests +const extraStateTests = [{ + desc: 'Input has no extra enabled state when aria and native disabled ' + + 'attributes are set at once', + attrs: [{ + attr: 'aria-disabled', + value: 'true' + }, { + attr: 'disabled', + value: 'true' + }], + expected: [0, 0, 0, EXT_STATE_ENABLED] +}, { + desc: 'Input has an extra enabled state when aria and native disabled ' + + 'attributes are unset at once', + attrs: [{ + attr: 'aria-disabled' + }, { + attr: 'disabled' + }], + expected: [0, EXT_STATE_ENABLED] +}]; + +function* runStateTests(browser, accDoc, id, tests) { + let acc = findAccessibleChildByID(accDoc, id); + for (let { desc, attrs, expected } of tests) { + info(desc); + let onUpdate = waitForEvent(EVENT_STATE_CHANGE, id); + for (let { attr, value } of attrs) { + yield invokeSetAttribute(browser, id, attr, value); + } + yield onUpdate; + testStates(acc, ...expected); + } +} + +/** + * Test caching of accessible object states + */ +addAccessibleTask(` + + + `, + function* (browser, accDoc) { + yield runStateTests(browser, accDoc, 'checkbox', attributeTests); + yield runStateTests(browser, accDoc, 'file', ariaTests); + yield runStateTests(browser, accDoc, 'text', extraStateTests); + } +); diff --git a/accessible/tests/browser/e10s/browser_caching_value.js b/accessible/tests/browser/e10s/browser_caching_value.js new file mode 100644 index 000000000..2669cbfab --- /dev/null +++ b/accessible/tests/browser/e10s/browser_caching_value.js @@ -0,0 +1,155 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global nsIAccessibleValue, EVENT_VALUE_CHANGE, EVENT_TEXT_VALUE_CHANGE */ + +loadScripts({ name: 'value.js', dir: MOCHITESTS_DIR }); + +/** + * Test data has the format of: + * { + * desc {String} description for better logging + * id {String} given accessible DOMNode ID + * expected {String} expected value for a given accessible + * action {?Function*} an optional action that yields a value change + * attrs {?Array} an optional list of attributes to update + * waitFor {?Number} an optional value change event to wait for + * } + */ +const valueTests = [{ + desc: 'Initially value is set to 1st element of select', + id: 'select', + expected: '1st' +}, { + desc: 'Value should update to 3rd when 3 is pressed', + id: 'select', + action: function*(browser) { + yield invokeFocus(browser, 'select'); + yield BrowserTestUtils.synthesizeKey('3', {}, browser); + }, + waitFor: EVENT_TEXT_VALUE_CHANGE, + expected: '3rd' +}, { + desc: 'Initially value is set to @aria-valuenow for slider', + id: 'slider', + expected: ['5', 5, 0, 7, 0] +}, { + desc: 'Value should change when @aria-valuenow is updated', + id: 'slider', + attrs: [{ + attr: 'aria-valuenow', + value: '6' + }], + waitFor: EVENT_VALUE_CHANGE, + expected: ['6', 6, 0, 7, 0] +}, { + desc: 'Value should change when @aria-valuetext is set', + id: 'slider', + attrs: [{ + attr: 'aria-valuetext', + value: 'plain' + }], + waitFor: EVENT_TEXT_VALUE_CHANGE, + expected: ['plain', 6, 0, 7, 0] +}, { + desc: 'Value should change when @aria-valuetext is updated', + id: 'slider', + attrs: [{ + attr: 'aria-valuetext', + value: 'hey!' + }], + waitFor: EVENT_TEXT_VALUE_CHANGE, + expected: ['hey!', 6, 0, 7, 0] +}, { + desc: 'Value should change to @aria-valuetext when @aria-valuenow is removed', + id: 'slider', + attrs: [{ + attr: 'aria-valuenow' + }], + expected: ['hey!', 0, 0, 7, 0] +}, { + desc: 'Initially value is not set for combobox', + id: 'combobox', + expected: '' +}, { + desc: 'Value should change when @value attribute is updated', + id: 'combobox', + attrs: [{ + attr: 'value', + value: 'hello' + }], + waitFor: EVENT_TEXT_VALUE_CHANGE, + expected: 'hello' +}, { + desc: 'Initially value corresponds to @value attribute for progress', + id: 'progress', + expected: '22%' +}, { + desc: 'Value should change when @value attribute is updated', + id: 'progress', + attrs: [{ + attr: 'value', + value: '50' + }], + waitFor: EVENT_VALUE_CHANGE, + expected: '50%' +}, { + desc: 'Initially value corresponds to @value attribute for range', + id: 'range', + expected: '6' +}, { + desc: 'Value should change when slider is moved', + id: 'range', + action: function*(browser) { + yield invokeFocus(browser, 'range'); + yield BrowserTestUtils.synthesizeKey('VK_LEFT', {}, browser); + }, + waitFor: EVENT_VALUE_CHANGE, + expected: '5' +}]; + +/** + * Test caching of accessible object values + */ +addAccessibleTask(` +
slider
+ + + + `, + function* (browser, accDoc) { + for (let { desc, id, action, attrs, expected, waitFor } of valueTests) { + info(desc); + let acc = findAccessibleChildByID(accDoc, id); + let onUpdate; + + if (waitFor) { + onUpdate = waitForEvent(waitFor, id); + } + + if (action) { + yield action(browser); + } else if (attrs) { + for (let { attr, value } of attrs) { + yield invokeSetAttribute(browser, id, attr, value); + } + } + + yield onUpdate; + if (Array.isArray(expected)) { + acc.QueryInterface(nsIAccessibleValue); + testValue(acc, ...expected); + } else { + is(acc.value, expected, `Correct value for ${prettyName(acc)}`); + } + } + } +); diff --git a/accessible/tests/browser/e10s/browser_events_caretmove.js b/accessible/tests/browser/e10s/browser_events_caretmove.js new file mode 100644 index 000000000..506945f30 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_events_caretmove.js @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* global EVENT_TEXT_CARET_MOVED, nsIAccessibleCaretMoveEvent */ + +'use strict'; + +/** + * Test caret move event and its interface: + * - caretOffset + */ +addAccessibleTask('', function*(browser) { + let onCaretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, 'textbox'); + yield invokeFocus(browser, 'textbox'); + let event = yield onCaretMoved; + + let caretMovedEvent = event.QueryInterface(nsIAccessibleCaretMoveEvent); + is(caretMovedEvent.caretOffset, 5, + 'Correct caret offset.'); +}); diff --git a/accessible/tests/browser/e10s/browser_events_hide.js b/accessible/tests/browser/e10s/browser_events_hide.js new file mode 100644 index 000000000..bb9ee3961 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_events_hide.js @@ -0,0 +1,35 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* global EVENT_HIDE */ + +'use strict'; + +/** + * Test hide event and its interface: + * - targetParent + * - targetNextSibling + * - targetPrevSibling + */ +addAccessibleTask(` +
+ +
+ +
`, + function*(browser, accDoc) { + let acc = findAccessibleChildByID(accDoc, 'to-hide'); + let onHide = waitForEvent(EVENT_HIDE, acc); + yield invokeSetStyle(browser, 'to-hide', 'visibility', 'hidden'); + let event = yield onHide; + let hideEvent = event.QueryInterface(Ci.nsIAccessibleHideEvent); + + is(getAccessibleDOMNodeID(hideEvent.targetParent), 'parent', + 'Correct target parent.'); + is(getAccessibleDOMNodeID(hideEvent.targetNextSibling), 'next', + 'Correct target next sibling.'); + is(getAccessibleDOMNodeID(hideEvent.targetPrevSibling), 'previous', + 'Correct target previous sibling.'); + } +); diff --git a/accessible/tests/browser/e10s/browser_events_show.js b/accessible/tests/browser/e10s/browser_events_show.js new file mode 100644 index 000000000..5003c14f7 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_events_show.js @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* global EVENT_SHOW */ + +'use strict'; + +/** + * Test show event + */ +addAccessibleTask('', + function*(browser) { + let onShow = waitForEvent(EVENT_SHOW, 'div'); + yield invokeSetStyle(browser, 'div', 'visibility', 'visible'); + yield onShow; + }); diff --git a/accessible/tests/browser/e10s/browser_events_statechange.js b/accessible/tests/browser/e10s/browser_events_statechange.js new file mode 100644 index 000000000..7f353efa7 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_events_statechange.js @@ -0,0 +1,62 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* global STATE_CHECKED, EXT_STATE_EDITABLE, nsIAccessibleStateChangeEvent, + EVENT_STATE_CHANGE */ + +'use strict'; + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }, + { name: 'states.js', dir: MOCHITESTS_DIR }); + +function checkStateChangeEvent(event, state, isExtraState, isEnabled) { + let scEvent = event.QueryInterface(nsIAccessibleStateChangeEvent); + is(scEvent.state, state, 'Correct state of the statechange event.'); + is(scEvent.isExtraState, isExtraState, + 'Correct extra state bit of the statechange event.'); + is(scEvent.isEnabled, isEnabled, 'Correct state of statechange event state'); +} + +// Insert mock source into the iframe to be able to verify the right document +// body id. +let iframeSrc = `data:text/html, + + + + Inner Iframe + + + `; + +/** + * Test state change event and its interface: + * - state + * - isExtraState + * - isEnabled + */ +addAccessibleTask(` + + `, function*(browser) { + // Test state change + let onStateChange = waitForEvent(EVENT_STATE_CHANGE, 'checkbox'); + // Set checked for a checkbox. + yield ContentTask.spawn(browser, {}, () => { + content.document.getElementById('checkbox').checked = true; + }); + let event = yield onStateChange; + + checkStateChangeEvent(event, STATE_CHECKED, false, true); + testStates(event.accessible, STATE_CHECKED, 0); + + // Test extra state + onStateChange = waitForEvent(EVENT_STATE_CHANGE, 'iframe'); + // Set design mode on. + yield ContentTask.spawn(browser, {}, () => { + content.document.getElementById('iframe').contentDocument.designMode = 'on'; + }); + event = yield onStateChange; + + checkStateChangeEvent(event, EXT_STATE_EDITABLE, true, true); + testStates(event.accessible, 0, EXT_STATE_EDITABLE); +}); diff --git a/accessible/tests/browser/e10s/browser_events_textchange.js b/accessible/tests/browser/e10s/browser_events_textchange.js new file mode 100644 index 000000000..a1aed52d1 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_events_textchange.js @@ -0,0 +1,74 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* global EVENT_TEXT_INSERTED, EVENT_TEXT_REMOVED, + nsIAccessibleTextChangeEvent */ + +'use strict'; + +function checkTextChangeEvent(event, id, text, start, end, isInserted, isFromUserInput) { + let tcEvent = event.QueryInterface(nsIAccessibleTextChangeEvent); + is(tcEvent.start, start, `Correct start offset for ${prettyName(id)}`); + is(tcEvent.length, end - start, `Correct length for ${prettyName(id)}`); + is(tcEvent.isInserted, isInserted, + `Correct isInserted flag for ${prettyName(id)}`); + is(tcEvent.modifiedText, text, `Correct text for ${prettyName(id)}`); + is(tcEvent.isFromUserInput, isFromUserInput, + `Correct value of isFromUserInput for ${prettyName(id)}`); +} + +function* changeText(browser, id, value, events) { + let onEvents = waitForMultipleEvents(events.map(({ isInserted }) => { + let eventType = isInserted ? EVENT_TEXT_INSERTED : EVENT_TEXT_REMOVED; + return { id, eventType }; + })); + // Change text in the subtree. + yield ContentTask.spawn(browser, [id, value], ([contentId, contentValue]) => { + content.document.getElementById(contentId).firstChild.textContent = + contentValue; + }); + let resolvedEvents = yield onEvents; + + events.forEach(({ isInserted, str, offset }, idx) => + checkTextChangeEvent(resolvedEvents[idx], + id, str, offset, offset + str.length, isInserted, false)); +} + +function* removeTextFromInput(browser, id, value, start, end) { + let onTextRemoved = waitForEvent(EVENT_TEXT_REMOVED, id); + // Select text and delete it. + yield ContentTask.spawn(browser, [id, start, end], ([contentId, contentStart, contentEnd]) => { + let el = content.document.getElementById(contentId); + el.focus(); + el.setSelectionRange(contentStart, contentEnd); + }); + yield BrowserTestUtils.sendChar('VK_DELETE', browser); + + let event = yield onTextRemoved; + checkTextChangeEvent(event, id, value, start, end, false, true); +} + +/** + * Test text change event and its interface: + * - start + * - length + * - isInserted + * - modifiedText + * - isFromUserInput + */ +addAccessibleTask(` +

abc

+ `, function*(browser) { + let events = [ + { isInserted: false, str: 'abc', offset: 0 }, + { isInserted: true, str: 'def', offset: 0 } + ]; + yield changeText(browser, 'p', 'def', events); + + events = [{ isInserted: true, str: 'DEF', offset: 2 }]; + yield changeText(browser, 'p', 'deDEFf', events); + + // Test isFromUserInput property. + yield removeTextFromInput(browser, 'input', 'n', 1, 2); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_ariadialog.js b/accessible/tests/browser/e10s/browser_treeupdate_ariadialog.js new file mode 100644 index 000000000..a9544bc5c --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_ariadialog.js @@ -0,0 +1,43 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_SHOW, ROLE_DIALOG, ROLE_PUSHBUTTON, ROLE_TEXT_LEAF, ROLE_ENTRY, + ROLE_DOCUMENT */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +// Test ARIA Dialog +addAccessibleTask('doc_treeupdate_ariadialog.html', function*(browser, accDoc) { + testAccessibleTree(accDoc, { + role: ROLE_DOCUMENT, + children: [ ] + }); + + // Make dialog visible and update its inner content. + let onShow = waitForEvent(EVENT_SHOW, 'dialog'); + yield ContentTask.spawn(browser, {}, () => { + content.document.getElementById('dialog').style.display = 'block'; + }); + yield onShow; + + testAccessibleTree(accDoc, { + role: ROLE_DOCUMENT, + children: [ + { + role: ROLE_DIALOG, + children: [ + { + role: ROLE_PUSHBUTTON, + children: [ { role: ROLE_TEXT_LEAF } ] + }, + { + role: ROLE_ENTRY + } + ] + } + ] + }); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js b/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js new file mode 100644 index 000000000..998da32a1 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js @@ -0,0 +1,318 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_REORDER */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +function* testContainer1(browser, accDoc) { + const id = 't1_container'; + const docID = getAccessibleDOMNodeID(accDoc); + const acc = findAccessibleChildByID(accDoc, id); + + /* ================= Initial tree test ==================================== */ + // children are swapped by ARIA owns + let tree = { + SECTION: [ + { CHECKBUTTON: [ + { SECTION: [] } + ] }, + { PUSHBUTTON: [ ] } + ] + }; + testAccessibleTree(acc, tree); + + /* ================ Change ARIA owns ====================================== */ + let onReorder = waitForEvent(EVENT_REORDER, id); + yield invokeSetAttribute(browser, id, 'aria-owns', 't1_button t1_subdiv'); + yield onReorder; + + // children are swapped again, button and subdiv are appended to + // the children. + tree = { + SECTION: [ + { CHECKBUTTON: [ ] }, // checkbox, native order + { PUSHBUTTON: [ ] }, // button, rearranged by ARIA own + { SECTION: [ ] } // subdiv from the subtree, ARIA owned + ] + }; + testAccessibleTree(acc, tree); + + /* ================ Remove ARIA owns ====================================== */ + onReorder = waitForEvent(EVENT_REORDER, id); + yield invokeSetAttribute(browser, id, 'aria-owns'); + yield onReorder; + + // children follow the DOM order + tree = { + SECTION: [ + { PUSHBUTTON: [ ] }, + { CHECKBUTTON: [ + { SECTION: [] } + ] } + ] + }; + testAccessibleTree(acc, tree); + + /* ================ Set ARIA owns ========================================= */ + onReorder = waitForEvent(EVENT_REORDER, id); + yield invokeSetAttribute(browser, id, 'aria-owns', 't1_button t1_subdiv'); + yield onReorder; + + // children are swapped again, button and subdiv are appended to + // the children. + tree = { + SECTION: [ + { CHECKBUTTON: [ ] }, // checkbox + { PUSHBUTTON: [ ] }, // button, rearranged by ARIA own + { SECTION: [ ] } // subdiv from the subtree, ARIA owned + ] + }; + testAccessibleTree(acc, tree); + + /* ================ Add ID to ARIA owns =================================== */ + onReorder = waitForEvent(EVENT_REORDER, docID); + yield invokeSetAttribute(browser, id, 'aria-owns', + 't1_button t1_subdiv t1_group'); + yield onReorder; + + // children are swapped again, button and subdiv are appended to + // the children. + tree = { + SECTION: [ + { CHECKBUTTON: [ ] }, // t1_checkbox + { PUSHBUTTON: [ ] }, // button, t1_button + { SECTION: [ ] }, // subdiv from the subtree, t1_subdiv + { GROUPING: [ ] } // group from outside, t1_group + ] + }; + testAccessibleTree(acc, tree); + + /* ================ Append element ======================================== */ + onReorder = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, id, contentId => { + let div = content.document.createElement('div'); + div.setAttribute('id', 't1_child3'); + div.setAttribute('role', 'radio'); + content.document.getElementById(contentId).appendChild(div); + }); + yield onReorder; + + // children are invalidated, they includes aria-owns swapped kids and + // newly inserted child. + tree = { + SECTION: [ + { CHECKBUTTON: [ ] }, // existing explicit, t1_checkbox + { RADIOBUTTON: [ ] }, // new explicit, t1_child3 + { PUSHBUTTON: [ ] }, // ARIA owned, t1_button + { SECTION: [ ] }, // ARIA owned, t1_subdiv + { GROUPING: [ ] } // ARIA owned, t1_group + ] + }; + testAccessibleTree(acc, tree); + + /* ================ Remove element ======================================== */ + onReorder = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, {}, () => + content.document.getElementById('t1_span').parentNode.removeChild( + content.document.getElementById('t1_span'))); + yield onReorder; + + // subdiv should go away + tree = { + SECTION: [ + { CHECKBUTTON: [ ] }, // explicit, t1_checkbox + { RADIOBUTTON: [ ] }, // explicit, t1_child3 + { PUSHBUTTON: [ ] }, // ARIA owned, t1_button + { GROUPING: [ ] } // ARIA owned, t1_group + ] + }; + testAccessibleTree(acc, tree); + + /* ================ Remove ID ============================================= */ + onReorder = waitForEvent(EVENT_REORDER, docID); + yield invokeSetAttribute(browser, 't1_group', 'id'); + yield onReorder; + + tree = { + SECTION: [ + { CHECKBUTTON: [ ] }, + { RADIOBUTTON: [ ] }, + { PUSHBUTTON: [ ] } // ARIA owned, t1_button + ] + }; + testAccessibleTree(acc, tree); + + /* ================ Set ID ================================================ */ + onReorder = waitForEvent(EVENT_REORDER, docID); + yield invokeSetAttribute(browser, 't1_grouptmp', 'id', 't1_group'); + yield onReorder; + + tree = { + SECTION: [ + { CHECKBUTTON: [ ] }, + { RADIOBUTTON: [ ] }, + { PUSHBUTTON: [ ] }, // ARIA owned, t1_button + { GROUPING: [ ] } // ARIA owned, t1_group, previously t1_grouptmp + ] + }; + testAccessibleTree(acc, tree); +} + +function* removeContainer(browser, accDoc) { + const id = 't2_container1'; + const acc = findAccessibleChildByID(accDoc, id); + + let tree = { + SECTION: [ + { CHECKBUTTON: [ ] } // ARIA owned, 't2_owned' + ] + }; + testAccessibleTree(acc, tree); + + let onReorder = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, {}, () => + content.document.getElementById('t2_container2').removeChild( + content.document.getElementById('t2_container3'))); + yield onReorder; + + tree = { + SECTION: [ ] + }; + testAccessibleTree(acc, tree); +} + +function* stealAndRecacheChildren(browser, accDoc) { + const id1 = 't3_container1'; + const id2 = 't3_container2'; + const acc1 = findAccessibleChildByID(accDoc, id1); + const acc2 = findAccessibleChildByID(accDoc, id2); + + /* ================ Steal from other ARIA owns ============================ */ + let onReorder = waitForEvent(EVENT_REORDER, id2); + yield invokeSetAttribute(browser, id2, 'aria-owns', 't3_child'); + yield onReorder; + + let tree = { + SECTION: [ ] + }; + testAccessibleTree(acc1, tree); + + tree = { + SECTION: [ + { CHECKBUTTON: [ ] } + ] + }; + testAccessibleTree(acc2, tree); + + /* ================ Append element to recache children ==================== */ + onReorder = waitForEvent(EVENT_REORDER, id2); + yield ContentTask.spawn(browser, id2, id => { + let div = content.document.createElement('div'); + div.setAttribute('role', 'radio'); + content.document.getElementById(id).appendChild(div); + }); + yield onReorder; + + tree = { + SECTION: [ ] + }; + testAccessibleTree(acc1, tree); + + tree = { + SECTION: [ + { RADIOBUTTON: [ ] }, + { CHECKBUTTON: [ ] } // ARIA owned + ] + }; + testAccessibleTree(acc2, tree); +} + +function* showHiddenElement(browser, accDoc) { + const id = 't4_container1'; + const acc = findAccessibleChildByID(accDoc, id); + + let tree = { + SECTION: [ + { RADIOBUTTON: [] } + ] + }; + testAccessibleTree(acc, tree); + + let onReorder = waitForEvent(EVENT_REORDER, id); + yield invokeSetStyle(browser, 't4_child1', 'display', 'block'); + yield onReorder; + + tree = { + SECTION: [ + { CHECKBUTTON: [] }, + { RADIOBUTTON: [] } + ] + }; + testAccessibleTree(acc, tree); +} + +function* rearrangeARIAOwns(browser, accDoc) { + const id = 't5_container'; + const acc = findAccessibleChildByID(accDoc, id); + const tests = [{ + val: 't5_checkbox t5_radio t5_button', + roleList: [ 'CHECKBUTTON', 'RADIOBUTTON', 'PUSHBUTTON' ] + }, { + val: 't5_radio t5_button t5_checkbox', + roleList: [ 'RADIOBUTTON', 'PUSHBUTTON', 'CHECKBUTTON' ] + }]; + + for (let { val, roleList } of tests) { + let onReorder = waitForEvent(EVENT_REORDER, id); + yield invokeSetAttribute(browser, id, 'aria-owns', val); + yield onReorder; + + let tree = { SECTION: [ ] }; + for (let role of roleList) { + let ch = {}; + ch[role] = []; + tree.SECTION.push(ch); + } + testAccessibleTree(acc, tree); + } +} + +function* removeNotARIAOwnedEl(browser, accDoc) { + const id = 't6_container'; + const acc = findAccessibleChildByID(accDoc, id); + + let tree = { + SECTION: [ + { TEXT_LEAF: [ ] }, + { GROUPING: [ ] } + ] + }; + testAccessibleTree(acc, tree); + + let onReorder = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, id, contentId => { + content.document.getElementById(contentId).removeChild( + content.document.getElementById('t6_span')); + }); + yield onReorder; + + tree = { + SECTION: [ + { GROUPING: [ ] } + ] + }; + testAccessibleTree(acc, tree); +} + +addAccessibleTask('doc_treeupdate_ariaowns.html', function*(browser, accDoc) { + yield testContainer1(browser, accDoc); + yield removeContainer(browser, accDoc); + yield stealAndRecacheChildren(browser, accDoc); + yield showHiddenElement(browser, accDoc); + yield rearrangeARIAOwns(browser, accDoc); + yield removeNotARIAOwnedEl(browser, accDoc); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_canvas.js b/accessible/tests/browser/e10s/browser_treeupdate_canvas.js new file mode 100644 index 000000000..e4b3b70f7 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_canvas.js @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_SHOW */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +addAccessibleTask(` + + + `, function*(browser, accDoc) { + let canvas = findAccessibleChildByID(accDoc, 'canvas'); + let dialog = findAccessibleChildByID(accDoc, 'dialog'); + + testAccessibleTree(canvas, { CANVAS: [] }); + + let onShow = waitForEvent(EVENT_SHOW, 'dialog'); + yield invokeSetStyle(browser, 'dialog', 'display', 'block'); + yield onShow; + + testAccessibleTree(dialog, { DIALOG: [] }); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_cssoverflow.js b/accessible/tests/browser/e10s/browser_treeupdate_cssoverflow.js new file mode 100644 index 000000000..d8b217380 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_cssoverflow.js @@ -0,0 +1,64 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_REORDER */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +addAccessibleTask(` +
+
+
+
`, function*(browser, accDoc) { + const id1 = 'container'; + const id2 = 'container2'; + const container = findAccessibleChildByID(accDoc, id1); + const container2 = findAccessibleChildByID(accDoc, id2); + + /* ================= Change scroll range ================================== */ + let tree = { + SECTION: [ {// container + SECTION: [ {// scroll area + ENTRY: [ ] // child content + } ] + } ] + }; + testAccessibleTree(container, tree); + + let onReorder = waitForEvent(EVENT_REORDER, id1); + yield ContentTask.spawn(browser, id1, id => { + let doc = content.document; + doc.getElementById('scrollarea').style.width = '20px'; + doc.getElementById(id).appendChild(doc.createElement('input')); + }); + yield onReorder; + + tree = { + SECTION: [ {// container + SECTION: [ {// scroll area + ENTRY: [ ] // child content + } ] + }, { + ENTRY: [ ] // inserted input + } ] + }; + testAccessibleTree(container, tree); + + /* ================= Change scrollbar styles ============================== */ + tree = { SECTION: [ ] }; + testAccessibleTree(container2, tree); + + onReorder = waitForEvent(EVENT_REORDER, id2); + yield invokeSetStyle(browser, 'scrollarea2', 'overflow', 'auto'); + yield onReorder; + + tree = { + SECTION: [ // container + { SECTION: [] } // scroll area + ] + }; + testAccessibleTree(container2, tree); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_doc.js b/accessible/tests/browser/e10s/browser_treeupdate_doc.js new file mode 100644 index 000000000..ccb1d1566 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_doc.js @@ -0,0 +1,312 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global ROLE_PUSHBUTTON, ROLE_TEXT_LEAF, EVENT_REORDER, ROLE_DOCUMENT, + nsIAccessibleDocument */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +const iframeSrc = `data:text/html, + + + + Inner Iframe + + + `; + +addAccessibleTask(` + `, function*(browser, accDoc) { + // ID of the iframe that is being tested + const id = 'inner-iframe'; + + let iframe = findAccessibleChildByID(accDoc, id); + + /* ================= Initial tree check =================================== */ + let tree = { + role: ROLE_DOCUMENT, + children: [ ] + }; + testAccessibleTree(iframe, tree); + + /* ================= Write iframe document ================================ */ + let reorderEventPromise = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, id, contentId => { + let docNode = content.document.getElementById('iframe').contentDocument; + let newHTMLNode = docNode.createElement('html'); + let newBodyNode = docNode.createElement('body'); + let newTextNode = docNode.createTextNode('New Wave'); + newBodyNode.id = contentId; + newBodyNode.appendChild(newTextNode); + newHTMLNode.appendChild(newBodyNode); + docNode.replaceChild(newHTMLNode, docNode.documentElement); + }); + yield reorderEventPromise; + + tree = { + role: ROLE_DOCUMENT, + children: [ + { + role: ROLE_TEXT_LEAF, + name: 'New Wave' + } + ] + }; + testAccessibleTree(iframe, tree); + + /* ================= Replace iframe HTML element ========================== */ + reorderEventPromise = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, id, contentId => { + let docNode = content.document.getElementById('iframe').contentDocument; + // We can't use open/write/close outside of iframe document because of + // security error. + let script = docNode.createElement('script'); + script.textContent = ` + document.open(); + document.write('hello'); + document.close();`; + docNode.body.appendChild(script); + }); + yield reorderEventPromise; + + tree = { + role: ROLE_DOCUMENT, + children: [ + { + role: ROLE_TEXT_LEAF, + name: 'hello' + } + ] + }; + testAccessibleTree(iframe, tree); + + /* ================= Replace iframe body ================================== */ + reorderEventPromise = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, id, contentId => { + let docNode = content.document.getElementById('iframe').contentDocument; + let newBodyNode = docNode.createElement('body'); + let newTextNode = docNode.createTextNode('New Hello'); + newBodyNode.id = contentId; + newBodyNode.appendChild(newTextNode); + newBodyNode.setAttribute('role', 'button'); + docNode.documentElement.replaceChild(newBodyNode, docNode.body); + }); + yield reorderEventPromise; + + tree = { + role: ROLE_PUSHBUTTON, + children: [ + { + role: ROLE_TEXT_LEAF, + name: 'New Hello' + } + ] + }; + testAccessibleTree(iframe, tree); + + /* ================= Open iframe document ================================= */ + reorderEventPromise = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, id, contentId => { + // Open document. + let docNode = content.document.getElementById('iframe').contentDocument; + let script = docNode.createElement('script'); + script.textContent = ` + function closeMe() { + document.write('Works?'); + document.close(); + } + window.closeMe = closeMe; + document.open(); + document.write('');`; + docNode.body.appendChild(script); + }); + yield reorderEventPromise; + + tree = { + role: ROLE_DOCUMENT, + children: [ ] + }; + testAccessibleTree(iframe, tree); + + /* ================= Close iframe document ================================ */ + reorderEventPromise = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, {}, () => { + // Write and close document. + let docNode = content.document.getElementById('iframe').contentDocument; + docNode.write('Works?'); + docNode.close(); + }); + yield reorderEventPromise; + + tree = { + role: ROLE_DOCUMENT, + children: [ + { + role: ROLE_TEXT_LEAF, + name: 'Works?' + } + ] + }; + testAccessibleTree(iframe, tree); + + /* ================= Remove HTML from iframe document ===================== */ + reorderEventPromise = waitForEvent(EVENT_REORDER, iframe); + yield ContentTask.spawn(browser, {}, () => { + // Remove HTML element. + let docNode = content.document.getElementById('iframe').contentDocument; + docNode.removeChild(docNode.firstChild); + }); + let event = yield reorderEventPromise; + + ok(event.accessible instanceof nsIAccessibleDocument, + 'Reorder should happen on the document'); + tree = { + role: ROLE_DOCUMENT, + children: [ ] + }; + testAccessibleTree(iframe, tree); + + /* ================= Insert HTML to iframe document ======================= */ + reorderEventPromise = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, id, contentId => { + // Insert HTML element. + let docNode = content.document.getElementById('iframe').contentDocument; + let html = docNode.createElement('html'); + let body = docNode.createElement('body'); + let text = docNode.createTextNode('Haha'); + body.appendChild(text); + body.id = contentId; + html.appendChild(body); + docNode.appendChild(html); + }); + yield reorderEventPromise; + + tree = { + role: ROLE_DOCUMENT, + children: [ + { + role: ROLE_TEXT_LEAF, + name: 'Haha' + } + ] + }; + testAccessibleTree(iframe, tree); + + /* ================= Remove body from iframe document ===================== */ + reorderEventPromise = waitForEvent(EVENT_REORDER, iframe); + yield ContentTask.spawn(browser, {}, () => { + // Remove body element. + let docNode = content.document.getElementById('iframe').contentDocument; + docNode.documentElement.removeChild(docNode.body); + }); + event = yield reorderEventPromise; + + ok(event.accessible instanceof nsIAccessibleDocument, + 'Reorder should happen on the document'); + tree = { + role: ROLE_DOCUMENT, + children: [ ] + }; + testAccessibleTree(iframe, tree); + + /* ================ Insert element under document element while body missed */ + reorderEventPromise = waitForEvent(EVENT_REORDER, iframe); + yield ContentTask.spawn(browser, {}, () => { + let docNode = content.document.getElementById('iframe').contentDocument; + let inputNode = content.window.inputNode = docNode.createElement('input'); + docNode.documentElement.appendChild(inputNode); + }); + event = yield reorderEventPromise; + + ok(event.accessible instanceof nsIAccessibleDocument, + 'Reorder should happen on the document'); + tree = { + DOCUMENT: [ + { ENTRY: [ ] } + ] + }; + testAccessibleTree(iframe, tree); + + reorderEventPromise = waitForEvent(EVENT_REORDER, iframe); + yield ContentTask.spawn(browser, {}, () => { + let docEl = + content.document.getElementById('iframe').contentDocument.documentElement; + // Remove aftermath of this test before next test starts. + docEl.removeChild(docEl.firstChild); + }); + // Make sure reorder event was fired and that the input was removed. + yield reorderEventPromise; + tree = { + role: ROLE_DOCUMENT, + children: [ ] + }; + testAccessibleTree(iframe, tree); + + /* ================= Insert body to iframe document ======================= */ + reorderEventPromise = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, id, contentId => { + // Write and close document. + let docNode = content.document.getElementById('iframe').contentDocument; + // Insert body element. + let body = docNode.createElement('body'); + let text = docNode.createTextNode('Yo ho ho i butylka roma!'); + body.appendChild(text); + body.id = contentId; + docNode.documentElement.appendChild(body); + }); + yield reorderEventPromise; + + tree = { + role: ROLE_DOCUMENT, + children: [ + { + role: ROLE_TEXT_LEAF, + name: 'Yo ho ho i butylka roma!' + } + ] + }; + testAccessibleTree(iframe, tree); + + /* ================= Change source ======================================== */ + reorderEventPromise = waitForEvent(EVENT_REORDER, 'iframe'); + yield invokeSetAttribute(browser, 'iframe', 'src', + `data:text/html,`); + event = yield reorderEventPromise; + + tree = { + INTERNAL_FRAME: [ + { DOCUMENT: [ + { ENTRY: [ ] } + ] } + ] + }; + testAccessibleTree(event.accessible, tree); + iframe = findAccessibleChildByID(event.accessible, id); + + /* ================= Replace iframe body on ARIA role body ================ */ + reorderEventPromise = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, id, contentId => { + let docNode = content.document.getElementById('iframe').contentDocument; + let newBodyNode = docNode.createElement('body'); + let newTextNode = docNode.createTextNode('New Hello'); + newBodyNode.appendChild(newTextNode); + newBodyNode.setAttribute('role', 'button'); + newBodyNode.id = contentId; + docNode.documentElement.replaceChild(newBodyNode, docNode.body); + }); + yield reorderEventPromise; + + tree = { + role: ROLE_PUSHBUTTON, + children: [ + { + role: ROLE_TEXT_LEAF, + name: 'New Hello' + } + ] + }; + testAccessibleTree(iframe, tree); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_gencontent.js b/accessible/tests/browser/e10s/browser_treeupdate_gencontent.js new file mode 100644 index 000000000..126419288 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_gencontent.js @@ -0,0 +1,78 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_REORDER */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +addAccessibleTask(` + +
+
text
`, + function*(browser, accDoc) { + const id1 = 'container1'; + const id2 = 'container2'; + let container1 = findAccessibleChildByID(accDoc, id1); + let container2 = findAccessibleChildByID(accDoc, id2); + + let tree = { + SECTION: [ ] // container + }; + testAccessibleTree(container1, tree); + + tree = { + SECTION: [ { // container2 + SECTION: [ { // container2 child + TEXT_LEAF: [ ] // primary text + } ] + } ] + }; + testAccessibleTree(container2, tree); + + let onReorder = waitForEvent(EVENT_REORDER, id1); + // Create and add an element with CSS generated content to container1 + yield ContentTask.spawn(browser, id1, id => { + let node = content.document.createElement('div'); + node.textContent = 'text'; + node.setAttribute('class', 'gentext'); + content.document.getElementById(id).appendChild(node); + }); + yield onReorder; + + tree = { + SECTION: [ // container + { SECTION: [ // inserted node + { STATICTEXT: [] }, // :before + { TEXT_LEAF: [] }, // primary text + { STATICTEXT: [] } // :after + ] } + ] + }; + testAccessibleTree(container1, tree); + + onReorder = waitForEvent(EVENT_REORDER, id2); + // Add CSS generated content to an element in container2's subtree + yield invokeSetAttribute(browser, 'container2_child', 'class', 'gentext'); + yield onReorder; + + tree = { + SECTION: [ // container2 + { SECTION: [ // container2 child + { STATICTEXT: [] }, // :before + { TEXT_LEAF: [] }, // primary text + { STATICTEXT: [] } // :after + ] } + ] + }; + testAccessibleTree(container2, tree); + }); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_hidden.js b/accessible/tests/browser/e10s/browser_treeupdate_hidden.js new file mode 100644 index 000000000..00369ec05 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_hidden.js @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_REORDER */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +function* setHidden(browser, value) { + let onReorder = waitForEvent(EVENT_REORDER, 'container'); + yield invokeSetAttribute(browser, 'child', 'hidden', value); + yield onReorder; +} + +addAccessibleTask('
', + function*(browser, accDoc) { + let container = findAccessibleChildByID(accDoc, 'container'); + + testAccessibleTree(container, { SECTION: [ { ENTRY: [ ] } ] }); + + // Set @hidden attribute + yield setHidden(browser, 'true'); + testAccessibleTree(container, { SECTION: [ ] }); + + // Remove @hidden attribute + yield setHidden(browser); + testAccessibleTree(container, { SECTION: [ { ENTRY: [ ] } ] }); + }); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_imagemap.js b/accessible/tests/browser/e10s/browser_treeupdate_imagemap.js new file mode 100644 index 000000000..d299c0acb --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_imagemap.js @@ -0,0 +1,176 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_REORDER, ROLE_LINK */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +function* testImageMap(browser, accDoc) { + const id = 'imgmap'; + const acc = findAccessibleChildByID(accDoc, id); + + /* ================= Initial tree test ==================================== */ + let tree = { + IMAGE_MAP: [ + { role: ROLE_LINK, name: 'b', children: [ ] } + ] + }; + testAccessibleTree(acc, tree); + + /* ================= Insert area ========================================== */ + let onReorder = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, {}, () => { + let areaElm = content.document.createElement('area'); + let mapNode = content.document.getElementById('map'); + areaElm.setAttribute('href', + 'http://www.bbc.co.uk/radio4/atoz/index.shtml#a'); + areaElm.setAttribute('coords', '0,0,13,14'); + areaElm.setAttribute('alt', 'a'); + areaElm.setAttribute('shape', 'rect'); + mapNode.insertBefore(areaElm, mapNode.firstChild); + }); + yield onReorder; + + tree = { + IMAGE_MAP: [ + { role: ROLE_LINK, name: 'a', children: [ ] }, + { role: ROLE_LINK, name: 'b', children: [ ] } + ] + }; + testAccessibleTree(acc, tree); + + /* ================= Append area ========================================== */ + onReorder = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, {}, () => { + let areaElm = content.document.createElement('area'); + let mapNode = content.document.getElementById('map'); + areaElm.setAttribute('href', + 'http://www.bbc.co.uk/radio4/atoz/index.shtml#c'); + areaElm.setAttribute('coords', '34,0,47,14'); + areaElm.setAttribute('alt', 'c'); + areaElm.setAttribute('shape', 'rect'); + mapNode.appendChild(areaElm); + }); + yield onReorder; + + tree = { + IMAGE_MAP: [ + { role: ROLE_LINK, name: 'a', children: [ ] }, + { role: ROLE_LINK, name: 'b', children: [ ] }, + { role: ROLE_LINK, name: 'c', children: [ ] } + ] + }; + testAccessibleTree(acc, tree); + + /* ================= Remove area ========================================== */ + onReorder = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, {}, () => { + let mapNode = content.document.getElementById('map'); + mapNode.removeChild(mapNode.firstElementChild); + }); + yield onReorder; + + tree = { + IMAGE_MAP: [ + { role: ROLE_LINK, name: 'b', children: [ ] }, + { role: ROLE_LINK, name: 'c', children: [ ] } + ] + }; + testAccessibleTree(acc, tree); +} + +function* testContainer(browser) { + const id = 'container'; + /* ================= Remove name on map =================================== */ + let onReorder = waitForEvent(EVENT_REORDER, id); + yield invokeSetAttribute(browser, 'map', 'name'); + let event = yield onReorder; + const acc = event.accessible; + + let tree = { + SECTION: [ + { GRAPHIC: [ ] } + ] + }; + testAccessibleTree(acc, tree); + + /* ================= Restore name on map ================================== */ + onReorder = waitForEvent(EVENT_REORDER, id); + yield invokeSetAttribute(browser, 'map', 'name', 'atoz_map'); + // XXX: force repainting of the image (see bug 745788 for details). + yield BrowserTestUtils.synthesizeMouse('#imgmap', 10, 10, + { type: 'mousemove' }, browser); + yield onReorder; + + tree = { + SECTION: [ { + IMAGE_MAP: [ + { LINK: [ ] }, + { LINK: [ ] } + ] + } ] + }; + testAccessibleTree(acc, tree); + + /* ================= Remove map =========================================== */ + onReorder = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, {}, () => { + let mapNode = content.document.getElementById('map'); + mapNode.parentNode.removeChild(mapNode); + }); + yield onReorder; + + tree = { + SECTION: [ + { GRAPHIC: [ ] } + ] + }; + testAccessibleTree(acc, tree); + + /* ================= Insert map =========================================== */ + onReorder = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, id, contentId => { + let map = content.document.createElement('map'); + let area = content.document.createElement('area'); + + map.setAttribute('name', 'atoz_map'); + map.setAttribute('id', 'map'); + + area.setAttribute('href', + 'http://www.bbc.co.uk/radio4/atoz/index.shtml#b'); + area.setAttribute('coords', '17,0,30,14'); + area.setAttribute('alt', 'b'); + area.setAttribute('shape', 'rect'); + + map.appendChild(area); + content.document.getElementById(contentId).appendChild(map); + }); + yield onReorder; + + tree = { + SECTION: [ { + IMAGE_MAP: [ + { LINK: [ ] } + ] + } ] + }; + testAccessibleTree(acc, tree); + + /* ================= Hide image map ======================================= */ + onReorder = waitForEvent(EVENT_REORDER, id); + yield invokeSetStyle(browser, 'imgmap', 'display', 'none'); + yield onReorder; + + tree = { + SECTION: [ ] + }; + testAccessibleTree(acc, tree); +} + +addAccessibleTask('doc_treeupdate_imagemap.html', function*(browser, accDoc) { + yield testImageMap(browser, accDoc); + yield testContainer(browser); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_list.js b/accessible/tests/browser/e10s/browser_treeupdate_list.js new file mode 100644 index 000000000..023adf8e3 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_list.js @@ -0,0 +1,43 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global ROLE_TEXT_LEAF, EVENT_REORDER, ROLE_STATICTEXT, ROLE_LISTITEM */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +function* setDisplayAndWaitForReorder(browser, value) { + let onReorder = waitForEvent(EVENT_REORDER, 'ul'); + yield invokeSetStyle(browser, 'li', 'display', value); + return yield onReorder; +} + +addAccessibleTask(` + `, function*(browser, accDoc) { + let li = findAccessibleChildByID(accDoc, 'li'); + let bullet = li.firstChild; + let accTree = { + role: ROLE_LISTITEM, + children: [ { + role: ROLE_STATICTEXT, + children: [] + }, { + role: ROLE_TEXT_LEAF, + children: [] + } ] + }; + testAccessibleTree(li, accTree); + + yield setDisplayAndWaitForReorder(browser, 'none'); + + ok(isDefunct(li), 'Check that li is defunct.'); + ok(isDefunct(bullet), 'Check that bullet is defunct.'); + + let event = yield setDisplayAndWaitForReorder(browser, 'list-item'); + + testAccessibleTree(findAccessibleChildByID(event.accessible, 'li'), accTree); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_list_editabledoc.js b/accessible/tests/browser/e10s/browser_treeupdate_list_editabledoc.js new file mode 100644 index 000000000..7b01af87a --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_list_editabledoc.js @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global ROLE_TEXT_LEAF, EVENT_REORDER, ROLE_LISTITEM, ROLE_LIST, + ROLE_STATICTEXT */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +addAccessibleTask('
    ', function*(browser, accDoc) { + let list = findAccessibleChildByID(accDoc, 'list'); + + testAccessibleTree(list, { + role: ROLE_LIST, + children: [ ] + }); + + yield invokeSetAttribute(browser, 'body', 'contentEditable', 'true'); + let onReorder = waitForEvent(EVENT_REORDER, 'list'); + yield ContentTask.spawn(browser, {}, () => { + let li = content.document.createElement('li'); + li.textContent = 'item'; + content.document.getElementById('list').appendChild(li); + }); + yield onReorder; + + testAccessibleTree(list, { + role: ROLE_LIST, + children: [ { + role: ROLE_LISTITEM, + children: [ + { role: ROLE_STATICTEXT, name: "1. ", children: [] }, + { role: ROLE_TEXT_LEAF, children: [] } + ] + } ] + }); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_listener.js b/accessible/tests/browser/e10s/browser_treeupdate_listener.js new file mode 100644 index 000000000..7b7880312 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_listener.js @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_REORDER */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +addAccessibleTask('', + function*(browser, accDoc) { + is(findAccessibleChildByID(accDoc, 'parent'), null, + 'Check that parent is not accessible.'); + is(findAccessibleChildByID(accDoc, 'child'), null, + 'Check that child is not accessible.'); + + let onReorder = waitForEvent(EVENT_REORDER, 'body'); + // Add an event listener to parent. + yield ContentTask.spawn(browser, {}, () => { + content.window.dummyListener = () => {}; + content.document.getElementById('parent').addEventListener( + 'click', content.window.dummyListener); + }); + yield onReorder; + + let tree = { TEXT: [] }; + testAccessibleTree(findAccessibleChildByID(accDoc, 'parent'), tree); + }); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_optgroup.js b/accessible/tests/browser/e10s/browser_treeupdate_optgroup.js new file mode 100644 index 000000000..45001afaa --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_optgroup.js @@ -0,0 +1,91 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_REORDER */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +addAccessibleTask('', function*(browser, accDoc) { + let select = findAccessibleChildByID(accDoc, 'select'); + + let onEvent = waitForEvent(EVENT_REORDER, 'select'); + // Create a combobox with grouping and 2 standalone options + yield ContentTask.spawn(browser, {}, () => { + let doc = content.document; + let contentSelect = doc.getElementById('select'); + let optGroup = doc.createElement('optgroup'); + + for (let i = 0; i < 2; i++) { + let opt = doc.createElement('option'); + opt.value = i; + opt.text = 'Option: Value ' + i; + optGroup.appendChild(opt); + } + contentSelect.add(optGroup, null); + + for (let i = 0; i < 2; i++) { + let opt = doc.createElement('option'); + contentSelect.add(opt, null); + } + contentSelect.firstChild.firstChild.id = 'option1Node'; + }); + let event = yield onEvent; + let option1Node = findAccessibleChildByID(event.accessible, 'option1Node'); + + let tree = { + COMBOBOX: [ { + COMBOBOX_LIST: [ { + GROUPING: [ + { COMBOBOX_OPTION: [ { TEXT_LEAF: [] } ] }, + { COMBOBOX_OPTION: [ { TEXT_LEAF: [] } ] } + ] + }, { + COMBOBOX_OPTION: [] + }, { + COMBOBOX_OPTION: [] + } ] + } ] + }; + testAccessibleTree(select, tree); + ok(!isDefunct(option1Node), 'option shouldn\'t be defunct'); + + onEvent = waitForEvent(EVENT_REORDER, 'select'); + // Remove grouping from combobox + yield ContentTask.spawn(browser, {}, () => { + let contentSelect = content.document.getElementById('select'); + contentSelect.removeChild(contentSelect.firstChild); + }); + yield onEvent; + + tree = { + COMBOBOX: [ { + COMBOBOX_LIST: [ + { COMBOBOX_OPTION: [] }, + { COMBOBOX_OPTION: [] } + ] + } ] + }; + testAccessibleTree(select, tree); + ok(isDefunct(option1Node), + 'removed option shouldn\'t be accessible anymore!'); + + onEvent = waitForEvent(EVENT_REORDER, 'select'); + // Remove all options from combobox + yield ContentTask.spawn(browser, {}, () => { + let contentSelect = content.document.getElementById('select'); + while (contentSelect.length) { + contentSelect.remove(0); + } + }); + yield onEvent; + + tree = { + COMBOBOX: [ { + COMBOBOX_LIST: [ ] + } ] + }; + testAccessibleTree(select, tree); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_removal.js b/accessible/tests/browser/e10s/browser_treeupdate_removal.js new file mode 100644 index 000000000..9892bbcd6 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_removal.js @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_REORDER */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +addAccessibleTask('doc_treeupdate_removal.xhtml', function*(browser, accDoc) { + ok(isAccessible(findAccessibleChildByID(accDoc, 'the_table')), + 'table should be accessible'); + + // Move the_table element into hidden subtree. + let onReorder = waitForEvent(EVENT_REORDER, 'body'); + yield ContentTask.spawn(browser, {}, () => content.document.getElementById( + 'the_displaynone').appendChild(content.document.getElementById( + 'the_table'))); + yield onReorder; + + ok(!isAccessible(findAccessibleChildByID(accDoc, 'the_table')), + 'table in display none tree shouldn\'t be accessible'); + ok(!isAccessible(findAccessibleChildByID(accDoc, 'the_row')), + 'row shouldn\'t be accessible'); + + // Remove the_row element (since it did not have accessible, no event needed). + yield ContentTask.spawn(browser, {}, () => + content.document.body.removeChild( + content.document.getElementById('the_row'))); + + // make sure no accessibles have stuck around. + ok(!isAccessible(findAccessibleChildByID(accDoc, 'the_row')), + 'row shouldn\'t be accessible'); + ok(!isAccessible(findAccessibleChildByID(accDoc, 'the_table')), + 'table shouldn\'t be accessible'); + ok(!isAccessible(findAccessibleChildByID(accDoc, 'the_displayNone')), + 'display none things shouldn\'t be accessible'); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_table.js b/accessible/tests/browser/e10s/browser_treeupdate_table.js new file mode 100644 index 000000000..9609f51ac --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_table.js @@ -0,0 +1,51 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_REORDER */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +addAccessibleTask(` + + + + + +
    cell1cell2
    `, function*(browser, accDoc) { + let table = findAccessibleChildByID(accDoc, 'table'); + + let tree = { + TABLE: [ + { ROW: [ + { CELL: [ {TEXT_LEAF: [] }]}, + { CELL: [ {TEXT_LEAF: [] }]} + ] } + ] + }; + testAccessibleTree(table, tree); + + let onReorder = waitForEvent(EVENT_REORDER, 'table'); + yield ContentTask.spawn(browser, {}, () => { + // append a caption, it should appear as a first element in the + // accessible tree. + let doc = content.document; + let caption = doc.createElement('caption'); + caption.textContent = 'table caption'; + doc.getElementById('table').appendChild(caption); + }); + yield onReorder; + + tree = { + TABLE: [ + { CAPTION: [ { TEXT_LEAF: [] } ] }, + { ROW: [ + { CELL: [ {TEXT_LEAF: [] }]}, + { CELL: [ {TEXT_LEAF: [] }]} + ] } + ] + }; + testAccessibleTree(table, tree); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_textleaf.js b/accessible/tests/browser/e10s/browser_treeupdate_textleaf.js new file mode 100644 index 000000000..da45e2bc9 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_textleaf.js @@ -0,0 +1,35 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_REORDER, ROLE_TEXT_CONTAINER ROLE_PARAGRAPH, ROLE_TEXT_LEAF */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +function* removeTextData(browser, accessible, id, role) { + let tree = { + role: role, + children: [ { role: ROLE_TEXT_LEAF, name: "text" } ] + }; + testAccessibleTree(accessible, tree); + + let onReorder = waitForEvent(EVENT_REORDER, id); + yield ContentTask.spawn(browser, id, contentId => { + content.document.getElementById(contentId).firstChild.textContent = ''; + }); + yield onReorder; + + tree = { role: role, children: [] }; + testAccessibleTree(accessible, tree); +} + +addAccessibleTask(` +

    text

    +
    text
    `, function*(browser, accDoc) { + let p = findAccessibleChildByID(accDoc, 'p'); + let pre = findAccessibleChildByID(accDoc, 'pre'); + yield removeTextData(browser, p, 'p', ROLE_PARAGRAPH); + yield removeTextData(browser, pre, 'pre', ROLE_TEXT_CONTAINER); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_visibility.js b/accessible/tests/browser/e10s/browser_treeupdate_visibility.js new file mode 100644 index 000000000..65a55c914 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_visibility.js @@ -0,0 +1,196 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_REORDER */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +function* testTreeOnHide(browser, accDoc, containerID, id, before, after) { + let acc = findAccessibleChildByID(accDoc, containerID); + testAccessibleTree(acc, before); + + let onReorder = waitForEvent(EVENT_REORDER, containerID); + yield invokeSetStyle(browser, id, 'visibility', 'hidden'); + yield onReorder; + + testAccessibleTree(acc, after); +} + +function* test3(browser, accessible) { + let tree = { + SECTION: [ // container + { SECTION: [ // parent + { SECTION: [ // child + { TEXT_LEAF: [] } + ] } + ] }, + { SECTION: [ // parent2 + { SECTION: [ // child2 + { TEXT_LEAF: [] } + ] } + ] } + ] }; + testAccessibleTree(accessible, tree); + + let onReorder = waitForEvent(EVENT_REORDER, 't3_container'); + yield ContentTask.spawn(browser, {}, () => { + let doc = content.document; + doc.getElementById('t3_container').style.color = 'red'; + doc.getElementById('t3_parent').style.visibility = 'hidden'; + doc.getElementById('t3_parent2').style.visibility = 'hidden'; + }); + yield onReorder; + + tree = { + SECTION: [ // container + { SECTION: [ // child + { TEXT_LEAF: [] } + ] }, + { SECTION: [ // child2 + { TEXT_LEAF: [] } + ] } + ] }; + testAccessibleTree(accessible, tree); +} + +function* test4(browser, accessible) { + let tree = { + SECTION: [ + { TABLE: [ + { ROW: [ + { CELL: [ ] } + ] } + ] } + ] }; + testAccessibleTree(accessible, tree); + + let onReorder = waitForEvent(EVENT_REORDER, 't4_parent'); + yield ContentTask.spawn(browser, {}, () => { + let doc = content.document; + doc.getElementById('t4_container').style.color = 'red'; + doc.getElementById('t4_child').style.visibility = 'visible'; + }); + yield onReorder; + + tree = { + SECTION: [{ + TABLE: [{ + ROW: [{ + CELL: [{ + SECTION: [{ + TEXT_LEAF: [] + }] + }] + }] + }] + }] + }; + testAccessibleTree(accessible, tree); +} + +addAccessibleTask('doc_treeupdate_visibility.html', function*(browser, accDoc) { + let t3Container = findAccessibleChildByID(accDoc, 't3_container'); + let t4Container = findAccessibleChildByID(accDoc, 't4_container'); + + yield testTreeOnHide(browser, accDoc, 't1_container', 't1_parent', { + SECTION: [{ + SECTION: [{ + SECTION: [ { TEXT_LEAF: [] } ] + }] + }] + }, { + SECTION: [ { + SECTION: [ { TEXT_LEAF: [] } ] + } ] + }); + + yield testTreeOnHide(browser, accDoc, 't2_container', 't2_grandparent', { + SECTION: [{ // container + SECTION: [{ // grand parent + SECTION: [{ + SECTION: [{ // child + TEXT_LEAF: [] + }] + }, { + SECTION: [{ // child2 + TEXT_LEAF: [] + }] + }] + }] + }] + }, { + SECTION: [{ // container + SECTION: [{ // child + TEXT_LEAF: [] + }] + }, { + SECTION: [{ // child2 + TEXT_LEAF: [] + }] + }] + }); + + yield test3(browser, t3Container); + yield test4(browser, t4Container); + + yield testTreeOnHide(browser, accDoc, 't5_container', 't5_subcontainer', { + SECTION: [{ // container + SECTION: [{ // subcontainer + TABLE: [{ + ROW: [{ + CELL: [{ + SECTION: [{ // child + TEXT_LEAF: [] + }] + }] + }] + }] + }] + }] + }, { + SECTION: [{ // container + SECTION: [{ // child + TEXT_LEAF: [] + }] + }] + }); + + yield testTreeOnHide(browser, accDoc, 't6_container', 't6_subcontainer', { + SECTION: [{ // container + SECTION: [{ // subcontainer + TABLE: [{ + ROW: [{ + CELL: [{ + TABLE: [{ // nested table + ROW: [{ + CELL: [{ + SECTION: [{ // child + TEXT_LEAF: [] + }] + }] + }] + }] + }] + }] + }] + }, { + SECTION: [{ // child2 + TEXT_LEAF: [] + }] + }] + }] + }, { + SECTION: [{ // container + SECTION: [{ // child + TEXT_LEAF: [] + }] + }, { + SECTION: [{ // child2 + TEXT_LEAF: [] + }] + }] + }); +}); diff --git a/accessible/tests/browser/e10s/browser_treeupdate_whitespace.js b/accessible/tests/browser/e10s/browser_treeupdate_whitespace.js new file mode 100644 index 000000000..c9dbde691 --- /dev/null +++ b/accessible/tests/browser/e10s/browser_treeupdate_whitespace.js @@ -0,0 +1,71 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_REORDER */ + +loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR }); + +addAccessibleTask('doc_treeupdate_whitespace.html', function*(browser, accDoc) { + let container1 = findAccessibleChildByID(accDoc, 'container1'); + let container2Parent = findAccessibleChildByID(accDoc, 'container2-parent'); + + let tree = { + SECTION: [ + { GRAPHIC: [] }, + { TEXT_LEAF: [] }, + { GRAPHIC: [] }, + { TEXT_LEAF: [] }, + { GRAPHIC: [] } + ] + }; + testAccessibleTree(container1, tree); + + let onReorder = waitForEvent(EVENT_REORDER, 'container1'); + // Remove img1 from container1 + yield ContentTask.spawn(browser, {}, () => { + let doc = content.document; + doc.getElementById('container1').removeChild( + doc.getElementById('img1')); + }); + yield onReorder; + + tree = { + SECTION: [ + { GRAPHIC: [] }, + { TEXT_LEAF: [] }, + { GRAPHIC: [] } + ] + }; + testAccessibleTree(container1, tree); + + tree = { + SECTION: [ + { LINK: [] }, + { LINK: [ { GRAPHIC: [] } ] } + ] + }; + testAccessibleTree(container2Parent, tree); + + onReorder = waitForEvent(EVENT_REORDER, 'container2-parent'); + // Append an img with valid src to container2 + yield ContentTask.spawn(browser, {}, () => { + let doc = content.document; + let img = doc.createElement('img'); + img.setAttribute('src', + 'http://example.com/a11y/accessible/tests/mochitest/moz.png'); + doc.getElementById('container2').appendChild(img); + }); + yield onReorder; + + tree = { + SECTION: [ + { LINK: [ { GRAPHIC: [ ] } ] }, + { TEXT_LEAF: [ ] }, + { LINK: [ { GRAPHIC: [ ] } ] } + ] + }; + testAccessibleTree(container2Parent, tree); +}); diff --git a/accessible/tests/browser/e10s/doc_treeupdate_ariadialog.html b/accessible/tests/browser/e10s/doc_treeupdate_ariadialog.html new file mode 100644 index 000000000..9d08854b9 --- /dev/null +++ b/accessible/tests/browser/e10s/doc_treeupdate_ariadialog.html @@ -0,0 +1,23 @@ + + + + Tree Update ARIA Dialog Test + + + + + diff --git a/accessible/tests/browser/e10s/doc_treeupdate_ariaowns.html b/accessible/tests/browser/e10s/doc_treeupdate_ariaowns.html new file mode 100644 index 000000000..38b5c333a --- /dev/null +++ b/accessible/tests/browser/e10s/doc_treeupdate_ariaowns.html @@ -0,0 +1,44 @@ + + + + Tree Update ARIA Owns Test + + +
    +
    + +
    +
    +
    + +
    +
    +
    +
    + +
    + +
    + +
    +
    + + +
    + +
    +
    + + +
    + +
    + hey +
    +
    + + diff --git a/accessible/tests/browser/e10s/doc_treeupdate_imagemap.html b/accessible/tests/browser/e10s/doc_treeupdate_imagemap.html new file mode 100644 index 000000000..4dd230fc2 --- /dev/null +++ b/accessible/tests/browser/e10s/doc_treeupdate_imagemap.html @@ -0,0 +1,21 @@ + + + + Tree Update Imagemap Test + + + + b + + +
    +
    + + diff --git a/accessible/tests/browser/e10s/doc_treeupdate_removal.xhtml b/accessible/tests/browser/e10s/doc_treeupdate_removal.xhtml new file mode 100644 index 000000000..9c59fb9d1 --- /dev/null +++ b/accessible/tests/browser/e10s/doc_treeupdate_removal.xhtml @@ -0,0 +1,11 @@ + + + + Tree Update Removal Test + + + +
    + + + diff --git a/accessible/tests/browser/e10s/doc_treeupdate_visibility.html b/accessible/tests/browser/e10s/doc_treeupdate_visibility.html new file mode 100644 index 000000000..c33a2bc02 --- /dev/null +++ b/accessible/tests/browser/e10s/doc_treeupdate_visibility.html @@ -0,0 +1,78 @@ + + + + Tree Update Visibility Test + + + +
    +
    +
    text
    +
    +
    + + +
    +
    +
    +
    text
    +
    text
    +
    +
    +
    + + +
    +
    +
    text
    +
    +
    +
    text
    +
    +
    + + +
    + + + + +
    + +
    +
    + + +
    +
    + + + + +
    +
    text
    +
    +
    +
    + + +
    +
    + + + + +
    + + + + +
    +
    text
    +
    +
    +
    text
    +
    +
    + + diff --git a/accessible/tests/browser/e10s/doc_treeupdate_whitespace.html b/accessible/tests/browser/e10s/doc_treeupdate_whitespace.html new file mode 100644 index 000000000..d1770d300 --- /dev/null +++ b/accessible/tests/browser/e10s/doc_treeupdate_whitespace.html @@ -0,0 +1,10 @@ + + + + Whitespace text accessible creation/desctruction + + +
    +
    + + diff --git a/accessible/tests/browser/e10s/events.js b/accessible/tests/browser/e10s/events.js new file mode 100644 index 000000000..39dd743ef --- /dev/null +++ b/accessible/tests/browser/e10s/events.js @@ -0,0 +1,127 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global nsIAccessibleEvent, nsIAccessibleDocument, + nsIAccessibleStateChangeEvent, nsIAccessibleTextChangeEvent */ + +/* exported EVENT_REORDER, EVENT_SHOW, EVENT_TEXT_INSERTED, EVENT_TEXT_REMOVED, + EVENT_DOCUMENT_LOAD_COMPLETE, EVENT_HIDE, EVENT_TEXT_CARET_MOVED, + EVENT_DESCRIPTION_CHANGE, EVENT_NAME_CHANGE, EVENT_STATE_CHANGE, + EVENT_VALUE_CHANGE, EVENT_TEXT_VALUE_CHANGE, EVENT_FOCUS, + waitForEvent, waitForMultipleEvents */ + +const EVENT_DOCUMENT_LOAD_COMPLETE = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE; +const EVENT_HIDE = nsIAccessibleEvent.EVENT_HIDE; +const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER; +const EVENT_SHOW = nsIAccessibleEvent.EVENT_SHOW; +const EVENT_STATE_CHANGE = nsIAccessibleEvent.EVENT_STATE_CHANGE; +const EVENT_TEXT_CARET_MOVED = nsIAccessibleEvent.EVENT_TEXT_CARET_MOVED; +const EVENT_TEXT_INSERTED = nsIAccessibleEvent.EVENT_TEXT_INSERTED; +const EVENT_TEXT_REMOVED = nsIAccessibleEvent.EVENT_TEXT_REMOVED; +const EVENT_DESCRIPTION_CHANGE = nsIAccessibleEvent.EVENT_DESCRIPTION_CHANGE; +const EVENT_NAME_CHANGE = nsIAccessibleEvent.EVENT_NAME_CHANGE; +const EVENT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_VALUE_CHANGE; +const EVENT_TEXT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_TEXT_VALUE_CHANGE; +const EVENT_FOCUS = nsIAccessibleEvent.EVENT_FOCUS; + +/** + * Describe an event in string format. + * @param {nsIAccessibleEvent} event event to strigify + */ +function eventToString(event) { + let type = eventTypeToString(event.eventType); + let info = `Event type: ${type}`; + + if (event instanceof nsIAccessibleStateChangeEvent) { + let stateStr = statesToString(event.isExtraState ? 0 : event.state, + event.isExtraState ? event.state : 0); + info += `, state: ${stateStr}, is enabled: ${event.isEnabled}`; + } else if (event instanceof nsIAccessibleTextChangeEvent) { + let tcType = event.isInserted ? 'inserted' : 'removed'; + info += `, start: ${event.start}, length: ${event.length}, ${tcType} text: ${event.modifiedText}`; + } + + info += `. Target: ${prettyName(event.accessible)}`; + return info; +} + +/** + * A helper function that returns a promise that resolves when an accessible + * event of the given type with the given target (defined by its id or + * accessible) is observed. + * @param {String|nsIAccessible} expectedIdOrAcc expected content element id + * for the event + * @param {Number} eventType expected accessible event + * type + * @return {Promise} promise that resolves to an + * event + */ +function waitForEvent(eventType, expectedIdOrAcc) { + return new Promise(resolve => { + let eventObserver = { + observe(subject, topic, data) { + if (topic !== 'accessible-event') { + return; + } + + let event = subject.QueryInterface(nsIAccessibleEvent); + if (Logger.enabled) { + // Avoid calling eventToString if the logger isn't enabled in order + // to avoid an intermittent crash (bug 1307645). + Logger.log(eventToString(event)); + } + + // If event type does not match expected type, skip the event. + if (event.eventType !== eventType) { + return; + } + + let acc = event.accessible; + let id = getAccessibleDOMNodeID(acc); + let isID = typeof expectedIdOrAcc === 'string'; + let actualIdOrAcc = isID ? id : acc; + // If event's accessible does not match expected DOMNode id or + // accessible, skip the event. + if (actualIdOrAcc === expectedIdOrAcc) { + if (isID) { + Logger.log(`Correct event DOMNode id: ${id}`); + } else { + Logger.log(`Correct event accessible: ${prettyName(acc)}`); + } + Logger.log(`Correct event type: ${eventTypeToString(eventType)}`); + ok(event.accessibleDocument instanceof nsIAccessibleDocument, + 'Accessible document present.'); + + Services.obs.removeObserver(this, 'accessible-event'); + resolve(event); + } + } + }; + Services.obs.addObserver(eventObserver, 'accessible-event', false); + }); +} + +/** + * A helper function that waits for a sequence of accessible events in + * specified order. + * @param {Array} events a list of events to wait (same format as + * waitForEvent arguments) + */ +function waitForMultipleEvents(events) { + // Next expected event index. + let currentIdx = 0; + + return Promise.all(events.map(({ eventType, id }, idx) => + // In addition to waiting for an event, attach an order checker for the + // event. + waitForEvent(eventType, id).then(resolvedEvent => { + // Verify that event happens in order and increment expected index. + is(idx, currentIdx++, + `Unexpected event order: ${eventToString(resolvedEvent)}`); + return resolvedEvent; + }) + )); +} diff --git a/accessible/tests/browser/e10s/head.js b/accessible/tests/browser/e10s/head.js new file mode 100644 index 000000000..5cc102697 --- /dev/null +++ b/accessible/tests/browser/e10s/head.js @@ -0,0 +1,84 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* global EVENT_DOCUMENT_LOAD_COMPLETE, CURRENT_CONTENT_DIR, loadFrameScripts */ + +/* exported addAccessibleTask */ + +// Load the shared-head file first. +Services.scriptloader.loadSubScript( + 'chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js', + this); + +/** + * A wrapper around browser test add_task that triggers an accessible test task + * as a new browser test task with given document, data URL or markup snippet. + * @param {String} doc URL (relative to current directory) or + * data URL or markup snippet that is used + * to test content with + * @param {Function|Function*} task a generator or a function with tests to + * run + */ +function addAccessibleTask(doc, task) { + add_task(function*() { + let url; + if (doc.includes('doc_')) { + url = `${CURRENT_CONTENT_DIR}e10s/${doc}`; + } else { + // Assume it's a markup snippet. + url = `data:text/html, + + + + Accessibility Test + + ${doc} + `; + } + + registerCleanupFunction(() => { + let observers = Services.obs.enumerateObservers('accessible-event'); + while (observers.hasMoreElements()) { + Services.obs.removeObserver( + observers.getNext().QueryInterface(Ci.nsIObserver), + 'accessible-event'); + } + }); + + let onDocLoad = waitForEvent(EVENT_DOCUMENT_LOAD_COMPLETE, 'body'); + + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: url + }, function*(browser) { + registerCleanupFunction(() => { + if (browser) { + let tab = gBrowser.getTabForBrowser(browser); + if (tab && !tab.closing && tab.linkedBrowser) { + gBrowser.removeTab(tab); + } + } + }); + + yield SimpleTest.promiseFocus(browser); + + loadFrameScripts(browser, + 'let { document, window, navigator } = content;', + { name: 'common.js', dir: MOCHITESTS_DIR }); + + Logger.log( + `e10s enabled: ${Services.appinfo.browserTabsRemoteAutostart}`); + Logger.log(`Actually remote browser: ${browser.isRemoteBrowser}`); + + let event = yield onDocLoad; + yield task(browser, event.accessible); + }); + }); +} + +// Loading and common.js from accessible/tests/mochitest/ for all tests, as +// well as events.js. +loadScripts({ name: 'common.js', dir: MOCHITESTS_DIR }, 'e10s/events.js'); diff --git a/accessible/tests/browser/head.js b/accessible/tests/browser/head.js new file mode 100644 index 000000000..8e8d82205 --- /dev/null +++ b/accessible/tests/browser/head.js @@ -0,0 +1,116 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* exported initPromise, shutdownPromise, + setE10sPrefs, unsetE10sPrefs, forceGC */ + +/** + * Set e10s related preferences in the test environment. + * @return {Promise} promise that resolves when preferences are set. + */ +function setE10sPrefs() { + return new Promise(resolve => + SpecialPowers.pushPrefEnv({ + set: [ + ['browser.tabs.remote.autostart', true], + ['browser.tabs.remote.force-enable', true], + ['extensions.e10sBlocksEnabling', false] + ] + }, resolve)); +} + +/** + * Unset e10s related preferences in the test environment. + * @return {Promise} promise that resolves when preferences are unset. + */ +function unsetE10sPrefs() { + return new Promise(resolve => { + SpecialPowers.popPrefEnv(resolve); + }); +} + +// Load the shared-head file first. +Services.scriptloader.loadSubScript( + 'chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js', + this); + +/** + * Returns a promise that resolves when 'a11y-init-or-shutdown' event is fired. + * @return {Promise} event promise evaluating to event's data + */ +function a11yInitOrShutdownPromise() { + return new Promise(resolve => { + let observe = (subject, topic, data) => { + Services.obs.removeObserver(observe, 'a11y-init-or-shutdown'); + resolve(data); + }; + Services.obs.addObserver(observe, 'a11y-init-or-shutdown', false); + }); +} + +/** + * Returns a promise that resolves when 'a11y-init-or-shutdown' event is fired + * in content. + * @param {Object} browser current "tabbrowser" element + * @return {Promise} event promise evaluating to event's data + */ +function contentA11yInitOrShutdownPromise(browser) { + return ContentTask.spawn(browser, {}, a11yInitOrShutdownPromise); +} + +/** + * A helper function that maps 'a11y-init-or-shutdown' event to a promise that + * resovles or rejects depending on whether accessibility service is expected to + * be initialized or shut down. + */ +function promiseOK(promise, expected) { + return promise.then(flag => + flag === expected ? Promise.resolve() : Promise.reject()); +} + +/** + * Checks and returns a promise that resolves when accessibility service is + * initialized with the correct flag. + * @param {?Object} contentBrowser optinal remove browser object that indicates + * that accessibility service is expected to be + * initialized in content process. + * @return {Promise} promise that resolves when the accessibility + * service initialized correctly. + */ +function initPromise(contentBrowser) { + let a11yInitPromise = contentBrowser ? + contentA11yInitOrShutdownPromise(contentBrowser) : + a11yInitOrShutdownPromise(); + return promiseOK(a11yInitPromise, '1').then( + () => ok(true, 'Service initialized correctly'), + () => ok(false, 'Service shutdown incorrectly')); +} + +/** + * Checks and returns a promise that resolves when accessibility service is + * shut down with the correct flag. + * @param {?Object} contentBrowser optinal remove browser object that indicates + * that accessibility service is expected to be + * shut down in content process. + * @return {Promise} promise that resolves when the accessibility + * service shuts down correctly. + */ +function shutdownPromise(contentBrowser) { + let a11yShutdownPromise = contentBrowser ? + contentA11yInitOrShutdownPromise(contentBrowser) : + a11yInitOrShutdownPromise(); + return promiseOK(a11yShutdownPromise, '0').then( + () => ok(true, 'Service shutdown correctly'), + () => ok(false, 'Service initialized incorrectly')); +} + +/** + * Force garbage collection. + */ +function forceGC() { + Cu.forceCC(); + Cu.forceGC(); +} diff --git a/accessible/tests/browser/shared-head.js b/accessible/tests/browser/shared-head.js new file mode 100644 index 000000000..83a9fa612 --- /dev/null +++ b/accessible/tests/browser/shared-head.js @@ -0,0 +1,229 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +/* exported Logger, MOCHITESTS_DIR, isDefunct, invokeSetAttribute, invokeFocus, + invokeSetStyle, findAccessibleChildByID, getAccessibleDOMNodeID, + CURRENT_CONTENT_DIR, loadScripts, loadFrameScripts, Cc, Cu */ + +const { interfaces: Ci, utils: Cu, classes: Cc } = Components; + +/** + * Current browser test directory path used to load subscripts. + */ +const CURRENT_DIR = + 'chrome://mochitests/content/browser/accessible/tests/browser/'; +/** + * A11y mochitest directory where we find common files used in both browser and + * plain tests. + */ +const MOCHITESTS_DIR = + 'chrome://mochitests/content/a11y/accessible/tests/mochitest/'; +/** + * A base URL for test files used in content. + */ +const CURRENT_CONTENT_DIR = + 'http://example.com/browser/accessible/tests/browser/'; + +/** + * Used to dump debug information. + */ +let Logger = { + /** + * Set up this variable to dump log messages into console. + */ + dumpToConsole: false, + + /** + * Set up this variable to dump log messages into error console. + */ + dumpToAppConsole: false, + + /** + * Return true if dump is enabled. + */ + get enabled() { + return this.dumpToConsole || this.dumpToAppConsole; + }, + + /** + * Dump information into console if applicable. + */ + log(msg) { + if (this.enabled) { + this.logToConsole(msg); + this.logToAppConsole(msg); + } + }, + + /** + * Log message to console. + */ + logToConsole(msg) { + if (this.dumpToConsole) { + dump(`\n${msg}\n`); + } + }, + + /** + * Log message to error console. + */ + logToAppConsole(msg) { + if (this.dumpToAppConsole) { + Services.console.logStringMessage(`${msg}`); + } + } +}; + +/** + * Check if an accessible object has a defunct test. + * @param {nsIAccessible} accessible object to test defunct state for + * @return {Boolean} flag indicating defunct state + */ +function isDefunct(accessible) { + let defunct = false; + try { + let extState = {}; + accessible.getState({}, extState); + defunct = extState.value & Ci.nsIAccessibleStates.EXT_STATE_DEFUNCT; + } catch (x) { + defunct = true; + } finally { + if (defunct) { + Logger.log(`Defunct accessible: ${prettyName(accessible)}`); + } + } + return defunct; +} + +/** + * Asynchronously set or remove content element's attribute (in content process + * if e10s is enabled). + * @param {Object} browser current "tabbrowser" element + * @param {String} id content element id + * @param {String} attr attribute name + * @param {String?} value optional attribute value, if not present, remove + * attribute + * @return {Promise} promise indicating that attribute is set/removed + */ +function invokeSetAttribute(browser, id, attr, value) { + if (value) { + Logger.log(`Setting ${attr} attribute to ${value} for node with id: ${id}`); + } else { + Logger.log(`Removing ${attr} attribute from node with id: ${id}`); + } + return ContentTask.spawn(browser, [id, attr, value], + ([contentId, contentAttr, contentValue]) => { + let elm = content.document.getElementById(contentId); + if (contentValue) { + elm.setAttribute(contentAttr, contentValue); + } else { + elm.removeAttribute(contentAttr); + } + }); +} + +/** + * Asynchronously set or remove content element's style (in content process if + * e10s is enabled). + * @param {Object} browser current "tabbrowser" element + * @param {String} id content element id + * @param {String} aStyle style property name + * @param {String?} aValue optional style property value, if not present, + * remove style + * @return {Promise} promise indicating that style is set/removed + */ +function invokeSetStyle(browser, id, style, value) { + if (value) { + Logger.log(`Setting ${style} style to ${value} for node with id: ${id}`); + } else { + Logger.log(`Removing ${style} style from node with id: ${id}`); + } + return ContentTask.spawn(browser, [id, style, value], + ([contentId, contentStyle, contentValue]) => { + let elm = content.document.getElementById(contentId); + if (contentValue) { + elm.style[contentStyle] = contentValue; + } else { + delete elm.style[contentStyle]; + } + }); +} + +/** + * Asynchronously set focus on a content element (in content process if e10s is + * enabled). + * @param {Object} browser current "tabbrowser" element + * @param {String} id content element id + * @return {Promise} promise indicating that focus is set + */ +function invokeFocus(browser, id) { + Logger.log(`Setting focus on a node with id: ${id}`); + return ContentTask.spawn(browser, id, contentId => { + let elm = content.document.getElementById(contentId); + if (elm instanceof Ci.nsIDOMNSEditableElement && elm.editor || + elm instanceof Ci.nsIDOMXULTextBoxElement) { + elm.selectionStart = elm.selectionEnd = elm.value.length; + } + elm.focus(); + }); +} + +/** + * Traverses the accessible tree starting from a given accessible as a root and + * looks for an accessible that matches based on its DOMNode id. + * @param {nsIAccessible} accessible root accessible + * @param {String} id id to look up accessible for + * @return {nsIAccessible?} found accessible if any + */ +function findAccessibleChildByID(accessible, id) { + if (getAccessibleDOMNodeID(accessible) === id) { + return accessible; + } + for (let i = 0; i < accessible.children.length; ++i) { + let found = findAccessibleChildByID(accessible.getChildAt(i), id); + if (found) { + return found; + } + } +} + +/** + * Load a list of scripts into the test + * @param {Array} scripts a list of scripts to load + */ +function loadScripts(...scripts) { + for (let script of scripts) { + let path = typeof script === 'string' ? `${CURRENT_DIR}${script}` : + `${script.dir}${script.name}`; + Services.scriptloader.loadSubScript(path, this); + } +} + +/** + * Load a list of frame scripts into test's content. + * @param {Object} browser browser element that content belongs to + * @param {Array} scripts a list of scripts to load into content + */ +function loadFrameScripts(browser, ...scripts) { + let mm = browser.messageManager; + for (let script of scripts) { + let frameScript; + if (typeof script === 'string') { + if (script.includes('.js')) { + // If script string includes a .js extention, assume it is a script + // path. + frameScript = `${CURRENT_DIR}${script}`; + } else { + // Otherwise it is a serealized script. + frameScript = `data:,${script}`; + } + } else { + // Script is a object that has { dir, name } format. + frameScript = `${script.dir}${script.name}`; + } + mm.loadFrameScript(frameScript, false, true); + } +} diff --git a/accessible/tests/crashtests/448064.xhtml b/accessible/tests/crashtests/448064.xhtml new file mode 100644 index 000000000..64d6d851d --- /dev/null +++ b/accessible/tests/crashtests/448064.xhtml @@ -0,0 +1,73 @@ + + + + +
    +
    + +
    + + + + + + + + + \ No newline at end of file diff --git a/accessible/tests/crashtests/471493.xul b/accessible/tests/crashtests/471493.xul new file mode 100644 index 000000000..2524d47cc --- /dev/null +++ b/accessible/tests/crashtests/471493.xul @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + diff --git a/accessible/tests/crashtests/crashtests.list b/accessible/tests/crashtests/crashtests.list new file mode 100644 index 000000000..6718706aa --- /dev/null +++ b/accessible/tests/crashtests/crashtests.list @@ -0,0 +1,3 @@ +# Disabled because they cause assertions/crashes in later crashtests, see bug 918246 +skip load 448064.xhtml +skip load 471493.xul diff --git a/accessible/tests/mochitest/a11y.ini b/accessible/tests/mochitest/a11y.ini new file mode 100644 index 000000000..b197c7007 --- /dev/null +++ b/accessible/tests/mochitest/a11y.ini @@ -0,0 +1,17 @@ +[DEFAULT] +support-files = + ../../../dom/media/test/bug461281.ogg + dumbfile.zip + formimage.png + letters.gif + moz.png + longdesc_src.html + *.js + treeview.css + +[test_aria_token_attrs.html] +[test_bug420863.html] +[test_descr.html] +[test_nsIAccessibleDocument.html] +[test_nsIAccessibleImage.html] +[test_OuterDocAccessible.html] diff --git a/accessible/tests/mochitest/actions.js b/accessible/tests/mochitest/actions.js new file mode 100644 index 000000000..0c2765eeb --- /dev/null +++ b/accessible/tests/mochitest/actions.js @@ -0,0 +1,187 @@ +//////////////////////////////////////////////////////////////////////////////// +// Event constants + +const MOUSEDOWN_EVENT = 1; +const MOUSEUP_EVENT = 2; +const CLICK_EVENT = 4; +const COMMAND_EVENT = 8; +const FOCUS_EVENT = 16; + +const CLICK_EVENTS = MOUSEDOWN_EVENT | MOUSEUP_EVENT | CLICK_EVENT; +const XUL_EVENTS = CLICK_EVENTS | COMMAND_EVENT; + +//////////////////////////////////////////////////////////////////////////////// +// Public functions + +/** + * Test default accessible actions. + * + * Action tester interface is: + * + * var actionObj = { + * // identifier of accessible to perform an action on + * get ID() {}, + * + * // index of the action + * get actionIndex() {}, + * + * // name of the action + * get actionName() {}, + * + * // DOM events (see constants defined above) + * get events() {}, + * + * // [optional] identifier of target DOM events listeners are registered on, + * // used with 'events', if missing then 'ID' is used instead. + * get targetID() {}, + * + * // [optional] perform checks when 'click' event is handled if 'events' + * // is used. + * checkOnClickEvent: function() {}, + * + * // [optional] an array of invoker's checker objects (see eventQueue + * // constructor events.js) + * get eventSeq() {} + * }; + * + * + * @param aArray [in] an array of action cheker objects + */ +function testActions(aArray) +{ + gActionsQueue = new eventQueue(); + + for (var idx = 0; idx < aArray.length; idx++) { + + var actionObj = aArray[idx]; + var accOrElmOrID = actionObj.ID; + var actionIndex = actionObj.actionIndex; + var actionName = actionObj.actionName; + var events = actionObj.events; + var accOrElmOrIDOfTarget = actionObj.targetID ? + actionObj.targetID : accOrElmOrID; + + var eventSeq = new Array(); + if (events) { + var elm = getNode(accOrElmOrIDOfTarget); + if (events & MOUSEDOWN_EVENT) + eventSeq.push(new checkerOfActionInvoker("mousedown", elm)); + + if (events & MOUSEUP_EVENT) + eventSeq.push(new checkerOfActionInvoker("mouseup", elm)); + + if (events & CLICK_EVENT) + eventSeq.push(new checkerOfActionInvoker("click", elm, actionObj)); + + if (events & COMMAND_EVENT) + eventSeq.push(new checkerOfActionInvoker("command", elm)); + + if (events & FOCUS_EVENT) + eventSeq.push(new focusChecker(elm)); + } + + if (actionObj.eventSeq) + eventSeq = eventSeq.concat(actionObj.eventSeq); + + var invoker = new actionInvoker(accOrElmOrID, actionIndex, actionName, + eventSeq); + gActionsQueue.push(invoker); + } + + gActionsQueue.invoke(); +} + +/** + * Test action names and descriptions. + */ +function testActionNames(aID, aActions) +{ + var actions = (typeof aActions == "string") ? + [ aActions ] : (aActions || []); + + var acc = getAccessible(aID); + is(acc.actionCount, actions.length, "Wong number of actions."); + for (var i = 0; i < actions.length; i++ ) { + is(acc.getActionName(i), actions[i], "Wrong action name at " + i + " index."); + is(acc.getActionDescription(0), gActionDescrMap[actions[i]], + "Wrong action description at " + i + "index."); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Private + +var gActionsQueue = null; + +function actionInvoker(aAccOrElmOrId, aActionIndex, aActionName, aEventSeq) +{ + this.invoke = function actionInvoker_invoke() + { + var acc = getAccessible(aAccOrElmOrId); + if (!acc) + return INVOKER_ACTION_FAILED; + + var isThereActions = acc.actionCount > 0; + ok(isThereActions, + "No actions on the accessible for " + prettyName(aAccOrElmOrId)); + + if (!isThereActions) + return INVOKER_ACTION_FAILED; + + is(acc.getActionName(aActionIndex), aActionName, + "Wrong action name of the accessible for " + prettyName(aAccOrElmOrId)); + + try { + acc.doAction(aActionIndex); + } + catch (e){ + ok(false, "doAction(" + aActionIndex + ") failed with: " + e.name); + return INVOKER_ACTION_FAILED; + } + } + + this.eventSeq = aEventSeq; + + this.getID = function actionInvoker_getID() + { + return "invoke an action " + aActionName + " at index " + aActionIndex + + " on " + prettyName(aAccOrElmOrId); + } +} + +function checkerOfActionInvoker(aType, aTarget, aActionObj) +{ + this.type = aType; + + this.target = aTarget; + + this.phase = false; + + this.getID = function getID() + { + return aType + " event handling"; + } + + this.check = function check(aEvent) + { + if (aActionObj && "checkOnClickEvent" in aActionObj) + aActionObj.checkOnClickEvent(aEvent); + } +} + +var gActionDescrMap = +{ + jump: "Jump", + press: "Press", + check: "Check", + uncheck: "Uncheck", + select: "Select", + open: "Open", + close: "Close", + switch: "Switch", + click: "Click", + collapse: "Collapse", + expand: "Expand", + activate: "Activate", + cycle: "Cycle" +}; diff --git a/accessible/tests/mochitest/actions/a11y.ini b/accessible/tests/mochitest/actions/a11y.ini new file mode 100644 index 000000000..ca01f4104 --- /dev/null +++ b/accessible/tests/mochitest/actions/a11y.ini @@ -0,0 +1,18 @@ +[DEFAULT] +support-files = + !/accessible/tests/mochitest/*.js + !/dom/media/test/bug461281.ogg + +[test_anchors.html] +[test_aria.html] +[test_controls.html] +[test_general.html] +[test_general.xul] +[test_keys.html] +[test_keys_menu.xul] +[test_link.html] +[test_media.html] +skip-if = buildapp == 'mulet' +[test_select.html] +[test_tree.xul] +[test_treegrid.xul] diff --git a/accessible/tests/mochitest/actions/test_anchors.html b/accessible/tests/mochitest/actions/test_anchors.html new file mode 100644 index 000000000..5e8330683 --- /dev/null +++ b/accessible/tests/mochitest/actions/test_anchors.html @@ -0,0 +1,150 @@ + + + + nsIAccessible actions testing for HTML links that + scroll the page to named anchors + + + + + + + + + + + + + + + + Mozilla Bug 506389 +
    + + Mozilla Bug 437607 +
    + + Mozilla Bug 519303 + + +

    + +
    +  
    + +
    + +

    This is a test page for anchors

    + This is a top anchor + Link to anchor + Link to div +









    +









    +









    +









    +









    +









    +









    +









    +









    +









    +










    +










    +









    +









    +




    This is some text in the middle




    +









    +









    +









    +









    +









    +









    +









    +









    +









    +









    +









    +









    +









    +









    +









    +









    +









    +









    +









    + This is some text. + This is a bottom anchor +









    +









    +









    +
    This is a div
    + + diff --git a/accessible/tests/mochitest/actions/test_aria.html b/accessible/tests/mochitest/actions/test_aria.html new file mode 100644 index 000000000..c4eae812d --- /dev/null +++ b/accessible/tests/mochitest/actions/test_aria.html @@ -0,0 +1,202 @@ + + + + nsIAccessible actions testing + + + + + + + + + + + + + + + + Mozilla Bug 410765 + +

    + +
    +  
    + +
    Clickable text
    + +
    Button
    + + + + + + + +
    +
    Option of collapsed combobox
    +
    + +
    +
    Option of expanded combobox
    +
    + + + +
    + + + +
    + +
    + +
    + +
    Switch
    + +
    Switch
    + +
    + +
    + +
    Textbox
    + +
    +
    Treeitem
    +
    + +
    +
    + Columnheader +
    +
    + + +
    expanded
    + + diff --git a/accessible/tests/mochitest/actions/test_controls.html b/accessible/tests/mochitest/actions/test_controls.html new file mode 100644 index 000000000..d6109a82f --- /dev/null +++ b/accessible/tests/mochitest/actions/test_controls.html @@ -0,0 +1,109 @@ + + + + nsIAccessible actions testing for inputs + + + + + + + + + + + + + + + + + + Mozilla Bug 477975 + +

    + +
    +  
    + + + + + + Checkbox + + Checkbox + + Checkbox + +
    + Radio +
    + + + + + + diff --git a/accessible/tests/mochitest/actions/test_general.html b/accessible/tests/mochitest/actions/test_general.html new file mode 100644 index 000000000..5b9a18dab --- /dev/null +++ b/accessible/tests/mochitest/actions/test_general.html @@ -0,0 +1,107 @@ + + + + nsIAccessible actions testing on HTML elements + + + + + + + + + + + + + + + + Mozilla Bug 523789 +
    + + Mozilla Bug 423409 + + + Mozilla Bug 659620 + +

    + +
    +  
    + + + + + + + linkable textleaf accessible +
    linkable textleaf accessible
    + +
    + + +
    + + + diff --git a/accessible/tests/mochitest/actions/test_general.xul b/accessible/tests/mochitest/actions/test_general.xul new file mode 100644 index 000000000..14d8bb0d0 --- /dev/null +++ b/accessible/tests/mochitest/actions/test_general.xul @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + Mozilla Bug 410765 + + + Mozilla Bug 504252 +
    +

    + +
    +      
    + + + + + + + + + + + + + + + + + + + +
    +
    + diff --git a/accessible/tests/mochitest/actions/test_keys.html b/accessible/tests/mochitest/actions/test_keys.html new file mode 100644 index 000000000..2feebcadb --- /dev/null +++ b/accessible/tests/mochitest/actions/test_keys.html @@ -0,0 +1,60 @@ + + + + + Keyboard shortcuts tests + + + + + + + + + + + + + + Mozilla Bug 381599 + +

    + +
    +  
    + + +
    + +
    +
    Item 1
    +
    +
  1. Item 1A
  2. +
  3. Item 1B
  4. +
    +
    Item 2
    +
    +
    Item 2A
    +
    Item 2B
    +
    +
    + + +
    Item 1
    Item 2
    + + + + + + + + + + +
    cell1cell2
    cell3cell4
    + +
    +
    +
    cell1
    +
    cell2
    +
    +
    +
    cell1
    +
    cell2
    +
    +
    +
    cell1
    +
    cell2
    +
    +
    + +

    heading1

    +

    heading2

    +

    heading3

    +

    heading4

    +
    heading5
    +
    heading6
    + + + +
    + + +
    + +
    +
    +
    cell
    +
    +
    + +
    +
    Apples
    +
    Oranges
    + +
    Bananas
    + + diff --git a/accessible/tests/mochitest/attributes/test_obj_group.xul b/accessible/tests/mochitest/attributes/test_obj_group.xul new file mode 100644 index 000000000..c6943ae37 --- /dev/null +++ b/accessible/tests/mochitest/attributes/test_obj_group.xul @@ -0,0 +1,216 @@ + + + + + + + + + + + + Mozilla Bug 417317 +
    + + Mozilla Bug 443881 +
    + + Mozilla Bug 441888 +
    + +

    + +
    +    
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + diff --git a/accessible/tests/mochitest/attributes/test_obj_group_tree.xul b/accessible/tests/mochitest/attributes/test_obj_group_tree.xul new file mode 100644 index 000000000..6b8461ef7 --- /dev/null +++ b/accessible/tests/mochitest/attributes/test_obj_group_tree.xul @@ -0,0 +1,85 @@ + + + + + + + + + + + + Mozilla Bug 503727 +
    +

    + +
    +      
    + + + + + + + + + + + + +
    + +
    + diff --git a/accessible/tests/mochitest/attributes/test_tag.html b/accessible/tests/mochitest/attributes/test_tag.html new file mode 100644 index 000000000..e43147b24 --- /dev/null +++ b/accessible/tests/mochitest/attributes/test_tag.html @@ -0,0 +1,82 @@ + + + + HTML landmark tests + + + + + + + + + + + + + + Bug 593368 +
    + + Bug 613502 + + + Bug 610650 + + + Mozilla Bug 614310 + + + Bug 734982 + +

    + +
    +  
    + + + +
    a footer
    + +
    a section
    + +
    an article
    +
    a main area
    +
    a form area
    + + + diff --git a/accessible/tests/mochitest/attributes/test_xml-roles.html b/accessible/tests/mochitest/attributes/test_xml-roles.html new file mode 100644 index 000000000..9b3d5aa5a --- /dev/null +++ b/accessible/tests/mochitest/attributes/test_xml-roles.html @@ -0,0 +1,251 @@ + + + + XML roles tests + + + + + + + + + + + + + + Bug 593368 +
    + + Bug 613502 + + + Bug 610650 + + + Mozilla Bug 614310 + + + Bug 734982 + + + Bug 761891 + + + Bug 849624 + + + Bug 1121518 + +

    + +
    +  
    + + + +
    a footer
    +
    +
    a header within an article
    +
    a footer within an article
    +
    + + +
    a section
    +
    a main area
    +
    a form area
    +
    a feed
    +
    article
    +
    another main area
    + + + + + (x,y) + (x,y) + (x,y) + (x,y) + (x,y) + (x,y) + (x,y) + + + + + a + b + + + + + + + a + b + + + + + a + b + + + + + a + b + c + + + + + a + b + c + + d + + e + + f + g + + + + + + + a + b + + + + + a + b + + + + + a + b + c + + + + + + + a + b + + + + + diff --git a/accessible/tests/mochitest/autocomplete.js b/accessible/tests/mochitest/autocomplete.js new file mode 100644 index 000000000..4de881b4d --- /dev/null +++ b/accessible/tests/mochitest/autocomplete.js @@ -0,0 +1,221 @@ + +const nsISupports = Components.interfaces.nsISupports; +const nsIAutoCompleteResult = Components.interfaces.nsIAutoCompleteResult; +const nsIAutoCompleteSearch = Components.interfaces.nsIAutoCompleteSearch; +const nsIFactory = Components.interfaces.nsIFactory; +const nsIUUIDGenerator = Components.interfaces.nsIUUIDGenerator; +const nsIComponentRegistrar = Components.interfaces.nsIComponentRegistrar; + +var gDefaultAutoCompleteSearch = null; + +/** + * Register 'test-a11y-search' AutoCompleteSearch. + * + * @param aValues [in] set of possible results values + * @param aComments [in] set of possible results descriptions + */ +function initAutoComplete(aValues, aComments) +{ + var allResults = new ResultsHeap(aValues, aComments); + gDefaultAutoCompleteSearch = + new AutoCompleteSearch("test-a11y-search", allResults); + registerAutoCompleteSearch(gDefaultAutoCompleteSearch, + "Accessibility Test AutoCompleteSearch"); +} + +/** + * Unregister 'test-a11y-search' AutoCompleteSearch. + */ +function shutdownAutoComplete() +{ + unregisterAutoCompleteSearch(gDefaultAutoCompleteSearch); + gDefaultAutoCompleteSearch.cid = null; + gDefaultAutoCompleteSearch = null; +} + + +/** + * Register the given AutoCompleteSearch. + * + * @param aSearch [in] AutoCompleteSearch object + * @param aDescription [in] description of the search object + */ +function registerAutoCompleteSearch(aSearch, aDescription) +{ + var name = "@mozilla.org/autocomplete/search;1?name=" + aSearch.name; + + var uuidGenerator = Components.classes["@mozilla.org/uuid-generator;1"]. + getService(nsIUUIDGenerator); + var cid = uuidGenerator.generateUUID(); + + var componentManager = Components.manager.QueryInterface(nsIComponentRegistrar); + componentManager.registerFactory(cid, aDescription, name, aSearch); + + // Keep the id on the object so we can unregister later. + aSearch.cid = cid; +} + +/** + * Unregister the given AutoCompleteSearch. + */ +function unregisterAutoCompleteSearch(aSearch) +{ + var componentManager = Components.manager.QueryInterface(nsIComponentRegistrar); + componentManager.unregisterFactory(aSearch.cid, aSearch); +} + + +/** + * A container to keep all possible results of autocomplete search. + */ +function ResultsHeap(aValues, aComments) +{ + this.values = aValues; + this.comments = aComments; +} + +ResultsHeap.prototype = +{ + constructor: ResultsHeap, + + /** + * Return AutoCompleteResult for the given search string. + */ + getAutoCompleteResultFor: function(aSearchString) + { + var values = [], comments = []; + for (var idx = 0; idx < this.values.length; idx++) { + if (this.values[idx].indexOf(aSearchString) != -1) { + values.push(this.values[idx]); + comments.push(this.comments[idx]); + } + } + return new AutoCompleteResult(values, comments); + } +} + + +/** + * nsIAutoCompleteSearch implementation. + * + * @param aName [in] the name of autocomplete search + * @param aAllResults [in] ResultsHeap object + */ +function AutoCompleteSearch(aName, aAllResults) +{ + this.name = aName; + this.allResults = aAllResults; +} + +AutoCompleteSearch.prototype = +{ + constructor: AutoCompleteSearch, + + // nsIAutoCompleteSearch implementation + startSearch: function(aSearchString, aSearchParam, aPreviousResult, + aListener) + { + var result = this.allResults.getAutoCompleteResultFor(aSearchString); + aListener.onSearchResult(this, result); + }, + + stopSearch: function() {}, + + // nsISupports implementation + QueryInterface: function(iid) + { + if (iid.equals(nsISupports) || + iid.equals(nsIFactory) || + iid.equals(nsIAutoCompleteSearch)) + return this; + + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + + // nsIFactory implementation + createInstance: function(outer, iid) + { + return this.QueryInterface(iid); + }, + + // Search name. Used by AutoCompleteController. + name: null, + + // Results heap. + allResults: null +} + + +/** + * nsIAutoCompleteResult implementation. + */ +function AutoCompleteResult(aValues, aComments) +{ + this.values = aValues; + this.comments = aComments; + + if (this.values.length > 0) + this.searchResult = nsIAutoCompleteResult.RESULT_SUCCESS; + else + this.searchResult = nsIAutoCompleteResult.NOMATCH; +} + +AutoCompleteResult.prototype = +{ + constructor: AutoCompleteResult, + + searchString: "", + searchResult: null, + + defaultIndex: 0, + + get matchCount() + { + return this.values.length; + }, + + getValueAt: function(aIndex) + { + return this.values[aIndex]; + }, + + getLabelAt: function(aIndex) + { + return this.getValueAt(aIndex); + }, + + getCommentAt: function(aIndex) + { + return this.comments[aIndex]; + }, + + getStyleAt: function(aIndex) + { + return null; + }, + + getImageAt: function(aIndex) + { + return ""; + }, + + getFinalCompleteValueAt: function(aIndex) + { + return this.getValueAt(aIndex); + }, + + removeValueAt: function (aRowIndex, aRemoveFromDb) {}, + + // nsISupports implementation + QueryInterface: function(iid) { + if (iid.equals(nsISupports) || + iid.equals(nsIAutoCompleteResult)) + return this; + + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + + // Data + values: null, + comments: null +} diff --git a/accessible/tests/mochitest/bounds/a11y.ini b/accessible/tests/mochitest/bounds/a11y.ini new file mode 100644 index 000000000..d60bd46a5 --- /dev/null +++ b/accessible/tests/mochitest/bounds/a11y.ini @@ -0,0 +1,8 @@ +[DEFAULT] +support-files = + !/accessible/tests/mochitest/*.js + +[test_list.html] +[test_select.html] +[test_zoom.html] +[test_zoom_text.html] diff --git a/accessible/tests/mochitest/bounds/test_list.html b/accessible/tests/mochitest/bounds/test_list.html new file mode 100644 index 000000000..38a79689b --- /dev/null +++ b/accessible/tests/mochitest/bounds/test_list.html @@ -0,0 +1,81 @@ + + + + Accessible boundaries when page is zoomed + + + + + + + + + + + + + + + Mozilla Bug 754627 + +

    + +
    +  
    + + + + + + + diff --git a/accessible/tests/mochitest/bounds/test_select.html b/accessible/tests/mochitest/bounds/test_select.html new file mode 100644 index 000000000..395dad1b6 --- /dev/null +++ b/accessible/tests/mochitest/bounds/test_select.html @@ -0,0 +1,85 @@ + + + + Accessible boundaries when page is zoomed + + + + + + + + + + + + + + +

    + +
    +  
    + + + + diff --git a/accessible/tests/mochitest/bounds/test_zoom.html b/accessible/tests/mochitest/bounds/test_zoom.html new file mode 100644 index 000000000..fc2dee482 --- /dev/null +++ b/accessible/tests/mochitest/bounds/test_zoom.html @@ -0,0 +1,96 @@ + + + + Accessible boundaries when page is zoomed + + + + + + + + + + + + + + + + + + Mozilla Bug 650241 + +

    + +
    +  
    + + diff --git a/accessible/tests/mochitest/bounds/test_zoom_text.html b/accessible/tests/mochitest/bounds/test_zoom_text.html new file mode 100644 index 000000000..1637f344e --- /dev/null +++ b/accessible/tests/mochitest/bounds/test_zoom_text.html @@ -0,0 +1,77 @@ + + + + The text range boundary when page is zoomed + + + + + + + + + + + + + + + + + + Mozilla Bug 727942 + +

    + +
    +  
    + + diff --git a/accessible/tests/mochitest/browser.js b/accessible/tests/mochitest/browser.js new file mode 100644 index 000000000..f84f545d8 --- /dev/null +++ b/accessible/tests/mochitest/browser.js @@ -0,0 +1,153 @@ +/** + * Load the browser with the given url and then invokes the given function. + */ +function openBrowserWindow(aFunc, aURL, aRect) +{ + gBrowserContext.testFunc = aFunc; + gBrowserContext.startURL = aURL; + gBrowserContext.browserRect = aRect; + + addLoadEvent(openBrowserWindowIntl); +} + +/** + * Close the browser window. + */ +function closeBrowserWindow() +{ + gBrowserContext.browserWnd.close(); +} + +/** + * Return the browser window object. + */ +function browserWindow() +{ + return gBrowserContext.browserWnd; +} + +/** + * Return the document of the browser window. + */ +function browserDocument() +{ + return browserWindow().document; +} + +/** + * Return tab browser object. + */ +function tabBrowser() +{ + return browserWindow().gBrowser; +} + +/** + * Return browser element of the current tab. + */ +function currentBrowser() +{ + return tabBrowser().selectedBrowser; +} + +/** + * Return DOM document of the current tab. + */ +function currentTabDocument() +{ + return currentBrowser().contentDocument; +} + +/** + * Return window of the current tab. + */ +function currentTabWindow() +{ + return currentTabDocument().defaultView; +} + +/** + * Return browser element of the tab at the given index. + */ +function browserAt(aIndex) +{ + return tabBrowser().getBrowserAtIndex(aIndex); +} + +/** + * Return DOM document of the tab at the given index. + */ +function tabDocumentAt(aIndex) +{ + return browserAt(aIndex).contentDocument; +} + +/** + * Return input element of address bar. + */ +function urlbarInput() +{ + return browserWindow().document.getElementById("urlbar").inputField; +} + +/** + * Return reload button. + */ +function reloadButton() +{ + return browserWindow().document.getElementById("urlbar-reload-button"); +} + +//////////////////////////////////////////////////////////////////////////////// +// private section + +Components.utils.import("resource://gre/modules/Services.jsm"); + +var gBrowserContext = +{ + browserWnd: null, + testFunc: null, + startURL: "" +}; + +function openBrowserWindowIntl() +{ + var params = "chrome,all,dialog=no"; + var rect = gBrowserContext.browserRect; + if (rect) { + if ("left" in rect) + params += ",left=" + rect.left; + if ("top" in rect) + params += ",top=" + rect.top; + if ("width" in rect) + params += ",width=" + rect.width; + if ("height" in rect) + params += ",height=" + rect.height; + } + + gBrowserContext.browserWnd = + window.openDialog(Services.prefs.getCharPref("browser.chromeURL"), + "_blank", params, + gBrowserContext.startURL); + + whenDelayedStartupFinished(browserWindow(), function () { + addA11yLoadEvent(startBrowserTests, browserWindow()); + }); +} + +function startBrowserTests() +{ + if (gBrowserContext.startURL) // wait for load + addA11yLoadEvent(gBrowserContext.testFunc, currentBrowser().contentWindow); + else + gBrowserContext.testFunc(); +} + +function whenDelayedStartupFinished(aWindow, aCallback) { + Services.obs.addObserver(function observer(aSubject, aTopic) { + if (aWindow == aSubject) { + Services.obs.removeObserver(observer, aTopic); + setTimeout(aCallback, 0); + } + }, "browser-delayed-startup-finished", false); +} diff --git a/accessible/tests/mochitest/common.js b/accessible/tests/mochitest/common.js new file mode 100644 index 000000000..1e48fa067 --- /dev/null +++ b/accessible/tests/mochitest/common.js @@ -0,0 +1,952 @@ +//////////////////////////////////////////////////////////////////////////////// +// Interfaces + +const nsIAccessibilityService = Components.interfaces.nsIAccessibilityService; + +const nsIAccessibleEvent = Components.interfaces.nsIAccessibleEvent; +const nsIAccessibleStateChangeEvent = + Components.interfaces.nsIAccessibleStateChangeEvent; +const nsIAccessibleCaretMoveEvent = + Components.interfaces.nsIAccessibleCaretMoveEvent; +const nsIAccessibleTextChangeEvent = + Components.interfaces.nsIAccessibleTextChangeEvent; +const nsIAccessibleVirtualCursorChangeEvent = + Components.interfaces.nsIAccessibleVirtualCursorChangeEvent; +const nsIAccessibleObjectAttributeChangedEvent = + Components.interfaces.nsIAccessibleObjectAttributeChangedEvent; + +const nsIAccessibleStates = Components.interfaces.nsIAccessibleStates; +const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole; +const nsIAccessibleScrollType = Components.interfaces.nsIAccessibleScrollType; +const nsIAccessibleCoordinateType = Components.interfaces.nsIAccessibleCoordinateType; + +const nsIAccessibleRelation = Components.interfaces.nsIAccessibleRelation; +const nsIAccessibleTextRange = Components.interfaces.nsIAccessibleTextRange; + +const nsIAccessible = Components.interfaces.nsIAccessible; + +const nsIAccessibleDocument = Components.interfaces.nsIAccessibleDocument; +const nsIAccessibleApplication = Components.interfaces.nsIAccessibleApplication; + +const nsIAccessibleText = Components.interfaces.nsIAccessibleText; +const nsIAccessibleEditableText = Components.interfaces.nsIAccessibleEditableText; + +const nsIAccessibleHyperLink = Components.interfaces.nsIAccessibleHyperLink; +const nsIAccessibleHyperText = Components.interfaces.nsIAccessibleHyperText; + +const nsIAccessibleImage = Components.interfaces.nsIAccessibleImage; +const nsIAccessiblePivot = Components.interfaces.nsIAccessiblePivot; +const nsIAccessibleSelectable = Components.interfaces.nsIAccessibleSelectable; +const nsIAccessibleTable = Components.interfaces.nsIAccessibleTable; +const nsIAccessibleTableCell = Components.interfaces.nsIAccessibleTableCell; +const nsIAccessibleTraversalRule = Components.interfaces.nsIAccessibleTraversalRule; +const nsIAccessibleValue = Components.interfaces.nsIAccessibleValue; + +const nsIObserverService = Components.interfaces.nsIObserverService; + +const nsIDOMDocument = Components.interfaces.nsIDOMDocument; +const nsIDOMEvent = Components.interfaces.nsIDOMEvent; +const nsIDOMHTMLDocument = Components.interfaces.nsIDOMHTMLDocument; +const nsIDOMNode = Components.interfaces.nsIDOMNode; +const nsIDOMHTMLElement = Components.interfaces.nsIDOMHTMLElement; +const nsIDOMWindow = Components.interfaces.nsIDOMWindow; +const nsIDOMXULElement = Components.interfaces.nsIDOMXULElement; + +const nsIPropertyElement = Components.interfaces.nsIPropertyElement; + +//////////////////////////////////////////////////////////////////////////////// +// OS detect + +const MAC = (navigator.platform.indexOf("Mac") != -1); +const LINUX = (navigator.platform.indexOf("Linux") != -1); +const SOLARIS = (navigator.platform.indexOf("SunOS") != -1); +const WIN = (navigator.platform.indexOf("Win") != -1); + +//////////////////////////////////////////////////////////////////////////////// +// Application detect +// Firefox is assumed by default. + +const SEAMONKEY = navigator.userAgent.match(/ SeaMonkey\//); + +//////////////////////////////////////////////////////////////////////////////// +// Accessible general + +const STATE_BUSY = nsIAccessibleStates.STATE_BUSY; + +const SCROLL_TYPE_ANYWHERE = nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE; + +const COORDTYPE_SCREEN_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE; +const COORDTYPE_WINDOW_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_WINDOW_RELATIVE; +const COORDTYPE_PARENT_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_PARENT_RELATIVE; + +const kEmbedChar = String.fromCharCode(0xfffc); + +const kDiscBulletChar = String.fromCharCode(0x2022); +const kDiscBulletText = kDiscBulletChar + " "; +const kCircleBulletText = String.fromCharCode(0x25e6) + " "; +const kSquareBulletText = String.fromCharCode(0x25fe) + " "; + +const MAX_TRIM_LENGTH = 100; + +/** + * Services to determine if e10s is enabled. + */ +Components.utils.import('resource://gre/modules/Services.jsm'); + +/** + * nsIAccessibilityService service. + */ +var gAccService = Components.classes["@mozilla.org/accessibilityService;1"]. + getService(nsIAccessibilityService); + +/** + * Enable/disable logging. + */ +function enableLogging(aModules) +{ + gAccService.setLogging(aModules); +} +function disableLogging() +{ + gAccService.setLogging(""); +} +function isLogged(aModule) +{ + return gAccService.isLogged(aModule); +} + +/** + * Dumps the accessible tree into console. + */ +function dumpTree(aId, aMsg) +{ + function dumpTreeIntl(acc, indent) + { + dump(indent + prettyName(acc) + "\n"); + + var children = acc.children; + for (var i = 0; i < children.length; i++) { + var child = children.queryElementAt(i, nsIAccessible); + dumpTreeIntl(child, indent + " "); + } + } + + function dumpDOMTreeIntl(node, indent) + { + dump(indent + prettyName(node) + "\n"); + + var children = node.childNodes; + for (var i = 0; i < children.length; i++) { + var child = children.item(i); + dumpDOMTreeIntl(child, indent + " "); + } + } + + dump(aMsg + "\n"); + var root = getAccessible(aId); + dumpTreeIntl(root, " "); + + dump("DOM tree:\n"); + dumpDOMTreeIntl(getNode(aId), " "); +} + +/** + * Invokes the given function when document is loaded and focused. Preferable + * to mochitests 'addLoadEvent' function -- additionally ensures state of the + * document accessible is not busy. + * + * @param aFunc the function to invoke + */ +function addA11yLoadEvent(aFunc, aWindow) +{ + function waitForDocLoad() + { + window.setTimeout( + function() + { + var targetDocument = aWindow ? aWindow.document : document; + var accDoc = getAccessible(targetDocument); + var state = {}; + accDoc.getState(state, {}); + if (state.value & STATE_BUSY) + return waitForDocLoad(); + + window.setTimeout(aFunc, 0); + }, + 0 + ); + } + + SimpleTest.waitForFocus(waitForDocLoad, aWindow); +} + +/** + * Analogy of SimpleTest.is function used to compare objects. + */ +function isObject(aObj, aExpectedObj, aMsg) +{ + if (aObj == aExpectedObj) { + ok(true, aMsg); + return; + } + + ok(false, + aMsg + " - got '" + prettyName(aObj) + + "', expected '" + prettyName(aExpectedObj) + "'"); +} + +//////////////////////////////////////////////////////////////////////////////// +// Helpers for getting DOM node/accessible + +/** + * Return the DOM node by identifier (may be accessible, DOM node or ID). + */ +function getNode(aAccOrNodeOrID, aDocument) +{ + if (!aAccOrNodeOrID) + return null; + + if (aAccOrNodeOrID instanceof nsIDOMNode) + return aAccOrNodeOrID; + + if (aAccOrNodeOrID instanceof nsIAccessible) + return aAccOrNodeOrID.DOMNode; + + var node = (aDocument || document).getElementById(aAccOrNodeOrID); + if (!node) { + ok(false, "Can't get DOM element for " + aAccOrNodeOrID); + return null; + } + + return node; +} + +/** + * Constants indicates getAccessible doesn't fail if there is no accessible. + */ +const DONOTFAIL_IF_NO_ACC = 1; + +/** + * Constants indicates getAccessible won't fail if accessible doesn't implement + * the requested interfaces. + */ +const DONOTFAIL_IF_NO_INTERFACE = 2; + +/** + * Return accessible for the given identifier (may be ID attribute or DOM + * element or accessible object) or null. + * + * @param aAccOrElmOrID [in] identifier to get an accessible implementing + * the given interfaces + * @param aInterfaces [in, optional] the interface or an array interfaces + * to query it/them from obtained accessible + * @param aElmObj [out, optional] object to store DOM element which + * accessible is obtained for + * @param aDoNotFailIf [in, optional] no error for special cases (see + * constants above) + */ +function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIf) +{ + if (!aAccOrElmOrID) + return null; + + var elm = null; + + if (aAccOrElmOrID instanceof nsIAccessible) { + try { elm = aAccOrElmOrID.DOMNode; } catch(e) { } + + } else if (aAccOrElmOrID instanceof nsIDOMNode) { + elm = aAccOrElmOrID; + + } else { + elm = document.getElementById(aAccOrElmOrID); + if (!elm) { + ok(false, "Can't get DOM element for " + aAccOrElmOrID); + return null; + } + } + + if (aElmObj && (typeof aElmObj == "object")) + aElmObj.value = elm; + + var acc = (aAccOrElmOrID instanceof nsIAccessible) ? aAccOrElmOrID : null; + if (!acc) { + try { + acc = gAccService.getAccessibleFor(elm); + } catch (e) { + } + + if (!acc) { + if (!(aDoNotFailIf & DONOTFAIL_IF_NO_ACC)) + ok(false, "Can't get accessible for " + prettyName(aAccOrElmOrID)); + + return null; + } + } + + if (!aInterfaces) + return acc; + + if (!(aInterfaces instanceof Array)) + aInterfaces = [ aInterfaces ]; + + for (var index = 0; index < aInterfaces.length; index++) { + if (acc instanceof aInterfaces[index]) { + continue; + } + try { + acc.QueryInterface(aInterfaces[index]); + } catch (e) { + if (!(aDoNotFailIf & DONOTFAIL_IF_NO_INTERFACE)) + ok(false, "Can't query " + aInterfaces[index] + " for " + aAccOrElmOrID); + + return null; + } + } + + return acc; +} + +/** + * Return true if the given identifier has an accessible, or exposes the wanted + * interfaces. + */ +function isAccessible(aAccOrElmOrID, aInterfaces) +{ + return getAccessible(aAccOrElmOrID, aInterfaces, null, + DONOTFAIL_IF_NO_ACC | DONOTFAIL_IF_NO_INTERFACE) ? + true : false; +} + +/** + * Return an accessible that contains the DOM node for the given identifier. + */ +function getContainerAccessible(aAccOrElmOrID) +{ + var node = getNode(aAccOrElmOrID); + if (!node) + return null; + + while ((node = node.parentNode) && !isAccessible(node)); + return node ? getAccessible(node) : null; +} + +/** + * Return root accessible for the given identifier. + */ +function getRootAccessible(aAccOrElmOrID) +{ + var acc = getAccessible(aAccOrElmOrID ? aAccOrElmOrID : document); + return acc ? acc.rootDocument.QueryInterface(nsIAccessible) : null; +} + +/** + * Return tab document accessible the given accessible is contained by. + */ +function getTabDocAccessible(aAccOrElmOrID) +{ + var acc = getAccessible(aAccOrElmOrID ? aAccOrElmOrID : document); + + var docAcc = acc.document.QueryInterface(nsIAccessible); + var containerDocAcc = docAcc.parent.document; + + // Test is running is stand-alone mode. + if (acc.rootDocument == containerDocAcc) + return docAcc; + + // In the case of running all tests together. + return containerDocAcc.QueryInterface(nsIAccessible); +} + +/** + * Return application accessible. + */ +function getApplicationAccessible() +{ + return gAccService.getApplicationAccessible(). + QueryInterface(nsIAccessibleApplication); +} + +/** + * A version of accessible tree testing, doesn't fail if tree is not complete. + */ +function testElm(aID, aTreeObj) +{ + testAccessibleTree(aID, aTreeObj, kSkipTreeFullCheck); +} + +/** + * Flags used for testAccessibleTree + */ +const kSkipTreeFullCheck = 1; + +/** + * Compare expected and actual accessibles trees. + * + * @param aAccOrElmOrID [in] accessible identifier + * @param aAccTree [in] JS object, each field corresponds to property of + * accessible object. Additionally special properties + * are presented: + * children - an array of JS objects representing + * children of accessible + * states - an object having states and extraStates + * fields + * @param aFlags [in, optional] flags, see constants above + */ +function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags) +{ + var acc = getAccessible(aAccOrElmOrID); + if (!acc) + return; + + var accTree = aAccTree; + + // Support of simplified accessible tree object. + accTree = normalizeAccTreeObj(accTree); + + // Test accessible properties. + for (var prop in accTree) { + var msg = "Wrong value of property '" + prop + "' for " + + prettyName(acc) + "."; + + switch (prop) { + case "actions": { + testActionNames(acc, accTree.actions); + break; + } + + case "attributes": + testAttrs(acc, accTree[prop], true); + break; + + case "absentAttributes": + testAbsentAttrs(acc, accTree[prop]); + break; + + case "interfaces": { + var ifaces = (accTree[prop] instanceof Array) ? + accTree[prop] : [ accTree[prop] ]; + for (var i = 0; i < ifaces.length; i++) { + ok((acc instanceof ifaces[i]), + "No " + ifaces[i] + " interface on " + prettyName(acc)); + } + break; + } + + case "relations": { + for (var rel in accTree[prop]) + testRelation(acc, window[rel], accTree[prop][rel]); + break; + } + + case "role": + isRole(acc, accTree[prop], msg); + break; + + case "states": + case "extraStates": + case "absentStates": + case "absentExtraStates": { + testStates(acc, accTree["states"], accTree["extraStates"], + accTree["absentStates"], accTree["absentExtraStates"]); + break; + } + + case "tagName": + is(accTree[prop], acc.DOMNode.tagName, msg); + break; + + case "textAttrs": { + var prevOffset = -1; + for (var offset in accTree[prop]) { + if (prevOffset !=- 1) { + var attrs = accTree[prop][prevOffset]; + testTextAttrs(acc, prevOffset, attrs, { }, prevOffset, +offset, true); + } + prevOffset = +offset; + } + + if (prevOffset != -1) { + var charCount = getAccessible(acc, [nsIAccessibleText]).characterCount; + var attrs = accTree[prop][prevOffset]; + testTextAttrs(acc, prevOffset, attrs, { }, prevOffset, charCount, true); + } + + break; + } + + default: + if (prop.indexOf("todo_") == 0) + todo(false, msg); + else if (prop != "children") + is(acc[prop], accTree[prop], msg); + } + } + + // Test children. + if ("children" in accTree && accTree["children"] instanceof Array) { + var children = acc.children; + var childCount = children.length; + + if (accTree.children.length != childCount) { + for (var i = 0; i < Math.max(accTree.children.length, childCount); i++) { + var accChild = null, testChild = null; + try { + testChild = accTree.children[i]; + accChild = children.queryElementAt(i, nsIAccessible); + + if (!testChild) { + ok(false, prettyName(acc) + " has an extra child at index " + i + + " : " + prettyName(accChild)); + continue; + } + + testChild = normalizeAccTreeObj(testChild); + if (accChild.role !== testChild.role) { + ok(false, prettyName(accTree) + " and " + prettyName(acc) + + " have different children at index " + i + " : " + + prettyName(testChild) + ", " + prettyName(accChild)); + } + info("Matching " + prettyName(accTree) + " and " + prettyName(acc) + + " child at index " + i + " : " + prettyName(accChild)); + + } catch (e) { + ok(false, prettyName(accTree) + " is expected to have a child at index " + i + + " : " + prettyName(testChild) + ", original tested: " + + prettyName(aAccOrElmOrID) + ", " + e); + } + } + } else { + if (aFlags & kSkipTreeFullCheck) { + for (var i = 0; i < childCount; i++) { + var child = children.queryElementAt(i, nsIAccessible); + testAccessibleTree(child, accTree.children[i], aFlags); + } + return; + } + + // nsIAccessible::firstChild + var expectedFirstChild = childCount > 0 ? + children.queryElementAt(0, nsIAccessible) : null; + var firstChild = null; + try { firstChild = acc.firstChild; } catch (e) {} + is(firstChild, expectedFirstChild, + "Wrong first child of " + prettyName(acc)); + + // nsIAccessible::lastChild + var expectedLastChild = childCount > 0 ? + children.queryElementAt(childCount - 1, nsIAccessible) : null; + var lastChild = null; + try { lastChild = acc.lastChild; } catch (e) {} + is(lastChild, expectedLastChild, + "Wrong last child of " + prettyName(acc)); + + for (var i = 0; i < childCount; i++) { + var child = children.queryElementAt(i, nsIAccessible); + + // nsIAccessible::parent + var parent = null; + try { parent = child.parent; } catch (e) {} + is(parent, acc, "Wrong parent of " + prettyName(child)); + + // nsIAccessible::indexInParent + var indexInParent = -1; + try { indexInParent = child.indexInParent; } catch(e) {} + is(indexInParent, i, + "Wrong index in parent of " + prettyName(child)); + + // nsIAccessible::nextSibling + var expectedNextSibling = (i < childCount - 1) ? + children.queryElementAt(i + 1, nsIAccessible) : null; + var nextSibling = null; + try { nextSibling = child.nextSibling; } catch (e) {} + is(nextSibling, expectedNextSibling, + "Wrong next sibling of " + prettyName(child)); + + // nsIAccessible::previousSibling + var expectedPrevSibling = (i > 0) ? + children.queryElementAt(i - 1, nsIAccessible) : null; + var prevSibling = null; + try { prevSibling = child.previousSibling; } catch (e) {} + is(prevSibling, expectedPrevSibling, + "Wrong previous sibling of " + prettyName(child)); + + // Go down through subtree + testAccessibleTree(child, accTree.children[i], aFlags); + } + } + } +} + +/** + * Return true if accessible for the given node is in cache. + */ +function isAccessibleInCache(aNodeOrId) +{ + var node = getNode(aNodeOrId); + return gAccService.getAccessibleFromCache(node) ? true : false; +} + +/** + * Test accessible tree for defunct accessible. + * + * @param aAcc [in] the defunct accessible + * @param aNodeOrId [in] the DOM node identifier for the defunct accessible + */ +function testDefunctAccessible(aAcc, aNodeOrId) +{ + if (aNodeOrId) + ok(!isAccessible(aNodeOrId), + "Accessible for " + aNodeOrId + " wasn't properly shut down!"); + + var msg = " doesn't fail for shut down accessible " + + prettyName(aNodeOrId) + "!"; + + // firstChild + var success = false; + try { + aAcc.firstChild; + } catch (e) { + success = (e.result == Components.results.NS_ERROR_FAILURE) + } + ok(success, "firstChild" + msg); + + // lastChild + success = false; + try { + aAcc.lastChild; + } catch (e) { + success = (e.result == Components.results.NS_ERROR_FAILURE) + } + ok(success, "lastChild" + msg); + + // childCount + success = false; + try { + aAcc.childCount; + } catch (e) { + success = (e.result == Components.results.NS_ERROR_FAILURE) + } + ok(success, "childCount" + msg); + + // children + success = false; + try { + aAcc.children; + } catch (e) { + success = (e.result == Components.results.NS_ERROR_FAILURE) + } + ok(success, "children" + msg); + + // nextSibling + success = false; + try { + aAcc.nextSibling; + } catch (e) { + success = (e.result == Components.results.NS_ERROR_FAILURE); + } + ok(success, "nextSibling" + msg); + + // previousSibling + success = false; + try { + aAcc.previousSibling; + } catch (e) { + success = (e.result == Components.results.NS_ERROR_FAILURE); + } + ok(success, "previousSibling" + msg); + + // parent + success = false; + try { + aAcc.parent; + } catch (e) { + success = (e.result == Components.results.NS_ERROR_FAILURE); + } + ok(success, "parent" + msg); +} + +/** + * Convert role to human readable string. + */ +function roleToString(aRole) +{ + return gAccService.getStringRole(aRole); +} + +/** + * Convert states to human readable string. + */ +function statesToString(aStates, aExtraStates) +{ + var list = gAccService.getStringStates(aStates, aExtraStates); + + var str = ""; + for (var index = 0; index < list.length - 1; index++) + str += list.item(index) + ", "; + + if (list.length != 0) + str += list.item(index) + + return str; +} + +/** + * Convert event type to human readable string. + */ +function eventTypeToString(aEventType) +{ + return gAccService.getStringEventType(aEventType); +} + +/** + * Convert relation type to human readable string. + */ +function relationTypeToString(aRelationType) +{ + return gAccService.getStringRelationType(aRelationType); +} + +function getLoadContext() { + const Ci = Components.interfaces; + return window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsILoadContext); +} + +/** + * Return text from clipboard. + */ +function getTextFromClipboard() +{ + var clip = Components.classes["@mozilla.org/widget/clipboard;1"]. + getService(Components.interfaces.nsIClipboard); + if (!clip) + return ""; + + var trans = Components.classes["@mozilla.org/widget/transferable;1"]. + createInstance(Components.interfaces.nsITransferable); + trans.init(getLoadContext()); + if (!trans) + return ""; + + trans.addDataFlavor("text/unicode"); + clip.getData(trans, clip.kGlobalClipboard); + + var str = new Object(); + var strLength = new Object(); + trans.getTransferData("text/unicode", str, strLength); + + if (str) + str = str.value.QueryInterface(Components.interfaces.nsISupportsString); + if (str) + return str.data.substring(0, strLength.value / 2); + + return ""; +} + +/** + * Extract DOMNode id from an accessible. If e10s is enabled, DOMNode is not + * present in parent process but, if available, DOMNode id is attached to an + * accessible object. + * @param {nsIAccessible} accessible accessible + * @return {String?} DOMNode id if available + */ +function getAccessibleDOMNodeID(accessible) { + if (accessible instanceof nsIAccessibleDocument) { + // If accessible is a document, trying to find its document body id. + try { + return accessible.DOMNode.body.id; + } catch (e) { /* This only works if accessible is not a proxy. */ } + } + try { + return accessible.DOMNode.id; + } catch (e) { /* This will fail if DOMNode is in different process. */ } + try { + // When e10s is enabled, accessible will have an "id" property if its + // corresponding DOMNode has an id. If accessible is a document, its "id" + // property corresponds to the "id" of its body element. + return accessible.id; + } catch (e) { /* This will fail if accessible is not a proxy. */ } +} + +/** + * Return pretty name for identifier, it may be ID, DOM node or accessible. + */ +function prettyName(aIdentifier) +{ + if (aIdentifier instanceof Array) { + var msg = ""; + for (var idx = 0; idx < aIdentifier.length; idx++) { + if (msg != "") + msg += ", "; + + msg += prettyName(aIdentifier[idx]); + } + return msg; + } + + if (aIdentifier instanceof nsIAccessible) { + var acc = getAccessible(aIdentifier); + var domID = getAccessibleDOMNodeID(acc); + var msg = "["; + try { + if (Services.appinfo.browserTabsRemoteAutostart) { + if (domID) { + msg += `DOM node id: ${domID}, `; + } + } else { + msg += `${getNodePrettyName(acc.DOMNode)}, `; + } + msg += "role: " + roleToString(acc.role); + if (acc.name) + msg += ", name: '" + shortenString(acc.name) + "'"; + } catch (e) { + msg += "defunct"; + } + + if (acc) + msg += ", address: " + getObjAddress(acc); + msg += "]"; + + return msg; + } + + if (aIdentifier instanceof nsIDOMNode) + return "[ " + getNodePrettyName(aIdentifier) + " ]"; + + if (aIdentifier && typeof aIdentifier === "object" ) { + var treeObj = normalizeAccTreeObj(aIdentifier); + if ("role" in treeObj) { + function stringifyTree(aObj) { + var text = roleToString(aObj.role) + ": [ "; + if ("children" in aObj) { + for (var i = 0; i < aObj.children.length; i++) { + var c = normalizeAccTreeObj(aObj.children[i]); + text += stringifyTree(c); + if (i < aObj.children.length - 1) { + text += ", "; + } + } + } + return text + "] "; + } + return `{ ${stringifyTree(treeObj)} }`; + } + return JSON.stringify(aIdentifier); + } + + return " '" + aIdentifier + "' "; +} + +/** + * Shorten a long string if it exceeds MAX_TRIM_LENGTH. + * @param aString the string to shorten. + * @returns the shortened string. + */ +function shortenString(aString, aMaxLength) +{ + if (aString.length <= MAX_TRIM_LENGTH) + return aString; + + // Trim the string if its length is > MAX_TRIM_LENGTH characters. + var trimOffset = MAX_TRIM_LENGTH / 2; + return aString.substring(0, trimOffset - 1) + "..." + + aString.substring(aString.length - trimOffset, aString.length); +} + +//////////////////////////////////////////////////////////////////////////////// +// General Utils +//////////////////////////////////////////////////////////////////////////////// +/** + * Return main chrome window (crosses chrome boundary) + */ +function getMainChromeWindow(aWindow) +{ + return aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIWebNavigation) + .QueryInterface(Components.interfaces.nsIDocShellTreeItem) + .rootTreeItem + .QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIDOMWindow); +} + +/** Sets the test plugin(s) initially expected enabled state. + * It will automatically be reset to it's previous value after the test + * ends. + * @param aNewEnabledState [in] the enabled state, e.g. SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED + * @param aPluginName [in, optional] The name of the plugin, defaults to "Test Plug-in" + */ +function setTestPluginEnabledState(aNewEnabledState, aPluginName) +{ + var plugin = getTestPluginTag(aPluginName); + var oldEnabledState = plugin.enabledState; + plugin.enabledState = aNewEnabledState; + SimpleTest.registerCleanupFunction(function() { + getTestPluginTag(aPluginName).enabledState = oldEnabledState; + }); +} + +//////////////////////////////////////////////////////////////////////////////// +// Private +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Accessible general + +function getNodePrettyName(aNode) +{ + try { + var tag = ""; + if (aNode.nodeType == nsIDOMNode.DOCUMENT_NODE) { + tag = "document"; + } else { + tag = aNode.localName; + if (aNode.nodeType == nsIDOMNode.ELEMENT_NODE && aNode.hasAttribute("id")) + tag += "@id=\"" + aNode.getAttribute("id") + "\""; + } + + return "'" + tag + " node', address: " + getObjAddress(aNode); + } catch (e) { + return "' no node info '"; + } +} + +function getObjAddress(aObj) +{ + var exp = /native\s*@\s*(0x[a-f0-9]+)/g; + var match = exp.exec(aObj.toString()); + if (match) + return match[1]; + + return aObj.toString(); +} + +function getTestPluginTag(aPluginName) +{ + var ph = SpecialPowers.Cc["@mozilla.org/plugin/host;1"] + .getService(SpecialPowers.Ci.nsIPluginHost); + var tags = ph.getPluginTags(); + var name = aPluginName || "Test Plug-in"; + for (var tag of tags) { + if (tag.name == name) { + return tag; + } + } + + ok(false, "Could not find plugin tag with plugin name '" + name + "'"); + return null; +} + +function normalizeAccTreeObj(aObj) +{ + var key = Object.keys(aObj)[0]; + var roleName = "ROLE_" + key; + if (roleName in nsIAccessibleRole) { + return { + role: nsIAccessibleRole[roleName], + children: aObj[key] + }; + } + return aObj; +} diff --git a/accessible/tests/mochitest/dumbfile.zip b/accessible/tests/mochitest/dumbfile.zip new file mode 100644 index 000000000..15cb0ecb3 Binary files /dev/null and b/accessible/tests/mochitest/dumbfile.zip differ diff --git a/accessible/tests/mochitest/editabletext/a11y.ini b/accessible/tests/mochitest/editabletext/a11y.ini new file mode 100644 index 000000000..68466fdf2 --- /dev/null +++ b/accessible/tests/mochitest/editabletext/a11y.ini @@ -0,0 +1,7 @@ +[DEFAULT] +support-files = + editabletext.js + !/accessible/tests/mochitest/*.js + +[test_1.html] +[test_2.html] diff --git a/accessible/tests/mochitest/editabletext/editabletext.js b/accessible/tests/mochitest/editabletext/editabletext.js new file mode 100644 index 000000000..2fb1851bf --- /dev/null +++ b/accessible/tests/mochitest/editabletext/editabletext.js @@ -0,0 +1,353 @@ +/** + * Perform all editable text tests. + */ +function editableTextTestRun() +{ + this.add = function add(aTest) + { + this.seq.push(aTest); + } + + this.run = function run() + { + this.iterate(); + } + + this.index = 0; + this.seq = new Array(); + + this.iterate = function iterate() + { + if (this.index < this.seq.length) { + this.seq[this.index++].startTest(this); + return; + } + + this.seq = null; + SimpleTest.finish(); + } +} + +/** + * Used to test nsIEditableTextAccessible methods. + */ +function editableTextTest(aID) +{ + /** + * Schedule a test, the given function with its arguments will be executed + * when preceding test is complete. + */ + this.scheduleTest = function scheduleTest(aFunc) + { + // A data container acts like a dummy invoker, it's never invoked but + // it's used to generate real invoker when previous invoker was handled. + var dataContainer = { + func: aFunc, + funcArgs: Array.slice(arguments, 1) + }; + this.mEventQueue.push(dataContainer); + + if (!this.mEventQueueReady) { + this.unwrapNextTest(); + this.mEventQueueReady = true; + } + } + + /** + * setTextContents test. + */ + this.setTextContents = function setTextContents(aValue, aSkipStartOffset) + { + var testID = "setTextContents '" + aValue + "' for " + prettyName(aID); + + function setTextContentsInvoke() + { + dump(`\nsetTextContents '${aValue}'\n`); + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.setTextContents(aValue); + } + + aSkipStartOffset = aSkipStartOffset || 0; + var insertTripple = aValue ? + [ aSkipStartOffset, aSkipStartOffset + aValue.length, aValue ] : null; + var oldValue = getValue(aID); + var removeTripple = oldValue ? + [ aSkipStartOffset, aSkipStartOffset + oldValue.length, oldValue ] : null; + + this.generateTest(aID, removeTripple, insertTripple, setTextContentsInvoke, + getValueChecker(aID, aValue), testID); + } + + /** + * insertText test. + */ + this.insertText = function insertText(aStr, aPos, aResStr, aResPos) + { + var testID = "insertText '" + aStr + "' at " + aPos + " for " + + prettyName(aID); + + function insertTextInvoke() + { + dump(`\ninsertText '${aStr}' at ${aPos} pos\n`); + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.insertText(aStr, aPos); + } + + var resPos = (aResPos != undefined) ? aResPos : aPos; + this.generateTest(aID, null, [resPos, resPos + aStr.length, aStr], + insertTextInvoke, getValueChecker(aID, aResStr), testID); + } + + /** + * copyText test. + */ + this.copyText = function copyText(aStartPos, aEndPos, aClipboardStr) + { + var testID = "copyText from " + aStartPos + " to " + aEndPos + " for " + + prettyName(aID); + + function copyTextInvoke() + { + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.copyText(aStartPos, aEndPos); + } + + this.generateTest(aID, null, null, copyTextInvoke, + getClipboardChecker(aID, aClipboardStr), testID); + } + + /** + * copyText and pasteText test. + */ + this.copyNPasteText = function copyNPasteText(aStartPos, aEndPos, + aPos, aResStr) + { + var testID = "copyText from " + aStartPos + " to " + aEndPos + + "and pasteText at " + aPos + " for " + prettyName(aID); + + function copyNPasteTextInvoke() + { + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.copyText(aStartPos, aEndPos); + acc.pasteText(aPos); + } + + this.generateTest(aID, null, [aStartPos, aEndPos, getTextFromClipboard], + copyNPasteInvoke, getValueChecker(aID, aResStr), testID); + } + + /** + * cutText test. + */ + this.cutText = function cutText(aStartPos, aEndPos, aResStr, + aResStartPos, aResEndPos) + { + var testID = "cutText from " + aStartPos + " to " + aEndPos + " for " + + prettyName(aID); + + function cutTextInvoke() + { + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.cutText(aStartPos, aEndPos); + } + + var resStartPos = (aResStartPos != undefined) ? aResStartPos : aStartPos; + var resEndPos = (aResEndPos != undefined) ? aResEndPos : aEndPos; + this.generateTest(aID, [resStartPos, resEndPos, getTextFromClipboard], null, + cutTextInvoke, getValueChecker(aID, aResStr), testID); + } + + /** + * cutText and pasteText test. + */ + this.cutNPasteText = function copyNPasteText(aStartPos, aEndPos, + aPos, aResStr) + { + var testID = "cutText from " + aStartPos + " to " + aEndPos + + " and pasteText at " + aPos + " for " + prettyName(aID); + + function cutNPasteTextInvoke() + { + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.cutText(aStartPos, aEndPos); + acc.pasteText(aPos); + } + + this.generateTest(aID, [aStartPos, aEndPos, getTextFromClipboard], + [aPos, -1, getTextFromClipboard], + cutNPasteTextInvoke, getValueChecker(aID, aResStr), + testID); + } + + /** + * pasteText test. + */ + this.pasteText = function pasteText(aPos, aResStr) + { + var testID = "pasteText at " + aPos + " for " + prettyName(aID); + + function pasteTextInvoke() + { + var acc = getAccessible(aID, nsIAccessibleEditableText); + acc.pasteText(aPos); + } + + this.generateTest(aID, null, [aPos, -1, getTextFromClipboard], + pasteTextInvoke, getValueChecker(aID, aResStr), testID); + } + + /** + * deleteText test. + */ + this.deleteText = function deleteText(aStartPos, aEndPos, aResStr) + { + var testID = "deleteText from " + aStartPos + " to " + aEndPos + + " for " + prettyName(aID); + + var oldValue = getValue(aID).substring(aStartPos, aEndPos); + var removeTripple = oldValue ? [aStartPos, aEndPos, oldValue] : null; + + function deleteTextInvoke() + { + var acc = getAccessible(aID, [nsIAccessibleEditableText]); + acc.deleteText(aStartPos, aEndPos); + } + + this.generateTest(aID, removeTripple, null, deleteTextInvoke, + getValueChecker(aID, aResStr), testID); + } + + ////////////////////////////////////////////////////////////////////////////// + // Implementation details. + + function getValue(aID) + { + var value = ""; + var elm = getNode(aID); + if (elm instanceof Components.interfaces.nsIDOMNSEditableElement) + return elm.value; + + if (elm instanceof Components.interfaces.nsIDOMHTMLDocument) + return elm.body.textContent; + + return elm.textContent; + } + + /** + * Common checkers. + */ + function getValueChecker(aID, aValue) + { + var checker = { + check: function valueChecker_check() + { + is(getValue(aID), aValue, "Wrong value " + aValue); + } + }; + return checker; + } + + function getClipboardChecker(aID, aText) + { + var checker = { + check: function clipboardChecker_check() + { + is(getTextFromClipboard(), aText, "Wrong text in clipboard."); + } + }; + return checker; + } + + function getValueNClipboardChecker(aID, aValue, aText) + { + var valueChecker = getValueChecker(aID, aValue); + var clipboardChecker = getClipboardChecker(aID, aText); + + var checker = { + check: function() + { + valueChecker.check(); + clipboardChecker.check(); + } + }; + return checker; + } + + /** + * Process next scheduled test. + */ + this.unwrapNextTest = function unwrapNextTest() + { + var data = this.mEventQueue.mInvokers[this.mEventQueue.mIndex + 1]; + if (data) + data.func.apply(this, data.funcArgs); + } + + /** + * Used to generate an invoker object for the sheduled test. + */ + this.generateTest = function generateTest(aID, aRemoveTriple, aInsertTriple, + aInvokeFunc, aChecker, aInvokerID) + { + var et = this; + var invoker = { + eventSeq: [], + + invoke: aInvokeFunc, + finalCheck: function finalCheck() + { + //dumpTree(aID, `'${aID}' tree:`); + + aChecker.check(); + et.unwrapNextTest(); // replace dummy invoker on real invoker object. + }, + getID: function getID() { return aInvokerID; } + }; + + if (aRemoveTriple) { + var checker = new textChangeChecker(aID, aRemoveTriple[0], + aRemoveTriple[1], aRemoveTriple[2], + false); + invoker.eventSeq.push(checker); + } + + if (aInsertTriple) { + var checker = new textChangeChecker(aID, aInsertTriple[0], + aInsertTriple[1], aInsertTriple[2], + true); + invoker.eventSeq.push(checker); + } + + // Claim that we don't want to fail when no events are expected. + if (!aRemoveTriple && !aInsertTriple) + invoker.noEventsOnAction = true; + + this.mEventQueue.mInvokers[this.mEventQueue.mIndex + 1] = invoker; + } + + /** + * Run the tests. + */ + this.startTest = function startTest(aTestRun) + { + var testRunObj = aTestRun; + var thisObj = this; + this.mEventQueue.onFinish = function finishCallback() + { + // Notify textRun object that all tests were finished. + testRunObj.iterate(); + + // Help GC to avoid leaks (refer to aTestRun from local variable, drop + // onFinish function). + thisObj.mEventQueue.onFinish = null; + + return DO_NOT_FINISH_TEST; + } + + this.mEventQueue.invoke(); + } + + this.mEventQueue = new eventQueue(); + this.mEventQueueReady = false; +} + diff --git a/accessible/tests/mochitest/editabletext/test_1.html b/accessible/tests/mochitest/editabletext/test_1.html new file mode 100644 index 000000000..0c0b19696 --- /dev/null +++ b/accessible/tests/mochitest/editabletext/test_1.html @@ -0,0 +1,144 @@ + + + + + nsIAccessibleEditableText chrome tests + + + + + + + + + + + + + + + Bug 452161 + + + Bug 626660 + + + Bug 1105611 + +

    + +
    +  
    + + + +
    +
    +
    +
    + + + +

    heading1

    +

    heading2

    +

    heading3

    +

    heading4

    +
    heading5
    +
    heading6
    + + +
    +
    Not logo
    +
    +
    +
    Not logo
    +
    + +
    +

    normalitalic

    + + + + + + + +
    + +
    + +
    + +
    + + + + + + + + + + + +
    + +
    + +

    normalInserted

    +

    normalcmd

    + + + + + + + +
      +
    1. item1
    2. +
    + +
    main
    + + + b + a + + + + +

    + [Bypass navigation bar] + [Home] +

    +
    + +

    normalhighlighted

    + + + + + + a + 2 + + + + + b + 2 + + + = + + c + 2 + + + + + +
  5. + + + + +
  6. +
  7. + + + + + +
  8. +
    + + 200 Euro + + + + + + + + + + + + + + + + + +
    pre
    + + + + + + Oh my God, they killed Kenny! + + + + 漢 (Kan) + 字 (ji) + + +

    normalstriked

    +

    normalsample

    +
    section
    +

    normalsmall

    + +

    normalstrong

    +

    normalsub

    +

    normalsup

    + + + + +

    The concert took place on

    +

    normalunderline

    +

    An equation: x = y

    + + + + + + diff --git a/accessible/tests/mochitest/elm/test_MathMLSpec.html b/accessible/tests/mochitest/elm/test_MathMLSpec.html new file mode 100644 index 000000000..80f1e9e70 --- /dev/null +++ b/accessible/tests/mochitest/elm/test_MathMLSpec.html @@ -0,0 +1,620 @@ + + + + HTML a11y spec tests + + + + + + + + + + + + + + + + + + Mozilla Bug 658272 +
    +

    + +
    +  
    + + + + + + a + 2 + + + + + 2 + + + = + + c + 2 + + + + Arbitrary text + + InterpretedStringLiteral + + + + + x + 2 + + + x + 5 + + + + + x + y + + + + [ + + X + , + Y + + closing-fence + + + + a + + + b + + + + x + + + + y + + + + + + b + 1 + 2 + + + + x + + + y + + + z + + + + + + x + ^ + + + + 0 + + + + R + i + + + j + k + + l + + + + + + + (2.1) + + + + E + = + + m + + + c + 2 + + + + + + + + ( + + + 1 + 0 + 0 + + + 0 + 1 + 0 + + + 0 + 0 + 1 + + + ) + + + + + 6 + 8 + + + + 3 + + 2 + + + 4 + + 2 + + + + 3 + 4 + + + + + + Division by zero: + + 1 + 0 + + + + + + + + + x + 2 + + + + y + + + + + + + + x + 2 + + y + + + + + x^{2} + y + + + + + + + + 1 + + + 1 + + + 523 + + - + + 15 + + + 508 + + + + 5 + 1 + 5 + + + + + 123 + ×321 + + + + 123 + 246 + 369 + + + + + + + diff --git a/accessible/tests/mochitest/elm/test_canvas.html b/accessible/tests/mochitest/elm/test_canvas.html new file mode 100644 index 000000000..b4b743800 --- /dev/null +++ b/accessible/tests/mochitest/elm/test_canvas.html @@ -0,0 +1,58 @@ + + + + Accessible boundaries for hit regions + + + + + + + + + + + + + + + + + + + diff --git a/accessible/tests/mochitest/elm/test_figure.html b/accessible/tests/mochitest/elm/test_figure.html new file mode 100644 index 000000000..ba1bb489f --- /dev/null +++ b/accessible/tests/mochitest/elm/test_figure.html @@ -0,0 +1,62 @@ + + + + HTML5 figure/figcaption tests + + + + + + + + + + + + + + + + Mozilla Bug 658272 +
    +

    + +
    +  
    + +
    +
    figure caption
    +
    + + + diff --git a/accessible/tests/mochitest/elm/test_listbox.xul b/accessible/tests/mochitest/elm/test_listbox.xul new file mode 100644 index 000000000..e284b3e5c --- /dev/null +++ b/accessible/tests/mochitest/elm/test_listbox.xul @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + Mozilla Bug 418371 + +

    + +
    +    
    + + + + +
    + +
    + diff --git a/accessible/tests/mochitest/elm/test_nsApplicationAcc.html b/accessible/tests/mochitest/elm/test_nsApplicationAcc.html new file mode 100644 index 000000000..58763e437 --- /dev/null +++ b/accessible/tests/mochitest/elm/test_nsApplicationAcc.html @@ -0,0 +1,75 @@ + + + + application accessible name + + + + + + + + + + + Mozilla Bug 454211 + + +

    + +
    +  
    + + + diff --git a/accessible/tests/mochitest/elm/test_plugin.html b/accessible/tests/mochitest/elm/test_plugin.html new file mode 100644 index 000000000..3350e6ccc --- /dev/null +++ b/accessible/tests/mochitest/elm/test_plugin.html @@ -0,0 +1,79 @@ + + + + Plugin tests + + + + + + + + + + + + + Bug 485270 + Bug 816856 + Bug 881636 +

    + +
    +  
    + + + + foo + foo + + diff --git a/accessible/tests/mochitest/elm/test_shadowroot.html b/accessible/tests/mochitest/elm/test_shadowroot.html new file mode 100644 index 000000000..e4c39b8d6 --- /dev/null +++ b/accessible/tests/mochitest/elm/test_shadowroot.html @@ -0,0 +1,60 @@ + + + + ShadowRoot tests + + + + + + + + + + + + + Mozilla Bug 1026125 +
    +

    + +
    +  
    + +
    + + + + diff --git a/accessible/tests/mochitest/events.js b/accessible/tests/mochitest/events.js new file mode 100644 index 000000000..d1e5ec8a0 --- /dev/null +++ b/accessible/tests/mochitest/events.js @@ -0,0 +1,2329 @@ +//////////////////////////////////////////////////////////////////////////////// +// Constants + +const EVENT_ALERT = nsIAccessibleEvent.EVENT_ALERT; +const EVENT_DESCRIPTION_CHANGE = nsIAccessibleEvent.EVENT_DESCRIPTION_CHANGE; +const EVENT_DOCUMENT_LOAD_COMPLETE = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE; +const EVENT_DOCUMENT_RELOAD = nsIAccessibleEvent.EVENT_DOCUMENT_RELOAD; +const EVENT_DOCUMENT_LOAD_STOPPED = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_STOPPED; +const EVENT_HIDE = nsIAccessibleEvent.EVENT_HIDE; +const EVENT_FOCUS = nsIAccessibleEvent.EVENT_FOCUS; +const EVENT_NAME_CHANGE = nsIAccessibleEvent.EVENT_NAME_CHANGE; +const EVENT_MENU_START = nsIAccessibleEvent.EVENT_MENU_START; +const EVENT_MENU_END = nsIAccessibleEvent.EVENT_MENU_END; +const EVENT_MENUPOPUP_START = nsIAccessibleEvent.EVENT_MENUPOPUP_START; +const EVENT_MENUPOPUP_END = nsIAccessibleEvent.EVENT_MENUPOPUP_END; +const EVENT_OBJECT_ATTRIBUTE_CHANGED = nsIAccessibleEvent.EVENT_OBJECT_ATTRIBUTE_CHANGED; +const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER; +const EVENT_SCROLLING_START = nsIAccessibleEvent.EVENT_SCROLLING_START; +const EVENT_SELECTION = nsIAccessibleEvent.EVENT_SELECTION; +const EVENT_SELECTION_ADD = nsIAccessibleEvent.EVENT_SELECTION_ADD; +const EVENT_SELECTION_REMOVE = nsIAccessibleEvent.EVENT_SELECTION_REMOVE; +const EVENT_SELECTION_WITHIN = nsIAccessibleEvent.EVENT_SELECTION_WITHIN; +const EVENT_SHOW = nsIAccessibleEvent.EVENT_SHOW; +const EVENT_STATE_CHANGE = nsIAccessibleEvent.EVENT_STATE_CHANGE; +const EVENT_TEXT_ATTRIBUTE_CHANGED = nsIAccessibleEvent.EVENT_TEXT_ATTRIBUTE_CHANGED; +const EVENT_TEXT_CARET_MOVED = nsIAccessibleEvent.EVENT_TEXT_CARET_MOVED; +const EVENT_TEXT_INSERTED = nsIAccessibleEvent.EVENT_TEXT_INSERTED; +const EVENT_TEXT_REMOVED = nsIAccessibleEvent.EVENT_TEXT_REMOVED; +const EVENT_TEXT_SELECTION_CHANGED = nsIAccessibleEvent.EVENT_TEXT_SELECTION_CHANGED; +const EVENT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_VALUE_CHANGE; +const EVENT_TEXT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_TEXT_VALUE_CHANGE; +const EVENT_VIRTUALCURSOR_CHANGED = nsIAccessibleEvent.EVENT_VIRTUALCURSOR_CHANGED; + +const kNotFromUserInput = 0; +const kFromUserInput = 1; + +//////////////////////////////////////////////////////////////////////////////// +// General + +Components.utils.import("resource://gre/modules/Services.jsm"); + +/** + * Set up this variable to dump events into DOM. + */ +var gA11yEventDumpID = ""; + +/** + * Set up this variable to dump event processing into console. + */ +var gA11yEventDumpToConsole = false; + +/** + * Set up this variable to dump event processing into error console. + */ +var gA11yEventDumpToAppConsole = false; + +/** + * Semicolon separated set of logging features. + */ +var gA11yEventDumpFeature = ""; + +/** + * Executes the function when requested event is handled. + * + * @param aEventType [in] event type + * @param aTarget [in] event target + * @param aFunc [in] function to call when event is handled + * @param aContext [in, optional] object in which context the function is + * called + * @param aArg1 [in, optional] argument passed into the function + * @param aArg2 [in, optional] argument passed into the function + */ +function waitForEvent(aEventType, aTargetOrFunc, aFunc, aContext, aArg1, aArg2) +{ + var handler = { + handleEvent: function handleEvent(aEvent) { + + var target = aTargetOrFunc; + if (typeof aTargetOrFunc == "function") + target = aTargetOrFunc.call(); + + if (target) { + if (target instanceof nsIAccessible && + target != aEvent.accessible) + return; + + if (target instanceof nsIDOMNode && + target != aEvent.DOMNode) + return; + } + + unregisterA11yEventListener(aEventType, this); + + window.setTimeout( + function () + { + aFunc.call(aContext, aArg1, aArg2); + }, + 0 + ); + } + }; + + registerA11yEventListener(aEventType, handler); +} + +/** + * Generate mouse move over image map what creates image map accessible (async). + * See waitForImageMap() function. + */ +function waveOverImageMap(aImageMapID) +{ + var imageMapNode = getNode(aImageMapID); + synthesizeMouse(imageMapNode, 10, 10, { type: "mousemove" }, + imageMapNode.ownerDocument.defaultView); +} + +/** + * Call the given function when the tree of the given image map is built. + */ +function waitForImageMap(aImageMapID, aTestFunc) +{ + waveOverImageMap(aImageMapID); + + var imageMapAcc = getAccessible(aImageMapID); + if (imageMapAcc.firstChild) + return aTestFunc(); + + waitForEvent(EVENT_REORDER, imageMapAcc, aTestFunc); +} + +/** + * Register accessibility event listener. + * + * @param aEventType the accessible event type (see nsIAccessibleEvent for + * available constants). + * @param aEventHandler event listener object, when accessible event of the + * given type is handled then 'handleEvent' method of + * this object is invoked with nsIAccessibleEvent object + * as the first argument. + */ +function registerA11yEventListener(aEventType, aEventHandler) +{ + listenA11yEvents(true); + addA11yEventListener(aEventType, aEventHandler); +} + +/** + * Unregister accessibility event listener. Must be called for every registered + * event listener (see registerA11yEventListener() function) when the listener + * is not needed. + */ +function unregisterA11yEventListener(aEventType, aEventHandler) +{ + removeA11yEventListener(aEventType, aEventHandler); + listenA11yEvents(false); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Event queue + +/** + * Return value of invoke method of invoker object. Indicates invoker was unable + * to prepare action. + */ +const INVOKER_ACTION_FAILED = 1; + +/** + * Return value of eventQueue.onFinish. Indicates eventQueue should not finish + * tests. + */ +const DO_NOT_FINISH_TEST = 1; + +/** + * Creates event queue for the given event type. The queue consists of invoker + * objects, each of them generates the event of the event type. When queue is + * started then every invoker object is asked to generate event after timeout. + * When event is caught then current invoker object is asked to check whether + * event was handled correctly. + * + * Invoker interface is: + * + * var invoker = { + * // Generates accessible event or event sequence. If returns + * // INVOKER_ACTION_FAILED constant then stop tests. + * invoke: function(){}, + * + * // [optional] Invoker's check of handled event for correctness. + * check: function(aEvent){}, + * + * // [optional] Invoker's check before the next invoker is proceeded. + * finalCheck: function(aEvent){}, + * + * // [optional] Is called when event of any registered type is handled. + * debugCheck: function(aEvent){}, + * + * // [ignored if 'eventSeq' is defined] DOM node event is generated for + * // (used in the case when invoker expects single event). + * DOMNode getter: function() {}, + * + * // [optional] if true then event sequences are ignored (no failure if + * // sequences are empty). Use you need to invoke an action, do some check + * // after timeout and proceed a next invoker. + * noEventsOnAction getter: function() {}, + * + * // Array of checker objects defining expected events on invoker's action. + * // + * // Checker object interface: + * // + * // var checker = { + * // * DOM or a11y event type. * + * // type getter: function() {}, + * // + * // * DOM node or accessible. * + * // target getter: function() {}, + * // + * // * DOM event phase (false - bubbling). * + * // phase getter: function() {}, + * // + * // * Callback, called to match handled event. * + * // match : function(aEvent) {}, + * // + * // * Callback, called when event is handled + * // check: function(aEvent) {}, + * // + * // * Checker ID * + * // getID: function() {}, + * // + * // * Event that don't have predefined order relative other events. * + * // async getter: function() {}, + * // + * // * Event that is not expected. * + * // unexpected getter: function() {}, + * // + * // * No other event of the same type is not allowed. * + * // unique getter: function() {} + * // }; + * eventSeq getter() {}, + * + * // Array of checker objects defining unexpected events on invoker's + * // action. + * unexpectedEventSeq getter() {}, + * + * // The ID of invoker. + * getID: function(){} // returns invoker ID + * }; + * + * // Used to add a possible scenario of expected/unexpected events on + * // invoker's action. + * defineScenario(aInvokerObj, aEventSeq, aUnexpectedEventSeq) + * + * + * @param aEventType [in, optional] the default event type (isn't used if + * invoker defines eventSeq property). + */ +function eventQueue(aEventType) +{ + // public + + /** + * Add invoker object into queue. + */ + this.push = function eventQueue_push(aEventInvoker) + { + this.mInvokers.push(aEventInvoker); + } + + /** + * Start the queue processing. + */ + this.invoke = function eventQueue_invoke() + { + listenA11yEvents(true); + + // XXX: Intermittent test_events_caretmove.html fails withouth timeout, + // see bug 474952. + this.processNextInvokerInTimeout(true); + } + + /** + * This function is called when all events in the queue were handled. + * Override it if you need to be notified of this. + */ + this.onFinish = function eventQueue_finish() + { + } + + // private + + /** + * Process next invoker. + */ + this.processNextInvoker = function eventQueue_processNextInvoker() + { + // Some scenario was matched, we wait on next invoker processing. + if (this.mNextInvokerStatus == kInvokerCanceled) { + this.setInvokerStatus(kInvokerNotScheduled, + "scenario was matched, wait for next invoker activation"); + return; + } + + this.setInvokerStatus(kInvokerNotScheduled, "the next invoker is processed now"); + + // Finish processing of the current invoker if any. + var testFailed = false; + + var invoker = this.getInvoker(); + if (invoker) { + if ("finalCheck" in invoker) + invoker.finalCheck(); + + if (this.mScenarios && this.mScenarios.length) { + var matchIdx = -1; + for (var scnIdx = 0; scnIdx < this.mScenarios.length; scnIdx++) { + var eventSeq = this.mScenarios[scnIdx]; + if (!this.areExpectedEventsLeft(eventSeq)) { + for (var idx = 0; idx < eventSeq.length; idx++) { + var checker = eventSeq[idx]; + if (checker.unexpected && checker.wasCaught || + !checker.unexpected && checker.wasCaught != 1) { + break; + } + } + + // Ok, we have matched scenario. Report it was completed ok. In + // case of empty scenario guess it was matched but if later we + // find out that non empty scenario was matched then it will be + // a final match. + if (idx == eventSeq.length) { + if (matchIdx != -1 && eventSeq.length > 0 && + this.mScenarios[matchIdx].length > 0) { + ok(false, + "We have a matched scenario at index " + matchIdx + " already."); + } + + if (matchIdx == -1 || eventSeq.length > 0) + matchIdx = scnIdx; + + // Report everything is ok. + for (var idx = 0; idx < eventSeq.length; idx++) { + var checker = eventSeq[idx]; + + var typeStr = eventQueue.getEventTypeAsString(checker); + var msg = "Test with ID = '" + this.getEventID(checker) + + "' succeed. "; + + if (checker.unexpected) { + ok(true, msg + `There's no unexpected '${typeStr}' event.`); + } + else { + if (checker.todo) { + todo(false, `Todo event '${typeStr}' was caught`); + } + else { + ok(true, `${msg} Event '${typeStr}' was handled.`); + } + } + } + } + } + } + + // We don't have completely matched scenario. Report each failure/success + // for every scenario. + if (matchIdx == -1) { + testFailed = true; + for (var scnIdx = 0; scnIdx < this.mScenarios.length; scnIdx++) { + var eventSeq = this.mScenarios[scnIdx]; + for (var idx = 0; idx < eventSeq.length; idx++) { + var checker = eventSeq[idx]; + + var typeStr = eventQueue.getEventTypeAsString(checker); + var msg = "Scenario #" + scnIdx + " of test with ID = '" + + this.getEventID(checker) + "' failed. "; + + if (checker.wasCaught > 1) + ok(false, msg + "Dupe " + typeStr + " event."); + + if (checker.unexpected) { + if (checker.wasCaught) { + ok(false, msg + "There's unexpected " + typeStr + " event."); + } + } + else if (!checker.wasCaught) { + var rf = checker.todo ? todo : ok; + rf(false, `${msg} '${typeStr} event is missed.`); + } + } + } + } + } + } + + this.clearEventHandler(); + + // Check if need to stop the test. + if (testFailed || this.mIndex == this.mInvokers.length - 1) { + listenA11yEvents(false); + + var res = this.onFinish(); + if (res != DO_NOT_FINISH_TEST) + SimpleTest.executeSoon(SimpleTest.finish); + + return; + } + + // Start processing of next invoker. + invoker = this.getNextInvoker(); + + // Set up event listeners. Process a next invoker if no events were added. + if (!this.setEventHandler(invoker)) { + this.processNextInvoker(); + return; + } + + if (gLogger.isEnabled()) { + gLogger.logToConsole("Event queue: \n invoke: " + invoker.getID()); + gLogger.logToDOM("EQ: invoke: " + invoker.getID(), true); + } + + var infoText = "Invoke the '" + invoker.getID() + "' test { "; + var scnCount = this.mScenarios ? this.mScenarios.length : 0; + for (var scnIdx = 0; scnIdx < scnCount; scnIdx++) { + infoText += "scenario #" + scnIdx + ": "; + var eventSeq = this.mScenarios[scnIdx]; + for (var idx = 0; idx < eventSeq.length; idx++) { + infoText += eventSeq[idx].unexpected ? "un" : "" + + "expected '" + eventQueue.getEventTypeAsString(eventSeq[idx]) + + "' event; "; + } + } + infoText += " }"; + info(infoText); + + if (invoker.invoke() == INVOKER_ACTION_FAILED) { + // Invoker failed to prepare action, fail and finish tests. + this.processNextInvoker(); + return; + } + + if (this.hasUnexpectedEventsScenario()) + this.processNextInvokerInTimeout(true); + } + + this.processNextInvokerInTimeout = + function eventQueue_processNextInvokerInTimeout(aUncondProcess) + { + this.setInvokerStatus(kInvokerPending, "Process next invoker in timeout"); + + // No need to wait extra timeout when a) we know we don't need to do that + // and b) there's no any single unexpected event. + if (!aUncondProcess && this.areAllEventsExpected()) { + // We need delay to avoid events coalesce from different invokers. + var queue = this; + SimpleTest.executeSoon(function() { queue.processNextInvoker(); }); + return; + } + + // Check in timeout invoker didn't fire registered events. + window.setTimeout(function(aQueue) { aQueue.processNextInvoker(); }, 300, + this); + } + + /** + * Handle events for the current invoker. + */ + this.handleEvent = function eventQueue_handleEvent(aEvent) + { + var invoker = this.getInvoker(); + if (!invoker) // skip events before test was started + return; + + if (!this.mScenarios) { + // Bad invoker object, error will be reported before processing of next + // invoker in the queue. + this.processNextInvoker(); + return; + } + + if ("debugCheck" in invoker) + invoker.debugCheck(aEvent); + + for (var scnIdx = 0; scnIdx < this.mScenarios.length; scnIdx++) { + var eventSeq = this.mScenarios[scnIdx]; + for (var idx = 0; idx < eventSeq.length; idx++) { + var checker = eventSeq[idx]; + + // Search through handled expected events to report error if one of them + // is handled for a second time. + if (!checker.unexpected && (checker.wasCaught > 0) && + eventQueue.isSameEvent(checker, aEvent)) { + checker.wasCaught++; + continue; + } + + // Search through unexpected events, any match results in error report + // after this invoker processing (in case of matched scenario only). + if (checker.unexpected && eventQueue.compareEvents(checker, aEvent)) { + checker.wasCaught++; + continue; + } + + // Report an error if we hanlded not expected event of unique type + // (i.e. event types are matched, targets differs). + if (!checker.unexpected && checker.unique && + eventQueue.compareEventTypes(checker, aEvent)) { + var isExppected = false; + for (var jdx = 0; jdx < eventSeq.length; jdx++) { + isExpected = eventQueue.compareEvents(eventSeq[jdx], aEvent); + if (isExpected) + break; + } + + if (!isExpected) { + ok(false, + "Unique type " + + eventQueue.getEventTypeAsString(checker) + " event was handled."); + } + } + } + } + + var hasMatchedCheckers = false; + for (var scnIdx = 0; scnIdx < this.mScenarios.length; scnIdx++) { + var eventSeq = this.mScenarios[scnIdx]; + + // Check if handled event matches expected sync event. + var nextChecker = this.getNextExpectedEvent(eventSeq); + if (nextChecker) { + if (eventQueue.compareEvents(nextChecker, aEvent)) { + this.processMatchedChecker(aEvent, nextChecker, scnIdx, eventSeq.idx); + hasMatchedCheckers = true; + continue; + } + } + + // Check if handled event matches any expected async events. + var haveUnmatchedAsync = false; + for (idx = 0; idx < eventSeq.length; idx++) { + if (eventSeq[idx] instanceof orderChecker && haveUnmatchedAsync) { + break; + } + + if (!eventSeq[idx].wasCaught) { + haveUnmatchedAsync = true; + } + + if (!eventSeq[idx].unexpected && eventSeq[idx].async) { + if (eventQueue.compareEvents(eventSeq[idx], aEvent)) { + this.processMatchedChecker(aEvent, eventSeq[idx], scnIdx, idx); + hasMatchedCheckers = true; + break; + } + } + } + } + + if (hasMatchedCheckers) { + var invoker = this.getInvoker(); + if ("check" in invoker) + invoker.check(aEvent); + } + + for (idx = 0; idx < eventSeq.length; idx++) { + if (!eventSeq[idx].wasCaught) { + if (eventSeq[idx] instanceof orderChecker) { + eventSeq[idx].wasCaught++; + } else { + break; + } + } + } + + // If we don't have more events to wait then schedule next invoker. + if (this.hasMatchedScenario()) { + if (this.mNextInvokerStatus == kInvokerNotScheduled) { + this.processNextInvokerInTimeout(); + + } else if (this.mNextInvokerStatus == kInvokerCanceled) { + this.setInvokerStatus(kInvokerPending, + "Full match. Void the cancelation of next invoker processing"); + } + return; + } + + // If we have scheduled a next invoker then cancel in case of match. + if ((this.mNextInvokerStatus == kInvokerPending) && hasMatchedCheckers) { + this.setInvokerStatus(kInvokerCanceled, + "Cancel the scheduled invoker in case of match"); + } + } + + // Helpers + this.processMatchedChecker = + function eventQueue_function(aEvent, aMatchedChecker, aScenarioIdx, aEventIdx) + { + aMatchedChecker.wasCaught++; + + if ("check" in aMatchedChecker) + aMatchedChecker.check(aEvent); + + eventQueue.logEvent(aEvent, aMatchedChecker, aScenarioIdx, aEventIdx, + this.areExpectedEventsLeft(), + this.mNextInvokerStatus); + } + + this.getNextExpectedEvent = + function eventQueue_getNextExpectedEvent(aEventSeq) + { + if (!("idx" in aEventSeq)) + aEventSeq.idx = 0; + + while (aEventSeq.idx < aEventSeq.length && + (aEventSeq[aEventSeq.idx].unexpected || + aEventSeq[aEventSeq.idx].todo || + aEventSeq[aEventSeq.idx].async || + aEventSeq[aEventSeq.idx] instanceof orderChecker || + aEventSeq[aEventSeq.idx].wasCaught > 0)) { + aEventSeq.idx++; + } + + return aEventSeq.idx != aEventSeq.length ? aEventSeq[aEventSeq.idx] : null; + } + + this.areExpectedEventsLeft = + function eventQueue_areExpectedEventsLeft(aScenario) + { + function scenarioHasUnhandledExpectedEvent(aEventSeq) + { + // Check if we have unhandled async (can be anywhere in the sequance) or + // sync expcected events yet. + for (var idx = 0; idx < aEventSeq.length; idx++) { + if (!aEventSeq[idx].unexpected && !aEventSeq[idx].todo && + !aEventSeq[idx].wasCaught && !(aEventSeq[idx] instanceof orderChecker)) + return true; + } + + return false; + } + + if (aScenario) + return scenarioHasUnhandledExpectedEvent(aScenario); + + for (var scnIdx = 0; scnIdx < this.mScenarios.length; scnIdx++) { + var eventSeq = this.mScenarios[scnIdx]; + if (scenarioHasUnhandledExpectedEvent(eventSeq)) + return true; + } + return false; + } + + this.areAllEventsExpected = + function eventQueue_areAllEventsExpected() + { + for (var scnIdx = 0; scnIdx < this.mScenarios.length; scnIdx++) { + var eventSeq = this.mScenarios[scnIdx]; + for (var idx = 0; idx < eventSeq.length; idx++) { + if (eventSeq[idx].unexpected || eventSeq[idx].todo) + return false; + } + } + + return true; + } + + this.isUnexpectedEventScenario = + function eventQueue_isUnexpectedEventsScenario(aScenario) + { + for (var idx = 0; idx < aScenario.length; idx++) { + if (!aScenario[idx].unexpected && !aScenario[idx].todo) + break; + } + + return idx == aScenario.length; + } + + this.hasUnexpectedEventsScenario = + function eventQueue_hasUnexpectedEventsScenario() + { + if (this.getInvoker().noEventsOnAction) + return true; + + for (var scnIdx = 0; scnIdx < this.mScenarios.length; scnIdx++) { + if (this.isUnexpectedEventScenario(this.mScenarios[scnIdx])) + return true; + } + + return false; + } + + this.hasMatchedScenario = + function eventQueue_hasMatchedScenario() + { + for (var scnIdx = 0; scnIdx < this.mScenarios.length; scnIdx++) { + var scn = this.mScenarios[scnIdx]; + if (!this.isUnexpectedEventScenario(scn) && !this.areExpectedEventsLeft(scn)) + return true; + } + return false; + } + + this.getInvoker = function eventQueue_getInvoker() + { + return this.mInvokers[this.mIndex]; + } + + this.getNextInvoker = function eventQueue_getNextInvoker() + { + return this.mInvokers[++this.mIndex]; + } + + this.setEventHandler = function eventQueue_setEventHandler(aInvoker) + { + if (!("scenarios" in aInvoker) || aInvoker.scenarios.length == 0) { + var eventSeq = aInvoker.eventSeq; + var unexpectedEventSeq = aInvoker.unexpectedEventSeq; + if (!eventSeq && !unexpectedEventSeq && this.mDefEventType) + eventSeq = [ new invokerChecker(this.mDefEventType, aInvoker.DOMNode) ]; + + if (eventSeq || unexpectedEventSeq) + defineScenario(aInvoker, eventSeq, unexpectedEventSeq); + } + + if (aInvoker.noEventsOnAction) + return true; + + this.mScenarios = aInvoker.scenarios; + if (!this.mScenarios || !this.mScenarios.length) { + ok(false, "Broken invoker '" + aInvoker.getID() + "'"); + return false; + } + + // Register event listeners. + for (var scnIdx = 0; scnIdx < this.mScenarios.length; scnIdx++) { + var eventSeq = this.mScenarios[scnIdx]; + + if (gLogger.isEnabled()) { + var msg = "scenario #" + scnIdx + + ", registered events number: " + eventSeq.length; + gLogger.logToConsole(msg); + gLogger.logToDOM(msg, true); + } + + // Do not warn about empty event sequances when more than one scenario + // was registered. + if (this.mScenarios.length == 1 && eventSeq.length == 0) { + ok(false, + "Broken scenario #" + scnIdx + " of invoker '" + aInvoker.getID() + + "'. No registered events"); + return false; + } + + for (var idx = 0; idx < eventSeq.length; idx++) + eventSeq[idx].wasCaught = 0; + + for (var idx = 0; idx < eventSeq.length; idx++) { + if (gLogger.isEnabled()) { + var msg = "registered"; + if (eventSeq[idx].unexpected) + msg += " unexpected"; + if (eventSeq[idx].async) + msg += " async"; + + msg += ": event type: " + + eventQueue.getEventTypeAsString(eventSeq[idx]) + + ", target: " + eventQueue.getEventTargetDescr(eventSeq[idx], true); + + gLogger.logToConsole(msg); + gLogger.logToDOM(msg, true); + } + + var eventType = eventSeq[idx].type; + if (typeof eventType == "string") { + // DOM event + var target = eventSeq[idx].target; + if (!target) { + ok(false, "no target for DOM event!"); + return false; + } + var phase = eventQueue.getEventPhase(eventSeq[idx]); + target.ownerDocument.addEventListener(eventType, this, phase); + + } else { + // A11y event + addA11yEventListener(eventType, this); + } + } + } + + return true; + } + + this.clearEventHandler = function eventQueue_clearEventHandler() + { + if (!this.mScenarios) + return; + + for (var scnIdx = 0; scnIdx < this.mScenarios.length; scnIdx++) { + var eventSeq = this.mScenarios[scnIdx]; + for (var idx = 0; idx < eventSeq.length; idx++) { + var eventType = eventSeq[idx].type; + if (typeof eventType == "string") { + // DOM event + var target = eventSeq[idx].target; + var phase = eventQueue.getEventPhase(eventSeq[idx]); + target.ownerDocument.removeEventListener(eventType, this, phase); + + } else { + // A11y event + removeA11yEventListener(eventType, this); + } + } + } + this.mScenarios = null; + } + + this.getEventID = function eventQueue_getEventID(aChecker) + { + if ("getID" in aChecker) + return aChecker.getID(); + + var invoker = this.getInvoker(); + return invoker.getID(); + } + + this.setInvokerStatus = function eventQueue_setInvokerStatus(aStatus, aLogMsg) + { + this.mNextInvokerStatus = aStatus; + + // Uncomment it to debug invoker processing logic. + //gLogger.log(eventQueue.invokerStatusToMsg(aStatus, aLogMsg)); + } + + this.mDefEventType = aEventType; + + this.mInvokers = new Array(); + this.mIndex = -1; + this.mScenarios = null; + + this.mNextInvokerStatus = kInvokerNotScheduled; +} + +//////////////////////////////////////////////////////////////////////////////// +// eventQueue static members and constants + +const kInvokerNotScheduled = 0; +const kInvokerPending = 1; +const kInvokerCanceled = 2; + +eventQueue.getEventTypeAsString = + function eventQueue_getEventTypeAsString(aEventOrChecker) +{ + if (aEventOrChecker instanceof nsIDOMEvent) + return aEventOrChecker.type; + + if (aEventOrChecker instanceof nsIAccessibleEvent) + return eventTypeToString(aEventOrChecker.eventType); + + return (typeof aEventOrChecker.type == "string") ? + aEventOrChecker.type : eventTypeToString(aEventOrChecker.type); +} + +eventQueue.getEventTargetDescr = + function eventQueue_getEventTargetDescr(aEventOrChecker, aDontForceTarget) +{ + if (aEventOrChecker instanceof nsIDOMEvent) + return prettyName(aEventOrChecker.originalTarget); + + if (aEventOrChecker instanceof nsIDOMEvent) + return prettyName(aEventOrChecker.accessible); + + var descr = aEventOrChecker.targetDescr; + if (descr) + return descr; + + if (aDontForceTarget) + return "no target description"; + + var target = ("target" in aEventOrChecker) ? aEventOrChecker.target : null; + return prettyName(target); +} + +eventQueue.getEventPhase = function eventQueue_getEventPhase(aChecker) +{ + return ("phase" in aChecker) ? aChecker.phase : true; +} + +eventQueue.compareEventTypes = + function eventQueue_compareEventTypes(aChecker, aEvent) +{ + var eventType = (aEvent instanceof nsIDOMEvent) ? + aEvent.type : aEvent.eventType; + return aChecker.type == eventType; +} + +eventQueue.compareEvents = function eventQueue_compareEvents(aChecker, aEvent) +{ + if (!eventQueue.compareEventTypes(aChecker, aEvent)) + return false; + + // If checker provides "match" function then allow the checker to decide + // whether event is matched. + if ("match" in aChecker) + return aChecker.match(aEvent); + + var target1 = aChecker.target; + if (target1 instanceof nsIAccessible) { + var target2 = (aEvent instanceof nsIDOMEvent) ? + getAccessible(aEvent.target) : aEvent.accessible; + + return target1 == target2; + } + + // If original target isn't suitable then extend interface to support target + // (original target is used in test_elm_media.html). + var target2 = (aEvent instanceof nsIDOMEvent) ? + aEvent.originalTarget : aEvent.DOMNode; + return target1 == target2; +} + +eventQueue.isSameEvent = function eventQueue_isSameEvent(aChecker, aEvent) +{ + // We don't have stored info about handled event other than its type and + // target, thus we should filter text change and state change events since + // they may occur on the same element because of complex changes. + return this.compareEvents(aChecker, aEvent) && + !(aEvent instanceof nsIAccessibleTextChangeEvent) && + !(aEvent instanceof nsIAccessibleStateChangeEvent); +} + +eventQueue.invokerStatusToMsg = + function eventQueue_invokerStatusToMsg(aInvokerStatus, aMsg) +{ + var msg = "invoker status: "; + switch (aInvokerStatus) { + case kInvokerNotScheduled: + msg += "not scheduled"; + break; + case kInvokerPending: + msg += "pending"; + break; + case kInvokerCanceled: + msg += "canceled"; + break; + } + + if (aMsg) + msg += " (" + aMsg + ")"; + + return msg; +} + +eventQueue.logEvent = function eventQueue_logEvent(aOrigEvent, aMatchedChecker, + aScenarioIdx, aEventIdx, + aAreExpectedEventsLeft, + aInvokerStatus) +{ + // Dump DOM event information. Skip a11y event since it is dumped by + // gA11yEventObserver. + if (aOrigEvent instanceof nsIDOMEvent) { + var info = "Event type: " + eventQueue.getEventTypeAsString(aOrigEvent); + info += ". Target: " + eventQueue.getEventTargetDescr(aOrigEvent); + gLogger.logToDOM(info); + } + + var infoMsg = "unhandled expected events: " + aAreExpectedEventsLeft + + ", " + eventQueue.invokerStatusToMsg(aInvokerStatus); + + var currType = eventQueue.getEventTypeAsString(aMatchedChecker); + var currTargetDescr = eventQueue.getEventTargetDescr(aMatchedChecker); + var consoleMsg = "*****\nScenario " + aScenarioIdx + + ", event " + aEventIdx + " matched: " + currType + "\n" + infoMsg + "\n*****"; + gLogger.logToConsole(consoleMsg); + + var emphText = "matched "; + var msg = "EQ event, type: " + currType + ", target: " + currTargetDescr + + ", " + infoMsg; + gLogger.logToDOM(msg, true, emphText); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Action sequence + +/** + * Deal with action sequence. Used when you need to execute couple of actions + * each after other one. + */ +function sequence() +{ + /** + * Append new sequence item. + * + * @param aProcessor [in] object implementing interface + * { + * // execute item action + * process: function() {}, + * // callback, is called when item was processed + * onProcessed: function() {} + * }; + * @param aEventType [in] event type of expected event on item action + * @param aTarget [in] event target of expected event on item action + * @param aItemID [in] identifier of item + */ + this.append = function sequence_append(aProcessor, aEventType, aTarget, + aItemID) + { + var item = new sequenceItem(aProcessor, aEventType, aTarget, aItemID); + this.items.push(item); + } + + /** + * Process next sequence item. + */ + this.processNext = function sequence_processNext() + { + this.idx++; + if (this.idx >= this.items.length) { + ok(false, "End of sequence: nothing to process!"); + SimpleTest.finish(); + return; + } + + this.items[this.idx].startProcess(); + } + + this.items = new Array(); + this.idx = -1; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Event queue invokers + +/** + * Defines a scenario of expected/unexpected events. Each invoker can have + * one or more scenarios of events. Only one scenario must be completed. + */ +function defineScenario(aInvoker, aEventSeq, aUnexpectedEventSeq) +{ + if (!("scenarios" in aInvoker)) + aInvoker.scenarios = new Array(); + + // Create unified event sequence concatenating expected and unexpected + // events. + if (!aEventSeq) + aEventSeq = []; + + for (var idx = 0; idx < aEventSeq.length; idx++) { + aEventSeq[idx].unexpected |= false; + aEventSeq[idx].async |= false; + } + + if (aUnexpectedEventSeq) { + for (var idx = 0; idx < aUnexpectedEventSeq.length; idx++) { + aUnexpectedEventSeq[idx].unexpected = true; + aUnexpectedEventSeq[idx].async = false; + } + + aEventSeq = aEventSeq.concat(aUnexpectedEventSeq); + } + + aInvoker.scenarios.push(aEventSeq); +} + + +/** + * Invokers defined below take a checker object (or array of checker objects). + * An invoker listens for default event type registered in event queue object + * until its checker is provided. + * + * Note, checker object or array of checker objects is optional. + */ + +/** + * Click invoker. + */ +function synthClick(aNodeOrID, aCheckerOrEventSeq, aArgs) +{ + this.__proto__ = new synthAction(aNodeOrID, aCheckerOrEventSeq); + + this.invoke = function synthClick_invoke() + { + var targetNode = this.DOMNode; + if (targetNode instanceof nsIDOMDocument) { + targetNode = + this.DOMNode.body ? this.DOMNode.body : this.DOMNode.documentElement; + } + + // Scroll the node into view, otherwise synth click may fail. + if (targetNode instanceof nsIDOMHTMLElement) { + targetNode.scrollIntoView(true); + } else if (targetNode instanceof nsIDOMXULElement) { + var targetAcc = getAccessible(targetNode); + targetAcc.scrollTo(SCROLL_TYPE_ANYWHERE); + } + + var x = 1, y = 1; + if (aArgs && ("where" in aArgs) && aArgs.where == "right") { + if (targetNode instanceof nsIDOMHTMLElement) + x = targetNode.offsetWidth - 1; + else if (targetNode instanceof nsIDOMXULElement) + x = targetNode.boxObject.width - 1; + } + synthesizeMouse(targetNode, x, y, aArgs ? aArgs : {}); + } + + this.finalCheck = function synthClick_finalCheck() + { + // Scroll top window back. + window.top.scrollTo(0, 0); + } + + this.getID = function synthClick_getID() + { + return prettyName(aNodeOrID) + " click"; + } +} + +/** + * Mouse move invoker. + */ +function synthMouseMove(aID, aCheckerOrEventSeq) +{ + this.__proto__ = new synthAction(aID, aCheckerOrEventSeq); + + this.invoke = function synthMouseMove_invoke() + { + synthesizeMouse(this.DOMNode, 1, 1, { type: "mousemove" }); + synthesizeMouse(this.DOMNode, 2, 2, { type: "mousemove" }); + } + + this.getID = function synthMouseMove_getID() + { + return prettyName(aID) + " mouse move"; + } +} + +/** + * General key press invoker. + */ +function synthKey(aNodeOrID, aKey, aArgs, aCheckerOrEventSeq) +{ + this.__proto__ = new synthAction(aNodeOrID, aCheckerOrEventSeq); + + this.invoke = function synthKey_invoke() + { + synthesizeKey(this.mKey, this.mArgs, this.mWindow); + } + + this.getID = function synthKey_getID() + { + var key = this.mKey; + switch (this.mKey) { + case "VK_TAB": + key = "tab"; + break; + case "VK_DOWN": + key = "down"; + break; + case "VK_UP": + key = "up"; + break; + case "VK_LEFT": + key = "left"; + break; + case "VK_RIGHT": + key = "right"; + break; + case "VK_HOME": + key = "home"; + break; + case "VK_END": + key = "end"; + break; + case "VK_ESCAPE": + key = "escape"; + break; + case "VK_RETURN": + key = "enter"; + break; + } + if (aArgs) { + if (aArgs.shiftKey) + key += " shift"; + if (aArgs.ctrlKey) + key += " ctrl"; + if (aArgs.altKey) + key += " alt"; + } + return prettyName(aNodeOrID) + " '" + key + " ' key"; + } + + this.mKey = aKey; + this.mArgs = aArgs ? aArgs : {}; + this.mWindow = aArgs ? aArgs.window : null; +} + +/** + * Tab key invoker. + */ +function synthTab(aNodeOrID, aCheckerOrEventSeq, aWindow) +{ + this.__proto__ = new synthKey(aNodeOrID, "VK_TAB", + { shiftKey: false, window: aWindow }, + aCheckerOrEventSeq); +} + +/** + * Shift tab key invoker. + */ +function synthShiftTab(aNodeOrID, aCheckerOrEventSeq) +{ + this.__proto__ = new synthKey(aNodeOrID, "VK_TAB", { shiftKey: true }, + aCheckerOrEventSeq); +} + +/** + * Escape key invoker. + */ +function synthEscapeKey(aNodeOrID, aCheckerOrEventSeq) +{ + this.__proto__ = new synthKey(aNodeOrID, "VK_ESCAPE", null, + aCheckerOrEventSeq); +} + +/** + * Down arrow key invoker. + */ +function synthDownKey(aNodeOrID, aCheckerOrEventSeq, aArgs) +{ + this.__proto__ = new synthKey(aNodeOrID, "VK_DOWN", aArgs, + aCheckerOrEventSeq); +} + +/** + * Up arrow key invoker. + */ +function synthUpKey(aNodeOrID, aCheckerOrEventSeq, aArgs) +{ + this.__proto__ = new synthKey(aNodeOrID, "VK_UP", aArgs, + aCheckerOrEventSeq); +} + +/** + * Left arrow key invoker. + */ +function synthLeftKey(aNodeOrID, aCheckerOrEventSeq, aArgs) +{ + this.__proto__ = new synthKey(aNodeOrID, "VK_LEFT", aArgs, aCheckerOrEventSeq); +} + +/** + * Right arrow key invoker. + */ +function synthRightKey(aNodeOrID, aCheckerOrEventSeq, aArgs) +{ + this.__proto__ = new synthKey(aNodeOrID, "VK_RIGHT", aArgs, aCheckerOrEventSeq); +} + +/** + * Home key invoker. + */ +function synthHomeKey(aNodeOrID, aCheckerOrEventSeq) +{ + this.__proto__ = new synthKey(aNodeOrID, "VK_HOME", null, aCheckerOrEventSeq); +} + +/** + * End key invoker. + */ +function synthEndKey(aNodeOrID, aCheckerOrEventSeq) +{ + this.__proto__ = new synthKey(aNodeOrID, "VK_END", null, aCheckerOrEventSeq); +} + +/** + * Enter key invoker + */ +function synthEnterKey(aID, aCheckerOrEventSeq) +{ + this.__proto__ = new synthKey(aID, "VK_RETURN", null, aCheckerOrEventSeq); +} + +/** + * Synth alt + down arrow to open combobox. + */ +function synthOpenComboboxKey(aID, aCheckerOrEventSeq) +{ + this.__proto__ = new synthDownKey(aID, aCheckerOrEventSeq, { altKey: true }); + + this.getID = function synthOpenComboboxKey_getID() + { + return "open combobox (atl + down arrow) " + prettyName(aID); + } +} + +/** + * Focus invoker. + */ +function synthFocus(aNodeOrID, aCheckerOrEventSeq) +{ + var checkerOfEventSeq = + aCheckerOrEventSeq ? aCheckerOrEventSeq : new focusChecker(aNodeOrID); + this.__proto__ = new synthAction(aNodeOrID, checkerOfEventSeq); + + this.invoke = function synthFocus_invoke() + { + if (this.DOMNode instanceof Components.interfaces.nsIDOMNSEditableElement && + this.DOMNode.editor || + this.DOMNode instanceof Components.interfaces.nsIDOMXULTextBoxElement) { + this.DOMNode.selectionStart = this.DOMNode.selectionEnd = this.DOMNode.value.length; + } + this.DOMNode.focus(); + } + + this.getID = function synthFocus_getID() + { + return prettyName(aNodeOrID) + " focus"; + } +} + +/** + * Focus invoker. Focus the HTML body of content document of iframe. + */ +function synthFocusOnFrame(aNodeOrID, aCheckerOrEventSeq) +{ + var frameDoc = getNode(aNodeOrID).contentDocument; + var checkerOrEventSeq = + aCheckerOrEventSeq ? aCheckerOrEventSeq : new focusChecker(frameDoc); + this.__proto__ = new synthAction(frameDoc, checkerOrEventSeq); + + this.invoke = function synthFocus_invoke() + { + this.DOMNode.body.focus(); + } + + this.getID = function synthFocus_getID() + { + return prettyName(aNodeOrID) + " frame document focus"; + } +} + +/** + * Change the current item when the widget doesn't have a focus. + */ +function changeCurrentItem(aID, aItemID) +{ + this.eventSeq = [ new nofocusChecker() ]; + + this.invoke = function changeCurrentItem_invoke() + { + var controlNode = getNode(aID); + var itemNode = getNode(aItemID); + + // HTML + if (controlNode.localName == "input") { + if (controlNode.checked) + this.reportError(); + + controlNode.checked = true; + return; + } + + if (controlNode.localName == "select") { + if (controlNode.selectedIndex == itemNode.index) + this.reportError(); + + controlNode.selectedIndex = itemNode.index; + return; + } + + // XUL + if (controlNode.localName == "tree") { + if (controlNode.currentIndex == aItemID) + this.reportError(); + + controlNode.currentIndex = aItemID; + return; + } + + if (controlNode.localName == "menulist") { + if (controlNode.selectedItem == itemNode) + this.reportError(); + + controlNode.selectedItem = itemNode; + return; + } + + if (controlNode.currentItem == itemNode) + ok(false, "Error in test: proposed current item is already current" + prettyName(aID)); + + controlNode.currentItem = itemNode; + } + + this.getID = function changeCurrentItem_getID() + { + return "current item change for " + prettyName(aID); + } + + this.reportError = function changeCurrentItem_reportError() + { + ok(false, + "Error in test: proposed current item '" + aItemID + "' is already current"); + } +} + +/** + * Toggle top menu invoker. + */ +function toggleTopMenu(aID, aCheckerOrEventSeq) +{ + this.__proto__ = new synthKey(aID, "VK_ALT", null, + aCheckerOrEventSeq); + + this.getID = function toggleTopMenu_getID() + { + return "toggle top menu on " + prettyName(aID); + } +} + +/** + * Context menu invoker. + */ +function synthContextMenu(aID, aCheckerOrEventSeq) +{ + this.__proto__ = new synthClick(aID, aCheckerOrEventSeq, + { button: 0, type: "contextmenu" }); + + this.getID = function synthContextMenu_getID() + { + return "context menu on " + prettyName(aID); + } +} + +/** + * Open combobox, autocomplete and etc popup, check expandable states. + */ +function openCombobox(aComboboxID) +{ + this.eventSeq = [ + new stateChangeChecker(STATE_EXPANDED, false, true, aComboboxID) + ]; + + this.invoke = function openCombobox_invoke() + { + getNode(aComboboxID).focus(); + synthesizeKey("VK_DOWN", { altKey: true }); + } + + this.getID = function openCombobox_getID() + { + return "open combobox " + prettyName(aComboboxID); + } +} + +/** + * Close combobox, autocomplete and etc popup, check expandable states. + */ +function closeCombobox(aComboboxID) +{ + this.eventSeq = [ + new stateChangeChecker(STATE_EXPANDED, false, false, aComboboxID) + ]; + + this.invoke = function closeCombobox_invoke() + { + synthesizeKey("VK_ESCAPE", { }); + } + + this.getID = function closeCombobox_getID() + { + return "close combobox " + prettyName(aComboboxID); + } +} + + +/** + * Select all invoker. + */ +function synthSelectAll(aNodeOrID, aCheckerOrEventSeq) +{ + this.__proto__ = new synthAction(aNodeOrID, aCheckerOrEventSeq); + + this.invoke = function synthSelectAll_invoke() + { + if (this.DOMNode instanceof Components.interfaces.nsIDOMHTMLInputElement || + this.DOMNode instanceof Components.interfaces.nsIDOMXULTextBoxElement) { + this.DOMNode.select(); + + } else { + window.getSelection().selectAllChildren(this.DOMNode); + } + } + + this.getID = function synthSelectAll_getID() + { + return aNodeOrID + " selectall"; + } +} + +/** + * Move the caret to the end of line. + */ +function moveToLineEnd(aID, aCaretOffset) +{ + if (MAC) { + this.__proto__ = new synthKey(aID, "VK_RIGHT", { metaKey: true }, + new caretMoveChecker(aCaretOffset, aID)); + } else { + this.__proto__ = new synthEndKey(aID, + new caretMoveChecker(aCaretOffset, aID)); + } + + this.getID = function moveToLineEnd_getID() + { + return "move to line end in " + prettyName(aID); + } +} + +/** + * Move the caret to the end of previous line if any. + */ +function moveToPrevLineEnd(aID, aCaretOffset) +{ + this.__proto__ = new synthAction(aID, new caretMoveChecker(aCaretOffset, aID)); + + this.invoke = function moveToPrevLineEnd_invoke() + { + synthesizeKey("VK_UP", { }); + + if (MAC) + synthesizeKey("VK_RIGHT", { metaKey: true }); + else + synthesizeKey("VK_END", { }); + } + + this.getID = function moveToPrevLineEnd_getID() + { + return "move to previous line end in " + prettyName(aID); + } +} + +/** + * Move the caret to begining of the line. + */ +function moveToLineStart(aID, aCaretOffset) +{ + if (MAC) { + this.__proto__ = new synthKey(aID, "VK_LEFT", { metaKey: true }, + new caretMoveChecker(aCaretOffset, aID)); + } else { + this.__proto__ = new synthHomeKey(aID, + new caretMoveChecker(aCaretOffset, aID)); + } + + this.getID = function moveToLineEnd_getID() + { + return "move to line start in " + prettyName(aID); + } +} + +/** + * Move the caret to begining of the text. + */ +function moveToTextStart(aID) +{ + if (MAC) { + this.__proto__ = new synthKey(aID, "VK_UP", { metaKey: true }, + new caretMoveChecker(0, aID)); + } else { + this.__proto__ = new synthKey(aID, "VK_HOME", { ctrlKey: true }, + new caretMoveChecker(0, aID)); + } + + this.getID = function moveToTextStart_getID() + { + return "move to text start in " + prettyName(aID); + } +} + +/** + * Move the caret in text accessible. + */ +function moveCaretToDOMPoint(aID, aDOMPointNodeID, aDOMPointOffset, + aExpectedOffset, aFocusTargetID, + aCheckFunc) +{ + this.target = getAccessible(aID, [nsIAccessibleText]); + this.DOMPointNode = getNode(aDOMPointNodeID); + this.focus = aFocusTargetID ? getAccessible(aFocusTargetID) : null; + this.focusNode = this.focus ? this.focus.DOMNode : null; + + this.invoke = function moveCaretToDOMPoint_invoke() + { + if (this.focusNode) + this.focusNode.focus(); + + var selection = this.DOMPointNode.ownerDocument.defaultView.getSelection(); + var selRange = selection.getRangeAt(0); + selRange.setStart(this.DOMPointNode, aDOMPointOffset); + selRange.collapse(true); + + selection.removeRange(selRange); + selection.addRange(selRange); + } + + this.getID = function moveCaretToDOMPoint_getID() + { + return "Set caret on " + prettyName(aID) + " at point: " + + prettyName(aDOMPointNodeID) + " node with offset " + aDOMPointOffset; + } + + this.finalCheck = function moveCaretToDOMPoint_finalCheck() + { + if (aCheckFunc) + aCheckFunc.call(); + } + + this.eventSeq = [ + new caretMoveChecker(aExpectedOffset, this.target) + ]; + + if (this.focus) + this.eventSeq.push(new asyncInvokerChecker(EVENT_FOCUS, this.focus)); +} + +/** + * Set caret offset in text accessible. + */ +function setCaretOffset(aID, aOffset, aFocusTargetID) +{ + this.target = getAccessible(aID, [nsIAccessibleText]); + this.offset = aOffset == -1 ? this.target.characterCount: aOffset; + this.focus = aFocusTargetID ? getAccessible(aFocusTargetID) : null; + + this.invoke = function setCaretOffset_invoke() + { + this.target.caretOffset = this.offset; + } + + this.getID = function setCaretOffset_getID() + { + return "Set caretOffset on " + prettyName(aID) + " at " + this.offset; + } + + this.eventSeq = [ + new caretMoveChecker(this.offset, this.target) + ]; + + if (this.focus) + this.eventSeq.push(new asyncInvokerChecker(EVENT_FOCUS, this.focus)); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Event queue checkers + +/** + * Common invoker checker (see eventSeq of eventQueue). + */ +function invokerChecker(aEventType, aTargetOrFunc, aTargetFuncArg, aIsAsync) +{ + this.type = aEventType; + this.async = aIsAsync; + + this.__defineGetter__("target", invokerChecker_targetGetter); + this.__defineSetter__("target", invokerChecker_targetSetter); + + // implementation details + function invokerChecker_targetGetter() + { + if (typeof this.mTarget == "function") + return this.mTarget.call(null, this.mTargetFuncArg); + if (typeof this.mTarget == "string") + return getNode(this.mTarget); + + return this.mTarget; + } + + function invokerChecker_targetSetter(aValue) + { + this.mTarget = aValue; + return this.mTarget; + } + + this.__defineGetter__("targetDescr", invokerChecker_targetDescrGetter); + + function invokerChecker_targetDescrGetter() + { + if (typeof this.mTarget == "function") + return this.mTarget.name + ", arg: " + this.mTargetFuncArg; + + return prettyName(this.mTarget); + } + + this.mTarget = aTargetOrFunc; + this.mTargetFuncArg = aTargetFuncArg; +} + +/** + * event checker that forces preceeding async events to happen before this + * checker. + */ +function orderChecker() +{ + // XXX it doesn't actually work to inherit from invokerChecker, but maybe we + // should fix that? + // this.__proto__ = new invokerChecker(null, null, null, false); +} + +/** + * Generic invoker checker for todo events. + */ +function todo_invokerChecker(aEventType, aTargetOrFunc, aTargetFuncArg) +{ + this.__proto__ = new invokerChecker(aEventType, aTargetOrFunc, + aTargetFuncArg, true); + this.todo = true; +} + +/** + * Generic invoker checker for unexpected events. + */ +function unexpectedInvokerChecker(aEventType, aTargetOrFunc, aTargetFuncArg) +{ + this.__proto__ = new invokerChecker(aEventType, aTargetOrFunc, + aTargetFuncArg, true); + + this.unexpected = true; +} + +/** + * Common invoker checker for async events. + */ +function asyncInvokerChecker(aEventType, aTargetOrFunc, aTargetFuncArg) +{ + this.__proto__ = new invokerChecker(aEventType, aTargetOrFunc, + aTargetFuncArg, true); +} + +function focusChecker(aTargetOrFunc, aTargetFuncArg) +{ + this.__proto__ = new invokerChecker(EVENT_FOCUS, aTargetOrFunc, + aTargetFuncArg, false); + + this.unique = true; // focus event must be unique for invoker action + + this.check = function focusChecker_check(aEvent) + { + testStates(aEvent.accessible, STATE_FOCUSED); + } +} + +function nofocusChecker(aID) +{ + this.__proto__ = new focusChecker(aID); + this.unexpected = true; +} + +/** + * Text inserted/removed events checker. + * @param aFromUser [in, optional] kNotFromUserInput or kFromUserInput + */ +function textChangeChecker(aID, aStart, aEnd, aTextOrFunc, aIsInserted, aFromUser, aAsync) +{ + this.target = getNode(aID); + this.type = aIsInserted ? EVENT_TEXT_INSERTED : EVENT_TEXT_REMOVED; + this.startOffset = aStart; + this.endOffset = aEnd; + this.textOrFunc = aTextOrFunc; + this.async = aAsync; + + this.match = function stextChangeChecker_match(aEvent) + { + if (!(aEvent instanceof nsIAccessibleTextChangeEvent) || + aEvent.accessible !== getAccessible(this.target)) { + return false; + } + + let tcEvent = aEvent.QueryInterface(nsIAccessibleTextChangeEvent); + let modifiedText = (typeof this.textOrFunc === "function") ? + this.textOrFunc() : this.textOrFunc; + return modifiedText === tcEvent.modifiedText; + }; + + this.check = function textChangeChecker_check(aEvent) + { + aEvent.QueryInterface(nsIAccessibleTextChangeEvent); + + var modifiedText = (typeof this.textOrFunc == "function") ? + this.textOrFunc() : this.textOrFunc; + var modifiedTextLen = + (this.endOffset == -1) ? modifiedText.length : aEnd - aStart; + + is(aEvent.start, this.startOffset, + "Wrong start offset for " + prettyName(aID)); + is(aEvent.length, modifiedTextLen, "Wrong length for " + prettyName(aID)); + var changeInfo = (aIsInserted ? "inserted" : "removed"); + is(aEvent.isInserted, aIsInserted, + "Text was " + changeInfo + " for " + prettyName(aID)); + is(aEvent.modifiedText, modifiedText, + "Wrong " + changeInfo + " text for " + prettyName(aID)); + if (typeof aFromUser != "undefined") + is(aEvent.isFromUserInput, aFromUser, + "wrong value of isFromUserInput() for " + prettyName(aID)); + } +} + +/** + * Caret move events checker. + */ +function caretMoveChecker(aCaretOffset, aTargetOrFunc, aTargetFuncArg, + aIsAsync) +{ + this.__proto__ = new invokerChecker(EVENT_TEXT_CARET_MOVED, + aTargetOrFunc, aTargetFuncArg, aIsAsync); + + this.check = function caretMoveChecker_check(aEvent) + { + is(aEvent.QueryInterface(nsIAccessibleCaretMoveEvent).caretOffset, + aCaretOffset, + "Wrong caret offset for " + prettyName(aEvent.accessible)); + } +} + +function asyncCaretMoveChecker(aCaretOffset, aTargetOrFunc, aTargetFuncArg) +{ + this.__proto__ = new caretMoveChecker(aCaretOffset, aTargetOrFunc, + aTargetFuncArg, true); +} + +/** + * Text selection change checker. + */ +function textSelectionChecker(aID, aStartOffset, aEndOffset) +{ + this.__proto__ = new invokerChecker(EVENT_TEXT_SELECTION_CHANGED, aID); + + this.check = function textSelectionChecker_check(aEvent) + { + if (aStartOffset == aEndOffset) { + ok(true, "Collapsed selection triggered text selection change event."); + } else { + testTextGetSelection(aID, aStartOffset, aEndOffset, 0); + } + } +} + +/** + * Object attribute changed checker + */ +function objAttrChangedChecker(aID, aAttr) +{ + this.__proto__ = new invokerChecker(EVENT_OBJECT_ATTRIBUTE_CHANGED, aID); + + this.check = function objAttrChangedChecker_check(aEvent) + { + var event = null; + try { + var event = aEvent.QueryInterface( + nsIAccessibleObjectAttributeChangedEvent); + } catch (e) { + ok(false, "Object attribute changed event was expected"); + } + + if (!event) { + return; + } + + is(event.changedAttribute.toString(), aAttr, + "Wrong attribute name of the object attribute changed event."); + }; + + this.match = function objAttrChangedChecker_match(aEvent) + { + if (aEvent instanceof nsIAccessibleObjectAttributeChangedEvent) { + var scEvent = aEvent.QueryInterface( + nsIAccessibleObjectAttributeChangedEvent); + return (aEvent.accessible == getAccessible(this.target)) && + (scEvent.changedAttribute.toString() == aAttr); + } + return false; + }; +} + +/** + * State change checker. + */ +function stateChangeChecker(aState, aIsExtraState, aIsEnabled, + aTargetOrFunc, aTargetFuncArg, aIsAsync, + aSkipCurrentStateCheck) +{ + this.__proto__ = new invokerChecker(EVENT_STATE_CHANGE, aTargetOrFunc, + aTargetFuncArg, aIsAsync); + + this.check = function stateChangeChecker_check(aEvent) + { + var event = null; + try { + var event = aEvent.QueryInterface(nsIAccessibleStateChangeEvent); + } catch (e) { + ok(false, "State change event was expected"); + } + + if (!event) + return; + + is(event.isExtraState, aIsExtraState, + "Wrong extra state bit of the statechange event."); + isState(event.state, aState, aIsExtraState, + "Wrong state of the statechange event."); + is(event.isEnabled, aIsEnabled, + "Wrong state of statechange event state"); + + if (aSkipCurrentStateCheck) { + todo(false, "State checking was skipped!"); + return; + } + + var state = aIsEnabled ? (aIsExtraState ? 0 : aState) : 0; + var extraState = aIsEnabled ? (aIsExtraState ? aState : 0) : 0; + var unxpdState = aIsEnabled ? 0 : (aIsExtraState ? 0 : aState); + var unxpdExtraState = aIsEnabled ? 0 : (aIsExtraState ? aState : 0); + testStates(event.accessible, state, extraState, unxpdState, unxpdExtraState); + } + + this.match = function stateChangeChecker_match(aEvent) + { + if (aEvent instanceof nsIAccessibleStateChangeEvent) { + var scEvent = aEvent.QueryInterface(nsIAccessibleStateChangeEvent); + return (aEvent.accessible == getAccessible(this.target)) && + (scEvent.state == aState); + } + return false; + } +} + +function asyncStateChangeChecker(aState, aIsExtraState, aIsEnabled, + aTargetOrFunc, aTargetFuncArg) +{ + this.__proto__ = new stateChangeChecker(aState, aIsExtraState, aIsEnabled, + aTargetOrFunc, aTargetFuncArg, true); +} + +/** + * Expanded state change checker. + */ +function expandedStateChecker(aIsEnabled, aTargetOrFunc, aTargetFuncArg) +{ + this.__proto__ = new invokerChecker(EVENT_STATE_CHANGE, aTargetOrFunc, + aTargetFuncArg); + + this.check = function expandedStateChecker_check(aEvent) + { + var event = null; + try { + var event = aEvent.QueryInterface(nsIAccessibleStateChangeEvent); + } catch (e) { + ok(false, "State change event was expected"); + } + + if (!event) + return; + + is(event.state, STATE_EXPANDED, "Wrong state of the statechange event."); + is(event.isExtraState, false, + "Wrong extra state bit of the statechange event."); + is(event.isEnabled, aIsEnabled, + "Wrong state of statechange event state"); + + testStates(event.accessible, + (aIsEnabled ? STATE_EXPANDED : STATE_COLLAPSED)); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Event sequances (array of predefined checkers) + +/** + * Event seq for single selection change. + */ +function selChangeSeq(aUnselectedID, aSelectedID) +{ + if (!aUnselectedID) { + return [ + new stateChangeChecker(STATE_SELECTED, false, true, aSelectedID), + new invokerChecker(EVENT_SELECTION, aSelectedID) + ]; + } + + // Return two possible scenarios: depending on widget type when selection is + // moved the the order of items that get selected and unselected may vary. + return [ + [ + new stateChangeChecker(STATE_SELECTED, false, false, aUnselectedID), + new stateChangeChecker(STATE_SELECTED, false, true, aSelectedID), + new invokerChecker(EVENT_SELECTION, aSelectedID) + ], + [ + new stateChangeChecker(STATE_SELECTED, false, true, aSelectedID), + new stateChangeChecker(STATE_SELECTED, false, false, aUnselectedID), + new invokerChecker(EVENT_SELECTION, aSelectedID) + ] + ]; +} + +/** + * Event seq for item removed form the selection. + */ +function selRemoveSeq(aUnselectedID) +{ + return [ + new stateChangeChecker(STATE_SELECTED, false, false, aUnselectedID), + new invokerChecker(EVENT_SELECTION_REMOVE, aUnselectedID) + ]; +} + +/** + * Event seq for item added to the selection. + */ +function selAddSeq(aSelectedID) +{ + return [ + new stateChangeChecker(STATE_SELECTED, false, true, aSelectedID), + new invokerChecker(EVENT_SELECTION_ADD, aSelectedID) + ]; +} + +//////////////////////////////////////////////////////////////////////////////// +// Private implementation details. +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +// General + +var gA11yEventListeners = {}; +var gA11yEventApplicantsCount = 0; + +var gA11yEventObserver = +{ + observe: function observe(aSubject, aTopic, aData) + { + if (aTopic != "accessible-event") + return; + + var event; + try { + event = aSubject.QueryInterface(nsIAccessibleEvent); + } catch (ex) { + // After a test is aborted (i.e. timed out by the harness), this exception is soon triggered. + // Remove the leftover observer, otherwise it "leaks" to all the following tests. + Services.obs.removeObserver(this, "accessible-event"); + // Forward the exception, with added explanation. + throw "[accessible/events.js, gA11yEventObserver.observe] This is expected if a previous test has been aborted... Initial exception was: [ " + ex + " ]"; + } + var listenersArray = gA11yEventListeners[event.eventType]; + + var eventFromDumpArea = false; + if (gLogger.isEnabled()) { // debug stuff + eventFromDumpArea = true; + + var target = event.DOMNode; + var dumpElm = gA11yEventDumpID ? + document.getElementById(gA11yEventDumpID) : null; + + if (dumpElm) { + var parent = target; + while (parent && parent != dumpElm) + parent = parent.parentNode; + } + + if (!dumpElm || parent != dumpElm) { + var type = eventTypeToString(event.eventType); + var info = "Event type: " + type; + + if (event instanceof nsIAccessibleStateChangeEvent) { + var stateStr = statesToString(event.isExtraState ? 0 : event.state, + event.isExtraState ? event.state : 0); + info += ", state: " + stateStr + ", is enabled: " + event.isEnabled; + + } else if (event instanceof nsIAccessibleTextChangeEvent) { + info += ", start: " + event.start + ", length: " + event.length + + ", " + (event.isInserted ? "inserted" : "removed") + + " text: " + event.modifiedText; + } + + info += ". Target: " + prettyName(event.accessible); + + if (listenersArray) + info += ". Listeners count: " + listenersArray.length; + + if (gLogger.hasFeature("parentchain:" + type)) { + info += "\nParent chain:\n"; + var acc = event.accessible; + while (acc) { + info += " " + prettyName(acc) + "\n"; + acc = acc.parent; + } + } + + eventFromDumpArea = false; + gLogger.log(info); + } + } + + // Do not notify listeners if event is result of event log changes. + if (!listenersArray || eventFromDumpArea) + return; + + for (var index = 0; index < listenersArray.length; index++) + listenersArray[index].handleEvent(event); + } +}; + +function listenA11yEvents(aStartToListen) +{ + if (aStartToListen) { + // Add observer when adding the first applicant only. + if (!(gA11yEventApplicantsCount++)) + Services.obs.addObserver(gA11yEventObserver, "accessible-event", false); + } else { + // Remove observer when there are no more applicants only. + // '< 0' case should not happen, but just in case: removeObserver() will throw. + if (--gA11yEventApplicantsCount <= 0) + Services.obs.removeObserver(gA11yEventObserver, "accessible-event"); + } +} + +function addA11yEventListener(aEventType, aEventHandler) +{ + if (!(aEventType in gA11yEventListeners)) + gA11yEventListeners[aEventType] = new Array(); + + var listenersArray = gA11yEventListeners[aEventType]; + var index = listenersArray.indexOf(aEventHandler); + if (index == -1) + listenersArray.push(aEventHandler); +} + +function removeA11yEventListener(aEventType, aEventHandler) +{ + var listenersArray = gA11yEventListeners[aEventType]; + if (!listenersArray) + return false; + + var index = listenersArray.indexOf(aEventHandler); + if (index == -1) + return false; + + listenersArray.splice(index, 1); + + if (!listenersArray.length) { + gA11yEventListeners[aEventType] = null; + delete gA11yEventListeners[aEventType]; + } + + return true; +} + +/** + * Used to dump debug information. + */ +var gLogger = +{ + /** + * Return true if dump is enabled. + */ + isEnabled: function debugOutput_isEnabled() + { + return gA11yEventDumpID || gA11yEventDumpToConsole || + gA11yEventDumpToAppConsole; + }, + + /** + * Dump information into DOM and console if applicable. + */ + log: function logger_log(aMsg) + { + this.logToConsole(aMsg); + this.logToAppConsole(aMsg); + this.logToDOM(aMsg); + }, + + /** + * Log message to DOM. + * + * @param aMsg [in] the primary message + * @param aHasIndent [in, optional] if specified the message has an indent + * @param aPreEmphText [in, optional] the text is colored and appended prior + * primary message + */ + logToDOM: function logger_logToDOM(aMsg, aHasIndent, aPreEmphText) + { + if (gA11yEventDumpID == "") + return; + + var dumpElm = document.getElementById(gA11yEventDumpID); + if (!dumpElm) { + ok(false, + "No dump element '" + gA11yEventDumpID + "' within the document!"); + return; + } + + var containerTagName = document instanceof nsIDOMHTMLDocument ? + "div" : "description"; + + var container = document.createElement(containerTagName); + if (aHasIndent) + container.setAttribute("style", "padding-left: 10px;"); + + if (aPreEmphText) { + var inlineTagName = document instanceof nsIDOMHTMLDocument ? + "span" : "description"; + var emphElm = document.createElement(inlineTagName); + emphElm.setAttribute("style", "color: blue;"); + emphElm.textContent = aPreEmphText; + + container.appendChild(emphElm); + } + + var textNode = document.createTextNode(aMsg); + container.appendChild(textNode); + + dumpElm.appendChild(container); + }, + + /** + * Log message to console. + */ + logToConsole: function logger_logToConsole(aMsg) + { + if (gA11yEventDumpToConsole) + dump("\n" + aMsg + "\n"); + }, + + /** + * Log message to error console. + */ + logToAppConsole: function logger_logToAppConsole(aMsg) + { + if (gA11yEventDumpToAppConsole) + Services.console.logStringMessage("events: " + aMsg); + }, + + /** + * Return true if logging feature is enabled. + */ + hasFeature: function logger_hasFeature(aFeature) + { + var startIdx = gA11yEventDumpFeature.indexOf(aFeature); + if (startIdx == - 1) + return false; + + var endIdx = startIdx + aFeature.length; + return endIdx == gA11yEventDumpFeature.length || + gA11yEventDumpFeature[endIdx] == ";"; + } +}; + + +//////////////////////////////////////////////////////////////////////////////// +// Sequence + +/** + * Base class of sequence item. + */ +function sequenceItem(aProcessor, aEventType, aTarget, aItemID) +{ + // private + + this.startProcess = function sequenceItem_startProcess() + { + this.queue.invoke(); + } + + var item = this; + + this.queue = new eventQueue(); + this.queue.onFinish = function() + { + aProcessor.onProcessed(); + return DO_NOT_FINISH_TEST; + } + + var invoker = { + invoke: function invoker_invoke() { + return aProcessor.process(); + }, + getID: function invoker_getID() + { + return aItemID; + }, + eventSeq: [ new invokerChecker(aEventType, aTarget) ] + }; + + this.queue.push(invoker); +} + +//////////////////////////////////////////////////////////////////////////////// +// Event queue invokers + +/** + * Invoker base class for prepare an action. + */ +function synthAction(aNodeOrID, aEventsObj) +{ + this.DOMNode = getNode(aNodeOrID); + + if (aEventsObj) { + var scenarios = null; + if (aEventsObj instanceof Array) { + if (aEventsObj[0] instanceof Array) + scenarios = aEventsObj; // scenarios + else + scenarios = [ aEventsObj ]; // event sequance + } else { + scenarios = [ [ aEventsObj ] ]; // a single checker object + } + + for (var i = 0; i < scenarios.length; i++) + defineScenario(this, scenarios[i]); + } + + this.getID = function synthAction_getID() + { return prettyName(aNodeOrID) + " action"; } +} diff --git a/accessible/tests/mochitest/events/a11y.ini b/accessible/tests/mochitest/events/a11y.ini new file mode 100644 index 000000000..4ea7c9d10 --- /dev/null +++ b/accessible/tests/mochitest/events/a11y.ini @@ -0,0 +1,67 @@ +[DEFAULT] +support-files = + docload_wnd.html + focus.html + scroll.html + !/accessible/tests/mochitest/*.js + !/accessible/tests/mochitest/letters.gif + +[test_aria_alert.html] +[test_aria_menu.html] +[test_aria_objattr.html] +[test_aria_owns.html] +[test_aria_statechange.html] +[test_attrs.html] +[test_bug1322593.html] +[test_bug1322593-2.html] +[test_caretmove.html] +[test_caretmove.xul] +[test_coalescence.html] +[test_contextmenu.html] +[test_descrchange.html] +[test_docload.html] +[test_docload.xul] +skip-if = buildapp == 'mulet' +[test_docload_aria.html] +[test_dragndrop.html] +[test_flush.html] +[test_focus_aria_activedescendant.html] +[test_focus_autocomplete.xul] +# Disabled on Linux and Windows due to frequent failures - bug 695019, bug 890795 +skip-if = os == 'win' || os == 'linux' +[test_focus_browserui.xul] +[test_focus_canvas.html] +[test_focus_contextmenu.xul] +[test_focus_controls.html] +[test_focus_dialog.html] +[test_focus_doc.html] +[test_focus_general.html] +[test_focus_general.xul] +[test_focus_listcontrols.xul] +[test_focus_menu.xul] +[test_focus_name.html] +[test_focus_selects.html] +[test_focus_tabbox.xul] +[test_focus_tree.xul] +[test_fromUserInput.html] +[test_label.xul] +[test_menu.xul] +[test_mutation.html] +[test_mutation.xhtml] +[test_namechange.xul] +[test_namechange.html] +[test_scroll.xul] +[test_scroll_caret.xul] +[test_selection.html] +skip-if = buildapp == 'mulet' || os == 'mac' +[test_selection.xul] +skip-if = os == 'mac' +[test_selection_aria.html] +[test_statechange.html] +[test_text.html] +[test_text_alg.html] +[test_textattrchange.html] +[test_textselchange.html] +[test_tree.xul] +[test_valuechange.html] +skip-if = os == 'mac' diff --git a/accessible/tests/mochitest/events/docload_wnd.html b/accessible/tests/mochitest/events/docload_wnd.html new file mode 100644 index 000000000..86ddfac5e --- /dev/null +++ b/accessible/tests/mochitest/events/docload_wnd.html @@ -0,0 +1,39 @@ + + + Accessible events testing for document + + + + + + + diff --git a/accessible/tests/mochitest/events/focus.html b/accessible/tests/mochitest/events/focus.html new file mode 100644 index 000000000..ab055df82 --- /dev/null +++ b/accessible/tests/mochitest/events/focus.html @@ -0,0 +1,10 @@ + + + + editable document + + + + editable document + + diff --git a/accessible/tests/mochitest/events/scroll.html b/accessible/tests/mochitest/events/scroll.html new file mode 100644 index 000000000..562e0a382 --- /dev/null +++ b/accessible/tests/mochitest/events/scroll.html @@ -0,0 +1,181 @@ + + + + nsIAccessible actions testing for anchors + + + +

    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    +

    + link1 + +

    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    +

    + +

    heading 1

    +

    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    + text text text text text text text text text text text text text text
    +

    + + diff --git a/accessible/tests/mochitest/events/test_aria_alert.html b/accessible/tests/mochitest/events/test_aria_alert.html new file mode 100644 index 000000000..2dab35723 --- /dev/null +++ b/accessible/tests/mochitest/events/test_aria_alert.html @@ -0,0 +1,92 @@ + + + + ARIA alert event testing + + + + + + + + + + + + + + + + + Mozilla Bug 591199 + + +

    + +
    +  
    + + + diff --git a/accessible/tests/mochitest/events/test_aria_menu.html b/accessible/tests/mochitest/events/test_aria_menu.html new file mode 100644 index 000000000..5ac595ebf --- /dev/null +++ b/accessible/tests/mochitest/events/test_aria_menu.html @@ -0,0 +1,285 @@ + + + + ARIA menu events testing + + + + + + + + + + + + + + + + + + Bug 606207 + + + Bug 614829 + + + Bug 615189 + + + Bug 673958 + + + Bug 933322 + + + Bug 934460 + + + Bug 970005 + + +

    + +
    +  
    + + + +
    outsidemenu
    + + + + + + + + + + + + + +
    Obla
    + +
    + + + diff --git a/accessible/tests/mochitest/events/test_aria_objattr.html b/accessible/tests/mochitest/events/test_aria_objattr.html new file mode 100644 index 000000000..5f16ba794 --- /dev/null +++ b/accessible/tests/mochitest/events/test_aria_objattr.html @@ -0,0 +1,118 @@ + + + + Accessible ARIA object attribute changes + + + + + + + + + + + + + + + + Mozilla Bug 581096 + + + + Mozilla Bug 640707 + + + + Mozilla Bug 563862 + + +

    + +
    +  
    +
    + +
    Hi
    there
    + +
    aria-sort
    + +
    Fat free cheese
    + + diff --git a/accessible/tests/mochitest/events/test_aria_owns.html b/accessible/tests/mochitest/events/test_aria_owns.html new file mode 100644 index 000000000..a415a6d8d --- /dev/null +++ b/accessible/tests/mochitest/events/test_aria_owns.html @@ -0,0 +1,129 @@ + + + + Aria-owns targets shouldn't be on invalidation list so shouldn't have + show/hide events + + + + + + + + + + + + + + + + + Mozilla Bug 1296420 +
    + +
    +
    + +
    +
    + + + diff --git a/accessible/tests/mochitest/events/test_aria_statechange.html b/accessible/tests/mochitest/events/test_aria_statechange.html new file mode 100644 index 000000000..d8c833157 --- /dev/null +++ b/accessible/tests/mochitest/events/test_aria_statechange.html @@ -0,0 +1,208 @@ + + + + ARIA state change event testing + + + + + + + + + + + + + + + + + Mozilla Bug 551684 +
    + + Mozilla Bug 648133 +
    + + Mozilla Bug 467143 + + + Mozilla Bug 989958 + + + Mozilla Bug 1136563 + + +

    + +
    +  
    +
    + + + + + + +
    A document
    + + +
    + + + + +
    + + diff --git a/accessible/tests/mochitest/events/test_attrs.html b/accessible/tests/mochitest/events/test_attrs.html new file mode 100644 index 000000000..1d5577572 --- /dev/null +++ b/accessible/tests/mochitest/events/test_attrs.html @@ -0,0 +1,90 @@ + + + + Event object attributes tests + + + + + + + + + + + + + + + + + Mozilla Bug 540285 + +

    + +
    +  
    + + + + +
    + + diff --git a/accessible/tests/mochitest/events/test_bug1322593-2.html b/accessible/tests/mochitest/events/test_bug1322593-2.html new file mode 100644 index 000000000..20136d393 --- /dev/null +++ b/accessible/tests/mochitest/events/test_bug1322593-2.html @@ -0,0 +1,83 @@ + + + + Accessible mutation events testing + + + + + + + + + + + + + + + + Mozilla Bug 1322593 + + +

    + +
    +  
    + +
    + hello + your + world +
    + + diff --git a/accessible/tests/mochitest/events/test_bug1322593.html b/accessible/tests/mochitest/events/test_bug1322593.html new file mode 100644 index 000000000..38786d0b9 --- /dev/null +++ b/accessible/tests/mochitest/events/test_bug1322593.html @@ -0,0 +1,80 @@ + + + + Accessible mutation events testing + + + + + + + + + + + + + + + + Mozilla Bug 1322593 + + +

    + +
    +  
    + +
    hello
    +
    world
    + + diff --git a/accessible/tests/mochitest/events/test_caretmove.html b/accessible/tests/mochitest/events/test_caretmove.html new file mode 100644 index 000000000..6d39c4ef6 --- /dev/null +++ b/accessible/tests/mochitest/events/test_caretmove.html @@ -0,0 +1,140 @@ + + + + Accessible caret move events testing + + + + + + + + + + + + + + + + Bug 454377 + + + Bug 567571 + + + Bug 824901 + +

    + +
    +  
    + + + +

    text
    text

    +

    text

    text

    + +

    textohoho

    +

    textohoho

    +

    +

    + + + +
    + + diff --git a/accessible/tests/mochitest/events/test_caretmove.xul b/accessible/tests/mochitest/events/test_caretmove.xul new file mode 100644 index 000000000..cf4dcd483 --- /dev/null +++ b/accessible/tests/mochitest/events/test_caretmove.xul @@ -0,0 +1,72 @@ + + + + + + + + + + + + Mozilla Bug 634240 + +

    + +
    +      
    + + + + + + + +
    +
    diff --git a/accessible/tests/mochitest/events/test_coalescence.html b/accessible/tests/mochitest/events/test_coalescence.html new file mode 100644 index 000000000..d95ef99b0 --- /dev/null +++ b/accessible/tests/mochitest/events/test_coalescence.html @@ -0,0 +1,864 @@ + + + + Accessible mutation events coalescence testing + + + + + + + + + + + + + + + + + Mozilla Bug 513213 +
    + + Mozilla Bug 570275 + + +

    + +
    +  
    + +
    + + + + + + + + + + + + + +
    + +
    +
    +
    +
    +
    +
    + +
    +
    +
    opt
    +
    +
    + +
    +
    +
    opt1
    +
    opt2
    +
    +
    + +
    +
    btn
    +
    +
    opt
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + diff --git a/accessible/tests/mochitest/events/test_contextmenu.html b/accessible/tests/mochitest/events/test_contextmenu.html new file mode 100644 index 000000000..065e1b50e --- /dev/null +++ b/accessible/tests/mochitest/events/test_contextmenu.html @@ -0,0 +1,139 @@ + + + + Context menu tests + + + + + + + + + + + + + + + + + + Mozilla Bug 580535 +
    + +

    + +
    +  
    + + + +
    + + diff --git a/accessible/tests/mochitest/events/test_descrchange.html b/accessible/tests/mochitest/events/test_descrchange.html new file mode 100644 index 000000000..d51318532 --- /dev/null +++ b/accessible/tests/mochitest/events/test_descrchange.html @@ -0,0 +1,85 @@ + + + + Accessible description change event testing + + + + + + + + + + + + + + + + + + Bug 991969 + + +

    + +
    +  
    + + + + +
    + + diff --git a/accessible/tests/mochitest/events/test_docload.html b/accessible/tests/mochitest/events/test_docload.html new file mode 100644 index 000000000..a530592ee --- /dev/null +++ b/accessible/tests/mochitest/events/test_docload.html @@ -0,0 +1,360 @@ + + + + Accessible events testing for document + + + + + + + + + + + + + + + + + + + + Mozilla Bug 420845 +
    + + Mozilla Bug 506206 +
    + + Mozilla Bug 566103 +
    + + Mozilla Bug 571459 + + + Mozilla Bug 658185 + + + Mozilla Bug 754165 + + +

    + +
    +  
    + +
    +
    +
    + + diff --git a/accessible/tests/mochitest/events/test_docload.xul b/accessible/tests/mochitest/events/test_docload.xul new file mode 100644 index 000000000..4b07b0e72 --- /dev/null +++ b/accessible/tests/mochitest/events/test_docload.xul @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + Mozilla Bug 566103 + + + Mozilla Bug 754165 + +

    + +
    +    
    + + + +
    +
    diff --git a/accessible/tests/mochitest/events/test_docload_aria.html b/accessible/tests/mochitest/events/test_docload_aria.html new file mode 100644 index 000000000..c5f470aee --- /dev/null +++ b/accessible/tests/mochitest/events/test_docload_aria.html @@ -0,0 +1,83 @@ + + + + Accessible events testing for ARIA document + + + + + + + + + + + + + + + + + Mozilla Bug 759833 + + +

    + +
    +  
    + + + + + diff --git a/accessible/tests/mochitest/events/test_dragndrop.html b/accessible/tests/mochitest/events/test_dragndrop.html new file mode 100644 index 000000000..cfba80a46 --- /dev/null +++ b/accessible/tests/mochitest/events/test_dragndrop.html @@ -0,0 +1,110 @@ + + + + Accessible drag and drop event testing + + + + + + + + + + + + + + + + + Mozilla Bug 510441 + + +

    + +
    +  
    +
    + + +
    button
    + + +
    button
    + + diff --git a/accessible/tests/mochitest/events/test_flush.html b/accessible/tests/mochitest/events/test_flush.html new file mode 100644 index 000000000..44a9afd94 --- /dev/null +++ b/accessible/tests/mochitest/events/test_flush.html @@ -0,0 +1,77 @@ + + + + Flush delayed events testing + + + + + + + + + + + + + + + + Mozilla Bug 477551 + + +

    + +
    +  
    + + + + + diff --git a/accessible/tests/mochitest/events/test_focus_aria_activedescendant.html b/accessible/tests/mochitest/events/test_focus_aria_activedescendant.html new file mode 100644 index 000000000..4cd57fe3b --- /dev/null +++ b/accessible/tests/mochitest/events/test_focus_aria_activedescendant.html @@ -0,0 +1,120 @@ + + + + + aria-activedescendant focus tests + + + + + + + + + + + + + + + Mozilla Bug 429547 + + + Mozilla Bug 761102 + +

    + +
    +  
    + +
    +
    item1
    +
    item2
    +
    +
    item3
    + +
    + +
      +
    • option1
    • +
    • option2
    • +
    +
    + + diff --git a/accessible/tests/mochitest/events/test_focus_autocomplete.xul b/accessible/tests/mochitest/events/test_focus_autocomplete.xul new file mode 100644 index 000000000..2a32a6587 --- /dev/null +++ b/accessible/tests/mochitest/events/test_focus_autocomplete.xul @@ -0,0 +1,518 @@ + + + + + + + + + + + + + + + + + Mozilla Bug 383759 + + + Mozilla Bug 673958 + + + Mozilla Bug 559766 + +

    + +
    +      
    + + + + + + + + + + + + + +
    + + diff --git a/accessible/tests/mochitest/events/test_focus_doc.html b/accessible/tests/mochitest/events/test_focus_doc.html new file mode 100644 index 000000000..bd4934d84 --- /dev/null +++ b/accessible/tests/mochitest/events/test_focus_doc.html @@ -0,0 +1,95 @@ + + + + Accessible document focus event testing + + + + + + + + + + + + + + + + + + Mozilla Bug 512058 + + + Mozilla Bug 512059 + + + Mozilla Bug 618046 + + +

    + +
    +  
    + +
    + +
    + + + + +
    + + diff --git a/accessible/tests/mochitest/events/test_focus_general.html b/accessible/tests/mochitest/events/test_focus_general.html new file mode 100644 index 000000000..e881a5a4f --- /dev/null +++ b/accessible/tests/mochitest/events/test_focus_general.html @@ -0,0 +1,179 @@ + + + + Accessible focus testing + + + + + + + + + + + + + + + + + Mozilla Bug 352220 + + + Mozilla Bug 550338 + + + Mozilla Bug 673958 + + + Mozilla Bug 961696 + +

    + +
    +  
    + +
    editable area
    + + + link + + + + + + + + +
    + + diff --git a/accessible/tests/mochitest/events/test_focus_general.xul b/accessible/tests/mochitest/events/test_focus_general.xul new file mode 100644 index 000000000..f72834f39 --- /dev/null +++ b/accessible/tests/mochitest/events/test_focus_general.xul @@ -0,0 +1,179 @@ + + + + + + + + + + + + Mozilla Bug 492518 + + + Mozilla Bug 552368 + +

    + +
    +      
    + + + + + + + + + + diff --git a/accessible/tests/mochitest/events/test_mutation.xhtml b/accessible/tests/mochitest/events/test_mutation.xhtml new file mode 100644 index 000000000..e1aabe612 --- /dev/null +++ b/accessible/tests/mochitest/events/test_mutation.xhtml @@ -0,0 +1,97 @@ + + + + Accessible mutation events testing + + + + + + + + + + + + + + + + + + + + + + + + Mozilla Bug 646369 + +

    + +
    +  
    +
    + +
    + + diff --git a/accessible/tests/mochitest/events/test_namechange.html b/accessible/tests/mochitest/events/test_namechange.html new file mode 100644 index 000000000..935d865e9 --- /dev/null +++ b/accessible/tests/mochitest/events/test_namechange.html @@ -0,0 +1,123 @@ + + + + Accessible name change event testing + + + + + + + + + + + + + + + + + + Bug 991969 + + +

    + +
    +  
    + + + + + + +
    + + diff --git a/accessible/tests/mochitest/events/test_namechange.xul b/accessible/tests/mochitest/events/test_namechange.xul new file mode 100644 index 000000000..9d688585c --- /dev/null +++ b/accessible/tests/mochitest/events/test_namechange.xul @@ -0,0 +1,92 @@ + + + + + + + + + + + + + Mozilla Bug 986054 + + +

    + +
    +      
    + + + + + + + +
    +
    diff --git a/accessible/tests/mochitest/events/test_scroll.xul b/accessible/tests/mochitest/events/test_scroll.xul new file mode 100644 index 000000000..e33161376 --- /dev/null +++ b/accessible/tests/mochitest/events/test_scroll.xul @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + Mozilla Bug 691734 + + +

    + +
    +      
    + + + +
    +
    diff --git a/accessible/tests/mochitest/events/test_scroll_caret.xul b/accessible/tests/mochitest/events/test_scroll_caret.xul new file mode 100644 index 000000000..57e27747f --- /dev/null +++ b/accessible/tests/mochitest/events/test_scroll_caret.xul @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + Mozilla Bug 1056459 + + +

    + +
    +      
    + + + +
    +
    diff --git a/accessible/tests/mochitest/events/test_selection.html b/accessible/tests/mochitest/events/test_selection.html new file mode 100644 index 000000000..de25fedc3 --- /dev/null +++ b/accessible/tests/mochitest/events/test_selection.html @@ -0,0 +1,118 @@ + + + + Accessible selection event testing + + + + + + + + + + + + + + + + + + Bug 414302 + + + Bug 810268 + + +

    + +
    +  
    + + + + + +

    Pizza

    + + + diff --git a/accessible/tests/mochitest/events/test_selection.xul b/accessible/tests/mochitest/events/test_selection.xul new file mode 100644 index 000000000..2b0c388ff --- /dev/null +++ b/accessible/tests/mochitest/events/test_selection.xul @@ -0,0 +1,255 @@ + + + + + + + + + + + + Mozilla Bug 414302 + +

    + +
    +      
    + + + + + + + + + + + + + +
    +
    + + + +
    +
    +
    + + diff --git a/accessible/tests/mochitest/jsat/doc_content_text.html b/accessible/tests/mochitest/jsat/doc_content_text.html new file mode 100644 index 000000000..4e73dc6e7 --- /dev/null +++ b/accessible/tests/mochitest/jsat/doc_content_text.html @@ -0,0 +1,15 @@ + + + + Text content test document + + + +

    These are my awards, Mother. From Army. + The seal is for marksmanship, and the gorilla is for sand racing.

    +

    You're a good guy, mon frere. That means brother in French. + I don't know how I know that. I took four years of Spanish.

    + + + + \ No newline at end of file diff --git a/accessible/tests/mochitest/jsat/doc_traversal.html b/accessible/tests/mochitest/jsat/doc_traversal.html new file mode 100644 index 000000000..4c104b6b7 --- /dev/null +++ b/accessible/tests/mochitest/jsat/doc_traversal.html @@ -0,0 +1,164 @@ + + + + Traversal Rule test document + + + + +
    +

    A small first heading

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +

    A larger second

    +
    ARIA is fun
    + +
    ARIA fun
    +
    My little togglebutton
    +
    ARIA fun
    +
    +

    Invisible header

    +
    +
    Programming Language
    +
    A esoteric weapon wielded by only the most formidable warriors, + for its unrelenting strict power is unfathomable.
    +
    + +
    +
    The last (visible) one!
    + + stuff + +
    +
    + + Link + Words + Link the second + Sentences + Link the third +
    +
    +
    + + + + + + + + + +
    31
    41
    +
    +
      +
    1. +
    2. S
    3. +
    4. M
    5. +
    +
      +
    1. 1
    2. +
    3. 3
    4. +
    5. 4
      7
    6. +
    +
      +
    1. 2
    2. +
    3. 5
      8
    4. +
    5. + 6 +
    6. +
    +
    + + + + + + + + + + + + + + + + + + + + +
    Dirty WordsMeaning
    MudWet Dirt
    DirtMessy Stuff
    + + + +

    This is a MathML formula + + x+1 + 3/4 + + with some text after.

    + + diff --git a/accessible/tests/mochitest/jsat/dom_helper.js b/accessible/tests/mochitest/jsat/dom_helper.js new file mode 100644 index 000000000..c95d19dc1 --- /dev/null +++ b/accessible/tests/mochitest/jsat/dom_helper.js @@ -0,0 +1,209 @@ +'use strict'; + +/* global getMainChromeWindow, AccessFuTest, GestureSettings, GestureTracker, + SimpleTest, getBoundsForDOMElm, Point, Utils */ +/* exported loadJSON, eventMap */ + +var Ci = Components.interfaces; +var Cu = Components.utils; + +Cu.import('resource://gre/modules/Geometry.jsm'); + +var win = getMainChromeWindow(window); + +/** + * Convert inch based point coordinates into pixels. + * @param {Array} aPoints Array of coordinates in inches. + * @return {Array} Array of coordinates in pixels. + */ +function convertPointCoordinates(aPoints) { + var dpi = Utils.dpi; + return aPoints.map(function convert(aPoint) { + return { + x: aPoint.x * dpi, + y: aPoint.y * dpi, + identifier: aPoint.identifier + }; + }); +} + +/** + * For a given list of points calculate their coordinates in relation to the + * document body. + * @param {Array} aTouchPoints An array of objects of the following format: { + * base: {String}, // Id of an element to server as a base for the touch. + * x: {Number}, // An optional x offset from the base element's geometric + * // centre. + * y: {Number} // An optional y offset from the base element's geometric + * // centre. + * } + * @return {JSON} An array of {x, y} coordinations. + */ +function calculateTouchListCoordinates(aTouchPoints) { + var coords = []; + for (var i = 0, target = aTouchPoints[i]; i < aTouchPoints.length; ++i) { + var bounds = getBoundsForDOMElm(target.base); + var parentBounds = getBoundsForDOMElm('root'); + var point = new Point(target.x || 0, target.y || 0); + point.scale(Utils.dpi); + point.add(bounds[0], bounds[1]); + point.add(bounds[2] / 2, bounds[3] / 2); + point.subtract(parentBounds[0], parentBounds[0]); + coords.push({ + x: point.x, + y: point.y + }); + } + return coords; +} + +/** + * Send a touch event with specified touchPoints. + * @param {Array} aTouchPoints An array of points to be associated with + * touches. + * @param {String} aName A name of the touch event. + */ +function sendTouchEvent(aTouchPoints, aName) { + var touchList = sendTouchEvent.touchList; + if (aName === 'touchend') { + sendTouchEvent.touchList = null; + } else { + var coords = calculateTouchListCoordinates(aTouchPoints); + var touches = []; + for (var i = 0; i < coords.length; ++i) { + var {x, y} = coords[i]; + var node = document.elementFromPoint(x, y); + var touch = document.createTouch(window, node, aName === 'touchstart' ? + 1 : touchList.item(i).identifier, x, y, x, y); + touches.push(touch); + } + touchList = document.createTouchList(touches); + sendTouchEvent.touchList = touchList; + } + var evt = document.createEvent('TouchEvent'); + evt.initTouchEvent(aName, true, true, window, 0, false, false, false, false, + touchList, touchList, touchList); + document.dispatchEvent(evt); +} + +sendTouchEvent.touchList = null; + +/** + * A map of event names to the functions that actually send them. + * @type {Object} + */ +var eventMap = { + touchstart: sendTouchEvent, + touchend: sendTouchEvent, + touchmove: sendTouchEvent +}; + +/** + * Attach a listener for the mozAccessFuGesture event that tests its + * type. + * @param {Array} aExpectedGestures A stack of expected event types. + * @param {String} aTitle Title of this sequence, if any. + * Note: the listener is removed once the stack reaches 0. + */ +function testMozAccessFuGesture(aExpectedGestures, aTitle) { + var types = aExpectedGestures; + function handleGesture(aEvent) { + if (aEvent.detail.type !== types[0].type) { + info('Got ' + aEvent.detail.type + ' waiting for ' + types[0].type); + // The is not the event of interest. + return; + } + is(!!aEvent.detail.edge, !!types[0].edge); + is(aEvent.detail.touches.length, types[0].fingers || 1, + 'failed to count fingers: ' + types[0].type); + ok(true, 'Received correct mozAccessFuGesture: ' + + JSON.stringify(types.shift()) + '. (' + aTitle + ')'); + if (types.length === 0) { + win.removeEventListener('mozAccessFuGesture', handleGesture); + if (AccessFuTest.sequenceCleanup) { + AccessFuTest.sequenceCleanup(); + } + AccessFuTest.nextTest(); + } + } + win.addEventListener('mozAccessFuGesture', handleGesture); +} + +/** + * Reset the thresholds and max delays that affect gesture rejection. + * @param {Number} aTimeStamp Gesture time stamp. + * @param {Boolean} aRemoveDwellThreshold An optional flag to reset dwell + * threshold. + * @param {Boolean} aRemoveSwipeMaxDuration An optional flag to reset swipe max + * duration. + */ +function setTimers(aTimeStamp, aRemoveDwellThreshold, aRemoveSwipeMaxDuration) { + if (!aRemoveDwellThreshold && !aRemoveSwipeMaxDuration) { + return; + } + if (aRemoveDwellThreshold) { + GestureSettings.dwellThreshold = 0; + } + if (aRemoveSwipeMaxDuration) { + GestureSettings.swipeMaxDuration = 0; + } + GestureTracker.current.clearTimer(); + GestureTracker.current.startTimer(aTimeStamp); +} + +function resetTimers(aRemoveGestureResolveDelay) { + GestureSettings.dwellThreshold = AccessFuTest.dwellThreshold; + GestureSettings.swipeMaxDuration = AccessFuTest.swipeMaxDuration; + GestureSettings.maxGestureResolveTimeout = aRemoveGestureResolveDelay ? + 0 : AccessFuTest.maxGestureResolveTimeout; +} + +/** + * An extention to AccessFuTest that adds an ability to test a sequence of + * pointer events and their expected mozAccessFuGesture events. + * @param {Object} aSequence An object that has a list of pointer events to be + * generated and the expected mozAccessFuGesture events. + */ +AccessFuTest.addSequence = function AccessFuTest_addSequence(aSequence) { + AccessFuTest.addFunc(function testSequence() { + testMozAccessFuGesture(aSequence.expectedGestures, aSequence.title); + var events = aSequence.events; + function fireEvent(aEvent) { + var event = { + points: convertPointCoordinates(aEvent.points), + type: aEvent.type + }; + var timeStamp = Date.now(); + resetTimers(aEvent.removeGestureResolveDelay); + GestureTracker.handle(event, timeStamp); + setTimers(timeStamp, aEvent.removeDwellThreshold, + aEvent.removeSwipeMaxDuration); + processEvents(); + } + function processEvents() { + if (events.length === 0) { + return; + } + var event = events.shift(); + SimpleTest.executeSoon(function() { + fireEvent(event); + }); + } + processEvents(); + }); +}; + +/** + * A helper function that loads JSON files. + * @param {String} aPath A path to a JSON file. + * @param {Function} aCallback A callback to be called on success. + */ +function loadJSON(aPath, aCallback) { + var request = new XMLHttpRequest(); + request.open('GET', aPath, true); + request.responseType = 'json'; + request.onload = function onload() { + aCallback(request.response); + }; + request.send(); +} diff --git a/accessible/tests/mochitest/jsat/gestures.json b/accessible/tests/mochitest/jsat/gestures.json new file mode 100644 index 000000000..111994342 --- /dev/null +++ b/accessible/tests/mochitest/jsat/gestures.json @@ -0,0 +1,352 @@ +[ + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeGestureResolveDelay": true } + ], + "expectedGestures": [{ "type": "tap" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.03, "y": 1.03, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.03, "y": 1.03, "identifier": 1}], + "removeGestureResolveDelay": true } + ], + "expectedGestures": [{ "type": "tap" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeDwellThreshold": true}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "dwell" }, { "type": "dwellend" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.03, "y": 1.02, "identifier": 1}]}, + {"type": "pointerup", + "points": [{"x": 1.03, "y": 1.02, "identifier": 1}]}, + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 0.97, "y": 1.01, "identifier": 1}]}, + {"type": "pointerup", + "points": [{"x": 0.97, "y": 1.01, "identifier": 1}], + "removeGestureResolveDelay": true } + ], + "expectedGestures": [{ "type": "doubletap" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeGestureResolveDelay": true } + ], + "expectedGestures": [{ "type": "tripletap" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeDwellThreshold": true}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "doubletaphold" }, + { "type": "doubletapholdend" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeDwellThreshold": true}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "taphold" }, { "type": "tapholdend" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swiperight" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1.15, "y": 1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1.3, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.3, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swiperight" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1.5, "y": 1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swipeleft" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 1.5, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1.5, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swipedown" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swipeup" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.5, "y": 1.1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1.1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swiperight" }] + }, + { + "events": [ + {"type": "pointerdown", + "points": [{"x": 1.5, "y": 1.1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 0.95, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 0.95, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swipeleft" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 0.9, "y": 1.5, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 0.9, "y": 1.5, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swipedown" }] + }, + { + "events": [ + {"type": "pointerdown", + "points": [{"x": 1.1, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "swipeup" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}, + {"x": 1, "y": 1.5, "identifier": 2}]}, + {"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}]} + ], + "expectedGestures": [{ "type": "swiperight", "fingers": 2 }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}, + {"x": 1, "y": 1.5, "identifier": 2}]}, + {"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1.5, "identifier": 2}]} + ], + "expectedGestures": [{ "type": "swiperight", "fingers": 2 }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}, + {"x": 1, "y": 1.5, "identifier": 2}, + {"x": 1, "y": 2, "identifier": 3}]}, + {"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}, + {"x": 1.5, "y": 2, "identifier": 3}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}, + {"x": 1.5, "y": 2, "identifier": 3}]} + ], + "expectedGestures": [{ "type": "swiperight", "fingers": 3 }] + }, + { + "events": [ + {"type": "pointerdown", + "points": [{"x": 1.6, "y": 1.5, "identifier": 1}], + "removeDwellThreshold": true}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "dwell" }, { "type": "explore" }, + { "type": "exploreend" }] + }, + { + "events": [ + {"type": "pointerdown", + "points": [{"x": 1.6, "y": 1.5, "identifier": 1}], + "removeDwellThreshold": true}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 2, "y": 2, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 2, "y": 2, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "dwell" }, { "type": "explore" }, + { "type": "explore" }, { "type": "exploreend" }] + }, + { + "events": [ + {"type": "pointerdown", + "points": [{"x": 1.6, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeSwipeMaxDuration": true}, + {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "explore" }, { "type": "exploreend" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeSwipeMaxDuration": true}, + {"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "explore" }, { "type": "explore" }, + { "type": "exploreend" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}], + "removeDwellThreshold": true}, + {"type": "pointermove", + "points": [{"x": 1.5, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.55, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.6, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.65, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.7, "y": 1.5, "identifier": 1}]}, + {"type": "pointermove", + "points": [{"x": 1.75, "y": 1.5, "identifier": 1}]}, + {"type": "pointerup", "points": [{"x": 1.75, "y": 1.5, "identifier": 1}]} + ], + "expectedGestures": [{ "type": "dwell" }, { "type": "explore" }, + { "type": "explore" }, { "type": "exploreend" }] + }, + { + "events": [ + {"type": "pointerdown", "points": [{"x": 0.075, "y": 1, "identifier": 1}, + {"x": 1, "y": 1.5, "identifier": 2}]}, + {"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}]}, + {"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}, + {"x": 1.5, "y": 1.5, "identifier": 2}]} + ], + "expectedGestures": [{ "type": "swiperight", "edge": true, "fingers": 2 }] + }, + { + "title": "Bug 1182311 - 3 finger triple tap is not reliable 1/2", + "events": [ + {"points": [ + {"y": 1.88467, "x": 0.89311, "identifier": 0}, + {"y": 2.78481, "x": 0.56259, "identifier": 1}, + {"y": 1.35021, "x": 1.37834, "identifier": 2}], "type": "pointerdown"}, + {"points": [ + {"y": 1.88467, "x": 0.89311, "identifier": 0}, + {"y": 2.78481, "x": 0.56259, "identifier": 1}, + {"y": 1.35021, "x": 1.37834, "identifier": 2}], "type": "pointerup"}, + {"points": [ + {"y": 1.76512, "x": 0.98453, "identifier": 0}, + {"y": 1.1744, "x": 1.4346, "identifier": 1}, + {"y": 2.5879, "x": 0.61181, "identifier": 2}], "type": "pointerdown"}, + {"points": [ + {"y": 1.76512, "x": 0.98453, "identifier": 0}, + {"y": 1.1744, "x": 1.4346, "identifier": 1}, + {"y": 2.5879, "x": 0.61181, "identifier": 2}], "type": "pointerup"}, + {"points": [ + {"y": 1.30098, "x": 1.52602, "identifier": 0}, + {"y": 1.94093, "x": 1.02672, "identifier": 1}, + {"y": 2.67229, "x": 0.75246, "identifier": 2}], "type": "pointerdown"}, + {"points": [ + {"y": 1.30098, "x": 1.52602, "identifier": 0}, + {"y": 1.94093, "x": 1.02672, "identifier": 1}, + {"y": 2.67229, "x": 0.75246, "identifier": 2}], "type": "pointerup", + "removeGestureResolveDelay": true}], + "expectedGestures": [{ "type": "tripletap", "fingers": 3 }] + }, + { + "title": "Bug 1182311 - 3 finger triple tap is not reliable 2/2", + "events": [ + {"type": "pointerdown", + "points": [{"identifier": 0, "x": 2.21875, "y": 1.510417}]}, + {"type": "pointerdown", + "points": [{"identifier": 1, "x": 1.479167, "y": 2.53125}]}, + {"type": "pointerdown", + "points": [{"identifier": 2, "x": 1.072917, "y": 3.739583}]}, + {"type": "pointermove", + "points": [{"identifier": 1, "x": 1.46875, "y": 2.53125}]}, + {"type": "pointermove", + "points": [{"identifier": 1, "x": 1.447917, "y": 2.46875}]}, + {"type": "pointerup", + "points": [{"identifier": 0, "x": 2.21875, "y": 1.510417}]}, + {"type": "pointerup", + "points": [{"identifier": 1, "x": 1.447917, "y": 2.489583}]}, + {"type": "pointerup", + "points": [{"identifier": 2, "x": 1.072917, "y": 3.739583}]}, + {"type": "pointerdown", + "points": [{"identifier": 0, "x": 2.114583, "y": 1.572917}]}, + {"type": "pointerdown", + "points": [{"identifier": 1, "x": 1.364583, "y": 2.614583}]}, + {"type": "pointerdown", + "points": [{"identifier": 2, "x": 0.927083, "y": 3.864583}]}, + {"type": "pointermove", + "points": [{"identifier": 1, "x": 1.364583, "y": 2.614583}]}, + {"type": "pointermove", + "points": [{"identifier": 0, "x": 2.114583, "y": 1.572917}]}, + {"type": "pointerup", + "points": [{"identifier": 1, "x": 1.364583, "y": 2.614583}]}, + {"type": "pointerup", + "points": [{"identifier": 2, "x": 0.927083, "y": 3.864583}]}, + {"type": "pointerup", + "points": [{"identifier": 0, "x": 2.114583, "y": 1.572917}]}, + {"type": "pointerdown", + "points": [{"identifier": 0, "x": 1.4375, "y": 2.59375}]}, + {"type": "pointerdown", + "points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}]}, + {"type": "pointerdown", + "points": [{"identifier": 2, "x": 2.15625, "y": 1.489583}]}, + {"type": "pointermove", + "points": [{"identifier": 0, "x": 1.4375, "y": 2.59375}, + {"identifier": 2, "x": 2.15625, "y": 1.489583}]}, + {"type": "pointermove", + "points": [{"identifier": 0, "x": 1.4375, "y": 2.59375}, + {"identifier": 2, "x": 2.15625, "y": 1.489583}]}, + {"type": "pointerup", + "points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}], + "removeGestureResolveDelay": true} + ], + "expectedGestures": [{ "type": "tripletap", "fingers": 3 }] + } + +] diff --git a/accessible/tests/mochitest/jsat/jsatcommon.js b/accessible/tests/mochitest/jsat/jsatcommon.js new file mode 100644 index 000000000..aa7ee74e4 --- /dev/null +++ b/accessible/tests/mochitest/jsat/jsatcommon.js @@ -0,0 +1,739 @@ +// A common module to run tests on the AccessFu module + +'use strict'; + +/*global isDeeply, getMainChromeWindow, SimpleTest, SpecialPowers, Logger, + AccessFu, Utils, addMessageListener, currentTabDocument, currentBrowser*/ + +/** + * A global variable holding an array of test functions. + */ +var gTestFuncs = []; +/** + * A global Iterator for the array of test functions. + */ +var gIterator; + +Components.utils.import('resource://gre/modules/Services.jsm'); +Components.utils.import("resource://gre/modules/accessibility/Utils.jsm"); +Components.utils.import("resource://gre/modules/accessibility/EventManager.jsm"); +Components.utils.import("resource://gre/modules/accessibility/Gestures.jsm"); + +var AccessFuTest = { + + addFunc: function AccessFuTest_addFunc(aFunc) { + if (aFunc) { + gTestFuncs.push(aFunc); + } + }, + + _registerListener: function AccessFuTest__registerListener(aWaitForMessage, aListenerFunc) { + var listener = { + observe: function observe(aMessage) { + // Ignore unexpected messages. + if (!(aMessage instanceof Components.interfaces.nsIConsoleMessage)) { + return; + } + if (aMessage.message.indexOf(aWaitForMessage) < 0) { + return; + } + aListenerFunc.apply(listener); + } + }; + Services.console.registerListener(listener); + return listener; + }, + + on_log: function AccessFuTest_on_log(aWaitForMessage, aListenerFunc) { + return this._registerListener(aWaitForMessage, aListenerFunc); + }, + + off_log: function AccessFuTest_off_log(aListener) { + Services.console.unregisterListener(aListener); + }, + + once_log: function AccessFuTest_once_log(aWaitForMessage, aListenerFunc) { + return this._registerListener(aWaitForMessage, + function listenAndUnregister() { + Services.console.unregisterListener(this); + aListenerFunc(); + }); + }, + + _addObserver: function AccessFuTest__addObserver(aWaitForData, aListener) { + var listener = function listener(aSubject, aTopic, aData) { + var data = JSON.parse(aData)[1]; + // Ignore non-relevant outputs. + if (!data) { + return; + } + isDeeply(data.details, aWaitForData, "Data is correct"); + aListener.apply(listener); + }; + Services.obs.addObserver(listener, 'accessibility-output', false); + return listener; + }, + + on: function AccessFuTest_on(aWaitForData, aListener) { + return this._addObserver(aWaitForData, aListener); + }, + + off: function AccessFuTest_off(aListener) { + Services.obs.removeObserver(aListener, 'accessibility-output'); + }, + + once: function AccessFuTest_once(aWaitForData, aListener) { + return this._addObserver(aWaitForData, function observerAndRemove() { + Services.obs.removeObserver(this, 'accessibility-output'); + aListener(); + }); + }, + + _waitForExplicitFinish: false, + + waitForExplicitFinish: function AccessFuTest_waitForExplicitFinish() { + this._waitForExplicitFinish = true; + }, + + finish: function AccessFuTest_finish() { + // Disable the console service logging. + Logger.test = false; + Logger.logLevel = Logger.INFO; + // Reset Gesture Settings. + GestureSettings.dwellThreshold = this.dwellThreshold = + this.originalDwellThreshold; + GestureSettings.swipeMaxDuration = this.swipeMaxDuration = + this.originalSwipeMaxDuration; + GestureSettings.maxGestureResolveTimeout = + this.maxGestureResolveTimeout = + this.originalMaxGestureResolveTimeout; + // Finish through idle callback to let AccessFu._disable complete. + SimpleTest.executeSoon(function () { + AccessFu.detach(); + SimpleTest.finish(); + }); + }, + + nextTest: function AccessFuTest_nextTest() { + var result = gIterator.next(); + if (result.done) { + this.finish(); + return; + } + var testFunc = result.value; + testFunc(); + }, + + runTests: function AccessFuTest_runTests(aAdditionalPrefs) { + if (gTestFuncs.length === 0) { + ok(false, "No tests specified!"); + SimpleTest.finish(); + return; + } + + // Create an Iterator for gTestFuncs array. + gIterator = (function*() { + for (var testFunc of gTestFuncs) { + yield testFunc; + } + })(); + + // Start AccessFu and put it in stand-by. + Components.utils.import("resource://gre/modules/accessibility/AccessFu.jsm"); + + AccessFu.attach(getMainChromeWindow(window)); + + AccessFu.readyCallback = function readyCallback() { + // Enable logging to the console service. + Logger.test = true; + Logger.logLevel = Logger.DEBUG; + }; + + var prefs = [['accessibility.accessfu.notify_output', 1], + ['dom.mozSettings.enabled', true]]; + prefs.push.apply(prefs, aAdditionalPrefs); + + this.originalDwellThreshold = GestureSettings.dwellThreshold; + this.originalSwipeMaxDuration = GestureSettings.swipeMaxDuration; + this.originalMaxGestureResolveTimeout = + GestureSettings.maxGestureResolveTimeout; + // https://bugzilla.mozilla.org/show_bug.cgi?id=1001945 - sometimes + // SimpleTest.executeSoon timeout is bigger than the timer settings in + // GestureSettings that causes intermittents. + this.dwellThreshold = GestureSettings.dwellThreshold = + GestureSettings.dwellThreshold * 10; + this.swipeMaxDuration = GestureSettings.swipeMaxDuration = + GestureSettings.swipeMaxDuration * 10; + this.maxGestureResolveTimeout = GestureSettings.maxGestureResolveTimeout = + GestureSettings.maxGestureResolveTimeout * 10; + + SpecialPowers.pushPrefEnv({ 'set': prefs }, function () { + if (AccessFuTest._waitForExplicitFinish) { + // Run all test functions asynchronously. + AccessFuTest.nextTest(); + } else { + // Run all test functions synchronously. + gTestFuncs.forEach(testFunc => testFunc()); + AccessFuTest.finish(); + } + }); + } +}; + +function AccessFuContentTest(aFuncResultPairs) { + this.queue = aFuncResultPairs; +} + +AccessFuContentTest.prototype = { + expected: [], + currentAction: null, + actionNum: -1, + + start: function(aFinishedCallback) { + Logger.logLevel = Logger.DEBUG; + this.finishedCallback = aFinishedCallback; + var self = this; + + // Get top content message manager, and set it up. + this.mms = [Utils.getMessageManager(currentBrowser())]; + this.setupMessageManager(this.mms[0], function () { + // Get child message managers and set them up + var frames = currentTabDocument().querySelectorAll('iframe'); + if (frames.length === 0) { + self.pump(); + return; + } + + var toSetup = 0; + for (var i = 0; i < frames.length; i++ ) { + var mm = Utils.getMessageManager(frames[i]); + if (mm) { + toSetup++; + self.mms.push(mm); + self.setupMessageManager(mm, function () { + if (--toSetup === 0) { + // All message managers are loaded and ready to go. + self.pump(); + } + }); + } + } + }); + }, + + finish: function() { + Logger.logLevel = Logger.INFO; + for (var mm of this.mms) { + mm.sendAsyncMessage('AccessFu:Stop'); + mm.removeMessageListener('AccessFu:Present', this); + mm.removeMessageListener('AccessFu:Input', this); + mm.removeMessageListener('AccessFu:CursorCleared', this); + mm.removeMessageListener('AccessFu:Focused', this); + mm.removeMessageListener('AccessFu:AriaHidden', this); + mm.removeMessageListener('AccessFu:Ready', this); + mm.removeMessageListener('AccessFu:ContentStarted', this); + } + if (this.finishedCallback) { + this.finishedCallback(); + } + }, + + setupMessageManager: function (aMessageManager, aCallback) { + function contentScript() { + addMessageListener('AccessFuTest:Focus', function (aMessage) { + var elem = content.document.querySelector(aMessage.json.selector); + if (elem) { + if (aMessage.json.blur) { + elem.blur(); + } else { + elem.focus(); + } + } + }); + } + + aMessageManager.addMessageListener('AccessFu:Present', this); + aMessageManager.addMessageListener('AccessFu:Input', this); + aMessageManager.addMessageListener('AccessFu:CursorCleared', this); + aMessageManager.addMessageListener('AccessFu:Focused', this); + aMessageManager.addMessageListener('AccessFu:AriaHidden', this); + aMessageManager.addMessageListener('AccessFu:Ready', function () { + aMessageManager.addMessageListener('AccessFu:ContentStarted', aCallback); + aMessageManager.sendAsyncMessage('AccessFu:Start', + { buildApp: 'browser', + androidSdkVersion: Utils.AndroidSdkVersion, + logLevel: 'DEBUG', + inTest: true }); + }); + + aMessageManager.loadFrameScript( + 'chrome://global/content/accessibility/content-script.js', false); + aMessageManager.loadFrameScript( + 'data:,(' + contentScript.toString() + ')();', false); + }, + + pump: function() { + this.expected.shift(); + if (this.expected.length) { + return; + } + + var currentPair = this.queue.shift(); + + if (currentPair) { + this.actionNum++; + this.currentAction = currentPair[0]; + if (typeof this.currentAction === 'function') { + this.currentAction(this.mms[0]); + } else if (this.currentAction) { + this.mms[0].sendAsyncMessage(this.currentAction.name, + this.currentAction.json); + } + + this.expected = currentPair.slice(1, currentPair.length); + + if (!this.expected[0]) { + this.pump(); + } + } else { + this.finish(); + } + }, + + receiveMessage: function(aMessage) { + var expected = this.expected[0]; + + if (!expected) { + return; + } + + var actionsString = typeof this.currentAction === 'function' ? + this.currentAction.name + '()' : JSON.stringify(this.currentAction); + + if (typeof expected === 'string') { + ok(true, 'Got ' + expected + ' after ' + actionsString); + this.pump(); + } else if (expected.ignore && !expected.ignore(aMessage)) { + expected.is(aMessage.json, 'after ' + actionsString + + ' (' + this.actionNum + ')'); + expected.is_correct_focus(); + this.pump(); + } + } +}; + +// Common content messages + +var ContentMessages = { + simpleMoveFirst: { + name: 'AccessFu:MoveCursor', + json: { + action: 'moveFirst', + rule: 'Simple', + inputType: 'gesture', + origin: 'top' + } + }, + + simpleMoveLast: { + name: 'AccessFu:MoveCursor', + json: { + action: 'moveLast', + rule: 'Simple', + inputType: 'gesture', + origin: 'top' + } + }, + + simpleMoveNext: { + name: 'AccessFu:MoveCursor', + json: { + action: 'moveNext', + rule: 'Simple', + inputType: 'gesture', + origin: 'top' + } + }, + + simpleMovePrevious: { + name: 'AccessFu:MoveCursor', + json: { + action: 'movePrevious', + rule: 'Simple', + inputType: 'gesture', + origin: 'top' + } + }, + + clearCursor: { + name: 'AccessFu:ClearCursor', + json: { + origin: 'top' + } + }, + + moveOrAdjustUp: function moveOrAdjustUp(aRule) { + return { + name: 'AccessFu:MoveCursor', + json: { + origin: 'top', + action: 'movePrevious', + inputType: 'gesture', + rule: (aRule || 'Simple'), + adjustRange: true + } + } + }, + + moveOrAdjustDown: function moveOrAdjustUp(aRule) { + return { + name: 'AccessFu:MoveCursor', + json: { + origin: 'top', + action: 'moveNext', + inputType: 'gesture', + rule: (aRule || 'Simple'), + adjustRange: true + } + } + }, + + androidScrollForward: function adjustUp() { + return { + name: 'AccessFu:AndroidScroll', + json: { origin: 'top', direction: 'forward' } + }; + }, + + androidScrollBackward: function adjustDown() { + return { + name: 'AccessFu:AndroidScroll', + json: { origin: 'top', direction: 'backward' } + }; + }, + + focusSelector: function focusSelector(aSelector, aBlur) { + return { + name: 'AccessFuTest:Focus', + json: { + selector: aSelector, + blur: aBlur + } + }; + }, + + activateCurrent: function activateCurrent(aOffset) { + return { + name: 'AccessFu:Activate', + json: { + origin: 'top', + offset: aOffset + } + }; + }, + + moveNextBy: function moveNextBy(aGranularity) { + return { + name: 'AccessFu:MoveByGranularity', + json: { + direction: 'Next', + granularity: this._granularityMap[aGranularity] + } + }; + }, + + movePreviousBy: function movePreviousBy(aGranularity) { + return { + name: 'AccessFu:MoveByGranularity', + json: { + direction: 'Previous', + granularity: this._granularityMap[aGranularity] + } + }; + }, + + moveCaretNextBy: function moveCaretNextBy(aGranularity) { + return { + name: 'AccessFu:MoveCaret', + json: { + direction: 'Next', + granularity: this._granularityMap[aGranularity] + } + }; + }, + + moveCaretPreviousBy: function moveCaretPreviousBy(aGranularity) { + return { + name: 'AccessFu:MoveCaret', + json: { + direction: 'Previous', + granularity: this._granularityMap[aGranularity] + } + }; + }, + + _granularityMap: { + 'character': 1, // MOVEMENT_GRANULARITY_CHARACTER + 'word': 2, // MOVEMENT_GRANULARITY_WORD + 'paragraph': 8 // MOVEMENT_GRANULARITY_PARAGRAPH + } +}; + +function ExpectedMessage (aName, aOptions) { + this.name = aName; + this.options = aOptions || {}; + this.json = {}; +} + +ExpectedMessage.prototype.lazyCompare = function(aReceived, aExpected, aInfo) { + if (aExpected && !aReceived) { + return [false, 'Expected something but got nothing -- ' + aInfo]; + } + + var matches = true; + var delta = []; + for (var attr in aExpected) { + var expected = aExpected[attr]; + var received = aReceived[attr]; + if (typeof expected === 'object') { + var [childMatches, childDelta] = this.lazyCompare(received, expected); + if (!childMatches) { + delta.push(attr + ' [ ' + childDelta + ' ]'); + matches = false; + } + } else { + if (received !== expected) { + delta.push( + attr + ' [ expected ' + JSON.stringify(expected) + + ' got ' + JSON.stringify(received) + ' ]'); + matches = false; + } + } + } + + var msg = delta.length ? delta.join(' ') : 'Structures lazily match'; + return [matches, msg + ' -- ' + aInfo]; +}; + +ExpectedMessage.prototype.is = function(aReceived, aInfo) { + var checkFunc = this.options.todo ? 'todo' : 'ok'; + SimpleTest[checkFunc].apply( + SimpleTest, this.lazyCompare(aReceived, this.json, aInfo)); +}; + +ExpectedMessage.prototype.is_correct_focus = function(aInfo) { + if (!this.options.focused) { + return; + } + + var checkFunc = this.options.focused_todo ? 'todo_is' : 'is'; + var doc = currentTabDocument(); + SimpleTest[checkFunc].apply(SimpleTest, + [ doc.activeElement, doc.querySelector(this.options.focused), + 'Correct element is focused: ' + this.options.focused + ' -- ' + aInfo ]); +}; + +ExpectedMessage.prototype.ignore = function(aMessage) { + return aMessage.name !== this.name; +}; + +function ExpectedPresent(aB2g, aAndroid, aOptions) { + ExpectedMessage.call(this, 'AccessFu:Present', aOptions); + if (aB2g) { + this.json.b2g = aB2g; + } + + if (aAndroid) { + this.json.android = aAndroid; + } +} + +ExpectedPresent.prototype = Object.create(ExpectedMessage.prototype); + +ExpectedPresent.prototype.is = function(aReceived, aInfo) { + var received = this.extract_presenters(aReceived); + + for (var presenter of ['b2g', 'android']) { + if (!this.options['no_' + presenter]) { + var todo = this.options.todo || this.options[presenter + '_todo'] + SimpleTest[todo ? 'todo' : 'ok'].apply( + SimpleTest, this.lazyCompare(received[presenter], + this.json[presenter], aInfo + ' (' + presenter + ')')); + } + } +}; + +ExpectedPresent.prototype.extract_presenters = function(aReceived) { + var received = { count: 0 }; + for (var presenter of aReceived) { + if (presenter) { + received[presenter.type.toLowerCase()] = presenter.details; + received.count++; + } + } + + return received +}; + +ExpectedPresent.prototype.ignore = function(aMessage) { + if (ExpectedMessage.prototype.ignore.call(this, aMessage)) { + return true; + } + + var received = this.extract_presenters(aMessage.json); + return received.count === 0 || + (received.visual && received.visual.eventType === 'viewport-change') || + (received.android && + received.android[0].eventType === AndroidEvent.VIEW_SCROLLED); +}; + +function ExpectedCursorChange(aSpeech, aOptions) { + ExpectedPresent.call(this, { + eventType: 'vc-change', + data: aSpeech + }, [{ + eventType: 0x8000, // VIEW_ACCESSIBILITY_FOCUSED + }], aOptions); +} + +ExpectedCursorChange.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedCursorTextChange(aSpeech, aStartOffset, aEndOffset, aOptions) { + ExpectedPresent.call(this, { + eventType: 'vc-change', + data: aSpeech + }, [{ + eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, + fromIndex: aStartOffset, + toIndex: aEndOffset + }], aOptions); + + // bug 980509 + this.options.b2g_todo = true; +} + +ExpectedCursorTextChange.prototype = + Object.create(ExpectedCursorChange.prototype); + +function ExpectedClickAction(aOptions) { + ExpectedPresent.call(this, { + eventType: 'action', + data: [{ string: 'clickAction' }] + }, [{ + eventType: AndroidEvent.VIEW_CLICKED + }], aOptions); +} + +ExpectedClickAction.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedCheckAction(aChecked, aOptions) { + ExpectedPresent.call(this, { + eventType: 'action', + data: [{ string: aChecked ? 'checkAction' : 'uncheckAction' }] + }, [{ + eventType: AndroidEvent.VIEW_CLICKED, + checked: aChecked + }], aOptions); +} + +ExpectedCheckAction.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedSwitchAction(aSwitched, aOptions) { + ExpectedPresent.call(this, { + eventType: 'action', + data: [{ string: aSwitched ? 'onAction' : 'offAction' }] + }, [{ + eventType: AndroidEvent.VIEW_CLICKED, + checked: aSwitched + }], aOptions); +} + +ExpectedSwitchAction.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedNameChange(aName, aOptions) { + ExpectedPresent.call(this, { + eventType: 'name-change', + data: aName + }, null, aOptions); +} + +ExpectedNameChange.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedValueChange(aValue, aOptions) { + ExpectedPresent.call(this, { + eventType: 'value-change', + data: aValue + }, null, aOptions); +} + +ExpectedValueChange.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedTextChanged(aValue, aOptions) { + ExpectedPresent.call(this, { + eventType: 'text-change', + data: aValue + }, null, aOptions); +} + +ExpectedTextChanged.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedEditState(aEditState, aOptions) { + ExpectedMessage.call(this, 'AccessFu:Input', aOptions); + this.json = aEditState; +} + +ExpectedEditState.prototype = Object.create(ExpectedMessage.prototype); + +function ExpectedTextSelectionChanged(aStart, aEnd, aOptions) { + ExpectedPresent.call(this, null, [{ + eventType: AndroidEvent.VIEW_TEXT_SELECTION_CHANGED, + brailleOutput: { + selectionStart: aStart, + selectionEnd: aEnd + }}], aOptions); +} + +ExpectedTextSelectionChanged.prototype = + Object.create(ExpectedPresent.prototype); + +function ExpectedTextCaretChanged(aFrom, aTo, aOptions) { + ExpectedPresent.call(this, null, [{ + eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, + fromIndex: aFrom, + toIndex: aTo + }], aOptions); +} + +ExpectedTextCaretChanged.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedAnnouncement(aAnnouncement, aOptions) { + ExpectedPresent.call(this, null, [{ + eventType: AndroidEvent.ANNOUNCEMENT, + text: [ aAnnouncement], + addedCount: aAnnouncement.length + }], aOptions); +} + +ExpectedAnnouncement.prototype = Object.create(ExpectedPresent.prototype); + +function ExpectedNoMove(aOptions) { + ExpectedPresent.call(this, {eventType: 'no-move' }, null, aOptions); +} + +ExpectedNoMove.prototype = Object.create(ExpectedPresent.prototype); + +var AndroidEvent = { + VIEW_CLICKED: 0x01, + VIEW_LONG_CLICKED: 0x02, + VIEW_SELECTED: 0x04, + VIEW_FOCUSED: 0x08, + VIEW_TEXT_CHANGED: 0x10, + WINDOW_STATE_CHANGED: 0x20, + VIEW_HOVER_ENTER: 0x80, + VIEW_HOVER_EXIT: 0x100, + VIEW_SCROLLED: 0x1000, + VIEW_TEXT_SELECTION_CHANGED: 0x2000, + ANNOUNCEMENT: 0x4000, + VIEW_ACCESSIBILITY_FOCUSED: 0x8000, + VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: 0x20000 +}; diff --git a/accessible/tests/mochitest/jsat/output.js b/accessible/tests/mochitest/jsat/output.js new file mode 100644 index 000000000..5afcc8a66 --- /dev/null +++ b/accessible/tests/mochitest/jsat/output.js @@ -0,0 +1,114 @@ +var Cu = Components.utils; +const PREF_UTTERANCE_ORDER = "accessibility.accessfu.utterance"; + +Cu.import('resource://gre/modules/accessibility/Utils.jsm'); +Cu.import("resource://gre/modules/accessibility/OutputGenerator.jsm", this); + +/** + * Test context output generation. + * + * @param expected {Array} expected output. + * @param aAccOrElmOrID identifier to get an accessible to test. + * @param aOldAccOrElmOrID optional identifier to get an accessible relative to + * the |aAccOrElmOrID|. + * @param aGenerator the output generator to use when generating accessible + * output + * + * Note: if |aOldAccOrElmOrID| is not provided, the |aAccOrElmOrID| must be + * scoped to the "root" element in markup. + */ +function testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aGenerator) { + var accessible = getAccessible(aAccOrElmOrID); + var oldAccessible = aOldAccOrElmOrID !== null ? + getAccessible(aOldAccOrElmOrID || 'root') : null; + var context = new PivotContext(accessible, oldAccessible); + var output = aGenerator.genForContext(context); + + // Create a version of the output that has null members where we have + // null members in the expected output. Those are indexes that are not testable + // because of the changing nature of the test (different window names), or strings + // that are inaccessible to us, like the title of parent documents. + var masked_output = []; + for (var i=0; i < output.length; i++) { + if (expected[i] === null) { + masked_output.push(null); + } else { + masked_output[i] = typeof output[i] === "string" ? output[i].trim() : + output[i]; + } + } + + isDeeply(masked_output, expected, + "Context output is correct for " + aAccOrElmOrID + + " (output: " + JSON.stringify(output) + ") ==" + + " (expected: " + JSON.stringify(expected) + ")"); +} + +/** + * Test object output generated array that includes names. + * Note: test ignores outputs without the name. + * + * @param aAccOrElmOrID identifier to get an accessible to test. + * @param aGenerator the output generator to use when generating accessible + * output + */ +function testObjectOutput(aAccOrElmOrID, aGenerator) { + var accessible = getAccessible(aAccOrElmOrID); + if (!accessible.name || !accessible.name.trim()) { + return; + } + var context = new PivotContext(accessible); + var output = aGenerator.genForObject(accessible, context); + var outputOrder; + try { + outputOrder = SpecialPowers.getIntPref(PREF_UTTERANCE_ORDER); + } catch (ex) { + // PREF_UTTERANCE_ORDER not set. + outputOrder = 0; + } + var expectedNameIndex = outputOrder === 0 ? output.length - 1 : 0; + var nameIndex = output.indexOf(accessible.name); + + if (nameIndex > -1) { + ok(output.indexOf(accessible.name) === expectedNameIndex, + "Object output is correct for " + aAccOrElmOrID); + } +} + +/** + * Test object and context output for an accessible. + * + * @param expected {Array} expected output. + * @param aAccOrElmOrID identifier to get an accessible to test. + * @param aOldAccOrElmOrID optional identifier to get an accessible relative to + * the |aAccOrElmOrID|. + * @param aOutputKind the type of output + */ +function testOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aOutputKind) { + var generator; + if (aOutputKind === 1) { + generator = UtteranceGenerator; + } else { + generator = BrailleGenerator; + } + testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, generator); + // Just need to test object output for individual + // accOrElmOrID. + if (aOldAccOrElmOrID) { + return; + } + testObjectOutput(aAccOrElmOrID, generator); +} + +function testHints(expected, aAccOrElmOrID, aOldAccOrElmOrID) { + var accessible = getAccessible(aAccOrElmOrID); + var oldAccessible = aOldAccOrElmOrID !== null ? + getAccessible(aOldAccOrElmOrID || 'root') : null; + var context = new PivotContext(accessible, oldAccessible); + var hints = context.interactionHints; + + isDeeply(hints, expected, + "Context hitns are correct for " + aAccOrElmOrID + + " (hints: " + JSON.stringify(hints) + ") ==" + + " (expected: " + JSON.stringify(expected) + ")"); +} diff --git a/accessible/tests/mochitest/jsat/test_alive.html b/accessible/tests/mochitest/jsat/test_alive.html new file mode 100644 index 000000000..cd4eef712 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_alive.html @@ -0,0 +1,81 @@ + + + + AccessFu test for enabling + + + + + + + + + + + Mozilla Bug 811307 + + + diff --git a/accessible/tests/mochitest/jsat/test_content_integration.html b/accessible/tests/mochitest/jsat/test_content_integration.html new file mode 100644 index 000000000..809f79726 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_content_integration.html @@ -0,0 +1,343 @@ + + + + Tests AccessFu content integration + + + + + + + + + + + + + + + + + + + Mozilla Bug 933808 +

    + +
    +  
    + + diff --git a/accessible/tests/mochitest/jsat/test_content_text.html b/accessible/tests/mochitest/jsat/test_content_text.html new file mode 100644 index 000000000..558b819e9 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_content_text.html @@ -0,0 +1,292 @@ + + + + Tests AccessFu content integration + + + + + + + + + + + + + + + + + + + + Mozilla Bug 933808 +

    + +
    +  
    + + diff --git a/accessible/tests/mochitest/jsat/test_explicit_names.html b/accessible/tests/mochitest/jsat/test_explicit_names.html new file mode 100644 index 000000000..fb7ed2022 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_explicit_names.html @@ -0,0 +1,191 @@ + + + [AccessFu] Trust explicitly associated names when speaking certain elements + + + + + + + + +
    + + Mozilla Bug 845870 + +

    + +
    
    +    
    +    
    +    
    +    This is a link
    +    
    +    
    +    

    This is the heading.

    +

    + This is the heading. +

    +
      +
    1. list one
    2. +
    3. list two
    4. +
    +
    +
    dd one
    +
    + + + + + +
    Fruits and vegetables
    + +
    + + +
    + + diff --git a/accessible/tests/mochitest/jsat/test_gesture_tracker.html b/accessible/tests/mochitest/jsat/test_gesture_tracker.html new file mode 100644 index 000000000..af2755455 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_gesture_tracker.html @@ -0,0 +1,51 @@ + + + + AccessFu tests for gesture tracker. + + + + + + + + + + + + + Mozilla Bug 981015 + + + diff --git a/accessible/tests/mochitest/jsat/test_hints.html b/accessible/tests/mochitest/jsat/test_hints.html new file mode 100644 index 000000000..d5691b97a --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_hints.html @@ -0,0 +1,89 @@ + + + [AccessFu] Interaction Hints + + + + + + + + +
    + + Mozilla Bug 1069574 + +

    + +
    
    +      
    +        I can be clicked
    +      
    +      
    +        I can be clicked
    +      
    +      
    +        
    +      
    +      I can be clicked
    +      I am a special link
    +      
    +      
    +      Item 1
    +  
    + + diff --git a/accessible/tests/mochitest/jsat/test_landmarks.html b/accessible/tests/mochitest/jsat/test_landmarks.html new file mode 100644 index 000000000..8b1a16f83 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_landmarks.html @@ -0,0 +1,183 @@ + + + [AccessFu] Speak landmarks + + + + + + + + + +
    + + Mozilla Bug 888256 + +

    + +
    
    +    
    +    
    +    
    a footer
    +
    +
    a header within an article
    +
    a footer within an article
    +
    + + +
    a main area
    +
    another main area
    + +
    + a parent main +
    +
    + + diff --git a/accessible/tests/mochitest/jsat/test_live_regions.html b/accessible/tests/mochitest/jsat/test_live_regions.html new file mode 100644 index 000000000..53828f1b1 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_live_regions.html @@ -0,0 +1,472 @@ + + + + AccessFu tests for live regions support + + + + + + + + + + + Mozilla Bug 795957 + +
    +

    + +
    
    +
    +    

    I should not be announced 1

    +

    I should not be announced 2

    +

    I should not be announced 3

    +

    I will be hidden

    + + +

    I should not be announced 6

    +

    I should not be announced 7

    +

    I should not be announced 8

    +

    I will be hidden

    + +
    +

    I should not be announced 1

    +
    +
    +

    I should not be announced 2

    +
    +
    +

    I should not be announced 3

    +
    +
    +

    I will be hidden

    +
    + +
    +

    I should not be announced 4

    +
    +
    +

    I should not be announced 5

    +
    +
    +

    I should not be announced 6

    +
    +
    +

    I will be hidden

    +
    + + + + + + +

    I should not be announced 5

    + + + + + +
    + +
    +
    + +
    +
    + +
    +
    + +
    + +
    + +
    +
    + +
    +
    + +
    +
    + +
    + +
    +

    I will be hidden

    +
    + +
    +

    I will be hidden

    +
    + + + + + + + + +
    +

    I am replaced

    +
    + +

    I am going to be replaced

    + +

    +

    Text Removed

    + +
    +

    +
    +
    +

    Descendant Text Removed

    +
    +
    +

    +
    +
    +

    Descendant Text Removed

    +
    +
    + + diff --git a/accessible/tests/mochitest/jsat/test_output.html b/accessible/tests/mochitest/jsat/test_output.html new file mode 100644 index 000000000..ec2b289be --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_output.html @@ -0,0 +1,673 @@ + + + + + [AccessFu] utterance order test + + + + + + + + + +
    + + Mozilla Bug 753984 + + Mozilla Bug 758675 + + Mozilla Bug 876475 + + Mozilla Bug 924284 + + Mozilla Bug 925845 +

    + +
    
    +      
    +      Tests
    +      Tests
    +      Tests
    +      
    +      

    +
      +
    1. list one
    2. +
    + +
    +
    + dd one +
    +
    + + + + + +
    Fruits and vegetables
    + +
    + + + + + + + +
    + Account + Advanced +
    +
    + + +
    + + + + + + + + + + + + + +
    I am not pressed
    +
    I am pressed!
    + +
    +
      +
    1. +
    2. S
    3. +
    4. M
    5. +
    +
      +
    1. 1
    2. +
    3. 3
    4. +
    5. 4
      7
    6. +
    +
      +
    1. 2
    2. +
    3. 5
    4. +
    5. 6
    6. +
    +
    + + +
    Last sync:2 days ago
    +
    I should be ignored
    + + +
    + + diff --git a/accessible/tests/mochitest/jsat/test_output_mathml.html b/accessible/tests/mochitest/jsat/test_output_mathml.html new file mode 100644 index 000000000..3fe4779b2 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_output_mathml.html @@ -0,0 +1,313 @@ + + + [AccessFu] MathML Accessibility Support + + + + + + + + + +
    + + Mozilla Bug 1163374 + +

    + +
    
    +
    +    (x,y)
    +
    +    
    +      
    +        a
    +        b
    +      
    +    
    +
    +    
    +      
    +        a
    +        b
    +      
    +    
    +
    +    
    +      
    +        a
    +        b
    +      
    +    
    +    
    +      
    +        a
    +        b
    +      
    +    
    +    
    +      
    +        a
    +        b
    +        c
    +      
    +    
    +    
    +      
    +        a
    +        b
    +        c
    +        
    +        d
    +        
    +        e
    +        
    +        f
    +        g
    +      
    +    
    +
    +    
    +      
    +        a
    +        b
    +      
    +    
    +    
    +      
    +        a
    +        b
    +      
    +    
    +    
    +      
    +        a
    +        b
    +        c
    +      
    +    
    +
    +    
    +      
    +        a
    +        b
    +      
    +    
    +
    +    
    +      
    +        
    +          a
    +          b
    +          c
    +        
    +        
    +          d
    +          e
    +          f
    +        
    +      
    +    
    +
    +    
    +      a
    +    
    +    
    +      a
    +    
    +    
    +      a
    +    
    +
    +  
    + + diff --git a/accessible/tests/mochitest/jsat/test_pointer_relay.html b/accessible/tests/mochitest/jsat/test_pointer_relay.html new file mode 100644 index 000000000..cb58fe73b --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_pointer_relay.html @@ -0,0 +1,95 @@ + + + + AccessFu tests for pointer relay. + + + + + + + + + + + + + Mozilla Bug 981015 + +
    + +
    + + diff --git a/accessible/tests/mochitest/jsat/test_quicknav_modes.html b/accessible/tests/mochitest/jsat/test_quicknav_modes.html new file mode 100644 index 000000000..f99b64a84 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_quicknav_modes.html @@ -0,0 +1,107 @@ + + + + AccessFu test for enabling + + + + + + + + + + + Mozilla Bug 811307 + + + \ No newline at end of file diff --git a/accessible/tests/mochitest/jsat/test_tables.html b/accessible/tests/mochitest/jsat/test_tables.html new file mode 100644 index 000000000..aa7f482e9 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_tables.html @@ -0,0 +1,579 @@ + + + [AccessFu] Improve reading of table semantics + + + + + + + + + +
    + + Mozilla Bug 830748 + +

    + +
    
    +    
    +      
    +        
    +          
    +          
    +        
    +      
    +      
    +        
    +          
    +          
    +        
    +      
    +    
    col1col2
    cell1cell2
    + + + + + + + + + +
    cell1 + + + + + + + + + + + +
    colheader
    bla
    +
    col1col2
    + + + + + + + + + + + + + + + + + + + + +
    col1col2col3
    row1cell1cell2
    row2cell3cell4
    + + + +
    Row1
    Row2
    +
    + + \ No newline at end of file diff --git a/accessible/tests/mochitest/jsat/test_traversal.html b/accessible/tests/mochitest/jsat/test_traversal.html new file mode 100644 index 000000000..533e9d89f --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_traversal.html @@ -0,0 +1,167 @@ + + + + Tests AccessFu TraversalRules + + + + + + + + + + + + + + + + + + + Mozilla Bug 933808 +

    + +
    +  
    + + diff --git a/accessible/tests/mochitest/jsat/test_traversal_helper.html b/accessible/tests/mochitest/jsat/test_traversal_helper.html new file mode 100644 index 000000000..f6a347ed0 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_traversal_helper.html @@ -0,0 +1,113 @@ + + + + Tests AccessFu TraversalRules + + + + + + + + + + + + + + + + + + + Mozilla Bug xxx +

    + +
    +  
    + + diff --git a/accessible/tests/mochitest/layout.js b/accessible/tests/mochitest/layout.js new file mode 100644 index 000000000..e1fb14670 --- /dev/null +++ b/accessible/tests/mochitest/layout.js @@ -0,0 +1,258 @@ +/** + * Tests if the given child and grand child accessibles at the given point are + * expected. + * + * @param aID [in] accessible identifier + * @param aX [in] x coordinate of the point relative accessible + * @param aY [in] y coordinate of the point relative accessible + * @param aChildID [in] expected child accessible + * @param aGrandChildID [in] expected child accessible + */ +function testChildAtPoint(aID, aX, aY, aChildID, aGrandChildID) +{ + var child = getChildAtPoint(aID, aX, aY, false); + var expectedChild = getAccessible(aChildID); + + var msg = "Wrong direct child accessible at the point (" + aX + ", " + aY + + ") of " + prettyName(aID); + isObject(child, expectedChild, msg); + + var grandChild = getChildAtPoint(aID, aX, aY, true); + var expectedGrandChild = getAccessible(aGrandChildID); + + msg = "Wrong deepest child accessible at the point (" + aX + ", " + aY + + ") of " + prettyName(aID); + isObject(grandChild, expectedGrandChild, msg); +} + +/** + * Test if getChildAtPoint returns the given child and grand child accessibles + * at coordinates of child accessible (direct and deep hit test). + */ +function hitTest(aContainerID, aChildID, aGrandChildID) +{ + var container = getAccessible(aContainerID); + var child = getAccessible(aChildID); + var grandChild = getAccessible(aGrandChildID); + + var [x, y] = getBoundsForDOMElm(child); + + var actualChild = container.getChildAtPoint(x + 1, y + 1); + isObject(actualChild, child, + "Wrong direct child of " + prettyName(aContainerID)); + + var actualGrandChild = container.getDeepestChildAtPoint(x + 1, y + 1); + isObject(actualGrandChild, grandChild, + "Wrong deepest child of " + prettyName(aContainerID)); +} + +/** + * Test if getOffsetAtPoint returns the given text offset at given coordinates. + */ +function testOffsetAtPoint(aHyperTextID, aX, aY, aCoordType, aExpectedOffset) +{ + var hyperText = getAccessible(aHyperTextID, [nsIAccessibleText]); + var offset = hyperText.getOffsetAtPoint(aX, aY, aCoordType); + is(offset, aExpectedOffset, + "Wrong offset at given point (" + aX + ", " + aY + ") for " + + prettyName(aHyperTextID)); +} + +/** + * Zoom the given document. + */ +function zoomDocument(aDocument, aZoom) +{ + var docShell = aDocument.defaultView. + QueryInterface(Components.interfaces.nsIInterfaceRequestor). + getInterface(Components.interfaces.nsIWebNavigation). + QueryInterface(Components.interfaces.nsIDocShell); + var docViewer = docShell.contentViewer; + + docViewer.fullZoom = aZoom; +} + +/** + * Return child accessible at the given point. + * + * @param aIdentifier [in] accessible identifier + * @param aX [in] x coordinate of the point relative accessible + * @param aY [in] y coordinate of the point relative accessible + * @param aFindDeepestChild [in] points whether deepest or nearest child should + * be returned + * @return the child accessible at the given point + */ +function getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild) +{ + var acc = getAccessible(aIdentifier); + if (!acc) + return; + + var [screenX, screenY] = getBoundsForDOMElm(acc.DOMNode); + + var x = screenX + aX; + var y = screenY + aY; + + try { + if (aFindDeepestChild) + return acc.getDeepestChildAtPoint(x, y); + return acc.getChildAtPoint(x, y); + } catch (e) { } + + return null; +} + +/** + * Test the accessible position. + */ +function testPos(aID, aPoint) +{ + var [expectedX, expectedY] = + (aPoint != undefined) ? aPoint : getBoundsForDOMElm(aID); + + var [x, y] = getBounds(aID); + is(x, expectedX, "Wrong x coordinate of " + prettyName(aID)); + is(y, expectedY, "Wrong y coordinate of " + prettyName(aID)); +} + +/** + * Test the accessible boundaries. + */ +function testBounds(aID, aRect) +{ + var [expectedX, expectedY, expectedWidth, expectedHeight] = + (aRect != undefined) ? aRect : getBoundsForDOMElm(aID); + + var [x, y, width, height] = getBounds(aID); + is(x, expectedX, "Wrong x coordinate of " + prettyName(aID)); + is(y, expectedY, "Wrong y coordinate of " + prettyName(aID)); + is(width, expectedWidth, "Wrong width of " + prettyName(aID)); + is(height, expectedHeight, "Wrong height of " + prettyName(aID)); +} + +/** + * Test text position at the given offset. + */ +function testTextPos(aID, aOffset, aPoint, aCoordOrigin) +{ + var [expectedX, expectedY] = aPoint; + + var xObj = {}, yObj = {}; + var hyperText = getAccessible(aID, [nsIAccessibleText]); + hyperText.getCharacterExtents(aOffset, xObj, yObj, {}, {}, aCoordOrigin); + is(xObj.value, expectedX, + "Wrong x coordinate at offset " + aOffset + " for " + prettyName(aID)); + ok(yObj.value - expectedY < 2 && expectedY - yObj.value < 2, + "Wrong y coordinate at offset " + aOffset + " for " + prettyName(aID) + + " - got " + yObj.value + ", expected " + expectedY + + "The difference doesn't exceed 1."); +} + +/** + * Test text bounds that is enclosed betwene the given offsets. + */ +function testTextBounds(aID, aStartOffset, aEndOffset, aRect, aCoordOrigin) +{ + var [expectedX, expectedY, expectedWidth, expectedHeight] = aRect; + + var xObj = {}, yObj = {}, widthObj = {}, heightObj = {}; + var hyperText = getAccessible(aID, [nsIAccessibleText]); + hyperText.getRangeExtents(aStartOffset, aEndOffset, + xObj, yObj, widthObj, heightObj, aCoordOrigin); + is(xObj.value, expectedX, + "Wrong x coordinate of text between offsets (" + aStartOffset + ", " + + aEndOffset + ") for " + prettyName(aID)); + is(yObj.value, expectedY, + "Wrong y coordinate of text between offsets (" + aStartOffset + ", " + + aEndOffset + ") for " + prettyName(aID)); + + var msg = "Wrong width of text between offsets (" + aStartOffset + ", " + + aEndOffset + ") for " + prettyName(aID); + if (widthObj.value == expectedWidth) + ok(true, msg); + else + todo(false, msg); // fails on some windows machines + + is(heightObj.value, expectedHeight, + "Wrong height of text between offsets (" + aStartOffset + ", " + + aEndOffset + ") for " + prettyName(aID)); +} + +/** + * Return the accessible coordinates relative to the screen in device pixels. + */ +function getPos(aID) +{ + var accessible = getAccessible(aID); + var x = {}, y = {}; + accessible.getBounds(x, y, {}, {}); + return [x.value, y.value]; +} + +/** + * Return the accessible coordinates and size relative to the screen in device + * pixels. + */ +function getBounds(aID) +{ + var accessible = getAccessible(aID); + var x = {}, y = {}, width = {}, height = {}; + accessible.getBounds(x, y, width, height); + return [x.value, y.value, width.value, height.value]; +} + +/** + * Return DOM node coordinates relative the screen and its size in device + * pixels. + */ +function getBoundsForDOMElm(aID) +{ + var x = 0, y = 0, width = 0, height = 0; + + var elm = getNode(aID); + if (elm.localName == "area") { + var mapName = elm.parentNode.getAttribute("name"); + var selector = "[usemap='#" + mapName + "']"; + var img = elm.ownerDocument.querySelector(selector); + + var areaCoords = elm.coords.split(","); + var areaX = parseInt(areaCoords[0]); + var areaY = parseInt(areaCoords[1]); + var areaWidth = parseInt(areaCoords[2]) - areaX; + var areaHeight = parseInt(areaCoords[3]) - areaY; + + var rect = img.getBoundingClientRect(); + x = rect.left + areaX; + y = rect.top + areaY; + width = areaWidth; + height = areaHeight; + } + else { + var rect = elm.getBoundingClientRect(); + x = rect.left; + y = rect.top; + width = rect.width; + height = rect.height; + } + + var elmWindow = elm.ownerDocument.defaultView; + return CSSToDevicePixels(elmWindow, + x + elmWindow.mozInnerScreenX, + y + elmWindow.mozInnerScreenY, + width, + height); +} + +function CSSToDevicePixels(aWindow, aX, aY, aWidth, aHeight) +{ + var winUtil = aWindow. + QueryInterface(Components.interfaces.nsIInterfaceRequestor). + getInterface(Components.interfaces.nsIDOMWindowUtils); + + var ratio = winUtil.screenPixelsPerCSSPixel; + + // CSS pixels and ratio can be not integer. Device pixels are always integer. + // Do our best and hope it works. + return [ Math.round(aX * ratio), Math.round(aY * ratio), + Math.round(aWidth * ratio), Math.round(aHeight * ratio) ]; +} diff --git a/accessible/tests/mochitest/letters.gif b/accessible/tests/mochitest/letters.gif new file mode 100644 index 000000000..299b91784 Binary files /dev/null and b/accessible/tests/mochitest/letters.gif differ diff --git a/accessible/tests/mochitest/longdesc_src.html b/accessible/tests/mochitest/longdesc_src.html new file mode 100644 index 000000000..37248795d --- /dev/null +++ b/accessible/tests/mochitest/longdesc_src.html @@ -0,0 +1,8 @@ + + +Mozilla logo + + +

    This file would contain a longer description of the Mozilla logo, if I knew what it looked like.

    + + diff --git a/accessible/tests/mochitest/moz.build b/accessible/tests/mochitest/moz.build new file mode 100644 index 000000000..4fb277037 --- /dev/null +++ b/accessible/tests/mochitest/moz.build @@ -0,0 +1,37 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +A11Y_MANIFESTS += [ + 'a11y.ini', + 'actions/a11y.ini', + 'aom/a11y.ini', + 'attributes/a11y.ini', + 'bounds/a11y.ini', + 'editabletext/a11y.ini', + 'elm/a11y.ini', + 'events/a11y.ini', + 'focus/a11y.ini', + 'hittest/a11y.ini', + 'hyperlink/a11y.ini', + 'hypertext/a11y.ini', + 'jsat/a11y.ini', + 'name/a11y.ini', + 'pivot/a11y.ini', + 'relations/a11y.ini', + 'role/a11y.ini', + 'scroll/a11y.ini', + 'selectable/a11y.ini', + 'states/a11y.ini', + 'table/a11y.ini', + 'text/a11y.ini', + 'textattrs/a11y.ini', + 'textcaret/a11y.ini', + 'textrange/a11y.ini', + 'textselection/a11y.ini', + 'tree/a11y.ini', + 'treeupdate/a11y.ini', + 'value/a11y.ini', +] diff --git a/accessible/tests/mochitest/moz.png b/accessible/tests/mochitest/moz.png new file mode 100644 index 000000000..743292dc6 Binary files /dev/null and b/accessible/tests/mochitest/moz.png differ diff --git a/accessible/tests/mochitest/name.js b/accessible/tests/mochitest/name.js new file mode 100644 index 000000000..8d8290905 --- /dev/null +++ b/accessible/tests/mochitest/name.js @@ -0,0 +1,33 @@ +/** + * Test accessible name for the given accessible identifier. + */ +function testName(aAccOrElmOrID, aName, aMsg, aTodo) +{ + var msg = aMsg ? aMsg : ""; + + var acc = getAccessible(aAccOrElmOrID); + if (!acc) + return; + + var func = aTodo ? todo_is : is; + var txtID = prettyName(aAccOrElmOrID); + try { + func(acc.name, aName, msg + "Wrong name of the accessible for " + txtID); + } catch (e) { + ok(false, msg + "Can't get name of the accessible for " + txtID); + } + return acc; +} + +/** + * Test accessible description for the given accessible. + */ +function testDescr(aAccOrElmOrID, aDescr) +{ + var acc = getAccessible(aAccOrElmOrID); + if (!acc) + return; + + is(acc.description, aDescr, + "Wrong description for " + prettyName(aAccOrElmOrID)); +} diff --git a/accessible/tests/mochitest/name/a11y.ini b/accessible/tests/mochitest/name/a11y.ini new file mode 100644 index 000000000..4d743f1f5 --- /dev/null +++ b/accessible/tests/mochitest/name/a11y.ini @@ -0,0 +1,20 @@ +[DEFAULT] +support-files = + general.css + general.xbl + markup.js + markuprules.xml + !/accessible/tests/mochitest/*.js + !/accessible/tests/mochitest/moz.png + +[test_browserui.xul] +[test_counterstyle.html] +[test_general.html] +[test_general.xul] +[test_link.html] +[test_list.html] +[test_markup.html] +skip-if = (debug && os == 'win') # Bug 1296784 +[test_svg.html] +[test_toolbaritem.xul] +[test_tree.xul] diff --git a/accessible/tests/mochitest/name/general.css b/accessible/tests/mochitest/name/general.css new file mode 100644 index 000000000..5f750c4dc --- /dev/null +++ b/accessible/tests/mochitest/name/general.css @@ -0,0 +1,11 @@ +box.first { + -moz-binding: url('general.xbl#first'); +} + +.second { + -moz-binding: url('general.xbl#second'); +} + +.third { + -moz-binding: url('general.xbl#third'); +} diff --git a/accessible/tests/mochitest/name/general.xbl b/accessible/tests/mochitest/name/general.xbl new file mode 100644 index 000000000..07489f5f4 --- /dev/null +++ b/accessible/tests/mochitest/name/general.xbl @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/accessible/tests/mochitest/name/markup.js b/accessible/tests/mochitest/name/markup.js new file mode 100644 index 000000000..d3ecd8982 --- /dev/null +++ b/accessible/tests/mochitest/name/markup.js @@ -0,0 +1,382 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name tests described by "markuprules.xml" file. + +var gNameRulesFileURL = "markuprules.xml"; + +var gRuleDoc = null; + +// Debuggin stuff. +var gDumpToConsole = false; + +/** + * Start name tests. Run through markup elements and test names for test + * element (see namerules.xml for details). + */ +function testNames() +{ + //enableLogging("tree,stack"); // debugging + + var request = new XMLHttpRequest(); + request.open("get", gNameRulesFileURL, false); + request.send(); + + gRuleDoc = request.responseXML; + + var markupElms = evaluateXPath(gRuleDoc, "//rules/rulesample/markup"); + gTestIterator.iterateMarkups(markupElms); +} + +//////////////////////////////////////////////////////////////////////////////// +// Private section. + +/** + * Helper class to interate through name tests. + */ +var gTestIterator = +{ + iterateMarkups: function gTestIterator_iterateMarkups(aMarkupElms) + { + this.markupElms = aMarkupElms; + + this.iterateNext(); + }, + + iterateRules: function gTestIterator_iterateRules(aElm, aContainer, + aRuleSetElm, aRuleElms, + aTestID) + { + this.ruleSetElm = aRuleSetElm; + this.ruleElms = aRuleElms; + this.elm = aElm; + this.container = aContainer; + this.testID = aTestID; + + this.iterateNext(); + }, + + iterateNext: function gTestIterator_iterateNext() + { + if (this.markupIdx == -1) { + this.markupIdx++; + testNamesForMarkup(this.markupElms[this.markupIdx]); + return; + } + + this.ruleIdx++; + if (this.ruleIdx == this.ruleElms.length) { + // When test is finished then name is empty and no explict-name. + var defaultName = this.ruleSetElm.hasAttribute("defaultName") ? + this.ruleSetElm.getAttribute("defaultName") : null; + testName(this.elm, defaultName, + "Default name test (" + gTestIterator.testID + "). "); + testAbsentAttrs(this.elm, {"explicit-name" : "true"}); + + this.markupIdx++; + if (this.markupIdx == this.markupElms.length) { + //disableLogging("tree"); // debugging + SimpleTest.finish(); + return; + } + + this.ruleIdx = -1; + + if (gDumpToConsole) { + dump("\nPend next markup processing. Wait for reorder event on " + + prettyName(document) + "'\n"); + } + waitForEvent(EVENT_REORDER, document, testNamesForMarkup, + null, this.markupElms[this.markupIdx]); + + document.body.removeChild(this.container); + return; + } + + testNameForRule(this.elm, this.ruleElms[this.ruleIdx]); + }, + + markupElms: null, + markupIdx: -1, + rulesetElm: null, + ruleElms: null, + ruleIdx: -1, + elm: null, + container: null, + testID: "" +}; + +/** + * Process every 'markup' element and test names for it. Used by testNames + * function. + */ +function testNamesForMarkup(aMarkupElm) +{ + if (gDumpToConsole) + dump("\nProcessing markup '" + aMarkupElm.getAttribute("id") + "'\n"); + + var div = document.createElement("div"); + div.setAttribute("id", "test"); + + var child = aMarkupElm.firstChild; + while (child) { + var newChild = document.importNode(child, true); + div.appendChild(newChild); + child = child.nextSibling; + } + + if (gDumpToConsole) { + dump("\nProcessing markup. Wait for reorder event on " + + prettyName(document) + "'\n"); + } + waitForEvent(EVENT_REORDER, document, testNamesForMarkupRules, + null, aMarkupElm, div); + + document.body.appendChild(div); +} + +function testNamesForMarkupRules(aMarkupElm, aContainer) +{ + var testID = aMarkupElm.getAttribute("id"); + if (gDumpToConsole) + dump("\nProcessing markup rules '" + testID + "'\n"); + + var serializer = new XMLSerializer(); + + var expr = "//html/body/div[@id='test']/" + aMarkupElm.getAttribute("ref"); + var elm = evaluateXPath(document, expr, htmlDocResolver)[0]; + + var ruleId = aMarkupElm.getAttribute("ruleset"); + var ruleElm = gRuleDoc.querySelector("[id='" + ruleId + "']"); + var ruleElms = getRuleElmsByRulesetId(ruleId); + + var processMarkupRules = + gTestIterator.iterateRules.bind(gTestIterator, elm, aContainer, + ruleElm, ruleElms, testID); + + // Images may be recreated after we append them into subtree. We need to wait + // in this case. If we are on profiling enabled build then stack tracing + // works and thus let's log instead. Note, that works if you enabled logging + // (refer to testNames() function). + if (isAccessible(elm) || isLogged("stack")) + processMarkupRules(); + else + waitForEvent(EVENT_SHOW, elm, processMarkupRules); +} + +/** + * Test name for current rule and current 'markup' element. Used by + * testNamesForMarkup function. + */ +function testNameForRule(aElm, aRuleElm) +{ + if (aRuleElm.hasAttribute("attr")) { + if (gDumpToConsole) { + dump("\nProcessing rule { attr: " + aRuleElm.getAttribute("attr") +" }\n"); + } + + testNameForAttrRule(aElm, aRuleElm); + + } else if (aRuleElm.hasAttribute("elm")) { + if (gDumpToConsole) { + dump("\nProcessing rule { elm: " + aRuleElm.getAttribute("elm") + + ", elmattr: " + aRuleElm.getAttribute("elmattr") +" }\n"); + } + + testNameForElmRule(aElm, aRuleElm); + + } else if (aRuleElm.getAttribute("fromsubtree") == "true") { + if (gDumpToConsole) { + dump("\nProcessing rule { fromsubtree: " + + aRuleElm.getAttribute("fromsubtree") +" }\n"); + } + + testNameForSubtreeRule(aElm, aRuleElm); + } +} + +function testNameForAttrRule(aElm, aRule) +{ + var name = ""; + + var attr = aRule.getAttribute("attr"); + var attrValue = aElm.getAttribute(attr); + + var type = aRule.getAttribute("type"); + if (type == "string") { + name = attrValue; + + } else if (type == "ref" && attrValue) { + var ids = attrValue.split(/\s+/); + for (var idx = 0; idx < ids.length; idx++) { + var labelElm = getNode(ids[idx]); + if (name != "") + name += " "; + + name += labelElm.getAttribute("textequiv"); + } + } + + var msg = "Attribute '" + attr + "' test (" + gTestIterator.testID + "). "; + testName(aElm, name, msg); + + if (aRule.getAttribute("explict-name") != "false") + testAttrs(aElm, {"explicit-name" : "true"}, true); + else + testAbsentAttrs(aElm, {"explicit-name" : "true"}); + + // If @recreated attribute is used then this attribute change recreates an + // accessible. Wait for reorder event in this case or otherwise proceed next + // test immediately. + if (aRule.hasAttribute("recreated")) { + waitForEvent(EVENT_REORDER, aElm.parentNode, + gTestIterator.iterateNext, gTestIterator); + aElm.removeAttribute(attr); + + } else if (aRule.hasAttribute("textchanged")) { + waitForEvent(EVENT_TEXT_INSERTED, aElm, + gTestIterator.iterateNext, gTestIterator); + aElm.removeAttribute(attr); + + } else if (aRule.hasAttribute("contentchanged")) { + waitForEvent(EVENT_REORDER, aElm, + gTestIterator.iterateNext, gTestIterator); + aElm.removeAttribute(attr); + + } else { + aElm.removeAttribute(attr); + gTestIterator.iterateNext(); + } +} + +function testNameForElmRule(aElm, aRule) +{ + var labelElm; + + var tagname = aRule.getAttribute("elm"); + var attrname = aRule.getAttribute("elmattr"); + if (attrname) { + var filter = { + acceptNode: function filter_acceptNode(aNode) + { + if (aNode.localName == this.mLocalName && + aNode.getAttribute(this.mAttrName) == this.mAttrValue) + return NodeFilter.FILTER_ACCEPT; + + return NodeFilter.FILTER_SKIP; + }, + + mLocalName: tagname, + mAttrName: attrname, + mAttrValue: aElm.getAttribute("id") + }; + + var treeWalker = document.createTreeWalker(document.body, + NodeFilter.SHOW_ELEMENT, + filter); + labelElm = treeWalker.nextNode(); + + } else { + // if attrname is empty then look for the element in subtree. + labelElm = aElm.getElementsByTagName(tagname)[0]; + if (!labelElm) + labelElm = aElm.getElementsByTagName("html:" + tagname)[0]; + } + + if (!labelElm) { + ok(false, msg + " Failed to find '" + tagname + "' element."); + gTestIterator.iterateNext(); + return; + } + + var msg = "Element '" + tagname + "' test (" + gTestIterator.testID + ")."; + testName(aElm, labelElm.getAttribute("textequiv"), msg); + testAttrs(aElm, {"explicit-name" : "true"}, true); + + var parentNode = labelElm.parentNode; + + if (gDumpToConsole) { + dump("\nProcessed elm rule. Wait for reorder event on " + + prettyName(parentNode) + "\n"); + } + waitForEvent(EVENT_REORDER, parentNode, + gTestIterator.iterateNext, gTestIterator); + + parentNode.removeChild(labelElm); +} + +function testNameForSubtreeRule(aElm, aRule) +{ + var msg = "From subtree test (" + gTestIterator.testID + ")."; + testName(aElm, aElm.getAttribute("textequiv"), msg); + testAbsentAttrs(aElm, {"explicit-name" : "true"}); + + if (gDumpToConsole) { + dump("\nProcessed from subtree rule. Wait for reorder event on " + + prettyName(aElm) + "\n"); + } + waitForEvent(EVENT_REORDER, aElm, gTestIterator.iterateNext, gTestIterator); + + while (aElm.firstChild) + aElm.removeChild(aElm.firstChild); +} + +/** + * Return array of 'rule' elements. Used in conjunction with + * getRuleElmsFromRulesetElm() function. + */ +function getRuleElmsByRulesetId(aRulesetId) +{ + var expr = "//rules/ruledfn/ruleset[@id='" + aRulesetId + "']"; + var rulesetElm = evaluateXPath(gRuleDoc, expr); + return getRuleElmsFromRulesetElm(rulesetElm[0]); +} + +function getRuleElmsFromRulesetElm(aRulesetElm) +{ + var rulesetId = aRulesetElm.getAttribute("ref"); + if (rulesetId) + return getRuleElmsByRulesetId(rulesetId); + + var ruleElms = []; + + var child = aRulesetElm.firstChild; + while (child) { + if (child.localName == "ruleset") + ruleElms = ruleElms.concat(getRuleElmsFromRulesetElm(child)); + if (child.localName == "rule") + ruleElms.push(child); + + child = child.nextSibling; + } + + return ruleElms; +} + +/** + * Helper method to evaluate xpath expression. + */ +function evaluateXPath(aNode, aExpr, aResolver) +{ + var xpe = new XPathEvaluator(); + + var resolver = aResolver; + if (!resolver) { + var node = aNode.ownerDocument == null ? + aNode.documentElement : aNode.ownerDocument.documentElement; + resolver = xpe.createNSResolver(node); + } + + var result = xpe.evaluate(aExpr, aNode, resolver, 0, null); + var found = []; + var res; + while (res = result.iterateNext()) + found.push(res); + + return found; +} + +function htmlDocResolver(aPrefix) { + var ns = { + 'html' : 'http://www.w3.org/1999/xhtml' + }; + return ns[aPrefix] || null; +} diff --git a/accessible/tests/mochitest/name/markuprules.xml b/accessible/tests/mochitest/name/markuprules.xml new file mode 100644 index 000000000..7f64ada34 --- /dev/null +++ b/accessible/tests/mochitest/name/markuprules.xml @@ -0,0 +1,373 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + test2 + test3 + test4 + press me + + + + test2 + test3 + test4 + + + + + test2 + test3 + test4 + + + + + test2 + test3 + test4 + + + + + test2 + test3 + test4 + + + + + test2 + test3 + test4 + + + + + test2 + test3 + + option1 + option2 + + + + + test2 + test3 + + + + + test2 + test3 + + + + + test2 + test3 + test4 + + + + This is a paragraph + This is a link + + This is a list + + + + + + + + test2 + test3 + test4 + + + + This is a paragraph + This is a link + + Listitem1 + Listitem2 + + + + + + + + lby_tst6_1 + lby_tst6_2 + label_tst6 + + + caption_tst6 + cell1 + cell2 + + + + + + diff --git a/accessible/tests/mochitest/name/test_browserui.xul b/accessible/tests/mochitest/name/test_browserui.xul new file mode 100644 index 000000000..ec21708fd --- /dev/null +++ b/accessible/tests/mochitest/name/test_browserui.xul @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + Mozilla Bug + +

    + +
    +    
    + + + +
    +
    diff --git a/accessible/tests/mochitest/name/test_counterstyle.html b/accessible/tests/mochitest/name/test_counterstyle.html new file mode 100644 index 000000000..506cea69a --- /dev/null +++ b/accessible/tests/mochitest/name/test_counterstyle.html @@ -0,0 +1,153 @@ + + + + nsIAccessible::name calculation for @counter-style + + + + + + + + + + + + + + + + + Bug 966166 + + +
      + + + + + diff --git a/accessible/tests/mochitest/name/test_general.html b/accessible/tests/mochitest/name/test_general.html new file mode 100644 index 000000000..28e7a11a9 --- /dev/null +++ b/accessible/tests/mochitest/name/test_general.html @@ -0,0 +1,631 @@ + + + + nsIAccessible::name calculation + + + + + + + + + + + + + + + Bug 428479 + + + Bug 429666 + + + Bug 444279 + + + Bug 459635 + + + Bug 530081 +
      + + Bug 604391 + + + Bug 669312 + + + Bug 704416 + + + Bug 812041 + + + Bug 823927 + + + Bug 835666 + + + Mozilla Bug 833256 + +

      + +
      +  
      + + + +
      + + +
      + + + text + +
      + + + text1 + text2 + +
      + + + + + + + nomore text + +
      + + + + nomore + hidden + text2 + hidden2 + + + +
      + + +
      + +
      + + +
      text
      more text
      + +
      + + + + +
      textspacetext
      + +
      + + + textimage + +
      + + + + + + + + + +
      + + + + + + +
      + + + text
      text
      + +
      + + + + + + +

      Choose country from.

      + + + +

      Country

      + + + + + + +    + + + +
      + + +
      + + +
      + + + +
      + +
      + + + + + + + + + + + + + + + 14 + + + + + +
      +
      + i am visible + i am hidden +
      +
      + + + + + + + + +
      menuitem 2
      + + + +
      +

      This is a paragraph inside the article.

      +
      + + + 15 + + +
      + +
      + + + + + + + + + + + + + + + + + + +
      + + + + + + + + + + + + + + + + + +
      + + + + + + + + + + + + + +

      Image: + x^2 + y^2 + z^2 + +

      + +

      Text: + x2 + + y2 + z2 + + +

      subtree
      + + + diff --git a/accessible/tests/mochitest/name/test_general.xul b/accessible/tests/mochitest/name/test_general.xul new file mode 100644 index 000000000..c144e6f4f --- /dev/null +++ b/accessible/tests/mochitest/name/test_general.xul @@ -0,0 +1,382 @@ + + + + + + + + + + + + + + + + + + + Mozilla Bug 444279 + + + Mozilla Bug 441991 + +

      + +
      +    
      + + + + + + +
      +
      + + + + + + + + + + + + + + + + + + + + + + Mozilla Bug 421242 + + +

      + +
      +  
      +
      + + +
      + + diff --git a/accessible/tests/mochitest/relations/test_embeds.xul b/accessible/tests/mochitest/relations/test_embeds.xul new file mode 100644 index 000000000..0cb6d6c65 --- /dev/null +++ b/accessible/tests/mochitest/relations/test_embeds.xul @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + Mozilla Bug 707654 + +

      + +
      +    
      + +
      +
      diff --git a/accessible/tests/mochitest/relations/test_general.html b/accessible/tests/mochitest/relations/test_general.html new file mode 100644 index 000000000..bcb1d282a --- /dev/null +++ b/accessible/tests/mochitest/relations/test_general.html @@ -0,0 +1,406 @@ + + + + nsIAccessible::getAccessibleRelated() tests + + + + + + + + + + + + + + + + Bug 475298 + + + Bug 527461 + + + Bug 558036 + + + Bug 682790 + + + Bug 687393 + + + Bug 864224 + +

      + +
      +  
      + + + + + + + + + + + + + + + + + + + + + + label + + + label1 + label2 + + + description + + + description1 + description2 + + +
      Yellow
      +
      Orange
      +
      +
      Blue
      +
      Green
      +
      Light green
      +
      Green2
      +
      +
      Super light green
      +
      +
      + +
      +
      +
      cell 1,1
      +
      cell 1,2
      +
      +
      +
      cell 2,1
      +
      cell 2,2
      +
      +
      +
      cell 3,1
      +
      cell 3,2
      +
      +
      + +
        +
      • Item 1 +
          +
        • Item 1A
        • +
        • Item 1B
        • +
        +
      • +
      + +
      +
      + cell1cell2 +
      +
      + cell3cell4 +
      +
      + cell5cell6 +
      +
      + +
      +
      Item 1 +
      +
      Item 1A
      +
      Item 1B
      +
      +
      +
      + + + +
      + +
      +
      tabpanel
      + +
      1
      +
      a
      + + +
      live region
      + + flow to + flow from + + flow to + flow from + flow from + +
      + + + + + +
      + + + + + + +
      tabple caption
      cell1cell2
      + +
      + legend + +
      + +
      +
      + + diff --git a/accessible/tests/mochitest/relations/test_general.xul b/accessible/tests/mochitest/relations/test_general.xul new file mode 100644 index 000000000..23bf7276b --- /dev/null +++ b/accessible/tests/mochitest/relations/test_general.xul @@ -0,0 +1,238 @@ + + + + + + + + + + + + Mozilla Bug 475298 +
      + + Mozilla Bug 67389 +
      + +

      + +
      +      
      + + + + + + + + + + label + + + label + label + + + description + + + label + label + + + description + + + description + description + + + Yellow + Orange + + Blue + Green + Light green + + + Dark green + + + + + + + + diff --git a/accessible/tests/mochitest/states/test_inputs.html b/accessible/tests/mochitest/states/test_inputs.html new file mode 100644 index 000000000..20c6deaf8 --- /dev/null +++ b/accessible/tests/mochitest/states/test_inputs.html @@ -0,0 +1,271 @@ + + + + HTML input states + + + + + + + + + + + + + + + Bug 559275 + + + Bug 389238 + + + Bug 599163 + + + Bug 601205 + + + Bug 601205 + + + Bug 559766 + + + Bug 699017 + + + Bug 733382 + + + Bug 878590 + + +

      + +
      +  
      + + +
      + + + + + + + + + + + + + + + + + + +
      + + + + + + + + +
      + + +
      + + + + + + + + + + + + + + + + + + + +
      + +
      + + + + + + + + + Email Address: + + + + + + +
      Search for: + + + + + + + + diff --git a/accessible/tests/mochitest/states/test_link.html b/accessible/tests/mochitest/states/test_link.html new file mode 100644 index 000000000..3f89f9f7f --- /dev/null +++ b/accessible/tests/mochitest/states/test_link.html @@ -0,0 +1,144 @@ + + + + HTML link states testing + + + + + + + + + + + + + + + + + + + Mozilla Bug 423409 + + + Mozilla Bug 754830 + + + Mozilla Bug 757774 + +

      + +
      +  
      + + link + link + link + link + aria link + aria button + not link + + example.com + + + diff --git a/accessible/tests/mochitest/states/test_popup.xul b/accessible/tests/mochitest/states/test_popup.xul new file mode 100644 index 000000000..bc40a8b70 --- /dev/null +++ b/accessible/tests/mochitest/states/test_popup.xul @@ -0,0 +1,55 @@ + + + + + + + + + + + + Mozilla Bug 504252 +
      +

      + +
      +      
      + + + +
      + +
      + diff --git a/accessible/tests/mochitest/states/test_selects.html b/accessible/tests/mochitest/states/test_selects.html new file mode 100644 index 000000000..0029fcbe4 --- /dev/null +++ b/accessible/tests/mochitest/states/test_selects.html @@ -0,0 +1,203 @@ + + + + HTML selects accessible states tests + + + + + + + + + + + + + + + + + Mozilla Bug 443889 + + + Mozilla Bug 640716 + + + Mozilla Bug 689847 + + + Mozilla Bug 756983 + + + Mozilla Bug 907682 + +

      + +
      +  
      + + + + + + + + + + + diff --git a/accessible/tests/mochitest/states/test_stale.html b/accessible/tests/mochitest/states/test_stale.html new file mode 100644 index 000000000..8f85a1995 --- /dev/null +++ b/accessible/tests/mochitest/states/test_stale.html @@ -0,0 +1,115 @@ + + + + Stale state testing + + + + + + + + + + + + + + + Mozilla Bug 676267 + +

      + +
      +  
      + +
      + + + diff --git a/accessible/tests/mochitest/states/test_tabs.xul b/accessible/tests/mochitest/states/test_tabs.xul new file mode 100644 index 000000000..a596e178b --- /dev/null +++ b/accessible/tests/mochitest/states/test_tabs.xul @@ -0,0 +1,70 @@ + + + + + + + + + + + + Mozilla Bug 577727 +
      +

      + +
      +      
      + + + + + + + + + + + + + + + +
      + +
      + diff --git a/accessible/tests/mochitest/states/test_textbox.xul b/accessible/tests/mochitest/states/test_textbox.xul new file mode 100644 index 000000000..3daf2abe1 --- /dev/null +++ b/accessible/tests/mochitest/states/test_textbox.xul @@ -0,0 +1,153 @@ + + + + + + + + + + + + + Mozilla Bug 442648 + + + Mozilla Bug 648235 + +

      + +
      +    
      + + + + + + + + + + + + + + + +
      +
      diff --git a/accessible/tests/mochitest/states/test_tree.xul b/accessible/tests/mochitest/states/test_tree.xul new file mode 100644 index 000000000..878a8d25b --- /dev/null +++ b/accessible/tests/mochitest/states/test_tree.xul @@ -0,0 +1,152 @@ + + + + + + + + + + + + + Mozilla Bug 503727 +
      +

      + +
      +      
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      diff --git a/accessible/tests/mochitest/states/test_visibility.html b/accessible/tests/mochitest/states/test_visibility.html new file mode 100644 index 000000000..a2e4a34e6 --- /dev/null +++ b/accessible/tests/mochitest/states/test_visibility.html @@ -0,0 +1,175 @@ + + + visibility state testing + + + + + + + + + + + + + + + + + + + + Mozilla Bug 591363 + + + Mozilla Bug 768786 + +

      + +
      +  
      + +
      + + +
      div
      +
      + offscreen! +
      +
      + transformed! +
      + + +
      +

      absolute

      +
      + +
      + + diff --git a/accessible/tests/mochitest/states/test_visibility.xul b/accessible/tests/mochitest/states/test_visibility.xul new file mode 100644 index 000000000..8b2ac990c --- /dev/null +++ b/accessible/tests/mochitest/states/test_visibility.xul @@ -0,0 +1,152 @@ + + + + + + + + + + + + Mozilla Bug 810260 + + + Mozilla Bug 865591 + + +

      + +
      +      
      + + + + + + + + +
      + + + + +
      cell
      + + + + +
      cell
      +
      + +
      + + + + +
      cell
      + + + + +
      cell
      +
      + +
      +
        +
      • item
      • +
      +
        +
      • item
      • +
      +
      + +
      + + + diff --git a/accessible/tests/mochitest/tree/test_aria_table.html b/accessible/tests/mochitest/tree/test_aria_table.html new file mode 100644 index 000000000..64d3bd891 --- /dev/null +++ b/accessible/tests/mochitest/tree/test_aria_table.html @@ -0,0 +1,63 @@ + + + + ARIA table tests + + + + + + + + + + + + + Bug 1173364 + +

      + +
      +  
      + +
      +
      +
      +
      cell
      +
      +
      +
      + + + diff --git a/accessible/tests/mochitest/tree/test_brokencontext.html b/accessible/tests/mochitest/tree/test_brokencontext.html new file mode 100644 index 000000000..d63b4ae11 --- /dev/null +++ b/accessible/tests/mochitest/tree/test_brokencontext.html @@ -0,0 +1,265 @@ + + + + Broken context hierarchy + + + + + + + + + + + + + + Bug 706849 + + + Bug 804461 + + + Bug 945435 + +

      + +
      +  
      + + + + + + + +
      not a headernot a cell
      + + + + + + +
      not a headernot a cell
      + + + + + + +
      table1 cell1table1 cell2
      + +
      + + + + +
      cell
      +
      + + + + + + +
      + + + + +
      cell0
      +
      cell1
      + + + + + + + + +
        +
      • item
      • + Oranges +
      + +
        +
      1. item
      2. +
      + +
      +
      term +
      definition
      +
      + + + Google +

      h1

      +

      h2

      +

      h3

      +

      h4

      +
      h5
      +
      h6
      + + diff --git a/accessible/tests/mochitest/tree/test_button.xul b/accessible/tests/mochitest/tree/test_button.xul new file mode 100644 index 000000000..39d189f41 --- /dev/null +++ b/accessible/tests/mochitest/tree/test_button.xul @@ -0,0 +1,73 @@ + + + + + + + + + + + + Mozilla Bug 249292 +
      +

      + +
      +      
      + + + + +
      + + + +
      +
      + + +
      + + + diff --git a/accessible/tests/mochitest/tree/test_cssoverflow.html b/accessible/tests/mochitest/tree/test_cssoverflow.html new file mode 100644 index 000000000..c67128fbc --- /dev/null +++ b/accessible/tests/mochitest/tree/test_cssoverflow.html @@ -0,0 +1,146 @@ + + + + CSS overflow testing + + + + + + + + + + + + + + + + + + Mozilla Bug 591163 +
      + + Mozilla Bug 570275 +
      + + Mozilla Bug 686247 +
      + +

      + +
      +  
      +
      + +
      + link +
      +
      + link2 +
      + + diff --git a/accessible/tests/mochitest/tree/test_dochierarchy.html b/accessible/tests/mochitest/tree/test_dochierarchy.html new file mode 100644 index 000000000..0104c6aba --- /dev/null +++ b/accessible/tests/mochitest/tree/test_dochierarchy.html @@ -0,0 +1,86 @@ + + + + Test document hierarchy + + + + + + + + + + + + + + Mozilla Bug 592913 + +

      + +
      +  
      + + + + diff --git a/accessible/tests/mochitest/tree/test_dockids.html b/accessible/tests/mochitest/tree/test_dockids.html new file mode 100644 index 000000000..943ac18b3 --- /dev/null +++ b/accessible/tests/mochitest/tree/test_dockids.html @@ -0,0 +1,65 @@ + + + + Test document hierarchy + + + + + + + + + + + + + + Mozilla Bug 608887 + +

      + +
      +  
      + + + + diff --git a/accessible/tests/mochitest/tree/test_filectrl.html b/accessible/tests/mochitest/tree/test_filectrl.html new file mode 100644 index 000000000..f989d1eea --- /dev/null +++ b/accessible/tests/mochitest/tree/test_filectrl.html @@ -0,0 +1,58 @@ + + + + + File Input Control tests + + + + + + + + + + + + Mozilla Bug 483573 +

      + +
      +  
      + + + + diff --git a/accessible/tests/mochitest/tree/test_formctrl.html b/accessible/tests/mochitest/tree/test_formctrl.html new file mode 100644 index 000000000..c5d5bc0b1 --- /dev/null +++ b/accessible/tests/mochitest/tree/test_formctrl.html @@ -0,0 +1,132 @@ + + + + + HTML form controls tests + + + + + + + + + + + + + Bug 342045 + + + Bug 524521 + + + Bug 558036 + + + Bug 559764 + +

      + +
      +  
      + + + + + + + + + + + 1337 + + + diff --git a/accessible/tests/mochitest/tree/test_formctrl.xul b/accessible/tests/mochitest/tree/test_formctrl.xul new file mode 100644 index 000000000..34dc3795e --- /dev/null +++ b/accessible/tests/mochitest/tree/test_formctrl.xul @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + Mozilla Bug 342045 +
      +

      + +
      +      
      + + + + + + + + + + + + + + + + + +
      + +
      + diff --git a/accessible/tests/mochitest/tree/test_gencontent.html b/accessible/tests/mochitest/tree/test_gencontent.html new file mode 100644 index 000000000..0932f5c29 --- /dev/null +++ b/accessible/tests/mochitest/tree/test_gencontent.html @@ -0,0 +1,71 @@ + + + + + Generated content tests + + + + + + + + + + + + + + + Mozilla Bug 530081 + +

      + +
      +  
      + +
      MIDDLE
      + + diff --git a/accessible/tests/mochitest/tree/test_groupbox.xul b/accessible/tests/mochitest/tree/test_groupbox.xul new file mode 100644 index 000000000..0b68e6018 --- /dev/null +++ b/accessible/tests/mochitest/tree/test_groupbox.xul @@ -0,0 +1,64 @@ + + + + + + + + + + + + Mozilla Bug 342045 +
      +

      + +
      +      
      + + + + + + + + +
      + +
      + diff --git a/accessible/tests/mochitest/tree/test_iframe.html b/accessible/tests/mochitest/tree/test_iframe.html new file mode 100644 index 000000000..dae398fd8 --- /dev/null +++ b/accessible/tests/mochitest/tree/test_iframe.html @@ -0,0 +1,52 @@ + + + + Outer document accessible tests + + + + + + + + + + + + + Mozilla Bug 342045 + +

      + +
      +  
      + + + + + + + diff --git a/accessible/tests/mochitest/treeupdate/test_bug1276857.html b/accessible/tests/mochitest/treeupdate/test_bug1276857.html new file mode 100644 index 000000000..5eceae9eb --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_bug1276857.html @@ -0,0 +1,143 @@ + + + + + DOM mutations test + + + + + + + + + + + + + +

      + +
      +  
      + +
      + +
      + + + +
      + + + + diff --git a/accessible/tests/mochitest/treeupdate/test_bug852150.xhtml b/accessible/tests/mochitest/treeupdate/test_bug852150.xhtml new file mode 100644 index 000000000..094d148a0 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_bug852150.xhtml @@ -0,0 +1,59 @@ + + + Canvas subdom mutation + + + + + + + + + + + + + + Mozilla Bug 852150 + + +

      + +
      +  
      + + +
      + + + diff --git a/accessible/tests/mochitest/treeupdate/test_bug883708.xhtml b/accessible/tests/mochitest/treeupdate/test_bug883708.xhtml new file mode 100644 index 000000000..6265a1c7f --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_bug883708.xhtml @@ -0,0 +1,33 @@ + + + + + + + + + + Mozilla Bug 883708 + + +

      + +
      +  
      + +
      + diff --git a/accessible/tests/mochitest/treeupdate/test_bug884251.xhtml b/accessible/tests/mochitest/treeupdate/test_bug884251.xhtml new file mode 100644 index 000000000..d1821188b --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_bug884251.xhtml @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/accessible/tests/mochitest/treeupdate/test_bug895082.html b/accessible/tests/mochitest/treeupdate/test_bug895082.html new file mode 100644 index 000000000..aaefdc46c --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_bug895082.html @@ -0,0 +1,51 @@ + + + +Replace body test + + + + + + + + + + + + + + Bug 895082 +

      + +
      +  
      + +
      + + + diff --git a/accessible/tests/mochitest/treeupdate/test_canvas.html b/accessible/tests/mochitest/treeupdate/test_canvas.html new file mode 100644 index 000000000..6ae129a67 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_canvas.html @@ -0,0 +1,92 @@ + + + + + Canvas subdom mutation + + + + + + + + + + + + + + + Mozilla Bug 495912 + + +

      + +
      +  
      + + + + + +
      + + diff --git a/accessible/tests/mochitest/treeupdate/test_colorpicker.xul b/accessible/tests/mochitest/treeupdate/test_colorpicker.xul new file mode 100644 index 000000000..9b15c9174 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_colorpicker.xul @@ -0,0 +1,150 @@ + + + + + + + + + + + + Mozilla Bug 249292 + + + Mozilla Bug 630486 + +
      +

      + +
      +      
      + + + + + +
      + +
      + diff --git a/accessible/tests/mochitest/treeupdate/test_contextmenu.xul b/accessible/tests/mochitest/treeupdate/test_contextmenu.xul new file mode 100644 index 000000000..5b31e0136 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_contextmenu.xul @@ -0,0 +1,317 @@ + + + + + + + + + + + + Mozilla Bug 630194 + + + Mozilla Bug 630486 + +

      + +
      +    
      + + + + + + + + + + + + + + + + + + + + +
      +
      diff --git a/accessible/tests/mochitest/treeupdate/test_cssoverflow.html b/accessible/tests/mochitest/treeupdate/test_cssoverflow.html new file mode 100644 index 000000000..ed9edd66e --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_cssoverflow.html @@ -0,0 +1,143 @@ + + + + Testing HTML scrollable frames (css overflow style) + + + + + + + + + + + + + + + + Mozilla Bug 677154 + +

      + +
      +  
      +
      + +
      +
      + + diff --git a/accessible/tests/mochitest/treeupdate/test_deck.xul b/accessible/tests/mochitest/treeupdate/test_deck.xul new file mode 100644 index 000000000..13561abab --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_deck.xul @@ -0,0 +1,109 @@ + + + + + + + + + + + + Mozilla Bug 814836 + + +

      + +
      +      
      + + + + + + This is the first page + + + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + diff --git a/accessible/tests/mochitest/treeupdate/test_optgroup.html b/accessible/tests/mochitest/treeupdate/test_optgroup.html new file mode 100644 index 000000000..27323bbc3 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_optgroup.html @@ -0,0 +1,137 @@ + + + + Add and remove optgroup test + + + + + + + + + + + + + + Bug 616452 +

      + +
      +  
      + + + +
      + + diff --git a/accessible/tests/mochitest/treeupdate/test_recreation.html b/accessible/tests/mochitest/treeupdate/test_recreation.html new file mode 100644 index 000000000..7754eb703 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_recreation.html @@ -0,0 +1,155 @@ + + + + + Test accessible recreation + + + + + + + + + + + + + + + Mozilla Bug 570275 + + +

      + +
      +  
      + + span +
      div
      + anchor +
      list
      + +
      + + diff --git a/accessible/tests/mochitest/treeupdate/test_select.html b/accessible/tests/mochitest/treeupdate/test_select.html new file mode 100644 index 000000000..006618b80 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_select.html @@ -0,0 +1,130 @@ + + + + Add select options test + + + + + + + + + + + + + + Mozilla Bug 616452 + + Mozilla Bug 616940 +

      + +
      +  
      + + + +
      + + diff --git a/accessible/tests/mochitest/treeupdate/test_shutdown.xul b/accessible/tests/mochitest/treeupdate/test_shutdown.xul new file mode 100644 index 000000000..2e6f7a7b3 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_shutdown.xul @@ -0,0 +1,132 @@ + + + + + + + + + + + + Bug 503727 +
      +

      + +
      +      
      + + + + + + + + + + + + + + + + + + +
      + +
      diff --git a/accessible/tests/mochitest/treeupdate/test_table.html b/accessible/tests/mochitest/treeupdate/test_table.html new file mode 100644 index 000000000..abadefdb0 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_table.html @@ -0,0 +1,81 @@ + + + + Table update tests + + + + + + + + + + + +

      + +
      +  
      + + + + + + +
      cell1cell2
      + + diff --git a/accessible/tests/mochitest/treeupdate/test_textleaf.html b/accessible/tests/mochitest/treeupdate/test_textleaf.html new file mode 100644 index 000000000..16d3a1a2b --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_textleaf.html @@ -0,0 +1,180 @@ + + + + + Test accessible recreation + + + + + + + + + + + + + + + Mozilla Bug 545465 + + + Mozilla Bug 625652 + + + Mozilla Bug 706335 + + +

      + +
      +  
      + +
      +
      div
      + span +
      + +

      text

      +
      text
      + +
      + + diff --git a/accessible/tests/mochitest/treeupdate/test_visibility.html b/accessible/tests/mochitest/treeupdate/test_visibility.html new file mode 100644 index 000000000..a1c130fb6 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_visibility.html @@ -0,0 +1,437 @@ + + + + + Style visibility tree update test + + + + + + + + + + + + + + + Mozilla Bug 606125 + + +

      + +
      +  
      + + +
      +
      +
      text
      +
      +
      + + +
      +
      +
      +
      text
      +
      text
      +
      +
      +
      + + +
      +
      +
      text
      +
      +
      +
      text
      +
      +
      + + +
      + + + + +
      + +
      +
      + + +
      +
      + + + + +
      +
      text
      +
      +
      +
      + + +
      +
      + + + + +
      + + + + +
      +
      text
      +
      +
      +
      text
      +
      +
      + +
      + + diff --git a/accessible/tests/mochitest/treeupdate/test_whitespace.html b/accessible/tests/mochitest/treeupdate/test_whitespace.html new file mode 100644 index 000000000..e7ba9b059 --- /dev/null +++ b/accessible/tests/mochitest/treeupdate/test_whitespace.html @@ -0,0 +1,187 @@ + + + + + Whitespace text accessible creation/desctruction + + + + + + + + + + + + + + + Mozilla Bug 625652 + + +

      + +
      +  
      + +
      +
      + +
      + + diff --git a/accessible/tests/mochitest/treeview.css b/accessible/tests/mochitest/treeview.css new file mode 100644 index 000000000..1bffb1798 --- /dev/null +++ b/accessible/tests/mochitest/treeview.css @@ -0,0 +1,15 @@ +treechildren::-moz-tree-checkbox(checked) { + list-style-image: url("chrome://global/skin/checkbox/cbox-check.gif"); +} + +treechildren::-moz-tree-image(cyclerState1) { + list-style-image: url("chrome://global/skin/console/bullet-question.png"); +} + +treechildren::-moz-tree-image(cyclerState2) { + list-style-image: url("chrome://global/skin/console/bullet-warning.png"); +} + +treechildren::-moz-tree-image(cyclerState3) { + list-style-image: url("chrome://global/skin/console/bullet-error.png"); +} diff --git a/accessible/tests/mochitest/treeview.js b/accessible/tests/mochitest/treeview.js new file mode 100644 index 000000000..869471c85 --- /dev/null +++ b/accessible/tests/mochitest/treeview.js @@ -0,0 +1,289 @@ +/** + * Helper method to start a single XUL tree test. + */ +function loadXULTreeAndDoTest(aDoTestFunc, aTreeID, aTreeView) +{ + var doTestFunc = aDoTestFunc ? aDoTestFunc : gXULTreeLoadContext.doTestFunc; + var treeID = aTreeID ? aTreeID : gXULTreeLoadContext.treeID; + var treeView = aTreeView ? aTreeView : gXULTreeLoadContext.treeView; + + function loadXULTree(aTreeID, aTreeView) + { + this.treeNode = getNode(aTreeID); + + this.eventSeq = [ + new invokerChecker(EVENT_REORDER, this.treeNode) + ]; + + this.invoke = function loadXULTree_invoke() + { + this.treeNode.view = aTreeView; + } + + this.getID = function loadXULTree_getID() + { + return "Load XUL tree " + prettyName(aTreeID); + } + } + + gXULTreeLoadContext.queue = new eventQueue(); + gXULTreeLoadContext.queue.push(new loadXULTree(treeID, treeView)); + gXULTreeLoadContext.queue.onFinish = function() + { + SimpleTest.executeSoon(doTestFunc); + return DO_NOT_FINISH_TEST; + } + gXULTreeLoadContext.queue.invoke(); +} + +/** + * Analogy of addA11yLoadEvent, nice helper to load XUL tree and start the test. + */ +function addA11yXULTreeLoadEvent(aDoTestFunc, aTreeID, aTreeView) +{ + gXULTreeLoadContext.doTestFunc = aDoTestFunc; + gXULTreeLoadContext.treeID = aTreeID; + gXULTreeLoadContext.treeView = aTreeView; + + addA11yLoadEvent(loadXULTreeAndDoTest); +} + + +function nsTableTreeView(aRowCount) +{ + this.__proto__ = new nsTreeView(); + + for (var idx = 0; idx < aRowCount; idx++) + this.mData.push(new treeItem("row" + String(idx) + "_")); +} + +function nsTreeTreeView() +{ + this.__proto__ = new nsTreeView(); + + this.mData = [ + new treeItem("row1"), + new treeItem("row2_", true, [new treeItem("row2.1_"), new treeItem("row2.2_")]), + new treeItem("row3_", false, [new treeItem("row3.1_"), new treeItem("row3.2_")]), + new treeItem("row4") + ]; +} + +function nsTreeView() +{ + this.mTree = null; + this.mData = []; +} + +nsTreeView.prototype = +{ + ////////////////////////////////////////////////////////////////////////////// + // nsITreeView implementation + + get rowCount() + { + return this.getRowCountIntl(this.mData); + }, + setTree: function setTree(aTree) + { + this.mTree = aTree; + }, + getCellText: function getCellText(aRow, aCol) + { + var data = this.getDataForIndex(aRow); + if (aCol.id in data.colsText) + return data.colsText[aCol.id]; + + return data.text + aCol.id; + }, + getCellValue: function getCellValue(aRow, aCol) + { + var data = this.getDataForIndex(aRow); + return data.value; + }, + getRowProperties: function getRowProperties(aIndex) { return ""; }, + getCellProperties: function getCellProperties(aIndex, aCol) + { + if (!aCol.cycler) + return ""; + + var data = this.getDataForIndex(aIndex); + return this.mCyclerStates[data.cyclerState]; + }, + getColumnProperties: function getColumnProperties(aCol) { return ""; }, + getParentIndex: function getParentIndex(aRowIndex) + { + var info = this.getInfoByIndex(aRowIndex); + return info.parentIndex; + }, + hasNextSibling: function hasNextSibling(aRowIndex, aAfterIndex) { }, + getLevel: function getLevel(aIndex) + { + var info = this.getInfoByIndex(aIndex); + return info.level; + }, + getImageSrc: function getImageSrc(aRow, aCol) {}, + getProgressMode: function getProgressMode(aRow, aCol) {}, + isContainer: function isContainer(aIndex) + { + var data = this.getDataForIndex(aIndex); + return data.open != undefined; + }, + isContainerOpen: function isContainerOpen(aIndex) + { + var data = this.getDataForIndex(aIndex); + return data.open; + }, + isContainerEmpty: function isContainerEmpty(aIndex) + { + var data = this.getDataForIndex(aIndex); + return data.open == undefined; + }, + isSeparator: function isSeparator(aIndex) {}, + isSorted: function isSorted() {}, + toggleOpenState: function toggleOpenState(aIndex) + { + var data = this.getDataForIndex(aIndex); + + data.open = !data.open; + var rowCount = this.getRowCountIntl(data.children); + + if (data.open) + this.mTree.rowCountChanged(aIndex + 1, rowCount); + else + this.mTree.rowCountChanged(aIndex + 1, -rowCount); + }, + selectionChanged: function selectionChanged() {}, + cycleHeader: function cycleHeader(aCol) {}, + cycleCell: function cycleCell(aRow, aCol) + { + var data = this.getDataForIndex(aRow); + data.cyclerState = (data.cyclerState + 1) % 3; + + this.mTree.invalidateCell(aRow, aCol); + }, + isEditable: function isEditable(aRow, aCol) + { + return true; + }, + isSelectable: function isSelectable(aRow, aCol) {}, + setCellText: function setCellText(aRow, aCol, aValue) + { + var data = this.getDataForIndex(aRow); + data.colsText[aCol.id] = aValue; + }, + setCellValue: function setCellValue(aRow, aCol, aValue) + { + var data = this.getDataForIndex(aRow); + data.value = aValue; + + this.mTree.invalidateCell(aRow, aCol); + }, + performAction: function performAction(aAction) {}, + performActionOnRow: function performActionOnRow(aAction, aRow) {}, + performActionOnCell: function performActionOnCell(aAction, aRow, aCol) {}, + + ////////////////////////////////////////////////////////////////////////////// + // public implementation + + appendItem: function appendItem(aText) + { + this.mData.push(new treeItem(aText)); + }, + + ////////////////////////////////////////////////////////////////////////////// + // private implementation + + getDataForIndex: function getDataForIndex(aRowIndex) + { + return this.getInfoByIndex(aRowIndex).data; + }, + + getInfoByIndex: function getInfoByIndex(aRowIndex) + { + var info = { + data: null, + parentIndex: -1, + level: 0, + index: -1 + }; + + this.getInfoByIndexIntl(aRowIndex, info, this.mData, 0); + return info; + }, + + getRowCountIntl: function getRowCountIntl(aChildren) + { + var rowCount = 0; + for (var childIdx = 0; childIdx < aChildren.length; childIdx++) { + rowCount++; + + var data = aChildren[childIdx]; + if (data.open) + rowCount += this.getRowCountIntl(data.children); + } + + return rowCount; + }, + + getInfoByIndexIntl: function getInfoByIndexIntl(aRowIdx, aInfo, + aChildren, aLevel) + { + var rowIdx = aRowIdx; + for (var childIdx = 0; childIdx < aChildren.length; childIdx++) { + var data = aChildren[childIdx]; + + aInfo.index++; + + if (rowIdx == 0) { + aInfo.data = data; + aInfo.level = aLevel; + return -1; + } + + if (data.open) { + var parentIdx = aInfo.index; + rowIdx = this.getInfoByIndexIntl(rowIdx - 1, aInfo, data.children, + aLevel + 1); + + if (rowIdx == -1) { + if (aInfo.parentIndex == -1) + aInfo.parentIndex = parentIdx; + return 0; + } + } else { + rowIdx--; + } + } + + return rowIdx; + }, + + mCyclerStates: [ + "cyclerState1", + "cyclerState2", + "cyclerState3" + ] +}; + +function treeItem(aText, aOpen, aChildren) +{ + this.text = aText; + this.colsText = {}; + this.open = aOpen; + this.value = "true"; + this.cyclerState = 0; + if (aChildren) + this.children = aChildren; +} + +/** + * Used in conjunction with loadXULTreeAndDoTest and addA11yXULTreeLoadEvent. + */ +var gXULTreeLoadContext = +{ + doTestFunc: null, + treeID: null, + treeView: null, + queue: null +}; diff --git a/accessible/tests/mochitest/value.js b/accessible/tests/mochitest/value.js new file mode 100644 index 000000000..cc9dffe00 --- /dev/null +++ b/accessible/tests/mochitest/value.js @@ -0,0 +1,32 @@ +//////////////////////////////////////////////////////////////////////////////// +// Public methods + +/** + * Tests nsIAccessibleValue interface. + * + * @param aAccOrElmOrId [in] identifier of accessible + * @param aValue [in] accessible value (nsIAccessible::value) + * @param aCurrValue [in] current value (nsIAccessibleValue::currentValue) + * @param aMinValue [in] minimum value (nsIAccessibleValue::minimumValue) + * @param aMaxValue [in] maximumn value (nsIAccessibleValue::maximumValue) + * @param aMinIncr [in] minimum increment value + * (nsIAccessibleValue::minimumIncrement) + */ +function testValue(aAccOrElmOrId, aValue, aCurrValue, + aMinValue, aMaxValue, aMinIncr) +{ + var acc = getAccessible(aAccOrElmOrId, [nsIAccessibleValue]); + if (!acc) + return; + + is(acc.value, aValue, "Wrong value of " + prettyName(aAccOrElmOrId)); + + is(acc.currentValue, aCurrValue, + "Wrong current value of " + prettyName(aAccOrElmOrId)); + is(acc.minimumValue, aMinValue, + "Wrong minimum value of " + prettyName(aAccOrElmOrId)); + is(acc.maximumValue, aMaxValue, + "Wrong maximum value of " + prettyName(aAccOrElmOrId)); + is(acc.minimumIncrement, aMinIncr, + "Wrong minimum increment value of " + prettyName(aAccOrElmOrId)); +} diff --git a/accessible/tests/mochitest/value/a11y.ini b/accessible/tests/mochitest/value/a11y.ini new file mode 100644 index 000000000..b93d9b180 --- /dev/null +++ b/accessible/tests/mochitest/value/a11y.ini @@ -0,0 +1,9 @@ +[DEFAULT] +support-files = + !/accessible/tests/mochitest/*.js + +[test_general.html] +[test_number.html] +[test_progress.html] +[test_progress.xul] +[test_range.html] diff --git a/accessible/tests/mochitest/value/test_general.html b/accessible/tests/mochitest/value/test_general.html new file mode 100644 index 000000000..12e718ba1 --- /dev/null +++ b/accessible/tests/mochitest/value/test_general.html @@ -0,0 +1,159 @@ + + + + nsIAccessible value testing + + + + + + + + + + + + + + + + + + + Bug 494807 + + + Bug 819273 + + + Bug 887250 + +

      + +
      +  
      + + menuitem + button + checkbox + + + app + main + nav + + + link + +
      helo
      + +
      +
      +
        +
      • Zebra
      • +
      • Zoom
      • +
      + +
      +
      +
        +
      • Zebra
      • +
      • Zoom
      • +
      + +
      +
      +
        +
      • 1
      • +
      • 2
      • +
      • 3
      • +
      +
      + + + + + + diff --git a/accessible/tests/mochitest/value/test_number.html b/accessible/tests/mochitest/value/test_number.html new file mode 100644 index 000000000..68825b445 --- /dev/null +++ b/accessible/tests/mochitest/value/test_number.html @@ -0,0 +1,59 @@ + + + + nsIAccessible value testing for input@type=range element + + + + + + + + + + + + + + + + + + Bug 559761 + +

      + +
      +  
      + + + + + + + + + diff --git a/accessible/tests/mochitest/value/test_progress.html b/accessible/tests/mochitest/value/test_progress.html new file mode 100644 index 000000000..b99cce14c --- /dev/null +++ b/accessible/tests/mochitest/value/test_progress.html @@ -0,0 +1,61 @@ + + + + nsIAccessible value testing for progress element + + + + + + + + + + + + + + + + + + Mozilla Bug 559773 +
      +

      + +
      +  
      + + + this will be read by legacy browsers + this will be read by legacy browsers + this will be read by legacy browsers + this will be read by legacy browsers + this will be read by legacy browsers + this will be read by legacy browsers + + diff --git a/accessible/tests/mochitest/value/test_progress.xul b/accessible/tests/mochitest/value/test_progress.xul new file mode 100644 index 000000000..5ae4a358f --- /dev/null +++ b/accessible/tests/mochitest/value/test_progress.xul @@ -0,0 +1,72 @@ + + + + + + + + + + + + Mozilla Bug 489551 +
      +

      + +
      +      
      + + + + + + + + + + + + + + +
      + +
      + diff --git a/accessible/tests/mochitest/value/test_range.html b/accessible/tests/mochitest/value/test_range.html new file mode 100644 index 000000000..b795f7a79 --- /dev/null +++ b/accessible/tests/mochitest/value/test_range.html @@ -0,0 +1,59 @@ + + + + nsIAccessible value testing for input@type=range element + + + + + + + + + + + + + + + + + + Bug 559764 + +

      + +
      +  
      + + + + + + + + + -- cgit v1.2.3