summaryrefslogtreecommitdiff
path: root/browser/devtools/webconsole/test
diff options
context:
space:
mode:
Diffstat (limited to 'browser/devtools/webconsole/test')
-rw-r--r--browser/devtools/webconsole/test/browser.ini380
-rw-r--r--browser/devtools/webconsole/test/browser_bug1045902_console_csp_ignore_reflected_xss_message.js59
-rw-r--r--browser/devtools/webconsole/test/browser_bug664688_sandbox_update_after_navigation.js91
-rw-r--r--browser/devtools/webconsole/test/browser_bug_638949_copy_link_location.js105
-rw-r--r--browser/devtools/webconsole/test/browser_bug_862916_console_dir_and_filter_off.js31
-rw-r--r--browser/devtools/webconsole/test/browser_bug_865288_repeat_different_objects.js63
-rw-r--r--browser/devtools/webconsole/test/browser_bug_865871_variables_view_close_on_esc_key.js98
-rw-r--r--browser/devtools/webconsole/test/browser_bug_869003_inspect_cross_domain_object.js76
-rw-r--r--browser/devtools/webconsole/test/browser_bug_871156_ctrlw_close_tab.js79
-rw-r--r--browser/devtools/webconsole/test/browser_cached_messages.js53
-rw-r--r--browser/devtools/webconsole/test/browser_console.js120
-rw-r--r--browser/devtools/webconsole/test/browser_console_addonsdk_loader_exception.js90
-rw-r--r--browser/devtools/webconsole/test/browser_console_clear_on_reload.js54
-rw-r--r--browser/devtools/webconsole/test/browser_console_click_focus.js55
-rw-r--r--browser/devtools/webconsole/test/browser_console_consolejsm_output.js137
-rw-r--r--browser/devtools/webconsole/test/browser_console_copy_command.js70
-rw-r--r--browser/devtools/webconsole/test/browser_console_copy_entire_message_context_menu.js64
-rw-r--r--browser/devtools/webconsole/test/browser_console_dead_objects.js86
-rw-r--r--browser/devtools/webconsole/test/browser_console_error_source_click.js73
-rw-r--r--browser/devtools/webconsole/test/browser_console_filters.js60
-rw-r--r--browser/devtools/webconsole/test/browser_console_hide_jsterm_when_devtools_chrome_enabled_false.js105
-rw-r--r--browser/devtools/webconsole/test/browser_console_iframe_messages.js104
-rw-r--r--browser/devtools/webconsole/test/browser_console_keyboard_accessibility.js79
-rw-r--r--browser/devtools/webconsole/test/browser_console_log_inspectable_object.js50
-rw-r--r--browser/devtools/webconsole/test/browser_console_native_getters.js99
-rw-r--r--browser/devtools/webconsole/test/browser_console_navigation_marker.js75
-rw-r--r--browser/devtools/webconsole/test/browser_console_nsiconsolemessage.js80
-rw-r--r--browser/devtools/webconsole/test/browser_console_open_or_focus.js47
-rw-r--r--browser/devtools/webconsole/test/browser_console_optimized_out_vars.js82
-rw-r--r--browser/devtools/webconsole/test/browser_console_private_browsing.js200
-rw-r--r--browser/devtools/webconsole/test/browser_console_variables_view.js189
-rw-r--r--browser/devtools/webconsole/test/browser_console_variables_view_dom_nodes.js56
-rw-r--r--browser/devtools/webconsole/test/browser_console_variables_view_dont_sort_non_sortable_classes_properties.js101
-rw-r--r--browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js97
-rw-r--r--browser/devtools/webconsole/test/browser_console_variables_view_while_debugging.js131
-rw-r--r--browser/devtools/webconsole/test/browser_console_variables_view_while_debugging_and_inspecting.js129
-rw-r--r--browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe.js147
-rw-r--r--browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe2.js63
-rw-r--r--browser/devtools/webconsole/test/browser_jsterm_inspect.js28
-rw-r--r--browser/devtools/webconsole/test/browser_longstring_hang.js53
-rw-r--r--browser/devtools/webconsole/test/browser_netpanel_longstring_expand.js307
-rw-r--r--browser/devtools/webconsole/test/browser_output_breaks_after_console_dir_uninspectable.js44
-rw-r--r--browser/devtools/webconsole/test/browser_output_longstring_expand.js83
-rw-r--r--browser/devtools/webconsole/test/browser_repeated_messages_accuracy.js125
-rw-r--r--browser/devtools/webconsole/test/browser_result_format_as_string.js43
-rw-r--r--browser/devtools/webconsole/test/browser_warn_user_about_replaced_api.js81
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_abbreviate_source_url.js21
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_allow_mixedcontent_securityerrors.js61
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_assert.js51
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js40
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_autocomplete_and_selfxss.js127
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_autocomplete_crossdomain_iframe.js59
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_autocomplete_in_debugger_stackframe.js242
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_autocomplete_popup_close_on_tab_switch.js33
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_basic_net_logging.js42
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_block_mixedcontent_securityerrors.js122
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_1006027_message_timestamps_incorrect.js41
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_1010953_cspro.js47
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_578437_page_reload.js39
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_579412_input_focus.js19
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_580001_closing_after_completion.js48
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_580030_errors_after_page_reload.js42
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_580454_timestamp_l10n.js30
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_582201_duplicate_errors.js44
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js31
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_585237_line_limit.js87
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_585956_console_trace.js48
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js376
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_popup.js119
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js91
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_587617_output_copy.js98
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_588342_document_focus.js39
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_588730_text_node_insertion.js53
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_588967_input_expansion.js45
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_589162_css_filter.js49
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_592442_closing_brackets.js37
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_593003_iframe_wrong_hud.js65
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js131
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_594497_history_arrow_keys.js156
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_595223_file_uri.js64
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_595350_multiple_windows_and_tabs.js101
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js203
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js104
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_597136_external_script_errors.js36
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_597136_network_requests_from_chrome.js48
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_597460_filter_scroll.js82
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_597756_reopen_closed_tab.js62
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_599725_response_headers.js87
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js66
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_601177_log_levels.js73
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_601352_scroll.js69
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_601667_filter_buttons.js241
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js177
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_603750_websocket.js37
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_611795.js64
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_613013_console_api_iframe.js29
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_613280_jsterm_copy.js80
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_613642_maintain_scroll.js116
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_613642_prune_scroll.js81
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_614793_jsterm_scroll.js63
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_618078_network_exceptions.js29
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_618311_close_panels.js90
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_621644_jsterm_dollar.js49
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_622303_persistent_filters.js139
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js28
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js130
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_632275_getters_document_width.js43
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js81
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_632817.js241
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_642108_pruneTest.js80
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_644419_log_limits.js225
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_646025_console_file_location.js54
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js109
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js107
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_658368_time_methods.js66
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_659907_console_dir.js28
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_660806_history_nav.js51
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_664131_console_group.js77
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_686937_autocomplete_JSTerm_helpers.js60
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_704295.js39
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_734061_No_input_change_and_Tab_key_pressed.js32
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js60
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_752559_ineffective_iframe_sandbox_warning.js73
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_about_blank_web_console_warning.js28
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_web_console_warning.js51
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_764572_output_open_url.js137
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_766001_JS_Console_in_Debugger.js78
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js31
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js147
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_804845_ctrl_key_nav.js217
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_817834_add_edited_input_to_history.js63
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_837351_securityerrors.js36
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_846918_hsts_invalid-headers.js35
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js113
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_cached_autocomplete.js108
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_cd_iframe.js110
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_certificate_messages.js94
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_change_font_size.js39
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_chrome.js38
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_clickable_urls.js85
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_closure_inspection.js89
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_column_numbers.js42
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_completion.js101
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_console_api_stackframe.js81
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_console_custom_styles.js79
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_console_extras.js40
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_console_logging_api.js101
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_console_trace_duplicates.js46
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_count.js77
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_dont_navigate_on_doubleclick.js50
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_execution_scope.js34
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_expandable_timestamps.js56
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_filter_buttons_contextmenu.js91
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_for_of.js27
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_history.js61
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_input_field_focus_on_panel_select.js33
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_inspect-parsed-documents.js34
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_js_input_expansion.js55
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_jsterm.js144
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_live_filtering_of_message_types.js55
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_live_filtering_on_search_strings.js96
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_log_file_filter.js82
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_message_node_id.js27
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_netlogging.js213
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_network_panel.js541
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_notifications.js77
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_open-links-without-callback.js52
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_01.js125
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_02.js160
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_03.js165
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_04.js127
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_05.js130
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_06.js127
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_copy_newlines.js67
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_01.js108
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_02.js111
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_03.js67
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_04.js106
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_events.js53
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_order.js47
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_output_table.js158
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_property_provider.js45
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_reflow.js32
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_scratchpad_panel_link.js63
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_show_subresource_security_errors.js30
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_split.js247
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_split_escape_key.js171
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_split_focus.js74
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_split_persist.js111
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_start_netmon_first.js37
-rw-r--r--browser/devtools/webconsole/test/browser_webconsole_view_source.js82
-rw-r--r--browser/devtools/webconsole/test/head.js1677
-rw-r--r--browser/devtools/webconsole/test/test-autocomplete-in-stackframe.html50
-rw-r--r--browser/devtools/webconsole/test/test-bug-585956-console-trace.html27
-rw-r--r--browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud-iframe.html13
-rw-r--r--browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud.html14
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-canvas-css.html17
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-canvas-css.js10
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-css-loader.css10
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-css-loader.css^headers^1
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-css-loader.html13
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-css-parser.css10
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-css-parser.html14
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-empty-getelementbyid.html16
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-empty-getelementbyid.js8
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-html.html16
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-image.html15
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-image.jpgbin0 -> 2532 bytes
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-imagemap.html17
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-malformedxml-external.html19
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-malformedxml-external.xml8
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-malformedxml.xhtml10
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-svg.xhtml17
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-workers.html18
-rw-r--r--browser/devtools/webconsole/test/test-bug-595934-workers.js9
-rw-r--r--browser/devtools/webconsole/test/test-bug-597136-external-script-errors.html25
-rw-r--r--browser/devtools/webconsole/test/test-bug-597136-external-script-errors.js14
-rw-r--r--browser/devtools/webconsole/test/test-bug-597756-reopen-closed-tab.html18
-rw-r--r--browser/devtools/webconsole/test/test-bug-599725-response-headers.sjs25
-rw-r--r--browser/devtools/webconsole/test/test-bug-600183-charset.html9
-rw-r--r--browser/devtools/webconsole/test/test-bug-600183-charset.html^headers^1
-rw-r--r--browser/devtools/webconsole/test/test-bug-601177-log-levels.html20
-rw-r--r--browser/devtools/webconsole/test/test-bug-601177-log-levels.js8
-rw-r--r--browser/devtools/webconsole/test/test-bug-603750-websocket.html14
-rw-r--r--browser/devtools/webconsole/test/test-bug-603750-websocket.js18
-rw-r--r--browser/devtools/webconsole/test/test-bug-609872-cd-iframe-child.html13
-rw-r--r--browser/devtools/webconsole/test/test-bug-609872-cd-iframe-parent.html14
-rw-r--r--browser/devtools/webconsole/test/test-bug-613013-console-api-iframe.html21
-rw-r--r--browser/devtools/webconsole/test/test-bug-618078-network-exceptions.html24
-rw-r--r--browser/devtools/webconsole/test/test-bug-621644-jsterm-dollar.html23
-rw-r--r--browser/devtools/webconsole/test/test-bug-630733-response-redirect-headers.sjs16
-rw-r--r--browser/devtools/webconsole/test/test-bug-632275-getters.html20
-rw-r--r--browser/devtools/webconsole/test/test-bug-632347-iterators-generators.html56
-rw-r--r--browser/devtools/webconsole/test/test-bug-644419-log-limits.html21
-rw-r--r--browser/devtools/webconsole/test/test-bug-646025-console-file-location.html12
-rw-r--r--browser/devtools/webconsole/test/test-bug-658368-time-methods.html24
-rw-r--r--browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html15
-rw-r--r--browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-inner.html13
-rw-r--r--browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-nested1.html14
-rw-r--r--browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-nested2.html14
-rw-r--r--browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning0.html13
-rw-r--r--browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning1.html13
-rw-r--r--browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning2.html13
-rw-r--r--browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning3.html14
-rw-r--r--browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning4.html14
-rw-r--r--browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning5.html14
-rw-r--r--browser/devtools/webconsole/test/test-bug-762593-insecure-passwords-about-blank-web-console-warning.html28
-rw-r--r--browser/devtools/webconsole/test/test-bug-762593-insecure-passwords-web-console-warning.html16
-rw-r--r--browser/devtools/webconsole/test/test-bug-766001-console-log.js10
-rw-r--r--browser/devtools/webconsole/test/test-bug-766001-js-console-links.html14
-rw-r--r--browser/devtools/webconsole/test/test-bug-766001-js-errors.js7
-rw-r--r--browser/devtools/webconsole/test/test-bug-782653-css-errors-1.css10
-rw-r--r--browser/devtools/webconsole/test/test-bug-782653-css-errors-2.css10
-rw-r--r--browser/devtools/webconsole/test/test-bug-782653-css-errors.html14
-rw-r--r--browser/devtools/webconsole/test/test-bug-837351-security-errors.html15
-rw-r--r--browser/devtools/webconsole/test/test-bug-846918-hsts-invalid-headers.html13
-rw-r--r--browser/devtools/webconsole/test/test-bug-846918-hsts-invalid-headers.html^headers^1
-rw-r--r--browser/devtools/webconsole/test/test-bug-859170-longstring-hang.html23
-rw-r--r--browser/devtools/webconsole/test/test-bug-869003-iframe.html20
-rw-r--r--browser/devtools/webconsole/test/test-bug-869003-top-window.html14
-rw-r--r--browser/devtools/webconsole/test/test-bug-952277-highlight-nodes-in-vview.html15
-rw-r--r--browser/devtools/webconsole/test/test-bug-989025-iframe-parent.html13
-rw-r--r--browser/devtools/webconsole/test/test-bug_923281_console_log_filter.html12
-rw-r--r--browser/devtools/webconsole/test/test-bug_923281_test1.js5
-rw-r--r--browser/devtools/webconsole/test/test-bug_923281_test2.js4
-rw-r--r--browser/devtools/webconsole/test/test-bug_939783_console_trace_duplicates.html35
-rw-r--r--browser/devtools/webconsole/test/test-certificate-messages.html22
-rw-r--r--browser/devtools/webconsole/test/test-closure-optimized-out.html34
-rw-r--r--browser/devtools/webconsole/test/test-closures.html26
-rw-r--r--browser/devtools/webconsole/test/test-console-api-stackframe.html32
-rw-r--r--browser/devtools/webconsole/test/test-console-assert.html23
-rw-r--r--browser/devtools/webconsole/test/test-console-column.html17
-rw-r--r--browser/devtools/webconsole/test/test-console-count-external-file.js7
-rw-r--r--browser/devtools/webconsole/test/test-console-count.html56
-rw-r--r--browser/devtools/webconsole/test/test-console-extras.html19
-rw-r--r--browser/devtools/webconsole/test/test-console-output-02.html61
-rw-r--r--browser/devtools/webconsole/test/test-console-output-03.html30
-rw-r--r--browser/devtools/webconsole/test/test-console-output-04.html77
-rw-r--r--browser/devtools/webconsole/test/test-console-output-dom-elements.html69
-rw-r--r--browser/devtools/webconsole/test/test-console-output-events.html42
-rw-r--r--browser/devtools/webconsole/test/test-console-replaced-api.html12
-rw-r--r--browser/devtools/webconsole/test/test-console-table.html52
-rw-r--r--browser/devtools/webconsole/test/test-console.html23
-rw-r--r--browser/devtools/webconsole/test/test-consoleiframes.html13
-rw-r--r--browser/devtools/webconsole/test/test-data.json1
-rw-r--r--browser/devtools/webconsole/test/test-data.json^headers^1
-rw-r--r--browser/devtools/webconsole/test/test-duplicate-error.html21
-rw-r--r--browser/devtools/webconsole/test/test-encoding-ISO-8859-1.html7
-rw-r--r--browser/devtools/webconsole/test/test-error.html21
-rw-r--r--browser/devtools/webconsole/test/test-eval-in-stackframe.html39
-rw-r--r--browser/devtools/webconsole/test/test-file-location.js9
-rw-r--r--browser/devtools/webconsole/test/test-filter.html11
-rw-r--r--browser/devtools/webconsole/test/test-for-of.html8
-rw-r--r--browser/devtools/webconsole/test/test-iframe-762593-insecure-form-action.html15
-rw-r--r--browser/devtools/webconsole/test/test-iframe-762593-insecure-frame.html15
-rw-r--r--browser/devtools/webconsole/test/test-iframe1.html10
-rw-r--r--browser/devtools/webconsole/test/test-iframe2.html11
-rw-r--r--browser/devtools/webconsole/test/test-iframe3.html11
-rw-r--r--browser/devtools/webconsole/test/test-image.pngbin0 -> 580 bytes
-rw-r--r--browser/devtools/webconsole/test/test-mixedcontent-securityerrors.html21
-rw-r--r--browser/devtools/webconsole/test/test-mutation.html16
-rw-r--r--browser/devtools/webconsole/test/test-network-request.html40
-rw-r--r--browser/devtools/webconsole/test/test-network.html11
-rw-r--r--browser/devtools/webconsole/test/test-observe-http-ajax.html17
-rw-r--r--browser/devtools/webconsole/test/test-own-console.html24
-rw-r--r--browser/devtools/webconsole/test/test-property-provider.html14
-rw-r--r--browser/devtools/webconsole/test/test-repeated-messages.html38
-rw-r--r--browser/devtools/webconsole/test/test-result-format-as-string.html25
-rw-r--r--browser/devtools/webconsole/test/test-webconsole-error-observer.html25
-rw-r--r--browser/devtools/webconsole/test/test_bug1045902_console_csp_ignore_reflected_xss_message.html10
-rw-r--r--browser/devtools/webconsole/test/test_bug1045902_console_csp_ignore_reflected_xss_message.html^headers^1
-rw-r--r--browser/devtools/webconsole/test/test_bug1092055_shouldwarn.html15
-rw-r--r--browser/devtools/webconsole/test/test_bug1092055_shouldwarn.js2
-rw-r--r--browser/devtools/webconsole/test/test_bug1092055_shouldwarn.js^headers^1
-rw-r--r--browser/devtools/webconsole/test/test_bug_1010953_cspro.html20
-rw-r--r--browser/devtools/webconsole/test/test_bug_1010953_cspro.html^headers^2
-rw-r--r--browser/devtools/webconsole/test/test_bug_770099_violation.html13
-rw-r--r--browser/devtools/webconsole/test/test_bug_770099_violation.html^headers^1
-rw-r--r--browser/devtools/webconsole/test/testscript.js1
319 files changed, 20899 insertions, 0 deletions
diff --git a/browser/devtools/webconsole/test/browser.ini b/browser/devtools/webconsole/test/browser.ini
new file mode 100644
index 000000000..4dca6e15e
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -0,0 +1,380 @@
+[DEFAULT]
+subsuite = devtools
+support-files =
+ head.js
+ test-bug-585956-console-trace.html
+ test-bug-593003-iframe-wrong-hud-iframe.html
+ test-bug-593003-iframe-wrong-hud.html
+ test-bug-595934-canvas-css.html
+ test-bug-595934-canvas-css.js
+ test-bug-595934-css-loader.css
+ test-bug-595934-css-loader.css^headers^
+ test-bug-595934-css-loader.html
+ test-bug-595934-css-parser.css
+ test-bug-595934-css-parser.html
+ test-bug-595934-empty-getelementbyid.html
+ test-bug-595934-empty-getelementbyid.js
+ test-bug-595934-html.html
+ test-bug-595934-image.html
+ test-bug-595934-image.jpg
+ test-bug-595934-imagemap.html
+ test-bug-595934-malformedxml-external.html
+ test-bug-595934-malformedxml-external.xml
+ test-bug-595934-malformedxml.xhtml
+ test-bug-595934-svg.xhtml
+ test-bug-595934-workers.html
+ test-bug-595934-workers.js
+ test-bug-597136-external-script-errors.html
+ test-bug-597136-external-script-errors.js
+ test-bug-597756-reopen-closed-tab.html
+ test-bug-599725-response-headers.sjs
+ test-bug-600183-charset.html
+ test-bug-600183-charset.html^headers^
+ test-bug-601177-log-levels.html
+ test-bug-601177-log-levels.js
+ test-bug-603750-websocket.html
+ test-bug-603750-websocket.js
+ test-bug-613013-console-api-iframe.html
+ test-bug-618078-network-exceptions.html
+ test-bug-621644-jsterm-dollar.html
+ test-bug-630733-response-redirect-headers.sjs
+ test-bug-632275-getters.html
+ test-bug-632347-iterators-generators.html
+ test-bug-644419-log-limits.html
+ test-bug-646025-console-file-location.html
+ test-bug-658368-time-methods.html
+ test-bug-737873-mixedcontent.html
+ test-bug-752559-ineffective-iframe-sandbox-warning0.html
+ test-bug-752559-ineffective-iframe-sandbox-warning1.html
+ test-bug-752559-ineffective-iframe-sandbox-warning2.html
+ test-bug-752559-ineffective-iframe-sandbox-warning3.html
+ test-bug-752559-ineffective-iframe-sandbox-warning4.html
+ test-bug-752559-ineffective-iframe-sandbox-warning5.html
+ test-bug-752559-ineffective-iframe-sandbox-warning-inner.html
+ test-bug-752559-ineffective-iframe-sandbox-warning-nested1.html
+ test-bug-752559-ineffective-iframe-sandbox-warning-nested2.html
+ test-bug-762593-insecure-passwords-about-blank-web-console-warning.html
+ test-bug-762593-insecure-passwords-web-console-warning.html
+ test-bug-766001-console-log.js
+ test-bug-766001-js-console-links.html
+ test-bug-766001-js-errors.js
+ test-bug-782653-css-errors-1.css
+ test-bug-782653-css-errors-2.css
+ test-bug-782653-css-errors.html
+ test-bug-837351-security-errors.html
+ test-bug-846918-hsts-invalid-headers.html
+ test-bug-846918-hsts-invalid-headers.html^headers^
+ test-bug-859170-longstring-hang.html
+ test-bug-869003-iframe.html
+ test-bug-869003-top-window.html
+ test-closure-optimized-out.html
+ test-closures.html
+ test-console-assert.html
+ test-console-count.html
+ test-console-count-external-file.js
+ test-console-extras.html
+ test-console-replaced-api.html
+ test-console.html
+ test-console-table.html
+ test-console-output-02.html
+ test-console-output-03.html
+ test-console-output-04.html
+ test-console-output-dom-elements.html
+ test-console-output-events.html
+ test-console-column.html
+ test-consoleiframes.html
+ test-certificate-messages.html
+ test-data.json
+ test-data.json^headers^
+ test-duplicate-error.html
+ test-encoding-ISO-8859-1.html
+ test-error.html
+ test-eval-in-stackframe.html
+ test-file-location.js
+ test-filter.html
+ test-for-of.html
+ test-iframe-762593-insecure-form-action.html
+ test-iframe-762593-insecure-frame.html
+ test-iframe1.html
+ test-iframe2.html
+ test-iframe3.html
+ test-image.png
+ test-mixedcontent-securityerrors.html
+ test-mutation.html
+ test-network-request.html
+ test-network.html
+ test-observe-http-ajax.html
+ test-own-console.html
+ test-property-provider.html
+ test-repeated-messages.html
+ test-result-format-as-string.html
+ test-webconsole-error-observer.html
+ test_bug_770099_violation.html
+ test_bug_770099_violation.html^headers^
+ test-autocomplete-in-stackframe.html
+ testscript.js
+ test-bug_923281_console_log_filter.html
+ test-bug_923281_test1.js
+ test-bug_923281_test2.js
+ test-bug_939783_console_trace_duplicates.html
+ test-bug-952277-highlight-nodes-in-vview.html
+ test-bug-609872-cd-iframe-parent.html
+ test-bug-609872-cd-iframe-child.html
+ test-bug-989025-iframe-parent.html
+ test-console-api-stackframe.html
+ test_bug_1010953_cspro.html^headers^
+ test_bug_1010953_cspro.html
+ test_bug1045902_console_csp_ignore_reflected_xss_message.html^headers^
+ test_bug1045902_console_csp_ignore_reflected_xss_message.html
+ test_bug1092055_shouldwarn.js^headers^
+ test_bug1092055_shouldwarn.js
+ test_bug1092055_shouldwarn.html
+
+[browser_bug1045902_console_csp_ignore_reflected_xss_message.js]
+[browser_bug664688_sandbox_update_after_navigation.js]
+skip-if = e10s # Bug 1042253 - webconsole e10s tests (intermittent Linux debug)
+[browser_bug_638949_copy_link_location.js]
+[browser_bug_862916_console_dir_and_filter_off.js]
+[browser_bug_865288_repeat_different_objects.js]
+[browser_bug_865871_variables_view_close_on_esc_key.js]
+[browser_bug_869003_inspect_cross_domain_object.js]
+[browser_bug_871156_ctrlw_close_tab.js]
+skip-if = e10s # Bug 1042253 - webconsole e10s tests (intermittent Linux debug)
+[browser_cached_messages.js]
+skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests (expectUncaughtException)
+[browser_console.js]
+[browser_console_addonsdk_loader_exception.js]
+[browser_console_clear_on_reload.js]
+[browser_console_click_focus.js]
+[browser_console_consolejsm_output.js]
+[browser_console_copy_command.js]
+[browser_console_dead_objects.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_console_copy_entire_message_context_menu.js]
+[browser_console_error_source_click.js]
+skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests
+[browser_console_filters.js]
+[browser_console_iframe_messages.js]
+skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests
+[browser_console_keyboard_accessibility.js]
+[browser_console_log_inspectable_object.js]
+[browser_console_native_getters.js]
+[browser_console_navigation_marker.js]
+[browser_console_nsiconsolemessage.js]
+skip-if = buildapp == 'mulet'
+[browser_console_optimized_out_vars.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_console_private_browsing.js]
+skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests
+[browser_console_variables_view.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_console_variables_view_dom_nodes.js]
+[browser_console_variables_view_dont_sort_non_sortable_classes_properties.js]
+skip-if = buildapp == 'mulet'
+[browser_console_variables_view_while_debugging.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_console_variables_view_while_debugging_and_inspecting.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_eval_in_debugger_stackframe.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_eval_in_debugger_stackframe2.js]
+[browser_jsterm_inspect.js]
+[browser_longstring_hang.js]
+[browser_netpanel_longstring_expand.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_output_breaks_after_console_dir_uninspectable.js]
+[browser_output_longstring_expand.js]
+[browser_repeated_messages_accuracy.js]
+skip-if = buildapp == 'mulet'
+[browser_result_format_as_string.js]
+[browser_warn_user_about_replaced_api.js]
+[browser_webconsole_abbreviate_source_url.js]
+[browser_webconsole_allow_mixedcontent_securityerrors.js]
+skip-if = buildapp == 'mulet'
+[browser_webconsole_assert.js]
+[browser_webconsole_basic_net_logging.js]
+[browser_webconsole_block_mixedcontent_securityerrors.js]
+skip-if = buildapp == 'mulet'
+[browser_webconsole_bug_579412_input_focus.js]
+[browser_webconsole_bug_580001_closing_after_completion.js]
+[browser_webconsole_bug_580030_errors_after_page_reload.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException)
+[browser_webconsole_bug_580454_timestamp_l10n.js]
+[browser_webconsole_bug_582201_duplicate_errors.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException)
+[browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js]
+[browser_webconsole_bug_585237_line_limit.js]
+[browser_webconsole_bug_585956_console_trace.js]
+[browser_webconsole_bug_585991_autocomplete_keys.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_bug_585991_autocomplete_popup.js]
+[browser_webconsole_bug_586388_select_all.js]
+[browser_webconsole_bug_587617_output_copy.js]
+[browser_webconsole_bug_588342_document_focus.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_bug_588730_text_node_insertion.js]
+[browser_webconsole_bug_588967_input_expansion.js]
+[browser_webconsole_bug_589162_css_filter.js]
+[browser_webconsole_bug_592442_closing_brackets.js]
+[browser_webconsole_bug_593003_iframe_wrong_hud.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_bug_594477_clickable_output.js]
+[browser_webconsole_bug_594497_history_arrow_keys.js]
+[browser_webconsole_bug_595223_file_uri.js]
+[browser_webconsole_bug_595350_multiple_windows_and_tabs.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_bug_595934_message_categories.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException)
+[browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_bug_597136_external_script_errors.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException)
+[browser_webconsole_bug_597136_network_requests_from_chrome.js]
+[browser_webconsole_bug_597460_filter_scroll.js]
+[browser_webconsole_bug_597756_reopen_closed_tab.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException)
+[browser_webconsole_bug_599725_response_headers.js]
+[browser_webconsole_bug_600183_charset.js]
+[browser_webconsole_bug_601177_log_levels.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException)
+[browser_webconsole_bug_601352_scroll.js]
+[browser_webconsole_bug_601667_filter_buttons.js]
+[browser_webconsole_bug_602572_log_bodies_checkbox.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_bug_603750_websocket.js]
+[browser_webconsole_bug_611795.js]
+[browser_webconsole_bug_613013_console_api_iframe.js]
+[browser_webconsole_bug_613280_jsterm_copy.js]
+[browser_webconsole_bug_613642_maintain_scroll.js]
+[browser_webconsole_bug_613642_prune_scroll.js]
+[browser_webconsole_bug_614793_jsterm_scroll.js]
+[browser_webconsole_bug_618078_network_exceptions.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException)
+[browser_webconsole_bug_618311_close_panels.js]
+[browser_webconsole_bug_621644_jsterm_dollar.js]
+[browser_webconsole_bug_622303_persistent_filters.js]
+[browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js]
+skip-if = os != "win"
+[browser_webconsole_bug_630733_response_redirect_headers.js]
+[browser_webconsole_bug_632275_getters_document_width.js]
+[browser_webconsole_bug_632347_iterators_generators.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_bug_632817.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_bug_642108_pruneTest.js]
+[browser_webconsole_autocomplete_and_selfxss.js]
+[browser_webconsole_bug_644419_log_limits.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException)
+[browser_webconsole_bug_646025_console_file_location.js]
+[browser_webconsole_bug_651501_document_body_autocomplete.js]
+[browser_webconsole_bug_653531_highlighter_console_helper.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_bug_658368_time_methods.js]
+[browser_webconsole_bug_659907_console_dir.js]
+[browser_webconsole_bug_660806_history_nav.js]
+[browser_webconsole_bug_664131_console_group.js]
+[browser_webconsole_bug_686937_autocomplete_JSTerm_helpers.js]
+[browser_webconsole_bug_704295.js]
+[browser_webconsole_bug_734061_No_input_change_and_Tab_key_pressed.js]
+[browser_webconsole_bug_737873_mixedcontent.js]
+[browser_webconsole_bug_752559_ineffective_iframe_sandbox_warning.js]
+skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
+[browser_webconsole_bug_762593_insecure_passwords_about_blank_web_console_warning.js]
+skip-if = buildapp == 'mulet'
+[browser_webconsole_bug_762593_insecure_passwords_web_console_warning.js]
+skip-if = true # Bug 1110500 - mouse event failure in test
+[browser_webconsole_bug_764572_output_open_url.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_bug_766001_JS_Console_in_Debugger.js]
+skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests (expectUncaughtException)
+[browser_webconsole_bug_770099_violation.js]
+[browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js]
+skip-if = buildapp == 'mulet'
+[browser_webconsole_bug_804845_ctrl_key_nav.js]
+skip-if = os != "mac"
+[browser_webconsole_bug_817834_add_edited_input_to_history.js]
+[browser_webconsole_bug_837351_securityerrors.js]
+skip-if = buildapp == 'mulet'
+[browser_webconsole_bug_846918_hsts_invalid-headers.js]
+skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests
+[browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js]
+[browser_webconsole_filter_buttons_contextmenu.js]
+[browser_webconsole_bug_1006027_message_timestamps_incorrect.js]
+skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug intermittent)
+[browser_webconsole_bug_1010953_cspro.js]
+[browser_webconsole_certificate_messages.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_show_subresource_security_errors.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_cached_autocomplete.js]
+[browser_webconsole_change_font_size.js]
+[browser_webconsole_chrome.js]
+[browser_webconsole_clickable_urls.js]
+skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
+[browser_webconsole_closure_inspection.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_completion.js]
+[browser_webconsole_console_extras.js]
+[browser_webconsole_console_logging_api.js]
+[browser_webconsole_count.js]
+[browser_webconsole_dont_navigate_on_doubleclick.js]
+[browser_webconsole_execution_scope.js]
+[browser_webconsole_for_of.js]
+[browser_webconsole_history.js]
+[browser_webconsole_input_field_focus_on_panel_select.js]
+[browser_webconsole_inspect-parsed-documents.js]
+[browser_webconsole_js_input_expansion.js]
+[browser_webconsole_jsterm.js]
+skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
+[browser_webconsole_live_filtering_of_message_types.js]
+[browser_webconsole_live_filtering_on_search_strings.js]
+[browser_webconsole_message_node_id.js]
+[browser_webconsole_netlogging.js]
+[browser_webconsole_network_panel.js]
+[browser_webconsole_notifications.js]
+[browser_webconsole_open-links-without-callback.js]
+[browser_webconsole_output_copy_newlines.js]
+[browser_webconsole_output_order.js]
+[browser_webconsole_property_provider.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_scratchpad_panel_link.js]
+[browser_webconsole_split.js]
+[browser_webconsole_split_escape_key.js]
+[browser_webconsole_split_focus.js]
+[browser_webconsole_split_persist.js]
+skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
+[browser_webconsole_view_source.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException)
+[browser_webconsole_reflow.js]
+[browser_webconsole_log_file_filter.js]
+[browser_webconsole_expandable_timestamps.js]
+[browser_webconsole_autocomplete_in_debugger_stackframe.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_autocomplete_popup_close_on_tab_switch.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js]
+[browser_console_hide_jsterm_when_devtools_chrome_enabled_false.js]
+[browser_webconsole_output_01.js]
+skip-if = e10s # Bug 1042253 - webconsole e10s tests
+[browser_webconsole_output_02.js]
+[browser_webconsole_output_03.js]
+[browser_webconsole_output_04.js]
+[browser_webconsole_output_05.js]
+[browser_webconsole_output_06.js]
+[browser_webconsole_output_dom_elements_01.js]
+[browser_webconsole_output_dom_elements_02.js]
+skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
+[browser_webconsole_output_dom_elements_03.js]
+[browser_webconsole_output_dom_elements_04.js]
+skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
+[browser_webconsole_output_events.js]
+[browser_webconsole_output_table.js]
+[browser_console_variables_view_highlighter.js]
+[browser_webconsole_start_netmon_first.js]
+[browser_webconsole_console_trace_duplicates.js]
+[browser_webconsole_cd_iframe.js]
+[browser_webconsole_autocomplete_crossdomain_iframe.js]
+[browser_webconsole_console_custom_styles.js]
+[browser_webconsole_console_api_stackframe.js]
+[browser_webconsole_column_numbers.js]
+[browser_console_open_or_focus.js]
diff --git a/browser/devtools/webconsole/test/browser_bug1045902_console_csp_ignore_reflected_xss_message.js b/browser/devtools/webconsole/test/browser_bug1045902_console_csp_ignore_reflected_xss_message.js
new file mode 100644
index 000000000..27cbf8ad0
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_bug1045902_console_csp_ignore_reflected_xss_message.js
@@ -0,0 +1,59 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/* Description of the test:
+ * We are loading a file with the following CSP:
+ * 'reflected-xss filter'
+ * This directive is not supported, hence we confirm that
+ * the according message is displayed in the web console.
+ */
+
+const EXPECTED_RESULT = "Not supporting directive 'reflected-xss'. Directive and values will be ignored.";
+const TEST_FILE = "http://example.com/browser/browser/devtools/webconsole/test/" +
+ "test_bug1045902_console_csp_ignore_reflected_xss_message.html";
+
+let hud = undefined;
+
+let TEST_URI = "data:text/html;charset=utf8,Web Console CSP ignoring reflected XSS (bug 1045902)";
+
+let test = asyncTest(function* () {
+ let { browser } = yield loadTab(TEST_URI);
+
+ hud = yield openConsole();
+
+ yield loadDocument(browser);
+ yield testViolationMessage();
+
+ hud = null;
+});
+
+
+function loadDocument(browser) {
+ let deferred = promise.defer();
+
+ hud.jsterm.clearOutput()
+ browser.addEventListener("load", function onLoad() {
+ browser.removeEventListener("load", onLoad, true);
+ deferred.resolve();
+ }, true);
+ content.location = TEST_FILE;
+
+ return deferred.promise;
+}
+
+function testViolationMessage() {
+ let deferred = promise.defer();
+ let aOutputNode = hud.outputNode;
+
+ return waitForSuccess({
+ name: "Confirming that CSP logs messages to the console when 'reflected-xss' directive is used!",
+ validator: function() {
+ console.log(hud.outputNode.textContent);
+ let success = false;
+ success = hud.outputNode.textContent.indexOf(EXPECTED_RESULT) > -1;
+ return success;
+ }
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_bug664688_sandbox_update_after_navigation.js b/browser/devtools/webconsole/test/browser_bug664688_sandbox_update_after_navigation.js
new file mode 100644
index 000000000..2203e2209
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_bug664688_sandbox_update_after_navigation.js
@@ -0,0 +1,91 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests if the JSTerm sandbox is updated when the user navigates from one
+// domain to another, in order to avoid permission denied errors with a sandbox
+// created for a different origin.
+
+"use strict";
+
+let test = asyncTest(function* () {
+ const TEST_URI1 = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+ const TEST_URI2 = "http://example.org/browser/browser/devtools/webconsole/test/test-console.html";
+
+ yield loadTab(TEST_URI1);
+ let hud = yield openConsole();
+
+ hud.jsterm.clearOutput();
+ hud.jsterm.execute("window.location.href");
+
+ info("wait for window.location.href");
+
+ let msgForLocation1 = {
+ webconsole: hud,
+ messages: [
+ {
+ name: "window.location.href jsterm input",
+ text: "window.location.href",
+ category: CATEGORY_INPUT,
+ },
+ {
+ name: "window.location.href result is displayed",
+ text: TEST_URI1,
+ category: CATEGORY_OUTPUT,
+ },
+ ],
+ };
+
+ yield waitForMessages(msgForLocation1);
+
+ // load second url
+ content.location = TEST_URI2;
+ yield loadBrowser(gBrowser.selectedBrowser);
+
+ is(hud.outputNode.textContent.indexOf("Permission denied"), -1,
+ "no permission denied errors");
+
+ hud.jsterm.clearOutput();
+ hud.jsterm.execute("window.location.href");
+
+ info("wait for window.location.href after page navigation");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "window.location.href jsterm input",
+ text: "window.location.href",
+ category: CATEGORY_INPUT,
+ },
+ {
+ name: "window.location.href result is displayed",
+ text: TEST_URI2,
+ category: CATEGORY_OUTPUT,
+ },
+ ],
+ });
+
+ is(hud.outputNode.textContent.indexOf("Permission denied"), -1,
+ "no permission denied errors");
+
+ gBrowser.goBack();
+
+ yield waitForSuccess({
+ name: "go back",
+ validator: function() {
+ return content.location.href == TEST_URI1;
+ },
+ });
+
+ hud.jsterm.clearOutput();
+ executeSoon(() => {
+ hud.jsterm.execute("window.location.href");
+ });
+
+ info("wait for window.location.href after goBack()");
+ yield waitForMessages(msgForLocation1);
+ is(hud.outputNode.textContent.indexOf("Permission denied"), -1,
+ "no permission denied errors");
+});
diff --git a/browser/devtools/webconsole/test/browser_bug_638949_copy_link_location.js b/browser/devtools/webconsole/test/browser_bug_638949_copy_link_location.js
new file mode 100644
index 000000000..40ae04394
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_bug_638949_copy_link_location.js
@@ -0,0 +1,105 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Test for the "Copy link location" context menu item shown when you right
+// click network requests in the output.
+
+"use strict";
+
+let test = asyncTest(function* () {
+ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" +
+ "test/test-console.html?_date=" + Date.now();
+ const COMMAND_NAME = "consoleCmd_copyURL";
+ const CONTEXT_MENU_ID = "#menu_copyURL";
+
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("devtools.webconsole.filter.networkinfo");
+ });
+
+ Services.prefs.setBoolPref("devtools.webconsole.filter.networkinfo", true);
+
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ let output = hud.outputNode;
+ let menu = hud.iframeWindow.document.getElementById("output-contextmenu");
+
+ hud.jsterm.clearOutput();
+ content.console.log("bug 638949");
+
+ // Test that the "Copy Link Location" command is disabled for non-network
+ // messages.
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "bug 638949",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ output.focus();
+ let message = [...result.matched][0];
+
+ goUpdateCommand(COMMAND_NAME);
+ ok(!isEnabled(), COMMAND_NAME + " is disabled");
+
+ // Test that the "Copy Link Location" menu item is hidden for non-network
+ // messages.
+ message.scrollIntoView();
+
+ yield waitForContextMenu(menu, message, () => {
+ let isHidden = menu.querySelector(CONTEXT_MENU_ID).hidden;
+ ok(isHidden, CONTEXT_MENU_ID + " is hidden");
+ });
+
+ hud.jsterm.clearOutput();
+ content.location.reload(); // Reloading will produce network logging
+
+ // Test that the "Copy Link Location" command is enabled and works
+ // as expected for any network-related message.
+ // This command should copy only the URL.
+ [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "test-console.html",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ output.focus();
+ message = [...result.matched][0];
+ hud.ui.output.selectMessage(message);
+
+ goUpdateCommand(COMMAND_NAME);
+ ok(isEnabled(), COMMAND_NAME + " is enabled");
+
+ info("expected clipboard value: " + message.url);
+
+ let deferred = promise.defer();
+
+ waitForClipboard((aData) => { return aData.trim() == message.url; },
+ () => { goDoCommand(COMMAND_NAME); },
+ () => { deferred.resolve(null); },
+ () => { deferred.reject(null); });
+
+ yield deferred.promise;
+
+ // Test that the "Copy Link Location" menu item is visible for network-related
+ // messages.
+ message.scrollIntoView();
+
+ yield waitForContextMenu(menu, message, () => {
+ let isVisible = !menu.querySelector(CONTEXT_MENU_ID).hidden;
+ ok(isVisible, CONTEXT_MENU_ID + " is visible");
+ });
+
+ // Return whether "Copy Link Location" command is enabled or not.
+ function isEnabled() {
+ let controller = top.document.commandDispatcher
+ .getControllerForCommand(COMMAND_NAME);
+ return controller && controller.isCommandEnabled(COMMAND_NAME);
+ }
+});
diff --git a/browser/devtools/webconsole/test/browser_bug_862916_console_dir_and_filter_off.js b/browser/devtools/webconsole/test/browser_bug_862916_console_dir_and_filter_off.js
new file mode 100644
index 000000000..676fd5a93
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_bug_862916_console_dir_and_filter_off.js
@@ -0,0 +1,31 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that the output for console.dir() works even if Logging filter is off.
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf8,<p>test for bug 862916";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+
+ ok(hud, "web console opened");
+
+ hud.setFilterState("log", false);
+ registerCleanupFunction(() => hud.setFilterState("log", true));
+
+ hud.jsterm.execute("window.fooBarz = 'bug862916'; " +
+ "console.dir(window)");
+
+ let varView = yield hud.jsterm.once("variablesview-fetched");
+ ok(varView, "variables view object");
+
+ yield findVariableViewProperties(varView, [
+ { name: "fooBarz", value: "bug862916" },
+ ], { webconsole: hud });
+});
+
diff --git a/browser/devtools/webconsole/test/browser_bug_865288_repeat_different_objects.js b/browser/devtools/webconsole/test/browser_bug_865288_repeat_different_objects.js
new file mode 100644
index 000000000..a3e3a8abe
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_bug_865288_repeat_different_objects.js
@@ -0,0 +1,63 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that makes sure messages are not considered repeated when console.log()
+// is invoked with different objects, see bug 865288.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-repeated-messages.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+
+ info("waiting for 3 console.log objects");
+
+ hud.jsterm.clearOutput(true);
+ hud.jsterm.execute("window.testConsoleObjects()");
+
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "3 console.log messages",
+ text: "abba",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ count: 3,
+ repeats: 1,
+ objects: true,
+ }],
+ });
+
+ let msgs = [...result.matched];
+ is(msgs.length, 3, "3 message elements");
+
+ for (let i = 0; i < msgs.length; i++) {
+ info("test message element #" + i);
+
+ let msg = msgs[i];
+ let clickable = msg.querySelector(".message-body a");
+ ok(clickable, "clickable object #" + i);
+
+ msg.scrollIntoView(false);
+ yield clickObject(clickable, i);
+ }
+
+ function* clickObject(obj, i)
+ {
+ executeSoon(() => {
+ EventUtils.synthesizeMouse(obj, 2, 2, {}, hud.iframeWindow);
+ });
+
+ let varView = yield hud.jsterm.once("variablesview-fetched");
+ ok(varView, "variables view fetched #" + i);
+
+ yield findVariableViewProperties(varView, [
+ { name: "id", value: "abba" + i },
+ ], { webconsole: hud });
+ }
+});
+
diff --git a/browser/devtools/webconsole/test/browser_bug_865871_variables_view_close_on_esc_key.js b/browser/devtools/webconsole/test/browser_bug_865871_variables_view_close_on_esc_key.js
new file mode 100644
index 000000000..a4dd76dbe
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_bug_865871_variables_view_close_on_esc_key.js
@@ -0,0 +1,98 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that the variables view sidebar can be closed by pressing Escape in the
+// web console.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-eval-in-stackframe.html";
+
+function test()
+{
+ let hud;
+
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ let {tab} = yield loadTab(TEST_URI);
+ hud = yield openConsole(tab);
+ let jsterm = hud.jsterm;
+
+ let msg = yield execute("fooObj");
+ ok(msg, "output message found");
+
+ let anchor = msg.querySelector("a");
+ let body = msg.querySelector(".message-body");
+ ok(anchor, "object anchor");
+ ok(body, "message body");
+ ok(body.textContent.contains('testProp: "testValue"'), "message text check");
+
+ msg.scrollIntoView();
+ executeSoon(() => {
+ EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow);
+ });
+
+ let vviewVar = yield jsterm.once("variablesview-fetched");
+ let vview = vviewVar._variablesView;
+ ok(vview, "variables view object");
+
+ let [result] = yield findVariableViewProperties(vviewVar, [
+ { name: "testProp", value: "testValue" },
+ ], { webconsole: hud });
+
+ let prop = result.matchedProp;
+ ok(prop, "matched the |testProp| property in the variables view");
+
+ vview.window.focus();
+
+ executeSoon(() => {
+ EventUtils.synthesizeKey("VK_ESCAPE", {});
+ });
+ yield jsterm.once("sidebar-closed");
+
+ jsterm.clearOutput();
+
+ msg = yield execute("window.location");
+ ok(msg, "output message found");
+
+ body = msg.querySelector(".message-body");
+ ok(body, "message body");
+ anchor = msg.querySelector("a");
+ ok(anchor, "object anchor");
+ ok(body.textContent.contains("Location \u2192 http://example.com/browser/"),
+ "message text check");
+
+ msg.scrollIntoView();
+ executeSoon(() => {
+ EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow)
+ });
+ vviewVar = yield jsterm.once("variablesview-fetched");
+
+ vview = vviewVar._variablesView;
+ ok(vview, "variables view object");
+
+ yield findVariableViewProperties(vviewVar, [
+ { name: "host", value: "example.com" },
+ ], { webconsole: hud });
+
+ vview.window.focus();
+
+ msg.scrollIntoView();
+ executeSoon(() => {
+ EventUtils.synthesizeKey("VK_ESCAPE", {});
+ });
+
+ yield jsterm.once("sidebar-closed");
+ }
+
+ function execute(str) {
+ let deferred = promise.defer();
+ hud.jsterm.execute(str, (msg) => {
+ deferred.resolve(msg);
+ });
+ return deferred.promise;
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_bug_869003_inspect_cross_domain_object.js b/browser/devtools/webconsole/test/browser_bug_869003_inspect_cross_domain_object.js
new file mode 100644
index 000000000..8a5ad49af
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_bug_869003_inspect_cross_domain_object.js
@@ -0,0 +1,76 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that users can inspect objects logged from cross-domain iframes -
+// bug 869003.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-869003-top-window.html";
+
+let test = asyncTest(function* () {
+ // This test is slightly more involved: it opens the web console, then the
+ // variables view for a given object, it updates a property in the view and
+ // checks the result. We can get a timeout with debug builds on slower machines.
+ requestLongerTimeout(2);
+
+ yield loadTab("data:text/html;charset=utf8,<p>hello");
+ let hud = yield openConsole();
+
+ content.location = TEST_URI;
+
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "console.log message",
+ text: "foobar",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ objects: true,
+ }],
+ });
+
+ let msg = [...result.matched][0];
+ ok(msg, "message element");
+
+ let body = msg.querySelector(".message-body");
+ ok(body, "message body");
+
+ let clickable = result.clickableElements[0];
+ ok(clickable, "clickable object found");
+ ok(body.textContent.contains('{ hello: "world!",'), "message text check");
+
+ executeSoon(() => {
+ EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow)
+ });
+
+ let aVar = yield hud.jsterm.once("variablesview-fetched");
+ ok(aVar, "variables view fetched");
+ ok(aVar._variablesView, "variables view object");
+
+ [result] = yield findVariableViewProperties(aVar, [
+ { name: "hello", value: "world!" },
+ { name: "bug", value: 869003 },
+ ], { webconsole: hud });
+
+ let prop = result.matchedProp;
+ ok(prop, "matched the |hello| property in the variables view");
+
+ // Check that property value updates work.
+ aVar = yield updateVariablesViewProperty({
+ property: prop,
+ field: "value",
+ string: "'omgtest'",
+ webconsole: hud,
+ });
+
+ info("onFetchAfterUpdate");
+
+ yield findVariableViewProperties(aVar, [
+ { name: "hello", value: "omgtest" },
+ { name: "bug", value: 869003 },
+ ], { webconsole: hud });
+});
+
diff --git a/browser/devtools/webconsole/test/browser_bug_871156_ctrlw_close_tab.js b/browser/devtools/webconsole/test/browser_bug_871156_ctrlw_close_tab.js
new file mode 100644
index 000000000..503103566
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_bug_871156_ctrlw_close_tab.js
@@ -0,0 +1,79 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that Ctrl-W closes the Browser Console and that Ctrl-W closes the
+// current tab when using the Web Console - bug 871156.
+
+"use strict";
+
+let test = asyncTest(function* () {
+ const TEST_URI = "data:text/html;charset=utf8,<title>bug871156</title>\n" +
+ "<p>hello world";
+ let firstTab = gBrowser.selectedTab;
+
+ Services.prefs.setBoolPref("browser.tabs.animate", false);
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("browser.tabs.animate");
+ });
+
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+ ok(hud, "Web Console opened");
+
+ let tabClosed = promise.defer();
+ let toolboxDestroyed = promise.defer();
+ let tabSelected = promise.defer();
+
+ let target = TargetFactory.forTab(gBrowser.selectedTab);
+ let toolbox = gDevTools.getToolbox(target);
+
+ gBrowser.tabContainer.addEventListener("TabClose", function onTabClose() {
+ gBrowser.tabContainer.removeEventListener("TabClose", onTabClose);
+ info("tab closed");
+ tabClosed.resolve(null);
+ });
+
+ gBrowser.tabContainer.addEventListener("TabSelect", function onTabSelect() {
+ gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect);
+ if (gBrowser.selectedTab == firstTab) {
+ info("tab selected");
+ tabSelected.resolve(null);
+ }
+ });
+
+ toolbox.once("destroyed", () => {
+ info("toolbox destroyed");
+ toolboxDestroyed.resolve(null);
+ });
+
+ // Get out of the web console initialization.
+ executeSoon(() => {
+ EventUtils.synthesizeKey("w", { accelKey: true });
+ });
+
+
+ yield promise.all([tabClosed.promise, toolboxDestroyed.promise,
+ tabSelected.promise]);
+ info("promise.all resolved. start testing the Browser Console");
+
+ hud = yield HUDService.toggleBrowserConsole();
+ ok(hud, "Browser Console opened");
+
+ let deferred = promise.defer();
+
+ Services.obs.addObserver(function onDestroy() {
+ Services.obs.removeObserver(onDestroy, "web-console-destroyed");
+ ok(true, "the Browser Console closed");
+
+ deferred.resolve(null);
+ }, "web-console-destroyed", false);
+
+ waitForFocus(() => {
+ EventUtils.synthesizeKey("w", { accelKey: true }, hud.iframeWindow);
+ }, hud.iframeWindow);
+
+ yield deferred.promise;
+});
diff --git a/browser/devtools/webconsole/test/browser_cached_messages.js b/browser/devtools/webconsole/test/browser_cached_messages.js
new file mode 100644
index 000000000..a9a98ac17
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_cached_messages.js
@@ -0,0 +1,53 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Test to see if the cached messages are displayed when the console UI is opened.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-webconsole-error-observer.html";
+
+function test()
+{
+ waitForExplicitFinish();
+
+ expectUncaughtException();
+
+ loadTab(TEST_URI).then(testOpenUI);
+}
+
+function testOpenUI(aTestReopen)
+{
+ openConsole().then((hud) => {
+ waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ text: "log Bazzle",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "error Bazzle",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_ERROR,
+ },
+ {
+ text: "bazBug611032",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ },
+ {
+ text: "cssColorBug611032",
+ category: CATEGORY_CSS,
+ severity: SEVERITY_WARNING,
+ },
+ ],
+ }).then(() => {
+ closeConsole(gBrowser.selectedTab).then(() => {
+ aTestReopen && info("will reopen the Web Console");
+ executeSoon(aTestReopen ? testOpenUI : finishTest);
+ });
+ });
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_console.js b/browser/devtools/webconsole/test/browser_console.js
new file mode 100644
index 000000000..df971ec0f
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console.js
@@ -0,0 +1,120 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test the basic features of the Browser Console, bug 587757.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html?" + Date.now();
+
+const TEST_XHR_ERROR_URI = `http://example.com/404.html?${Date.now()}`;
+
+"use strict";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+
+ let opened = waitForConsole();
+
+ let hud = HUDService.getBrowserConsole();
+ ok(!hud, "browser console is not open");
+ info("wait for the browser console to open with ctrl-shift-j");
+ EventUtils.synthesizeKey("j", { accelKey: true, shiftKey: true }, window);
+
+ hud = yield opened;
+ ok(hud, "browser console opened");
+
+ yield consoleOpened(hud);
+});
+
+function consoleOpened(hud)
+{
+ hud.jsterm.clearOutput(true);
+
+ expectUncaughtException();
+ executeSoon(() => {
+ foobarExceptionBug587757();
+ });
+
+ // Add a message from a chrome window.
+ hud.iframeWindow.console.log("bug587757a");
+
+ // Add a message from a content window.
+ content.console.log("bug587757b");
+
+ // Test eval.
+ hud.jsterm.execute("document.location.href");
+
+ // Check for network requests.
+ let xhr = new XMLHttpRequest();
+ xhr.onload = () => console.log("xhr loaded, status is: " + xhr.status);
+ xhr.open("get", TEST_URI, true);
+ xhr.send();
+
+ // Check for xhr error.
+ let xhrErr = new XMLHttpRequest();
+ xhrErr.onload = () => console.log("xhr error loaded, status is: " + xhrErr.status);
+ xhrErr.open("get", TEST_XHR_ERROR_URI, true);
+ xhrErr.send();
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "chrome window console.log() is displayed",
+ text: "bug587757a",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ },
+ {
+ name: "content window console.log() is displayed",
+ text: "bug587757b",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ },
+ {
+ name: "jsterm eval result",
+ text: "browser.xul",
+ category: CATEGORY_OUTPUT,
+ severity: SEVERITY_LOG,
+ },
+ {
+ name: "exception message",
+ text: "foobarExceptionBug587757",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ },
+ {
+ name: "network message",
+ text: "test-console.html",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_INFO,
+ isXhr: true,
+ },
+ {
+ name: "xhr error message",
+ text: "404.html",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_ERROR,
+ isXhr: true,
+ },
+ ],
+ });
+}
+
+function waitForConsole() {
+ let deferred = promise.defer();
+
+ Services.obs.addObserver(function observer(aSubject) {
+ Services.obs.removeObserver(observer, "web-console-created");
+ aSubject.QueryInterface(Ci.nsISupportsString);
+
+ let hud = HUDService.getBrowserConsole();
+ ok(hud, "browser console is open");
+ is(aSubject.data, hud.hudId, "notification hudId is correct");
+
+ executeSoon(() => deferred.resolve(hud));
+ }, "web-console-created", false);
+
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_console_addonsdk_loader_exception.js b/browser/devtools/webconsole/test/browser_console_addonsdk_loader_exception.js
new file mode 100644
index 000000000..bc485ebb1
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_addonsdk_loader_exception.js
@@ -0,0 +1,90 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that exceptions from scripts loaded with the addon-sdk loader are
+// opened correctly in View Source from the Browser Console.
+// See bug 866950.
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf8,<p>hello world from bug 866950";
+
+function test()
+{
+ requestLongerTimeout(2);
+
+ let webconsole, browserconsole;
+
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ let {tab} = yield loadTab(TEST_URI);
+ webconsole = yield openConsole(tab);
+ ok(webconsole, "web console opened");
+
+ browserconsole = yield HUDService.toggleBrowserConsole();
+ ok(browserconsole, "browser console opened");
+
+ // Cause an exception in a script loaded with the addon-sdk loader.
+ let toolbox = gDevTools.getToolbox(webconsole.target);
+ let oldPanels = toolbox._toolPanels;
+ toolbox._toolPanels = {}; // non-iterable
+
+ function fixToolbox() {
+ toolbox._toolPanels = oldPanels;
+ }
+
+ info("generate exception and wait for message");
+
+ executeSoon(() => {
+ executeSoon(fixToolbox);
+ expectUncaughtException();
+ toolbox.getToolPanels();
+ });
+
+ let [result] = yield waitForMessages({
+ webconsole: browserconsole,
+ messages: [{
+ text: "TypeError: this._toolPanels is not iterable",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ }],
+ });
+
+ fixToolbox();
+
+ let msg = [...result.matched][0];
+ ok(msg, "message element found");
+ let locationNode = msg.querySelector(".message-location");
+ ok(locationNode, "message location element found");
+
+ let title = locationNode.getAttribute("title");
+ info("location node title: " + title);
+ isnot(title.indexOf(" -> "), -1, "error comes from a subscript");
+
+ let viewSource = browserconsole.viewSource;
+ let URL = null;
+ let clickPromise = promise.defer();
+ browserconsole.viewSource = (aURL) => {
+ info("browserconsole.viewSource() was invoked: " + aURL);
+ URL = aURL;
+ clickPromise.resolve(null);
+ };
+
+ msg.scrollIntoView();
+ EventUtils.synthesizeMouse(locationNode, 2, 2, {},
+ browserconsole.iframeWindow);
+
+ info("wait for click on locationNode");
+ yield clickPromise;
+
+ info("view-source url: " + URL);
+ ok(URL, "we have some source URL after the click");
+ isnot(URL.indexOf("toolbox.js"), -1, "we have the expected view source URL");
+ is(URL.indexOf("->"), -1, "no -> in the URL given to view-source");
+
+ browserconsole.viewSource = viewSource;
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_console_clear_on_reload.js b/browser/devtools/webconsole/test/browser_console_clear_on_reload.js
new file mode 100644
index 000000000..c88fdc7d5
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_clear_on_reload.js
@@ -0,0 +1,54 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that clear output on page reload works - bug 705921.
+
+"use strict";
+
+let test = asyncTest(function*() {
+ const PREF = "devtools.webconsole.persistlog";
+ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+ Services.prefs.setBoolPref(PREF, false);
+ registerCleanupFunction(() => Services.prefs.clearUserPref(PREF));
+
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+ ok(hud, "Web Console opened");
+
+ hud.jsterm.clearOutput();
+ hud.jsterm.execute("console.log('foobarz1')");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "foobarz1",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ BrowserReload();
+ yield loadBrowser(gBrowser.selectedBrowser);
+
+ hud.jsterm.execute("console.log('foobarz2')");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "test-console.html",
+ category: CATEGORY_NETWORK,
+ },
+ {
+ text: "foobarz2",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ is(hud.outputNode.textContent.indexOf("foobarz1"), -1,
+ "foobarz1 has been removed from output");
+});
diff --git a/browser/devtools/webconsole/test/browser_console_click_focus.js b/browser/devtools/webconsole/test/browser_console_click_focus.js
new file mode 100644
index 000000000..30a18598c
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_click_focus.js
@@ -0,0 +1,55 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the input field is focused when the console is opened.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "Dolske Digs Bacon",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ let msg = [...result.matched][0];
+ let outputItem = msg.querySelector(".message-body");
+ ok(outputItem, "found a logged message");
+
+ let inputNode = hud.jsterm.inputNode;
+ ok(inputNode.getAttribute("focused"), "input node is focused, first");
+
+ let lostFocus = () => {
+ inputNode.removeEventListener("blur", lostFocus);
+ info("input node lost focus");
+ }
+
+ inputNode.addEventListener("blur", lostFocus);
+
+ document.getElementById("urlbar").click();
+
+ ok(!inputNode.getAttribute("focused"), "input node is not focused");
+
+ EventUtils.sendMouseEvent({type: "click"}, hud.outputNode);
+
+ ok(inputNode.getAttribute("focused"), "input node is focused, second time")
+
+ // test click-drags are not focusing the input element.
+ EventUtils.sendMouseEvent({type: "mousedown", clientX: 3, clientY: 4},
+ outputItem);
+ EventUtils.sendMouseEvent({type: "click", clientX: 15, clientY: 5},
+ outputItem);
+
+ todo(!inputNode.getAttribute("focused"), "input node is not focused after drag");
+});
+
diff --git a/browser/devtools/webconsole/test/browser_console_consolejsm_output.js b/browser/devtools/webconsole/test/browser_console_consolejsm_output.js
new file mode 100644
index 000000000..0601c11a4
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_consolejsm_output.js
@@ -0,0 +1,137 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that Console.jsm outputs messages to the Browser Console, bug 851231.
+
+"use strict";
+
+let test = asyncTest(function*() {
+ let storage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(Ci.nsIConsoleAPIStorage);
+ storage.clearEvents();
+
+ let console = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console;
+ console.log("bug861338-log-cached");
+
+ let hud = yield HUDService.toggleBrowserConsole();
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "cached console.log message",
+ text: "bug861338-log-cached",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ hud.jsterm.clearOutput(true);
+
+ function testTrace() {
+ console.trace();
+ }
+
+ console.time("foobarTimer");
+ let foobar = { bug851231prop: "bug851231value" };
+
+ console.log("bug851231-log");
+ console.info("bug851231-info");
+ console.warn("bug851231-warn");
+ console.error("bug851231-error", foobar);
+ console.debug("bug851231-debug");
+ console.dir(document);
+ testTrace();
+ console.timeEnd("foobarTimer");
+
+ info("wait for the Console.jsm messages");
+
+ let results = yield waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "console.log output",
+ text: "bug851231-log",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ },
+ {
+ name: "console.info output",
+ text: "bug851231-info",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_INFO,
+ },
+ {
+ name: "console.warn output",
+ text: "bug851231-warn",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_WARNING,
+ },
+ {
+ name: "console.error output",
+ text: /\bbug851231-error\b.+\{\s*bug851231prop:\s"bug851231value"\s*\}/,
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_ERROR,
+ objects: true,
+ },
+ {
+ name: "console.debug output",
+ text: "bug851231-debug",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ },
+ {
+ name: "console.trace output",
+ consoleTrace: {
+ file: "browser_console_consolejsm_output.js",
+ fn: "testTrace",
+ },
+ },
+ {
+ name: "console.dir output",
+ consoleDir: /XULDocument\s+.+\s+chrome:\/\/.+\/browser\.xul/,
+ },
+ {
+ name: "console.time output",
+ consoleTime: "foobarTimer",
+ },
+ {
+ name: "console.timeEnd output",
+ consoleTimeEnd: "foobarTimer",
+ },
+ ],
+ });
+
+ let consoleErrorMsg = results[3];
+ ok(consoleErrorMsg, "console.error message element found");
+ let clickable = consoleErrorMsg.clickableElements[0];
+ ok(clickable, "clickable object found for console.error");
+
+ let deferred = promise.defer();
+
+ let onFetch = (aEvent, aVar) => {
+ // Skip the notification from console.dir variablesview-fetched.
+ if (aVar._variablesView != hud.jsterm._variablesView) {
+ return;
+ }
+ hud.jsterm.off("variablesview-fetched", onFetch);
+
+ deferred.resolve(aVar);
+ };
+
+ hud.jsterm.on("variablesview-fetched", onFetch);
+
+ clickable.scrollIntoView(false);
+
+ info("wait for variablesview-fetched");
+ executeSoon(() =>
+ EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow));
+
+ let varView = yield deferred.promise;
+ ok(varView, "object inspector opened on click");
+
+ yield findVariableViewProperties(varView, [{
+ name: "bug851231prop",
+ value: "bug851231value",
+ }], { webconsole: hud });
+});
diff --git a/browser/devtools/webconsole/test/browser_console_copy_command.js b/browser/devtools/webconsole/test/browser_console_copy_command.js
new file mode 100644
index 000000000..711dfb5b5
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_copy_command.js
@@ -0,0 +1,70 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+// Tests that the `copy` console helper works as intended.
+
+let gWebConsole, gJSTerm;
+
+let TEXT = "Lorem ipsum dolor sit amet, consectetur adipisicing " +
+ "elit, sed do eiusmod tempor incididunt ut labore et dolore magna " +
+ "aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco " +
+ "laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure " +
+ "dolor in reprehenderit in voluptate velit esse cillum dolore eu " +
+ "fugiat nulla pariatur. Excepteur sint occaecat cupidatat non " +
+ "proident, sunt in culpa qui officia deserunt mollit anim id est laborum." +
+ new Date();
+
+let ID = "select-me";
+
+add_task(function* init() {
+ yield loadTab("data:text/html;charset=utf-8," +
+ "<body>" +
+ " <div>" +
+ " <h1>Testing copy command</h1>" +
+ " <p>This is some example text</p>" +
+ " <p id='select-me'>"+TEXT+"</p>" +
+ " </div>" +
+ " <div><p></p></div>" +
+ "</body>");
+
+ gWebConsole = yield openConsole();
+ gJSTerm = gWebConsole.jsterm;
+});
+
+add_task(function* test_copy() {
+ let RANDOM = Math.random();
+ let string = "Text: " + RANDOM;
+ let obj = {a: 1, b: "foo", c: RANDOM};
+
+ let samples = [[RANDOM, RANDOM],
+ [JSON.stringify(string), string],
+ [obj.toSource(), JSON.stringify(obj, null, " ")],
+ ["$('#" + ID + "')", content.document.getElementById(ID).outerHTML]
+ ];
+ for (let [source, reference] of samples) {
+ let deferredResult = promise.defer();
+
+ SimpleTest.waitForClipboard(
+ "" + reference,
+ () => {
+ let command = "copy(" + source + ")";
+ info("Attempting to copy: " + source);
+ info("Executing command: " + command);
+ gJSTerm.execute(command, msg => {
+ is(msg, undefined, "Command success: " + command);
+ });
+ },
+ deferredResult.resolve,
+ deferredResult.reject);
+
+ yield deferredResult.promise;
+ }
+});
+
+add_task(function* cleanup() {
+ gWebConsole = gJSTerm = null;
+ gBrowser.removeTab(gBrowser.selectedTab);
+ finishTest();
+});
diff --git a/browser/devtools/webconsole/test/browser_console_copy_entire_message_context_menu.js b/browser/devtools/webconsole/test/browser_console_copy_entire_message_context_menu.js
new file mode 100644
index 000000000..937793672
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_copy_entire_message_context_menu.js
@@ -0,0 +1,64 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test copying of the entire console message when right-clicked
+// with no other text selected. See Bug 1100562.
+
+function test() {
+ let hud;
+ let outputNode;
+ let contextMenu;
+
+ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+ const TEST_FILE = TEST_URI.substr(TEST_URI.lastIndexOf("/"));
+
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ const {tab} = yield loadTab(TEST_URI);
+ hud = yield openConsole(tab);
+ outputNode = hud.outputNode;
+ contextMenu = hud.iframeWindow.document.getElementById("output-contextmenu");
+
+ registerCleanupFunction(() => {
+ hud = outputNode = contextMenu = null;
+ });
+
+ hud.jsterm.clearOutput();
+ content.console.log("bug 1100562");
+
+ let [results] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "bug 1100562",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }]
+ });
+
+ outputNode.focus();
+ let message = [...results.matched][0];
+ message.scrollIntoView();
+
+ yield waitForContextMenu(contextMenu, message, copyFromPopup, testContextMenuCopy);
+
+ function copyFromPopup() {
+ let copyItem = contextMenu.querySelector("#cMenu_copy");
+ copyItem.doCommand();
+
+ let controller = top.document.commandDispatcher.getControllerForCommand("cmd_copy");
+ is(controller.isCommandEnabled("cmd_copy"), true, "cmd_copy is enabled");
+ }
+
+ function testContextMenuCopy() {
+ waitForClipboard((str) => { return message.textContent.trim() == str.trim(); },
+ () => { goDoCommand("cmd_copy") },
+ () => {}, () => {}
+ );
+ }
+
+ yield closeConsole(tab);
+ }
+} \ No newline at end of file
diff --git a/browser/devtools/webconsole/test/browser_console_dead_objects.js b/browser/devtools/webconsole/test/browser_console_dead_objects.js
new file mode 100644
index 000000000..574573064
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_dead_objects.js
@@ -0,0 +1,86 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that Dead Objects do not break the Web/Browser Consoles. See bug 883649.
+// This test does:
+// - opens a new tab,
+// - opens the Browser Console,
+// - stores a reference to the content document of the tab on the chrome window object,
+// - closes the tab,
+// - tries to use the object that was pointing to the now-defunct content
+// document. This is the dead object.
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf8,<p>dead objects!";
+
+function test()
+{
+ let hud = null;
+
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("devtools.chrome.enabled");
+ });
+
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ Services.prefs.setBoolPref("devtools.chrome.enabled", true);
+ let {tab} = yield loadTab(TEST_URI);
+
+ info("open the browser console");
+
+ hud = yield HUDService.toggleBrowserConsole();
+ ok(hud, "browser console opened");
+
+ let jsterm = hud.jsterm;
+
+ jsterm.clearOutput();
+
+ // Add the reference to the content document.
+ yield jsterm.execute("Cu = Components.utils;" +
+ "Cu.import('resource://gre/modules/Services.jsm');" +
+ "chromeWindow = Services.wm.getMostRecentWindow('navigator:browser');" +
+ "foobarzTezt = chromeWindow.content.document;" +
+ "delete chromeWindow");
+
+ gBrowser.removeCurrentTab();
+
+ let msg = yield jsterm.execute("foobarzTezt");
+
+ isnot(hud.outputNode.textContent.indexOf("[object DeadObject]"), -1,
+ "dead object found");
+
+ jsterm.setInputValue("foobarzTezt");
+
+ for (let c of ".hello") {
+ EventUtils.synthesizeKey(c, {}, hud.iframeWindow);
+ }
+
+ yield jsterm.execute();
+
+ isnot(hud.outputNode.textContent.indexOf("can't access dead object"), -1,
+ "'cannot access dead object' message found");
+
+ // Click the second execute output.
+ let clickable = msg.querySelector("a");
+ ok(clickable, "clickable object found");
+ isnot(clickable.textContent.indexOf("[object DeadObject]"), -1,
+ "message text check");
+
+ msg.scrollIntoView();
+
+ executeSoon(() => {
+ EventUtils.synthesizeMouseAtCenter(clickable, {}, hud.iframeWindow);
+ });
+
+ yield jsterm.once("variablesview-fetched");
+ ok(true, "variables view fetched");
+
+ msg = yield jsterm.execute("delete window.foobarzTezt; 2013-26");
+
+ isnot(msg.textContent.indexOf("1987"), -1, "result message found");
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_console_error_source_click.js b/browser/devtools/webconsole/test/browser_console_error_source_click.js
new file mode 100644
index 000000000..5e2ecb977
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_error_source_click.js
@@ -0,0 +1,73 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that JS errors and CSS warnings open view source when their source link
+// is clicked in the Browser Console. See bug 877778.
+
+const TEST_URI = "data:text/html;charset=utf8,<p>hello world from bug 877778 " +
+ "<button onclick='foobar.explode()' " +
+ "style='test-color: green-please'>click!</button>";
+function test()
+{
+ let hud;
+
+ loadTab(TEST_URI).then(() => {
+ HUDService.toggleBrowserConsole().then(browserConsoleOpened);
+ });
+
+ function browserConsoleOpened(aHud)
+ {
+ hud = aHud;
+ ok(hud, "browser console opened");
+
+ let button = content.document.querySelector("button");
+ ok(button, "button element found");
+
+ info("generate exception and wait for the message");
+ executeSoon(() => {
+ expectUncaughtException();
+ button.click();
+ });
+
+ waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ text: "ReferenceError: foobar is not defined",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ },
+ {
+ text: "Unknown property 'test-color'",
+ category: CATEGORY_CSS,
+ severity: SEVERITY_WARNING,
+ },
+ ],
+ }).then(onMessageFound);
+ }
+
+ function onMessageFound(results)
+ {
+ let viewSource = hud.viewSource;
+ let viewSourceCalled = false;
+ hud.viewSource = () => viewSourceCalled = true;
+
+ for (let result of results) {
+ viewSourceCalled = false;
+
+ let msg = [...results[0].matched][0];
+ ok(msg, "message element found for: " + result.text);
+ let locationNode = msg.querySelector(".message-location");
+ ok(locationNode, "message location element found");
+
+ EventUtils.synthesizeMouse(locationNode, 2, 2, {}, hud.iframeWindow);
+
+ ok(viewSourceCalled, "view source opened");
+ }
+
+ hud.viewSource = viewSource;
+ finishTest();
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_console_filters.js b/browser/devtools/webconsole/test/browser_console_filters.js
new file mode 100644
index 000000000..1524b6bb1
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_filters.js
@@ -0,0 +1,60 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that the Browser Console does not use the same filter prefs as the Web
+// Console. See bug 878186.
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf8,<p>browser console filters";
+const WEB_CONSOLE_PREFIX = "devtools.webconsole.filter.";
+const BROWSER_CONSOLE_PREFIX = "devtools.browserconsole.filter.";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+
+ info("open the web console");
+ let hud = yield openConsole();
+ ok(hud, "web console opened");
+
+ is(Services.prefs.getBoolPref(BROWSER_CONSOLE_PREFIX + "exception"), true,
+ "'exception' filter is enabled (browser console)");
+ is(Services.prefs.getBoolPref(WEB_CONSOLE_PREFIX + "exception"), true,
+ "'exception' filter is enabled (web console)");
+
+ info("toggle 'exception' filter");
+ hud.setFilterState("exception", false);
+
+ is(Services.prefs.getBoolPref(BROWSER_CONSOLE_PREFIX + "exception"), true,
+ "'exception' filter is enabled (browser console)");
+ is(Services.prefs.getBoolPref(WEB_CONSOLE_PREFIX + "exception"), false,
+ "'exception' filter is disabled (web console)");
+
+ hud.setFilterState("exception", true);
+
+ // We need to let the console opening event loop to finish.
+ let deferred = promise.defer();
+ executeSoon(() => closeConsole().then(() => deferred.resolve(null)));
+ yield deferred.promise;
+
+ info("web console closed");
+ hud = yield HUDService.toggleBrowserConsole();
+ ok(hud, "browser console opened");
+
+ is(Services.prefs.getBoolPref(BROWSER_CONSOLE_PREFIX + "exception"), true,
+ "'exception' filter is enabled (browser console)");
+ is(Services.prefs.getBoolPref(WEB_CONSOLE_PREFIX + "exception"), true,
+ "'exception' filter is enabled (web console)");
+
+ info("toggle 'exception' filter");
+ hud.setFilterState("exception", false);
+
+ is(Services.prefs.getBoolPref(BROWSER_CONSOLE_PREFIX + "exception"), false,
+ "'exception' filter is disabled (browser console)");
+ is(Services.prefs.getBoolPref(WEB_CONSOLE_PREFIX + "exception"), true,
+ "'exception' filter is enabled (web console)");
+
+ hud.setFilterState("exception", true);
+});
diff --git a/browser/devtools/webconsole/test/browser_console_hide_jsterm_when_devtools_chrome_enabled_false.js b/browser/devtools/webconsole/test/browser_console_hide_jsterm_when_devtools_chrome_enabled_false.js
new file mode 100644
index 000000000..c4f4cd836
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_hide_jsterm_when_devtools_chrome_enabled_false.js
@@ -0,0 +1,105 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/*
+ * Bug 922161 - hide Browser Console JS input field if devtools.chrome.enabled is false
+ * when devtools.chrome.enabled then
+ * -browser console jsterm should be enabled
+ * -browser console object inspector properties should be set.
+ * -webconsole jsterm should be enabled
+ * -webconsole object inspector properties should be set.
+ *
+ * when devtools.chrome.enabled == false then
+ * -browser console jsterm should be disabled
+ * -browser console object inspector properties should not be set.
+ * -webconsole jsterm should be enabled
+ * -webconsole object inspector properties should be set.
+ */
+
+function testObjectInspectorPropertiesAreNotSet(variablesView) {
+ is(variablesView.eval, null, "vview.eval is null");
+ is(variablesView.switch, null, "vview.switch is null");
+ is(variablesView.delete, null, "vview.delete is null");
+}
+
+function* getVariablesView(hud) {
+ function openVariablesView(event, vview) {
+ deferred.resolve(vview._variablesView);
+ }
+
+ let deferred = promise.defer();
+ hud.jsterm.clearOutput();
+ hud.jsterm.execute('new Object()');
+
+ let [message] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "Object",
+ category: CATEGORY_OUTPUT,
+ }],
+ })
+
+ hud.jsterm.once("variablesview-fetched", openVariablesView);
+
+ let anchor = [...message.matched][0].querySelector("a");
+
+ executeSoon(() =>
+ EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow)
+ );
+
+ return deferred.promise;
+}
+
+function testJSTermIsVisible(hud) {
+ let inputContainer = hud.ui.window.document.querySelector(".jsterm-input-container");
+ isnot(inputContainer.style.display, "none", "input is visible");
+}
+
+function testObjectInspectorPropertiesAreSet(variablesView) {
+ isnot(variablesView.eval, null, "vview.eval is set");
+ isnot(variablesView.switch, null, "vview.switch is set");
+ isnot(variablesView.delete, null, "vview.delete is set");
+}
+
+function testJSTermIsNotVisible(hud) {
+ let inputContainer = hud.ui.window.document.querySelector(".jsterm-input-container");
+ is(inputContainer.style.display, "none", "input is not visible");
+}
+
+function* testRunner() {
+ let browserConsole, webConsole, variablesView;
+
+ Services.prefs.setBoolPref("devtools.chrome.enabled", true);
+
+ browserConsole = yield HUDService.toggleBrowserConsole();
+ variablesView = yield getVariablesView(browserConsole);
+ testJSTermIsVisible(browserConsole);
+ testObjectInspectorPropertiesAreSet(variablesView);
+
+ let {tab: browserTab} = yield loadTab("data:text/html;charset=utf8,hello world");
+ webConsole = yield openConsole(browserTab);
+ variablesView = yield getVariablesView(webConsole);
+ testJSTermIsVisible(webConsole)
+ testObjectInspectorPropertiesAreSet(variablesView)
+ yield closeConsole(browserTab);
+
+ yield HUDService.toggleBrowserConsole();
+ Services.prefs.setBoolPref("devtools.chrome.enabled", false);
+
+ browserConsole = yield HUDService.toggleBrowserConsole();
+ variablesView = yield getVariablesView(browserConsole);
+ testJSTermIsNotVisible(browserConsole);
+ testObjectInspectorPropertiesAreNotSet(variablesView);
+
+ webConsole = yield openConsole(browserTab);
+ variablesView = yield getVariablesView(webConsole);
+ testJSTermIsVisible(webConsole)
+ testObjectInspectorPropertiesAreSet(variablesView)
+ yield closeConsole(browserTab);
+}
+
+function test() {
+ Task.spawn(testRunner).then(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_console_iframe_messages.js b/browser/devtools/webconsole/test/browser_console_iframe_messages.js
new file mode 100644
index 000000000..f8e32b23a
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_iframe_messages.js
@@ -0,0 +1,104 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that cached messages from nested iframes are displayed in the
+// Web/Browser Console.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-consoleiframes.html";
+
+const expectedMessages = [
+ {
+ text: "main file",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "blah",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR
+ },
+ {
+ text: "iframe 2",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG
+ },
+ {
+ text: "iframe 3",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG
+ }
+];
+
+// "iframe 1" console messages can be coalesced into one if they follow each
+// other in the sequence of messages (depending on timing). If they do not, then
+// they will be displayed in the console output independently, as separate
+// messages. This is why we need to match any of the following two rules.
+const expectedMessagesAny = [
+ {
+ name: "iframe 1 (count: 2)",
+ text: "iframe 1",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ count: 2
+ },
+ {
+ name: "iframe 1 (repeats: 2)",
+ text: "iframe 1",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ repeats: 2
+ },
+];
+
+function test()
+{
+ expectUncaughtException();
+ loadTab(TEST_URI).then(() => {
+ openConsole().then(consoleOpened);
+ });
+}
+
+function consoleOpened(hud)
+{
+ ok(hud, "web console opened");
+
+ waitForMessages({
+ webconsole: hud,
+ messages: expectedMessages,
+ }).then(() => {
+ info("first messages matched");
+ waitForMessages({
+ webconsole: hud,
+ messages: expectedMessagesAny,
+ matchCondition: "any",
+ }).then(() => {
+ closeConsole().then(onWebConsoleClose);
+ });
+ });
+}
+
+function onWebConsoleClose()
+{
+ info("web console closed");
+ HUDService.toggleBrowserConsole().then(onBrowserConsoleOpen);
+}
+
+function onBrowserConsoleOpen(hud)
+{
+ ok(hud, "browser console opened");
+ waitForMessages({
+ webconsole: hud,
+ messages: expectedMessages,
+ }).then(() => {
+ info("first messages matched");
+ waitForMessages({
+ webconsole: hud,
+ messages: expectedMessagesAny,
+ matchCondition: "any",
+ }).then(() => {
+ closeConsole().then(finishTest);
+ });
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_console_keyboard_accessibility.js b/browser/devtools/webconsole/test/browser_console_keyboard_accessibility.js
new file mode 100644
index 000000000..bbf767314
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_keyboard_accessibility.js
@@ -0,0 +1,79 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that basic keyboard shortcuts work in the web console.
+
+"use strict";
+
+let test = asyncTest(function*() {
+ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+ ok(hud, "Web Console opened");
+
+ info("dump some spew into the console for scrolling");
+ hud.jsterm.execute("(function() { for (var i = 0; i < 100; i++) { " +
+ "console.log('foobarz' + i);" +
+ "}})();");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "foobarz99",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ let currentPosition = hud.outputNode.parentNode.scrollTop;
+ let bottom = currentPosition;
+
+ EventUtils.synthesizeKey("VK_PAGE_UP", {});
+ isnot(hud.outputNode.parentNode.scrollTop, currentPosition, "scroll position changed after page up");
+
+ currentPosition = hud.outputNode.parentNode.scrollTop;
+ EventUtils.synthesizeKey("VK_PAGE_DOWN", {});
+ ok(hud.outputNode.parentNode.scrollTop > currentPosition, "scroll position now at bottom");
+
+ EventUtils.synthesizeKey("VK_HOME", {});
+ is(hud.outputNode.parentNode.scrollTop, 0, "scroll position now at top");
+
+ EventUtils.synthesizeKey("VK_END", {});
+
+ let scrollTop = hud.outputNode.parentNode.scrollTop;
+ ok(scrollTop > 0 && Math.abs(scrollTop - bottom) <= 5,
+ "scroll position now at bottom");
+
+ info("try ctrl-l to clear output");
+ executeSoon(() => { EventUtils.synthesizeKey("l", { ctrlKey: true }); });
+ yield hud.jsterm.once("messages-cleared");
+
+ is(hud.outputNode.textContent.indexOf("foobarz1"), -1, "output cleared");
+ is(hud.jsterm.inputNode.getAttribute("focused"), "true",
+ "jsterm input is focused");
+
+ info("try ctrl-f to focus filter");
+ EventUtils.synthesizeKey("F", { accelKey: true });
+ ok(!hud.jsterm.inputNode.getAttribute("focused"),
+ "jsterm input is not focused");
+ is(hud.ui.filterBox.getAttribute("focused"), "true",
+ "filter input is focused");
+
+ if (Services.appinfo.OS == "Darwin") {
+ ok(hud.ui.getFilterState("network"), "network category is enabled");
+ EventUtils.synthesizeKey("t", { ctrlKey: true });
+ ok(!hud.ui.getFilterState("network"), "accesskey for Network works");
+ EventUtils.synthesizeKey("t", { ctrlKey: true });
+ ok(hud.ui.getFilterState("network"), "accesskey for Network works (again)");
+ }
+ else {
+ EventUtils.synthesizeKey("N", { altKey: true });
+ let net = hud.ui.document.querySelector("toolbarbutton[category=net]");
+ is(hud.ui.document.activeElement, net,
+ "accesskey for Network category focuses the Net button");
+ }
+});
diff --git a/browser/devtools/webconsole/test/browser_console_log_inspectable_object.js b/browser/devtools/webconsole/test/browser_console_log_inspectable_object.js
new file mode 100644
index 000000000..075f2fb70
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_log_inspectable_object.js
@@ -0,0 +1,50 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that objects given to console.log() are inspectable.
+
+"use strict";
+
+let test = asyncTest(function*() {
+ yield loadTab("data:text/html;charset=utf8,test for bug 676722 - inspectable objects for window.console");
+
+ let hud = yield openConsole();
+ hud.jsterm.clearOutput(true);
+
+ hud.jsterm.execute("myObj = {abba: 'omgBug676722'}");
+ hud.jsterm.execute("console.log('fooBug676722', myObj)");
+
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "fooBug676722",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ objects: true,
+ }],
+ });
+
+ let msg = [...result.matched][0];
+ ok(msg, "message element");
+
+ let body = msg.querySelector(".message-body");
+ ok(body, "message body");
+
+ let clickable = result.clickableElements[0];
+ ok(clickable, "the console.log() object anchor was found");
+ ok(body.textContent.contains('{ abba: "omgBug676722" }'),
+ "clickable node content is correct");
+
+ executeSoon(() => {
+ EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow);
+ });
+
+ let varView = yield hud.jsterm.once("variablesview-fetched");
+ ok(varView, "object inspector opened on click");
+
+ yield findVariableViewProperties(varView, [{
+ name: "abba",
+ value: "omgBug676722",
+ }], { webconsole: hud });
+});
diff --git a/browser/devtools/webconsole/test/browser_console_native_getters.js b/browser/devtools/webconsole/test/browser_console_native_getters.js
new file mode 100644
index 000000000..8213108ab
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_native_getters.js
@@ -0,0 +1,99 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that native getters and setters for DOM elements work as expected in
+// variables view - bug 870220.
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf8,<title>bug870220</title>\n" +
+ "<p>hello world\n<p>native getters!";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ let jsterm = hud.jsterm;
+
+ jsterm.execute("document");
+
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "HTMLDocument \u2192 data:text/html;charset=utf8",
+ category: CATEGORY_OUTPUT,
+ objects: true,
+ }],
+ });
+
+ let clickable = result.clickableElements[0];
+ ok(clickable, "clickable object found");
+
+ executeSoon(() => {
+ EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow);
+ });
+
+ let fetchedVar = yield jsterm.once("variablesview-fetched");
+
+ let variablesView = fetchedVar._variablesView;
+ ok(variablesView, "variables view object");
+
+ let results = yield findVariableViewProperties(fetchedVar, [
+ { name: "title", value: "bug870220" },
+ { name: "bgColor" },
+ ], { webconsole: hud });
+
+ let prop = results[1].matchedProp;
+ ok(prop, "matched the |bgColor| property in the variables view");
+
+ // Check that property value updates work.
+ let updatedVar = yield updateVariablesViewProperty({
+ property: prop,
+ field: "value",
+ string: "'red'",
+ webconsole: hud,
+ });
+
+ info("on fetch after background update");
+
+ jsterm.clearOutput(true);
+ jsterm.execute("document.bgColor");
+
+ [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "red",
+ category: CATEGORY_OUTPUT,
+ }],
+ });
+
+ yield findVariableViewProperties(updatedVar, [
+ { name: "bgColor", value: "red" },
+ ], { webconsole: hud });
+
+ jsterm.execute("$$('p')");
+
+ [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "NodeList [",
+ category: CATEGORY_OUTPUT,
+ objects: true,
+ }],
+ });
+
+ clickable = result.clickableElements[0];
+ ok(clickable, "clickable object found");
+
+ executeSoon(() => {
+ EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow);
+ });
+
+ fetchedVar = yield jsterm.once("variablesview-fetched");
+
+ yield findVariableViewProperties(fetchedVar, [
+ { name: "0.textContent", value: /hello world/ },
+ { name: "1.textContent", value: /native getters/ },
+ ], { webconsole: hud });
+});
diff --git a/browser/devtools/webconsole/test/browser_console_navigation_marker.js b/browser/devtools/webconsole/test/browser_console_navigation_marker.js
new file mode 100644
index 000000000..280c525ae
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_navigation_marker.js
@@ -0,0 +1,75 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that the navigation marker shows on page reload - bug 793996.
+
+const PREF = "devtools.webconsole.persistlog";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let hud;
+
+let test = asyncTest(function* () {
+ Services.prefs.setBoolPref(PREF, true);
+
+ let { browser } = yield loadTab(TEST_URI);
+ hud = yield openConsole();
+
+ yield consoleOpened();
+
+ let loaded = loadBrowser(browser);
+ BrowserReload();
+ yield loaded;
+
+ yield onReload();
+
+ isnot(hud.outputNode.textContent.indexOf("foobarz1"), -1,
+ "foobarz1 is still in the output");
+
+ Services.prefs.clearUserPref(PREF);
+
+ hud = null;
+});
+
+function consoleOpened()
+{
+ ok(hud, "Web Console opened");
+
+ hud.jsterm.clearOutput();
+ content.console.log("foobarz1");
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "foobarz1",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+}
+
+function onReload()
+{
+ content.console.log("foobarz2");
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "page reload",
+ text: "test-console.html",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "foobarz2",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ },
+ {
+ name: "navigation marker",
+ text: "test-console.html",
+ type: Messages.NavigationMarker,
+ }],
+ });
+}
+
diff --git a/browser/devtools/webconsole/test/browser_console_nsiconsolemessage.js b/browser/devtools/webconsole/test/browser_console_nsiconsolemessage.js
new file mode 100644
index 000000000..ca87c057f
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_nsiconsolemessage.js
@@ -0,0 +1,80 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that nsIConsoleMessages are displayed in the Browser Console.
+// See bug 859756.
+
+const TEST_URI = "data:text/html;charset=utf8,<title>bug859756</title>\n" +
+ "<p>hello world\n<p>nsIConsoleMessages ftw!";
+
+function test()
+{
+ const FILTER_PREF = "devtools.browserconsole.filter.jslog";
+ Services.prefs.setBoolPref(FILTER_PREF, true);
+
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref(FILTER_PREF);
+ });
+
+ Task.spawn(function*() {
+ const {tab} = yield loadTab(TEST_URI);
+
+ // Test for cached nsIConsoleMessages.
+ Services.console.logStringMessage("test1 for bug859756");
+
+ info("open web console");
+ let hud = yield openConsole(tab);
+
+ ok(hud, "web console opened");
+ Services.console.logStringMessage("do-not-show-me");
+ content.console.log("foobarz");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "foobarz",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ let text = hud.outputNode.textContent;
+ is(text.indexOf("do-not-show-me"), -1,
+ "nsIConsoleMessages are not displayed");
+ is(text.indexOf("test1 for bug859756"), -1,
+ "nsIConsoleMessages are not displayed (confirmed)");
+
+ yield closeConsole(tab);
+
+ info("web console closed");
+ hud = yield HUDService.toggleBrowserConsole();
+ ok(hud, "browser console opened");
+
+ Services.console.logStringMessage("test2 for bug859756");
+
+ let results = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "test1 for bug859756",
+ category: CATEGORY_JS,
+ }, {
+ text: "test2 for bug859756",
+ category: CATEGORY_JS,
+ }, {
+ text: "do-not-show-me",
+ category: CATEGORY_JS,
+ }],
+ });
+
+ let msg = [...results[2].matched][0];
+ ok(msg, "message element for do-not-show-me (nsIConsoleMessage)");
+ isnot(msg.textContent.indexOf("do-not-show"), -1, "element content is correct");
+ ok(!msg.classList.contains("filtered-by-type"), "element is not filtered");
+
+ hud.setFilterState("jslog", false);
+
+ ok(msg.classList.contains("filtered-by-type"), "element is filtered");
+ }).then(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_console_open_or_focus.js b/browser/devtools/webconsole/test/browser_console_open_or_focus.js
new file mode 100644
index 000000000..94625bc10
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_open_or_focus.js
@@ -0,0 +1,47 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that the "browser console" menu item opens or focuses (if already open)
+// the console window instead of toggling it open/close.
+
+
+"use strict";
+
+let test = asyncTest(function* () {
+ let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+ .getService(Components.interfaces.nsIWindowMediator);
+ let currWindow, hud, mainWindow;
+
+ mainWindow = Services.wm.getMostRecentWindow(null);
+
+ yield HUDService.openBrowserConsoleOrFocus();
+
+ hud = HUDService.getBrowserConsole();
+
+ console.log("testmessage");
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "testmessage"
+ }],
+ });
+
+ currWindow = Services.wm.getMostRecentWindow(null);
+ is(currWindow.document.documentURI, devtools.Tools.webConsole.url,
+ "The Browser Console is open and has focus");
+
+ mainWindow.focus();
+
+ yield HUDService.openBrowserConsoleOrFocus();
+
+ currWindow = Services.wm.getMostRecentWindow(null);
+ is(currWindow.document.documentURI, devtools.Tools.webConsole.url,
+ "The Browser Console is open and has focus");
+
+ yield HUDService.toggleBrowserConsole();
+
+ hud = HUDService.getBrowserConsole();
+ ok(!hud, "Browser Console has been closed");
+});
diff --git a/browser/devtools/webconsole/test/browser_console_optimized_out_vars.js b/browser/devtools/webconsole/test/browser_console_optimized_out_vars.js
new file mode 100644
index 000000000..c3eceedf0
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_optimized_out_vars.js
@@ -0,0 +1,82 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Check that inspecting an optimized out variable works when execution is
+// paused.
+
+function test() {
+ Task.spawn(function* () {
+ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-closure-optimized-out.html";
+ let {tab} = yield loadTab(TEST_URI);
+ let hud = yield openConsole(tab);
+ let { toolbox, panel, panelWin } = yield openDebugger();
+
+ yield waitForThreadEvents(panel, "resumed");
+ ok(true, "Debugger resumed");
+
+ let sources = panelWin.DebuggerView.Sources;
+ yield panel.addBreakpoint({ actor: sources.values[0], line: 18 });
+ yield ensureThreadClientState(panel, "resumed");
+
+ let fetchedScopes = panelWin.once(panelWin.EVENTS.FETCHED_SCOPES);
+ let button = content.document.querySelector("button");
+ ok(button, "Button element found");
+ // Spin the event loop before causing the debuggee to pause, to allow
+ // this function to return first.
+ executeSoon(() => button.click());
+
+ let packet = yield fetchedScopes;
+ ok(true, "Scopes were fetched");
+
+ yield toolbox.selectTool("webconsole");
+
+ // This is the meat of the test: evaluate the optimized out variable.
+ hud.jsterm.execute("upvar");
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "optimized out",
+ category: CATEGORY_OUTPUT,
+ }]
+ });
+
+ finishTest();
+ }).then(null, aError => {
+ ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
+ });
+}
+
+// Debugger helper functions stolen from browser/devtools/debugger/test/head.js.
+
+function ensureThreadClientState(aPanel, aState) {
+ let thread = aPanel.panelWin.gThreadClient;
+ let state = thread.state;
+
+ info("Thread is: '" + state + "'.");
+
+ if (state == aState) {
+ return promise.resolve(null);
+ } else {
+ return waitForThreadEvents(aPanel, aState);
+ }
+}
+
+function waitForThreadEvents(aPanel, aEventName, aEventRepeat = 1) {
+ info("Waiting for thread event: '" + aEventName + "' to fire: " + aEventRepeat + " time(s).");
+
+ let deferred = promise.defer();
+ let thread = aPanel.panelWin.gThreadClient;
+ let count = 0;
+
+ thread.addListener(aEventName, function onEvent(aEventName, ...aArgs) {
+ info("Thread event '" + aEventName + "' fired: " + (++count) + " time(s).");
+
+ if (count == aEventRepeat) {
+ ok(true, "Enough '" + aEventName + "' thread events have been fired.");
+ thread.removeListener(aEventName, onEvent);
+ deferred.resolve.apply(deferred, aArgs);
+ }
+ });
+
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_console_private_browsing.js b/browser/devtools/webconsole/test/browser_console_private_browsing.js
new file mode 100644
index 000000000..f517fdd2c
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_private_browsing.js
@@ -0,0 +1,200 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Bug 874061: test for how the browser and web consoles display messages coming
+// from private windows. See bug for description of expected behavior.
+
+function test()
+{
+ const TEST_URI = "data:text/html;charset=utf8,<p>hello world! bug 874061" +
+ "<button onclick='console.log(\"foobar bug 874061\");" +
+ "fooBazBaz.yummy()'>click</button>";
+ let ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"]
+ .getService(Ci.nsIConsoleAPIStorage);
+ let privateWindow, privateBrowser, privateTab, privateContent;
+ let hud, expectedMessages, nonPrivateMessage;
+
+ // This test is slightly more involved: it opens the web console twice,
+ // a new private window once, and the browser console twice. We can get
+ // a timeout with debug builds on slower machines.
+ requestLongerTimeout(2);
+ start();
+
+ function start()
+ {
+ gBrowser.selectedTab = gBrowser.addTab("data:text/html;charset=utf8," +
+ "<p>hello world! I am not private!");
+ gBrowser.selectedBrowser.addEventListener("load", onLoadTab, true);
+ }
+
+ function onLoadTab()
+ {
+ gBrowser.selectedBrowser.removeEventListener("load", onLoadTab, true);
+ info("onLoadTab()");
+
+ // Make sure we have a clean state to start with.
+ Services.console.reset();
+ ConsoleAPIStorage.clearEvents();
+
+ // Add a non-private message to the browser console.
+ content.console.log("bug874061-not-private");
+
+ nonPrivateMessage = {
+ name: "console message from a non-private window",
+ text: "bug874061-not-private",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ };
+
+ privateWindow = OpenBrowserWindow({ private: true });
+ ok(privateWindow, "new private window");
+ ok(PrivateBrowsingUtils.isWindowPrivate(privateWindow), "window is private");
+
+ whenDelayedStartupFinished(privateWindow, onPrivateWindowReady);
+ }
+
+ function onPrivateWindowReady()
+ {
+ info("private browser window opened");
+ privateBrowser = privateWindow.gBrowser;
+
+ privateTab = privateBrowser.selectedTab = privateBrowser.addTab(TEST_URI);
+ privateBrowser.selectedBrowser.addEventListener("load", function onLoad() {
+ info("private tab opened");
+ privateBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
+ privateContent = privateBrowser.selectedBrowser.contentWindow;
+ ok(PrivateBrowsingUtils.isBrowserPrivate(privateBrowser.selectedBrowser), "tab window is private");
+ openConsole(privateTab).then(consoleOpened);
+ }, true);
+ }
+
+ function addMessages()
+ {
+ let button = privateContent.document.querySelector("button");
+ ok(button, "button in page");
+ EventUtils.synthesizeMouse(button, 2, 2, {}, privateContent);
+ }
+
+ function consoleOpened(aHud)
+ {
+ hud = aHud;
+ ok(hud, "web console opened");
+
+ addMessages();
+ expectedMessages = [
+ {
+ name: "script error",
+ text: "fooBazBaz is not defined",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ },
+ {
+ name: "console message",
+ text: "foobar bug 874061",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ },
+ ];
+
+ // Make sure messages are displayed in the web console as they happen, even
+ // if this is a private tab.
+ waitForMessages({
+ webconsole: hud,
+ messages: expectedMessages,
+ }).then(testCachedMessages);
+ }
+
+ function testCachedMessages()
+ {
+ info("testCachedMessages()");
+ closeConsole(privateTab).then(() => {
+ info("web console closed");
+ openConsole(privateTab).then(consoleReopened);
+ });
+ }
+
+ function consoleReopened(aHud)
+ {
+ hud = aHud;
+ ok(hud, "web console reopened");
+
+ // Make sure that cached messages are displayed in the web console, even
+ // if this is a private tab.
+ waitForMessages({
+ webconsole: hud,
+ messages: expectedMessages,
+ }).then(testBrowserConsole);
+ }
+
+ function testBrowserConsole()
+ {
+ info("testBrowserConsole()");
+ closeConsole(privateTab).then(() => {
+ info("web console closed");
+ privateWindow.HUDService.toggleBrowserConsole().then(onBrowserConsoleOpen);
+ });
+ }
+
+ // Make sure that the cached messages from private tabs are not displayed in
+ // the browser console.
+ function checkNoPrivateMessages()
+ {
+ let text = hud.outputNode.textContent;
+ is(text.indexOf("fooBazBaz"), -1, "no exception displayed");
+ is(text.indexOf("bug 874061"), -1, "no console message displayed");
+ }
+
+ function onBrowserConsoleOpen(aHud)
+ {
+ hud = aHud;
+ ok(hud, "browser console opened");
+
+ checkNoPrivateMessages();
+ addMessages();
+ expectedMessages.push(nonPrivateMessage);
+
+ // Make sure that live messages are displayed in the browser console, even
+ // from private tabs.
+ waitForMessages({
+ webconsole: hud,
+ messages: expectedMessages,
+ }).then(testPrivateWindowClose);
+ }
+
+ function testPrivateWindowClose()
+ {
+ info("close the private window and check if the private messages are removed");
+ hud.jsterm.once("private-messages-cleared", () => {
+ isnot(hud.outputNode.textContent.indexOf("bug874061-not-private"), -1,
+ "non-private messages are still shown after private window closed");
+ checkNoPrivateMessages();
+
+ info("close the browser console");
+ privateWindow.HUDService.toggleBrowserConsole().then(() => {
+ info("reopen the browser console");
+ executeSoon(() =>
+ HUDService.toggleBrowserConsole().then(onBrowserConsoleReopen));
+ });
+ });
+ privateWindow.BrowserTryToCloseWindow();
+ }
+
+ function onBrowserConsoleReopen(aHud)
+ {
+ hud = aHud;
+ ok(hud, "browser console reopened");
+
+ // Make sure that the non-private message is still shown after reopen.
+ waitForMessages({
+ webconsole: hud,
+ messages: [nonPrivateMessage],
+ }).then(() => {
+ // Make sure that no private message is displayed after closing the private
+ // window and reopening the Browser Console.
+ checkNoPrivateMessages();
+ executeSoon(finishTest);
+ });
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_console_variables_view.js b/browser/devtools/webconsole/test/browser_console_variables_view.js
new file mode 100644
index 000000000..bfd5a128a
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_variables_view.js
@@ -0,0 +1,189 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that variables view works as expected in the web console.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-eval-in-stackframe.html";
+
+let gWebConsole, gJSTerm, gVariablesView;
+
+let hud;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ hud = yield openConsole();
+
+ gWebConsole = hud;
+ gJSTerm = hud.jsterm;
+ let msg = yield gJSTerm.execute("fooObj");
+
+ ok(msg, "output message found");
+ ok(msg.textContent.contains('{ testProp: "testValue" }'), "message text check");
+
+ let anchor = msg.querySelector("a");
+ ok(anchor, "object link found");
+
+ let fetched = gJSTerm.once("variablesview-fetched");
+
+ // executeSoon
+ EventUtils.synthesizeMouse(anchor, 2, 2, {}, gWebConsole.iframeWindow);
+
+ let view = yield fetched;
+
+ let results = yield onFooObjFetch(view);
+
+ let vView = yield onTestPropFound(results);
+ let results2 = yield onFooObjFetchAfterUpdate(vView);
+
+ let vView2 = yield onUpdatedTestPropFound(results2);
+ let results3 = yield onFooObjFetchAfterPropRename(vView2);
+
+ let vView3 = yield onRenamedTestPropFound(results3);
+ let results4 = yield onPropUpdateError(vView3);
+
+ yield onRenamedTestPropFoundAgain(results4);
+
+ let prop = results4[0].matchedProp;
+ yield testPropDelete(prop);
+
+ gWebConsole = gJSTerm = gVariablesView = null;
+});
+
+function onFooObjFetch(aVar)
+{
+ gVariablesView = aVar._variablesView;
+ ok(gVariablesView, "variables view object");
+
+ return findVariableViewProperties(aVar, [
+ { name: "testProp", value: "testValue" },
+ ], { webconsole: gWebConsole });
+}
+
+function onTestPropFound(aResults)
+{
+ let prop = aResults[0].matchedProp;
+ ok(prop, "matched the |testProp| property in the variables view");
+
+ is("testValue", aResults[0].value,
+ "|fooObj.testProp| value is correct");
+
+ // Check that property value updates work and that jsterm functions can be
+ // used.
+ return updateVariablesViewProperty({
+ property: prop,
+ field: "value",
+ string: "document.title + window.location + $('p')",
+ webconsole: gWebConsole
+ });
+}
+
+function onFooObjFetchAfterUpdate(aVar)
+{
+ info("onFooObjFetchAfterUpdate");
+ let expectedValue = content.document.title + content.location
+ + '[object HTMLParagraphElement]';
+
+ return findVariableViewProperties(aVar, [
+ { name: "testProp", value: expectedValue },
+ ], { webconsole: gWebConsole });
+}
+
+function onUpdatedTestPropFound(aResults)
+{
+ let prop = aResults[0].matchedProp;
+ ok(prop, "matched the updated |testProp| property value");
+
+ is(content.wrappedJSObject.fooObj.testProp, aResults[0].value,
+ "|fooObj.testProp| value has been updated");
+
+ // Check that property name updates work.
+ return updateVariablesViewProperty({
+ property: prop,
+ field: "name",
+ string: "testUpdatedProp",
+ webconsole: gWebConsole
+ });
+}
+
+function onFooObjFetchAfterPropRename(aVar)
+{
+ info("onFooObjFetchAfterPropRename");
+
+ let para = content.wrappedJSObject.document.querySelector("p");
+ let expectedValue = content.document.title + content.location + para;
+
+ // Check that the new value is in the variables view.
+ return findVariableViewProperties(aVar, [
+ { name: "testUpdatedProp", value: expectedValue },
+ ], { webconsole: gWebConsole });
+}
+
+function onRenamedTestPropFound(aResults)
+{
+ let prop = aResults[0].matchedProp;
+ ok(prop, "matched the renamed |testProp| property");
+
+ ok(!content.wrappedJSObject.fooObj.testProp,
+ "|fooObj.testProp| has been deleted");
+ is(content.wrappedJSObject.fooObj.testUpdatedProp, aResults[0].value,
+ "|fooObj.testUpdatedProp| is correct");
+
+ // Check that property value updates that cause exceptions are reported in
+ // the web console output.
+ return updateVariablesViewProperty({
+ property: prop,
+ field: "value",
+ string: "foobarzFailure()",
+ webconsole: gWebConsole
+ });
+}
+
+function onPropUpdateError(aVar)
+{
+ info("onPropUpdateError");
+
+ let para = content.wrappedJSObject.document.querySelector("p");
+ let expectedValue = content.document.title + content.location + para;
+
+ // Make sure the property did not change.
+ return findVariableViewProperties(aVar, [
+ { name: "testUpdatedProp", value: expectedValue },
+ ], { webconsole: gWebConsole });
+}
+
+function onRenamedTestPropFoundAgain(aResults)
+{
+ let prop = aResults[0].matchedProp;
+ ok(prop, "matched the renamed |testProp| property again");
+
+ let outputNode = gWebConsole.outputNode;
+
+ return waitForMessages({
+ webconsole: gWebConsole,
+ messages: [{
+ name: "exception in property update reported in the web console output",
+ text: "foobarzFailure",
+ category: CATEGORY_OUTPUT,
+ severity: SEVERITY_ERROR,
+ }],
+ });
+}
+
+function testPropDelete(aProp)
+{
+ gVariablesView.window.focus();
+ aProp.focus();
+
+ executeSoon(() => {
+ EventUtils.synthesizeKey("VK_DELETE", {}, gVariablesView.window);
+ });
+
+ return waitForSuccess({
+ name: "property deleted",
+ timeout: 60000,
+ validator: () => !("testUpdatedProp" in content.wrappedJSObject.fooObj)
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_console_variables_view_dom_nodes.js b/browser/devtools/webconsole/test/browser_console_variables_view_dom_nodes.js
new file mode 100644
index 000000000..318392bdf
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_variables_view_dom_nodes.js
@@ -0,0 +1,56 @@
+/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/* Test that ensures DOM nodes are rendered correctly in VariablesView. */
+
+function test() {
+ const TEST_URI = 'data:text/html;charset=utf-8, \
+ <html> \
+ <head> \
+ <title>Test for DOM nodes in variables view</title> \
+ </head> \
+ <body> \
+ <div></div> \
+ <div id="testID"></div> \
+ <div class="single-class"></div> \
+ <div class="multiple-classes another-class"></div> \
+ <div class="class-and-id" id="class-and-id"></div> \
+ <div class="multiple-classes-and-id another-class" \
+ id="multiple-classes-and-id"></div> \
+ <div class=" whitespace-start"></div> \
+ <div class="whitespace-end "></div> \
+ <div class="multiple spaces"></div> \
+ </body> \
+ </html>';
+
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ const {tab} = yield loadTab(TEST_URI);
+ const hud = yield openConsole(tab);
+ const jsterm = hud.jsterm;
+
+ let deferred = promise.defer();
+ jsterm.once("variablesview-fetched", (_, aVar) => deferred.resolve(aVar));
+ jsterm.execute("inspect(document.querySelectorAll('div'))");
+
+ let variableScope = yield deferred.promise;
+ ok(variableScope, "Variables view opened");
+
+ yield findVariableViewProperties(variableScope, [
+ { name: "0", value: "<div>"},
+ { name: "1", value: "<div#testID>"},
+ { name: "2", value: "<div.single-class>"},
+ { name: "3", value: "<div.multiple-classes.another-class>"},
+ { name: "4", value: "<div#class-and-id.class-and-id>"},
+ { name: "5", value: "<div#multiple-classes-and-id.multiple-classes-and-id.another-class>"},
+ { name: "6", value: "<div.whitespace-start>"},
+ { name: "7", value: "<div.whitespace-end>"},
+ { name: "8", value: "<div.multiple.spaces>"},
+ ], { webconsole: hud});
+
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_console_variables_view_dont_sort_non_sortable_classes_properties.js b/browser/devtools/webconsole/test/browser_console_variables_view_dont_sort_non_sortable_classes_properties.js
new file mode 100644
index 000000000..60d82f99e
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_variables_view_dont_sort_non_sortable_classes_properties.js
@@ -0,0 +1,101 @@
+/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/* Test case that ensures Array and other list types are not sorted in variables
+ * view.
+ *
+ * The tested types are:
+ * - Array
+ * - Int8Array
+ * - Int16Array
+ * - Int32Array
+ * - Uint8Array
+ * - Uint16Array
+ * - Uint32Array
+ * - Uint8ClampedArray
+ * - Float32Array
+ * - Float64Array
+ * - NodeList
+ */
+
+function test() {
+ const TEST_URI = "data:text/html;charset=utf-8, \
+ <html> \
+ <head> \
+ <title>Test document for bug 977500</title> \
+ </head> \
+ <body> \
+ <div></div> \
+ <div></div> \
+ <div></div> \
+ <div></div> \
+ <div></div> \
+ <div></div> \
+ <div></div> \
+ <div></div> \
+ <div></div> \
+ <div></div> \
+ <div></div> \
+ <div></div> \
+ </body> \
+ </html>";
+
+ let jsterm;
+
+ function* runner() {
+ const typedArrayTypes = ["Int8Array", "Int16Array", "Int32Array",
+ "Uint8Array", "Uint16Array", "Uint32Array",
+ "Uint8ClampedArray", "Float32Array",
+ "Float64Array"];
+
+ const {tab} = yield loadTab(TEST_URI);
+ const hud = yield openConsole(tab);
+ jsterm = hud.jsterm;
+
+ // Create an ArrayBuffer of 80 bytes to test TypedArrays. 80 bytes is
+ // enough to get 10 items in all different TypedArrays.
+ yield jsterm.execute("let buf = new ArrayBuffer(80);");
+
+ // Array
+ yield testNotSorted("Array(0,1,2,3,4,5,6,7,8,9,10)");
+ // NodeList
+ yield testNotSorted("document.querySelectorAll('div')");
+
+ // Typed arrays.
+ for (let type of typedArrayTypes) {
+ yield testNotSorted("new " + type + "(buf)");
+ }
+ }
+
+ /**
+ * A helper that ensures the properties are not sorted when an object
+ * specified by aObject is inspected.
+ *
+ * @param string aObject
+ * A string that, once executed, creates and returns the object to
+ * inspect.
+ */
+ function testNotSorted(aObject) {
+ info("Testing " + aObject);
+ let deferred = promise.defer();
+ jsterm.once("variablesview-fetched", (_, aVar) => deferred.resolve(aVar));
+ jsterm.execute("inspect(" + aObject + ")");
+
+ let variableScope = yield deferred.promise;
+ ok(variableScope, "Variables view opened");
+
+ // If the properties are sorted: keys = ["0", "1", "10",...] <- incorrect
+ // If the properties are not sorted: keys = ["0", "1", "2",...] <- correct
+ let keyIterator = variableScope._store.keys();
+ is(keyIterator.next().value, "0", "First key is 0");
+ is(keyIterator.next().value, "1", "Second key is 1");
+
+ // If the properties are sorted, the next one will be 10.
+ is(keyIterator.next().value, "2", "Third key is 2, not 10");
+ }
+
+ Task.spawn(runner).then(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js b/browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js
new file mode 100644
index 000000000..6c7087a94
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js
@@ -0,0 +1,97 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that variables view is linked to the inspector for highlighting and
+// selecting DOM nodes
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-952277-highlight-nodes-in-vview.html";
+
+let gWebConsole, gJSTerm, gVariablesView, gToolbox;
+
+function test()
+{
+ loadTab(TEST_URI).then(() => {
+ openConsole().then(hud => {
+ consoleOpened(hud);
+ })
+ });
+}
+
+function consoleOpened(hud)
+{
+ gWebConsole = hud;
+ gJSTerm = hud.jsterm;
+ gToolbox = gDevTools.getToolbox(hud.target);
+ gJSTerm.execute("document.querySelectorAll('p')").then(onQSAexecuted);
+}
+
+function onQSAexecuted(msg)
+{
+ ok(msg, "output message found");
+ let anchor = msg.querySelector("a");
+ ok(anchor, "object link found");
+
+ gJSTerm.once("variablesview-fetched", onNodeListVviewFetched);
+
+ executeSoon(() =>
+ EventUtils.synthesizeMouse(anchor, 2, 2, {}, gWebConsole.iframeWindow)
+ );
+}
+
+function onNodeListVviewFetched(aEvent, aVar)
+{
+ gVariablesView = aVar._variablesView;
+ ok(gVariablesView, "variables view object");
+
+ // Transform the vview into an array we can filter properties from
+ let props = [[id, prop] for([id, prop] of aVar)];
+ // These properties are the DOM nodes ones
+ props = props.filter(v => v[0].match(/[0-9]+/));
+
+ function hoverOverDomNodeVariableAndAssertHighlighter(index) {
+ if (props[index]) {
+ let prop = props[index][1];
+ let valueEl = prop._valueLabel;
+
+ gToolbox.once("node-highlight", () => {
+ ok(true, "The highlighter was shown on hover of the DOMNode");
+ gToolbox.highlighterUtils.unhighlight().then(() => {
+ clickOnDomNodeVariableAndAssertInspectorSelected(index);
+ });
+ });
+
+ // Rather than trying to emulate a mouseenter event, let's call the
+ // variable's highlightDomNode and see if it has the desired effect
+ prop.highlightDomNode();
+ } else {
+ finishUp();
+ }
+ }
+
+ function clickOnDomNodeVariableAndAssertInspectorSelected(index) {
+ let prop = props[index][1];
+
+ // Make sure the inspector is initialized so we can listen to its events
+ gToolbox.initInspector().then(() => {
+ // Rather than trying to click on the value here, let's just call the
+ // variable's openNodeInInspector function and see if it has the
+ // desired effect
+ prop.openNodeInInspector().then(() => {
+ is(gToolbox.currentToolId, "inspector", "The toolbox switched over the inspector on DOMNode click");
+ gToolbox.selectTool("webconsole").then(() => {
+ hoverOverDomNodeVariableAndAssertHighlighter(index + 1);
+ });
+ });
+ });
+ }
+
+ hoverOverDomNodeVariableAndAssertHighlighter(0);
+}
+
+function finishUp() {
+ gWebConsole = gJSTerm = gVariablesView = gToolbox = null;
+
+ finishTest();
+}
diff --git a/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging.js b/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging.js
new file mode 100644
index 000000000..0c6f56973
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging.js
@@ -0,0 +1,131 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that makes sure web console eval happens in the user-selected stackframe
+// from the js debugger, when changing the value of a property in the variables
+// view.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-eval-in-stackframe.html";
+
+let gWebConsole, gJSTerm, gDebuggerWin, gThread, gDebuggerController,
+ gStackframes, gVariablesView;
+
+function test()
+{
+ loadTab(TEST_URI).then(() => {
+ openConsole().then(consoleOpened);
+ });
+}
+
+function consoleOpened(hud)
+{
+ gWebConsole = hud;
+ gJSTerm = hud.jsterm;
+
+ executeSoon(() => {
+ info("openDebugger");
+ openDebugger().then(debuggerOpened);
+ });
+}
+
+function debuggerOpened(aResult)
+{
+ gDebuggerWin = aResult.panelWin;
+ gDebuggerController = gDebuggerWin.DebuggerController;
+ gThread = gDebuggerController.activeThread;
+ gStackframes = gDebuggerController.StackFrames;
+
+ executeSoon(() => {
+ gThread.addOneTimeListener("framesadded", onFramesAdded);
+
+ info("firstCall()");
+ content.wrappedJSObject.firstCall();
+ });
+}
+
+function onFramesAdded()
+{
+ info("onFramesAdded");
+
+ executeSoon(() =>
+ openConsole().then(() =>
+ gJSTerm.execute("fooObj").then(onExecuteFooObj)
+ )
+ );
+}
+
+
+function onExecuteFooObj(msg)
+{
+ ok(msg, "output message found");
+ ok(msg.textContent.contains('{ testProp2: "testValue2" }'), "message text check");
+
+ let anchor = msg.querySelector("a");
+ ok(anchor, "object link found");
+
+ gJSTerm.once("variablesview-fetched", onFooObjFetch);
+
+ executeSoon(() => EventUtils.synthesizeMouse(anchor, 2, 2, {},
+ gWebConsole.iframeWindow));
+}
+
+function onFooObjFetch(aEvent, aVar)
+{
+ gVariablesView = aVar._variablesView;
+ ok(gVariablesView, "variables view object");
+
+ findVariableViewProperties(aVar, [
+ { name: "testProp2", value: "testValue2" },
+ { name: "testProp", value: "testValue", dontMatch: true },
+ ], { webconsole: gWebConsole }).then(onTestPropFound);
+}
+
+function onTestPropFound(aResults)
+{
+ let prop = aResults[0].matchedProp;
+ ok(prop, "matched the |testProp2| property in the variables view");
+
+ // Check that property value updates work and that jsterm functions can be
+ // used.
+ updateVariablesViewProperty({
+ property: prop,
+ field: "value",
+ string: "document.title + foo2 + $('p')",
+ webconsole: gWebConsole
+ }).then(onFooObjFetchAfterUpdate);
+}
+
+function onFooObjFetchAfterUpdate(aVar)
+{
+ info("onFooObjFetchAfterUpdate");
+ let para = content.wrappedJSObject.document.querySelector("p");
+ let expectedValue = content.document.title + "foo2SecondCall" + para;
+
+ findVariableViewProperties(aVar, [
+ { name: "testProp2", value: expectedValue },
+ ], { webconsole: gWebConsole }).then(onUpdatedTestPropFound);
+}
+
+function onUpdatedTestPropFound(aResults)
+{
+ let prop = aResults[0].matchedProp;
+ ok(prop, "matched the updated |testProp2| property value");
+
+ // Check that testProp2 was updated.
+ executeSoon(() => gJSTerm.execute("fooObj.testProp2").then(onExecuteFooObjTestProp2));
+}
+
+function onExecuteFooObjTestProp2()
+{
+ let para = content.wrappedJSObject.document.querySelector("p");
+ let expected = content.document.title + "foo2SecondCall" + para;
+
+ isnot(gWebConsole.outputNode.textContent.indexOf(expected), -1,
+ "fooObj.testProp2 is correct");
+
+ gWebConsole = gJSTerm = gDebuggerWin = gThread = gDebuggerController =
+ gStackframes = gVariablesView = null;
+ executeSoon(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging_and_inspecting.js b/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging_and_inspecting.js
new file mode 100644
index 000000000..55890c3f7
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging_and_inspecting.js
@@ -0,0 +1,129 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that makes sure web console eval works while the js debugger paused the
+// page, and while the inspector is active. See bug 886137.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-eval-in-stackframe.html";
+
+let gWebConsole, gJSTerm, gDebuggerWin, gThread, gDebuggerController,
+ gStackframes, gVariablesView;
+
+function test()
+{
+ loadTab(TEST_URI).then(() => {
+ openConsole().then(consoleOpened);
+ }, true);
+}
+
+function consoleOpened(hud)
+{
+ gWebConsole = hud;
+ gJSTerm = hud.jsterm;
+
+ info("openDebugger");
+ openDebugger().then(debuggerOpened);
+}
+
+function debuggerOpened(aResult)
+{
+ info("debugger opened");
+ gDebuggerWin = aResult.panelWin;
+ gDebuggerController = gDebuggerWin.DebuggerController;
+ gThread = gDebuggerController.activeThread;
+ gStackframes = gDebuggerController.StackFrames;
+
+ openInspector().then(inspectorOpened);
+}
+
+function inspectorOpened(aPanel)
+{
+ info("inspector opened");
+ gThread.addOneTimeListener("framesadded", onFramesAdded);
+
+ info("firstCall()");
+ content.wrappedJSObject.firstCall();
+}
+
+function onFramesAdded()
+{
+ info("onFramesAdded");
+
+ openConsole().then(() => gJSTerm.execute("fooObj").then(onExecuteFooObj));
+}
+
+function onExecuteFooObj(msg)
+{
+ ok(msg, "output message found");
+ ok(msg.textContent.contains('{ testProp2: "testValue2" }'),
+ "message text check");
+
+ let anchor = msg.querySelector("a");
+ ok(anchor, "object link found");
+
+ gJSTerm.once("variablesview-fetched", onFooObjFetch);
+
+ EventUtils.synthesizeMouse(anchor, 2, 2, {}, gWebConsole.iframeWindow);
+}
+
+function onFooObjFetch(aEvent, aVar)
+{
+ gVariablesView = aVar._variablesView;
+ ok(gVariablesView, "variables view object");
+
+ findVariableViewProperties(aVar, [
+ { name: "testProp2", value: "testValue2" },
+ { name: "testProp", value: "testValue", dontMatch: true },
+ ], { webconsole: gWebConsole }).then(onTestPropFound);
+}
+
+function onTestPropFound(aResults)
+{
+ let prop = aResults[0].matchedProp;
+ ok(prop, "matched the |testProp2| property in the variables view");
+
+ // Check that property value updates work and that jsterm functions can be
+ // used.
+ updateVariablesViewProperty({
+ property: prop,
+ field: "value",
+ string: "document.title + foo2 + $('p')",
+ webconsole: gWebConsole
+ }).then(onFooObjFetchAfterUpdate);
+}
+
+function onFooObjFetchAfterUpdate(aVar)
+{
+ info("onFooObjFetchAfterUpdate");
+ let para = content.wrappedJSObject.document.querySelector("p");
+ let expectedValue = content.document.title + "foo2SecondCall" + para;
+
+ findVariableViewProperties(aVar, [
+ { name: "testProp2", value: expectedValue },
+ ], { webconsole: gWebConsole }).then(onUpdatedTestPropFound);
+}
+
+function onUpdatedTestPropFound(aResults)
+{
+ let prop = aResults[0].matchedProp;
+ ok(prop, "matched the updated |testProp2| property value");
+
+ // Check that testProp2 was updated.
+ gJSTerm.execute("fooObj.testProp2").then(onExecuteFooObjTestProp2);
+}
+
+function onExecuteFooObjTestProp2()
+{
+ let para = content.wrappedJSObject.document.querySelector("p");
+ let expected = content.document.title + "foo2SecondCall" + para;
+
+ isnot(gWebConsole.outputNode.textContent.indexOf(expected), -1,
+ "fooObj.testProp2 is correct");
+
+ gWebConsole = gJSTerm = gDebuggerWin = gThread = gDebuggerController =
+ gStackframes = gVariablesView = null;
+
+ finishTest();
+}
diff --git a/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe.js b/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe.js
new file mode 100644
index 000000000..beed02552
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe.js
@@ -0,0 +1,147 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that makes sure web console eval happens in the user-selected stackframe
+// from the js debugger.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-eval-in-stackframe.html";
+
+let gWebConsole, gJSTerm, gDebuggerWin, gThread, gDebuggerController, gStackframes;
+
+function test()
+{
+ loadTab(TEST_URI).then(() => {
+ openConsole().then(consoleOpened);
+ });
+}
+
+function consoleOpened(hud)
+{
+ gWebConsole = hud;
+ gJSTerm = hud.jsterm;
+ gJSTerm.execute("foo").then(onExecuteFoo);
+}
+
+function onExecuteFoo()
+{
+ isnot(gWebConsole.outputNode.textContent.indexOf("globalFooBug783499"), -1,
+ "|foo| value is correct");
+
+ gJSTerm.clearOutput();
+
+ // Test for Bug 690529 - Web Console and Scratchpad should evaluate
+ // expressions in the scope of the content window, not in a sandbox.
+ executeSoon(() => gJSTerm.execute("foo2 = 'newFoo'; window.foo2").then(onNewFoo2));
+}
+
+function onNewFoo2(msg)
+{
+ is(gWebConsole.outputNode.textContent.indexOf("undefined"), -1,
+ "|undefined| is not displayed after adding |foo2|");
+
+ ok(msg, "output result found");
+
+ isnot(msg.textContent.indexOf("newFoo"), -1,
+ "'newFoo' is displayed after adding |foo2|");
+
+ gJSTerm.clearOutput();
+
+ info("openDebugger");
+ executeSoon(() => openDebugger().then(debuggerOpened));
+}
+
+function debuggerOpened(aResult)
+{
+ gDebuggerWin = aResult.panelWin;
+ gDebuggerController = gDebuggerWin.DebuggerController;
+ gThread = gDebuggerController.activeThread;
+ gStackframes = gDebuggerController.StackFrames;
+
+ info("openConsole");
+ executeSoon(() =>
+ openConsole().then(() =>
+ gJSTerm.execute("foo + foo2").then(onExecuteFooAndFoo2)
+ )
+ );
+}
+
+function onExecuteFooAndFoo2()
+{
+ let expected = "globalFooBug783499newFoo";
+ isnot(gWebConsole.outputNode.textContent.indexOf(expected), -1,
+ "|foo + foo2| is displayed after starting the debugger");
+
+ executeSoon(() => {
+ gJSTerm.clearOutput();
+
+ info("openDebugger");
+ openDebugger().then(() => {
+ gThread.addOneTimeListener("framesadded", onFramesAdded);
+
+ info("firstCall()");
+ content.wrappedJSObject.firstCall();
+ });
+ });
+}
+
+function onFramesAdded()
+{
+ info("onFramesAdded, openConsole() now");
+ executeSoon(() =>
+ openConsole().then(() =>
+ gJSTerm.execute("foo + foo2").then(onExecuteFooAndFoo2InSecondCall)
+ )
+ );
+}
+
+function onExecuteFooAndFoo2InSecondCall()
+{
+ let expected = "globalFooBug783499foo2SecondCall";
+ isnot(gWebConsole.outputNode.textContent.indexOf(expected), -1,
+ "|foo + foo2| from |secondCall()|");
+
+ executeSoon(() => {
+ gJSTerm.clearOutput();
+
+ info("openDebugger and selectFrame(1)");
+
+ openDebugger().then(() => {
+ gStackframes.selectFrame(1);
+
+ info("openConsole");
+ executeSoon(() =>
+ openConsole().then(() =>
+ gJSTerm.execute("foo + foo2 + foo3").then(onExecuteFoo23InFirstCall)
+ )
+ );
+ });
+ });
+}
+
+function onExecuteFoo23InFirstCall()
+{
+ let expected = "fooFirstCallnewFoofoo3FirstCall";
+ isnot(gWebConsole.outputNode.textContent.indexOf(expected), -1,
+ "|foo + foo2 + foo3| from |firstCall()|");
+
+ executeSoon(() =>
+ gJSTerm.execute("foo = 'abba'; foo3 = 'bug783499'; foo + foo3").then(
+ onExecuteFooAndFoo3ChangesInFirstCall));
+}
+
+function onExecuteFooAndFoo3ChangesInFirstCall()
+{
+ let expected = "abbabug783499";
+ isnot(gWebConsole.outputNode.textContent.indexOf(expected), -1,
+ "|foo + foo3| updated in |firstCall()|");
+
+ is(content.wrappedJSObject.foo, "globalFooBug783499", "|foo| in content window");
+ is(content.wrappedJSObject.foo2, "newFoo", "|foo2| in content window");
+ ok(!content.wrappedJSObject.foo3, "|foo3| was not added to the content window");
+
+ gWebConsole = gJSTerm = gDebuggerWin = gThread = gDebuggerController =
+ gStackframes = null;
+ executeSoon(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe2.js b/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe2.js
new file mode 100644
index 000000000..e94375181
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe2.js
@@ -0,0 +1,63 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test to make sure that web console commands can fire while paused at a breakpoint
+// that was triggered from a JS call. Relies on asynchronous js evaluation over the
+// protocol - see Bug 1088861.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-eval-in-stackframe.html";
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+
+ info("open the web console");
+ let hud = yield openConsole();
+ let {jsterm} = hud;
+
+ info("open the debugger");
+ let {panel,panelWin} = yield openDebugger();
+ let {DebuggerController} = panelWin;
+ let {activeThread,StackFrames} = DebuggerController;
+
+ let firstCall = promise.defer();
+ let frameAdded = promise.defer();
+ executeSoon(() => {
+ info ("Executing firstCall");
+ activeThread.addOneTimeListener("framesadded", () => {
+ executeSoon(frameAdded.resolve);
+ });
+ jsterm.execute("firstCall()").then(firstCall.resolve);
+ });
+
+ info ("Waiting for a frame to be added");
+ yield frameAdded.promise;
+
+ info ("Executing basic command while paused");
+ yield executeAndConfirm(jsterm, "1 + 2", "3");
+
+ info ("Executing command using scoped variables while paused");
+ yield executeAndConfirm(jsterm, "foo + foo2", '"globalFooBug783499foo2SecondCall"');
+
+ info ("Resuming the thread");
+ activeThread.resume();
+
+ info ("Checking the first command (which is the last to resolve since it paused");
+ let node = yield firstCall.promise;
+ is (node.querySelector(".message-body").textContent,
+ "undefined",
+ "firstCall() returned correct value");
+});
+
+function* executeAndConfirm(jsterm, input, output) {
+ info ("Executing command `"+input+"`");
+
+ let node = yield jsterm.execute(input);
+
+ is (node.querySelector(".message-body").textContent,
+ output,
+ "Expected result from call to " + input);
+}
+
diff --git a/browser/devtools/webconsole/test/browser_jsterm_inspect.js b/browser/devtools/webconsole/test/browser_jsterm_inspect.js
new file mode 100644
index 000000000..6bc5f5559
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_jsterm_inspect.js
@@ -0,0 +1,28 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that the inspect() jsterm helper function works.
+
+const TEST_URI = "data:text/html;charset=utf8,<p>hello bug 869981";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+ let jsterm = hud.jsterm;
+
+ jsterm.execute("testProp = 'testValue'");
+
+ let fetched = jsterm.once("variablesview-fetched");
+ jsterm.execute("inspect(window)");
+ let variable = yield fetched;
+
+ ok(variable._variablesView, "variables view object");
+
+ yield findVariableViewProperties(variable, [
+ { name: "testProp", value: "testValue" },
+ { name: "document", value: /HTMLDocument \u2192 data:/ },
+ ], { webconsole: hud });
+});
diff --git a/browser/devtools/webconsole/test/browser_longstring_hang.js b/browser/devtools/webconsole/test/browser_longstring_hang.js
new file mode 100644
index 000000000..5d8dc04cc
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_longstring_hang.js
@@ -0,0 +1,53 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that very long strings do not hang the browser.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-859170-longstring-hang.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ info("wait for the initial long string");
+
+ let results = yield waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "find 'foobar', no 'foobaz', in long string output",
+ text: "foobar",
+ noText: "foobaz",
+ category: CATEGORY_WEBDEV,
+ longString: true,
+ },
+ ],
+ });
+
+ let clickable = results[0].longStrings[0];
+ ok(clickable, "long string ellipsis is shown");
+ clickable.scrollIntoView(false);
+
+ EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow);
+
+ info("wait for long string expansion");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "find 'foobaz' after expand, but no 'boom!' at the end",
+ text: "foobaz",
+ noText: "boom!",
+ category: CATEGORY_WEBDEV,
+ longString: false,
+ },
+ {
+ text: "too long to be displayed",
+ longString: false,
+ },
+ ],
+ });
+});
diff --git a/browser/devtools/webconsole/test/browser_netpanel_longstring_expand.js b/browser/devtools/webconsole/test/browser_netpanel_longstring_expand.js
new file mode 100644
index 000000000..d19c393a7
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_netpanel_longstring_expand.js
@@ -0,0 +1,307 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the network panel works with LongStringActors.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/test/test-image.png";
+
+const TEST_IMG_BASE64 =
+ "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAVRJREFU" +
+ "OI2lk7FLw0AUxr+YpC1CBqcMWfsvCCLdXFzqEJCgDl1EQRGxg9AhSBEJONhFhG52UCuFDjq5dxD8" +
+ "FwoO0qGDOBQkl7vLOeWa2EQDffDBvTu+373Hu1OEEJgntGgxGD6J+7fLXKbt5VNUyhsKAChRBQcP" +
+ "FVFeWskFGH694mZroCQqCLlAwPxcgJBP254CmAD5B7C7dgHLMLF3uzoL4DQEod+Z5sP1FizDxGgy" +
+ "BqfhLID9AahX29J89bwPFgMsSEAQglAf9WobhPpScbPXr4FQHyzIADTsDizDRMPuIOC+zEeTMZo9" +
+ "BwH3EfAMACccbtfGaDKGZZg423yUZrdrg3EqxQlPr0BTdTR7joREN2uqnlBmCwW1hIJagtev4f3z" +
+ "A16/JvfiigMSYyzqJXlw/XKUyOORMUaBor6YavgdjKa8xGOnidadmwtwsnMu18q83/kHSou+bFND" +
+ "Dr4AAAAASUVORK5CYII=";
+
+let testDriver;
+
+function test() {
+ loadTab(TEST_URI).then(() => {
+ openConsole().then(testNetworkPanel);
+ });
+}
+
+function testNetworkPanel() {
+ testDriver = testGen();
+ testDriver.next();
+}
+
+function checkIsVisible(aPanel, aList) {
+ for (let id in aList) {
+ let node = aPanel.document.getElementById(id);
+ let isVisible = aList[id];
+ is(node.style.display, (isVisible ? "block" : "none"), id + " isVisible=" + isVisible);
+ }
+}
+
+function checkNodeContent(aPanel, aId, aContent) {
+ let node = aPanel.document.getElementById(aId);
+ if (node == null) {
+ ok(false, "Tried to access node " + aId + " that doesn't exist!");
+ }
+ else if (node.textContent.indexOf(aContent) != -1) {
+ ok(true, "checking content of " + aId);
+ }
+ else {
+ ok(false, "Got false value for " + aId + ": " + node.textContent + " doesn't have " + aContent);
+ }
+}
+
+function checkNodeKeyValue(aPanel, aId, aKey, aValue) {
+ let node = aPanel.document.getElementById(aId);
+
+ let headers = node.querySelectorAll("th");
+ for (let i = 0; i < headers.length; i++) {
+ if (headers[i].textContent == (aKey + ":")) {
+ is(headers[i].nextElementSibling.textContent, aValue,
+ "checking content of " + aId + " for key " + aKey);
+ return;
+ }
+ }
+
+ ok(false, "content check failed for " + aId + ", key " + aKey);
+}
+
+function testGen() {
+ let hud = HUDService.getHudByWindow(content);
+ let filterBox = hud.ui.filterBox;
+
+ let headerValue = (new Array(456)).join("fooz bar");
+ let headerValueGrip = {
+ type: "longString",
+ initial: headerValue.substr(0, 123),
+ length: headerValue.length,
+ actor: "faktor",
+ _fullString: headerValue,
+ };
+
+ let imageContentGrip = {
+ type: "longString",
+ initial: TEST_IMG_BASE64.substr(0, 143),
+ length: TEST_IMG_BASE64.length,
+ actor: "faktor2",
+ _fullString: TEST_IMG_BASE64,
+ };
+
+ let postDataValue = (new Array(123)).join("post me");
+ let postDataGrip = {
+ type: "longString",
+ initial: postDataValue.substr(0, 172),
+ length: postDataValue.length,
+ actor: "faktor3",
+ _fullString: postDataValue,
+ };
+
+ let httpActivity = {
+ updates: ["responseContent", "eventTimings"],
+ discardRequestBody: false,
+ discardResponseBody: false,
+ startedDateTime: (new Date()).toISOString(),
+ request: {
+ url: TEST_IMG,
+ method: "GET",
+ cookies: [],
+ headers: [
+ { name: "foo", value: "bar" },
+ { name: "loongstring", value: headerValueGrip },
+ ],
+ postData: { text: postDataGrip },
+ },
+ response: {
+ httpVersion: "HTTP/3.14",
+ status: 2012,
+ statusText: "ddahl likes tacos :)",
+ headers: [
+ { name: "Content-Type", value: "image/png" },
+ ],
+ content: { mimeType: "image/png", text: imageContentGrip },
+ cookies: [],
+ },
+ timings: { wait: 15, receive: 23 },
+ };
+
+ let networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+
+ is(filterBox._netPanel, networkPanel,
+ "Network panel stored on the anchor object");
+
+ networkPanel._onUpdate = function() {
+ networkPanel._onUpdate = null;
+ executeSoon(function() {
+ testDriver.next();
+ });
+ };
+
+ yield undefined;
+
+ info("test 1: check if a header value is expandable");
+
+ checkIsVisible(networkPanel, {
+ requestCookie: false,
+ requestFormData: false,
+ requestBody: false,
+ requestBodyFetchLink: true,
+ responseContainer: true,
+ responseBody: false,
+ responseNoBody: false,
+ responseImage: true,
+ responseImageCached: false,
+ responseBodyFetchLink: true,
+ });
+
+ checkNodeKeyValue(networkPanel, "requestHeadersContent", "foo", "bar");
+ checkNodeKeyValue(networkPanel, "requestHeadersContent", "loongstring",
+ headerValueGrip.initial + "[\u2026]");
+
+ let webConsoleClient = networkPanel.webconsole.webConsoleClient;
+ let longStringFn = webConsoleClient.longString;
+
+ let expectedGrip = headerValueGrip;
+
+ function longStringClientProvider(aLongString)
+ {
+ is(aLongString, expectedGrip,
+ "longString grip is correct");
+
+ return {
+ initial: expectedGrip.initial,
+ length: expectedGrip.length,
+ substring: function(aStart, aEnd, aCallback) {
+ is(aStart, expectedGrip.initial.length,
+ "substring start is correct");
+ is(aEnd, expectedGrip.length,
+ "substring end is correct");
+
+ executeSoon(function() {
+ aCallback({
+ substring: expectedGrip._fullString.substring(aStart, aEnd),
+ });
+
+ executeSoon(function() {
+ testDriver.next();
+ });
+ });
+ },
+ };
+ }
+
+ webConsoleClient.longString = longStringClientProvider;
+
+ let clickable = networkPanel.document
+ .querySelector("#requestHeadersContent .longStringEllipsis");
+ ok(clickable, "long string ellipsis is shown");
+
+ EventUtils.sendMouseEvent({ type: "mousedown"}, clickable,
+ networkPanel.document.defaultView);
+
+ yield undefined;
+
+ clickable = networkPanel.document
+ .querySelector("#requestHeadersContent .longStringEllipsis");
+ ok(!clickable, "long string ellipsis is not shown");
+
+ checkNodeKeyValue(networkPanel, "requestHeadersContent", "loongstring",
+ expectedGrip._fullString);
+
+ info("test 2: check that response body image fetching works");
+ expectedGrip = imageContentGrip;
+
+ let imgNode = networkPanel.document.getElementById("responseImageNode");
+ ok(!imgNode.getAttribute("src"), "no image is displayed");
+
+ clickable = networkPanel.document.querySelector("#responseBodyFetchLink");
+ EventUtils.sendMouseEvent({ type: "mousedown"}, clickable,
+ networkPanel.document.defaultView);
+
+ yield undefined;
+
+ imgNode = networkPanel.document.getElementById("responseImageNode");
+ is(imgNode.getAttribute("src"), "data:image/png;base64," + TEST_IMG_BASE64,
+ "displayed image is correct");
+ is(clickable.style.display, "none", "#responseBodyFetchLink is not visible");
+
+ info("test 3: expand the request body");
+
+ expectedGrip = postDataGrip;
+
+ clickable = networkPanel.document.querySelector("#requestBodyFetchLink");
+ EventUtils.sendMouseEvent({ type: "mousedown"}, clickable,
+ networkPanel.document.defaultView);
+ yield undefined;
+
+ is(clickable.style.display, "none", "#requestBodyFetchLink is not visible");
+
+ checkIsVisible(networkPanel, {
+ requestBody: true,
+ requestBodyFetchLink: false,
+ });
+
+ checkNodeContent(networkPanel, "requestBodyContent", expectedGrip._fullString);
+
+ webConsoleClient.longString = longStringFn;
+
+ networkPanel.panel.hidePopup();
+
+ info("test 4: reponse body long text");
+
+ httpActivity.response.content.mimeType = "text/plain";
+ httpActivity.response.headers[0].value = "text/plain";
+
+ expectedGrip = imageContentGrip;
+
+ // Reset response.content.text to avoid caching of the full string.
+ httpActivity.response.content.text = expectedGrip;
+
+ networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+ is(filterBox._netPanel, networkPanel,
+ "Network panel stored on httpActivity object");
+
+ networkPanel._onUpdate = function() {
+ networkPanel._onUpdate = null;
+ executeSoon(function() {
+ testDriver.next();
+ });
+ };
+
+ yield undefined;
+
+ checkIsVisible(networkPanel, {
+ requestCookie: false,
+ requestFormData: false,
+ requestBody: true,
+ requestBodyFetchLink: false,
+ responseContainer: true,
+ responseBody: true,
+ responseNoBody: false,
+ responseImage: false,
+ responseImageCached: false,
+ responseBodyFetchLink: true,
+ });
+
+ checkNodeContent(networkPanel, "responseBodyContent", expectedGrip.initial);
+
+ webConsoleClient.longString = longStringClientProvider;
+
+ clickable = networkPanel.document.querySelector("#responseBodyFetchLink");
+ EventUtils.sendMouseEvent({ type: "mousedown"}, clickable,
+ networkPanel.document.defaultView);
+
+ yield undefined;
+
+ webConsoleClient.longString = longStringFn;
+ is(clickable.style.display, "none", "#responseBodyFetchLink is not visible");
+ checkNodeContent(networkPanel, "responseBodyContent", expectedGrip._fullString);
+
+ networkPanel.panel.hidePopup();
+
+ // All done!
+ testDriver = null;
+ executeSoon(finishTest);
+
+ yield undefined;
+}
diff --git a/browser/devtools/webconsole/test/browser_output_breaks_after_console_dir_uninspectable.js b/browser/devtools/webconsole/test/browser_output_breaks_after_console_dir_uninspectable.js
new file mode 100644
index 000000000..b7e86b94c
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_output_breaks_after_console_dir_uninspectable.js
@@ -0,0 +1,44 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Make sure that the Web Console output does not break after we try to call
+// console.dir() for objects that are not inspectable.
+
+const TEST_URI = "data:text/html;charset=utf8,test for bug 773466";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ hud.jsterm.clearOutput(true);
+
+ hud.jsterm.execute("console.log('fooBug773466a')");
+ hud.jsterm.execute("myObj = Object.create(null)");
+ hud.jsterm.execute("console.dir(myObj)");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "fooBug773466a",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ },
+ {
+ name: "console.dir output",
+ consoleDir: "[object Object]",
+ }],
+ })
+
+ content.console.log("fooBug773466b");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "fooBug773466b",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+});
diff --git a/browser/devtools/webconsole/test/browser_output_longstring_expand.js b/browser/devtools/webconsole/test/browser_output_longstring_expand.js
new file mode 100644
index 000000000..7d5d785c3
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_output_longstring_expand.js
@@ -0,0 +1,83 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that long strings can be expanded in the console output.
+
+const TEST_URI = "data:text/html;charset=utf8,test for bug 787981 - check that long strings can be expanded in the output.";
+
+let test = asyncTest(function* () {
+ let tempScope = {};
+ Cu.import("resource://gre/modules/devtools/dbg-server.jsm", tempScope);
+ let DebuggerServer = tempScope.DebuggerServer;
+
+ let longString = (new Array(DebuggerServer.LONG_STRING_LENGTH + 4)).join("a") +
+ "foobar";
+ let initialString =
+ longString.substring(0, DebuggerServer.LONG_STRING_INITIAL_LENGTH);
+
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ hud.jsterm.clearOutput(true);
+ hud.jsterm.execute("console.log('bazbaz', '" + longString +"', 'boom')");
+
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "console.log output",
+ text: ["bazbaz", "boom", initialString],
+ noText: "foobar",
+ longString: true,
+ }],
+ });
+
+ let clickable = result.longStrings[0];
+ ok(clickable, "long string ellipsis is shown");
+
+ clickable.scrollIntoView(false);
+
+ EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow);
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "full string",
+ text: ["bazbaz", "boom", longString],
+ category: CATEGORY_WEBDEV,
+ longString: false,
+ }],
+ });
+
+ hud.jsterm.clearOutput(true);
+ let msg = yield execute(hud, "'" + longString +"'");
+
+ isnot(msg.textContent.indexOf(initialString), -1,
+ "initial string is shown");
+ is(msg.textContent.indexOf(longString), -1,
+ "full string is not shown");
+
+ clickable = msg.querySelector(".longStringEllipsis");
+ ok(clickable, "long string ellipsis is shown");
+
+ clickable.scrollIntoView(false);
+
+ EventUtils.synthesizeMouse(clickable, 3, 4, {}, hud.iframeWindow);
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "full string",
+ text: longString,
+ category: CATEGORY_OUTPUT,
+ longString: false,
+ }],
+ })
+});
+
+function execute(hud, str) {
+ let deferred = promise.defer();
+ hud.jsterm.execute(str, deferred.resolve);
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_repeated_messages_accuracy.js b/browser/devtools/webconsole/test/browser_repeated_messages_accuracy.js
new file mode 100644
index 000000000..bd092bbc2
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_repeated_messages_accuracy.js
@@ -0,0 +1,125 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that makes sure messages are not considered repeated when coming from
+// different lines of code, or from different severities, etc.
+// See bugs 720180 and 800510.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-repeated-messages.html";
+const PREF = "devtools.webconsole.persistlog";
+
+let test = asyncTest(function* () {
+ Services.prefs.setBoolPref(PREF, true);
+
+ let { browser } = yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ yield consoleOpened(hud);
+
+ let loaded = loadBrowser(browser);
+ BrowserReload();
+ yield loaded;
+
+ yield testCSSRepeats(hud);
+ yield testCSSRepeatsAfterReload(hud);
+ yield testConsoleRepeats(hud);
+
+ Services.prefs.clearUserPref(PREF);
+});
+
+function consoleOpened(hud) {
+ // Check that css warnings are not coalesced if they come from different lines.
+ info("waiting for 2 css warnings");
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "two css warnings",
+ category: CATEGORY_CSS,
+ count: 2,
+ repeats: 1,
+ }],
+ });
+}
+
+function testCSSRepeats(hud) {
+ info("wait for repeats after page reload");
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "two css warnings, repeated twice",
+ category: CATEGORY_CSS,
+ repeats: 2,
+ count: 2,
+ }],
+ });
+}
+
+function testCSSRepeatsAfterReload(hud) {
+ hud.jsterm.clearOutput(true);
+ hud.jsterm.execute("testConsole()");
+
+ info("wait for repeats with the console API");
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "console.log 'foo repeat' repeated twice",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ repeats: 2,
+ },
+ {
+ name: "console.log 'foo repeat' repeated once",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ repeats: 1,
+ },
+ {
+ name: "console.error 'foo repeat' repeated once",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_ERROR,
+ repeats: 1,
+ },
+ ],
+ })
+}
+
+function testConsoleRepeats(hud) {
+ hud.jsterm.clearOutput(true);
+ hud.jsterm.execute("undefined");
+
+ content.console.log("undefined");
+
+ info("make sure console API messages are not coalesced with jsterm output");
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "'undefined' jsterm input message",
+ text: "undefined",
+ category: CATEGORY_INPUT,
+ },
+ {
+ name: "'undefined' jsterm output message",
+ text: "undefined",
+ category: CATEGORY_OUTPUT,
+ },
+ {
+ name: "'undefined' console.log message",
+ text: "undefined",
+ category: CATEGORY_WEBDEV,
+ repeats: 1,
+ },
+ ],
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_result_format_as_string.js b/browser/devtools/webconsole/test/browser_result_format_as_string.js
new file mode 100644
index 000000000..70c3cc61a
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_result_format_as_string.js
@@ -0,0 +1,43 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+///////////////////
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Connection closed");
+
+// Make sure that JS eval result are properly formatted as strings.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-result-format-as-string.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ hud.jsterm.clearOutput(true);
+
+ let msg = yield execute(hud, "document.querySelector('p')");
+
+ is(hud.outputNode.textContent.indexOf("bug772506_content"), -1,
+ "no content element found");
+ ok(!hud.outputNode.querySelector("#foobar"), "no #foobar element found");
+
+ ok(msg, "eval output node found");
+ is(msg.textContent.indexOf("<div>"), -1,
+ "<div> string is not displayed");
+ isnot(msg.textContent.indexOf("<p>"), -1,
+ "<p> string is displayed");
+
+ EventUtils.synthesizeMouseAtCenter(msg, {type: "mousemove"});
+ ok(!gBrowser._bug772506, "no content variable");
+});
+
+function execute(hud, str) {
+ let deferred = promise.defer();
+ hud.jsterm.execute(str, deferred.resolve);
+ return deferred.promise;
+} \ No newline at end of file
diff --git a/browser/devtools/webconsole/test/browser_warn_user_about_replaced_api.js b/browser/devtools/webconsole/test/browser_warn_user_about_replaced_api.js
new file mode 100644
index 000000000..adef430ad
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_warn_user_about_replaced_api.js
@@ -0,0 +1,81 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const TEST_REPLACED_API_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-replaced-api.html";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/testscript.js";
+const PREF = "devtools.webconsole.persistlog";
+
+let test = asyncTest(function* () {
+ Services.prefs.setBoolPref(PREF, true);
+
+ let { browser } = yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+
+ yield testWarningNotPresent(hud);
+
+ let loaded = loadBrowser(browser);
+ content.location = TEST_REPLACED_API_URI;
+ yield loaded;
+
+ let hud2 = yield openConsole();
+
+ yield testWarningPresent(hud2);
+
+ Services.prefs.clearUserPref(PREF);
+});
+
+function testWarningNotPresent(hud)
+{
+ let deferred = promise.defer();
+
+ is(hud.outputNode.textContent.indexOf("logging API"), -1,
+ "no warning displayed");
+
+ // Bug 862024: make sure the warning doesn't show after page reload.
+ info("reload " + TEST_URI);
+ executeSoon(() => content.location.reload());
+
+ waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "testscript.js",
+ category: CATEGORY_NETWORK,
+ }],
+ }).then(() => executeSoon(() => {
+ is(hud.outputNode.textContent.indexOf("logging API"), -1,
+ "no warning displayed");
+ closeConsole().then(deferred.resolve);
+ }));
+
+ return deferred.promise;
+}
+
+function testWarningPresent(hud)
+{
+ info("wait for the warning to show");
+ let deferred = promise.defer();
+
+ let warning = {
+ webconsole: hud,
+ messages: [{
+ text: /logging API .+ disabled by a script/,
+ category: CATEGORY_JS,
+ severity: SEVERITY_WARNING,
+ }],
+ };
+
+ waitForMessages(warning).then(() => {
+ hud.jsterm.clearOutput();
+
+ executeSoon(() => {
+ info("reload the test page and wait for the warning to show");
+ waitForMessages(warning).then(deferred.resolve);
+ content.location.reload();
+ });
+ });
+
+ return deferred.promise;
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_abbreviate_source_url.js b/browser/devtools/webconsole/test/browser_webconsole_abbreviate_source_url.js
new file mode 100644
index 000000000..1bc94b5d3
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_abbreviate_source_url.js
@@ -0,0 +1,21 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that source URLs are abbreviated properly for display on the right-
+// hand side of the Web Console.
+
+function test() {
+ testAbbreviation("http://example.com/x.js", "x.js");
+ testAbbreviation("http://example.com/foo/bar/baz/boo.js", "boo.js");
+ testAbbreviation("http://example.com/foo/bar/", "bar");
+ testAbbreviation("http://example.com/foo.js?bar=1&baz=2", "foo.js");
+ testAbbreviation("http://example.com/foo/?bar=1&baz=2", "foo");
+
+ finishTest();
+}
+
+function testAbbreviation(aFullURL, aAbbreviatedURL) {
+ is(WebConsoleUtils.abbreviateSourceURL(aFullURL), aAbbreviatedURL, aFullURL +
+ " is abbreviated to " + aAbbreviatedURL);
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_allow_mixedcontent_securityerrors.js b/browser/devtools/webconsole/test/browser_webconsole_allow_mixedcontent_securityerrors.js
new file mode 100644
index 000000000..4913f5ccf
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_allow_mixedcontent_securityerrors.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// The test loads a web page with mixed active and display content
+// on it while the "block mixed content" settings are _off_.
+// It then checks that the loading mixed content warning messages
+// are logged to the console and have the correct "Learn More"
+// url appended to them.
+// Bug 875456 - Log mixed content messages from the Mixed Content
+// Blocker to the Security Pane in the Web Console
+
+const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-mixedcontent-securityerrors.html";
+const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Security/MixedContent";
+
+let test = asyncTest(function* () {
+ yield pushPrefEnv();
+
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ let results = yield waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "Logged mixed active content",
+ text: "Loading mixed (insecure) active content \"http://example.com/\" on a secure page",
+ category: CATEGORY_SECURITY,
+ severity: SEVERITY_WARNING,
+ objects: true,
+ },
+ {
+ name: "Logged mixed passive content - image",
+ text: "Loading mixed (insecure) display content \"http://example.com/tests/image/test/mochitest/blue.png\" on a secure page",
+ category: CATEGORY_SECURITY,
+ severity: SEVERITY_WARNING,
+ objects: true,
+ },
+ ],
+ });
+
+ yield testClickOpenNewTab(hud, results);
+});
+
+function pushPrefEnv()
+{
+ let deferred = promise.defer();
+ let options = {"set":
+ [["security.mixed_content.block_active_content", false],
+ ["security.mixed_content.block_display_content", false]
+ ]};
+ SpecialPowers.pushPrefEnv(options, deferred.resolve);
+ return deferred.promise;
+}
+
+function testClickOpenNewTab(hud, results) {
+ let warningNode = results[0].clickableElements[0];
+ ok(warningNode, "link element");
+ ok(warningNode.classList.contains("learn-more-link"), "link class name");
+ return simulateMessageLinkClick(warningNode, LEARN_MORE_URI);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_assert.js b/browser/devtools/webconsole/test/browser_webconsole_assert.js
new file mode 100644
index 000000000..10500a7a8
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_assert.js
@@ -0,0 +1,51 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that console.assert() works as expected (i.e. outputs only on falsy
+// asserts). See bug 760193.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-assert.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+ yield consoleOpened(hud);
+});
+
+function consoleOpened(hud) {
+ hud.jsterm.execute("test()");
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "undefined",
+ category: CATEGORY_OUTPUT,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "start",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "false assert",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_ERROR,
+ },
+ {
+ text: "falsy assert",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_ERROR,
+ },
+ {
+ text: "end",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ }).then(() => {
+ let nodes = hud.outputNode.querySelectorAll(".message");
+ is(nodes.length, 6, "only six messages are displayed, no output from the true assert");
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js b/browser/devtools/webconsole/test/browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js
new file mode 100644
index 000000000..0577b8cc2
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js
@@ -0,0 +1,40 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+// Test that properties starting with underscores or dollars can be
+// autocompleted (bug 967468).
+
+
+let test = asyncTest(function*() {
+ const TEST_URI = "data:text/html;charset=utf8,test autocompletion with $ or _";
+ yield loadTab(TEST_URI);
+
+ function autocomplete(term) {
+ let deferred = promise.defer();
+
+ jsterm.setInputValue(term);
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY, deferred.resolve);
+
+ yield deferred.promise;
+
+ ok(popup.itemCount > 0, "There's suggestions for '" + term + "'");
+ }
+
+ let { jsterm } = yield openConsole();
+ let popup = jsterm.autocompletePopup;
+
+ yield jsterm.execute("let testObject = {$$aaab: '', $$aaac: ''}");
+
+ // Should work with bug 967468.
+ yield autocomplete("Object.__d");
+ yield autocomplete("testObject.$$a");
+
+ // Here's when things go wrong in bug 967468.
+ yield autocomplete("Object.__de");
+ yield autocomplete("testObject.$$aa");
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_autocomplete_and_selfxss.js b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_and_selfxss.js
new file mode 100644
index 000000000..69ccb443e
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_and_selfxss.js
@@ -0,0 +1,127 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_URI = "data:text/html;charset=utf-8,<p>test for bug 642615";
+
+XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
+ "@mozilla.org/widget/clipboardhelper;1",
+ "nsIClipboardHelper");
+let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ yield consoleOpened(hud);
+});
+
+function consoleOpened(HUD) {
+ let deferred = promise.defer();
+
+ let jsterm = HUD.jsterm;
+ let stringToCopy = "foobazbarBug642615";
+
+ jsterm.clearOutput();
+
+ ok(!jsterm.completeNode.value, "no completeNode.value");
+
+ jsterm.setInputValue("doc");
+
+ let completionValue;
+
+ // wait for key "u"
+ function onCompletionValue() {
+ completionValue = jsterm.completeNode.value;
+
+ // Arguments: expected, setup, success, failure.
+ waitForClipboard(
+ stringToCopy,
+ function() {
+ clipboardHelper.copyString(stringToCopy, document);
+ },
+ onClipboardCopy,
+ finishTest);
+ }
+
+ function onClipboardCopy() {
+ testSelfXss();
+
+ jsterm.setInputValue("docu");
+ info("wait for completion update after clipboard paste");
+ updateEditUIVisibility();
+ jsterm.once("autocomplete-updated", onClipboardPaste);
+ goDoCommand("cmd_paste");
+ }
+
+
+ // Self xss prevention tests (bug 994134)
+ function testSelfXss(){
+ info("Self-xss paste tests")
+ WebConsoleUtils.usageCount = 0;
+ is(WebConsoleUtils.usageCount, 0, "Test for usage count getter")
+ // Input some commands to check if usage counting is working
+ for(let i = 0; i <= 3; i++){
+ jsterm.setInputValue(i);
+ jsterm.execute();
+ }
+ is(WebConsoleUtils.usageCount, 4, "Usage count incremented")
+ WebConsoleUtils.usageCount = 0;
+ updateEditUIVisibility();
+
+ let oldVal = jsterm.inputNode.value;
+ goDoCommand("cmd_paste");
+ let notificationbox = jsterm.hud.document.getElementById("webconsole-notificationbox");
+ let notification = notificationbox.getNotificationWithValue('selfxss-notification');
+ ok(notification, "Self-xss notification shown");
+ is(oldVal, jsterm.inputNode.value, "Paste blocked by self-xss prevention");
+
+ // Allow pasting
+ jsterm.inputNode.value = "allow pasting";
+ var evt = document.createEvent("KeyboardEvent");
+ evt.initKeyEvent ("keyup", true, true, window,
+ 0, 0, 0, 0,
+ 0, " ".charCodeAt(0));
+ jsterm.inputNode.dispatchEvent(evt);
+ jsterm.inputNode.value = "";
+ goDoCommand("cmd_paste");
+ isnot("", jsterm.inputNode.value, "Paste works");
+ }
+ function onClipboardPaste() {
+ ok(!jsterm.completeNode.value, "no completion value after paste");
+
+ info("wait for completion update after undo");
+ jsterm.once("autocomplete-updated", onCompletionValueAfterUndo);
+
+ // Get out of the webconsole event loop.
+ executeSoon(() => {
+ goDoCommand("cmd_undo");
+ });
+ }
+
+ function onCompletionValueAfterUndo() {
+ is(jsterm.completeNode.value, completionValue,
+ "same completeNode.value after undo");
+
+ info("wait for completion update after clipboard paste (ctrl-v)");
+ jsterm.once("autocomplete-updated", () => {
+ ok(!jsterm.completeNode.value, "no completion value after paste (ctrl-v)");
+
+ // using executeSoon() to get out of the webconsole event loop.
+ executeSoon(deferred.resolve);
+ });
+
+ // Get out of the webconsole event loop.
+ executeSoon(() => {
+ EventUtils.synthesizeKey("v", {accelKey: true});
+ });
+ }
+
+ info("wait for completion value after typing 'docu'");
+ jsterm.once("autocomplete-updated", onCompletionValue);
+
+ EventUtils.synthesizeKey("u", {});
+
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_autocomplete_crossdomain_iframe.js b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_crossdomain_iframe.js
new file mode 100644
index 000000000..b5e603164
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_crossdomain_iframe.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that autocomplete doesn't break when trying to reach into objects from
+// a different domain, bug 989025.
+
+function test() {
+ let hud;
+
+ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-989025-iframe-parent.html";
+
+ Task.spawn(function*() {
+ const {tab} = yield loadTab(TEST_URI);
+ hud = yield openConsole(tab);
+
+ hud.jsterm.execute('document.title');
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "989025 - iframe parent",
+ category: CATEGORY_OUTPUT,
+ }],
+ });
+
+ let autocompleteUpdated = hud.jsterm.once("autocomplete-updated");
+
+ hud.jsterm.setInputValue("window[0].document");
+ executeSoon(() => {
+ EventUtils.synthesizeKey(".", {});
+ });
+
+ yield autocompleteUpdated;
+
+ hud.jsterm.setInputValue("window[0].document.title");
+ EventUtils.synthesizeKey("VK_RETURN", {});
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "Permission denied",
+ category: CATEGORY_OUTPUT,
+ severity: SEVERITY_ERROR,
+ }],
+ });
+
+ hud.jsterm.execute("window.location");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "test-bug-989025-iframe-parent.html",
+ category: CATEGORY_OUTPUT,
+ }],
+ });
+
+ yield closeConsole(tab);
+ }).then(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_autocomplete_in_debugger_stackframe.js b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_in_debugger_stackframe.js
new file mode 100644
index 000000000..c3c838cb1
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_in_debugger_stackframe.js
@@ -0,0 +1,242 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that makes sure web console autocomplete happens in the user-selected stackframe
+// from the js debugger.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-autocomplete-in-stackframe.html";
+
+let testDriver, gStackframes;
+
+function test()
+{
+ requestLongerTimeout(2);
+ loadTab(TEST_URI).then(() => {
+ openConsole().then((hud) => {
+ testDriver = testCompletion(hud);
+ testDriver.next();
+ });
+ });
+}
+
+function testNext() {
+ executeSoon(function() {
+ testDriver.next();
+ });
+}
+
+function testCompletion(hud) {
+ let jsterm = hud.jsterm;
+ let input = jsterm.inputNode;
+ let popup = jsterm.autocompletePopup;
+
+ // Test that document.title gives string methods. Native getters must execute.
+ input.value = "document.title.";
+ input.setSelectionRange(input.value.length, input.value.length);
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+ yield undefined;
+
+ let newItems = popup.getItems();
+ ok(newItems.length > 0, "'document.title.' gave a list of suggestions");
+ ok(newItems.some(function(item) {
+ return item.label == "substr";
+ }), "autocomplete results do contain substr");
+ ok(newItems.some(function(item) {
+ return item.label == "toLowerCase";
+ }), "autocomplete results do contain toLowerCase");
+ ok(newItems.some(function(item) {
+ return item.label == "strike";
+ }), "autocomplete results do contain strike");
+
+ // Test if 'f' gives 'foo1' but not 'foo2' or 'foo3'
+ input.value = "f";
+ input.setSelectionRange(1, 1);
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+ yield undefined;
+
+ newItems = popup.getItems();
+ ok(newItems.length > 0, "'f' gave a list of suggestions");
+ ok(!newItems.every(function(item) {
+ return item.label != "foo1";
+ }), "autocomplete results do contain foo1");
+ ok(!newItems.every(function(item) {
+ return item.label != "foo1Obj";
+ }), "autocomplete results do contain foo1Obj");
+ ok(newItems.every(function(item) {
+ return item.label != "foo2";
+ }), "autocomplete results do not contain foo2");
+ ok(newItems.every(function(item) {
+ return item.label != "foo2Obj";
+ }), "autocomplete results do not contain foo2Obj");
+ ok(newItems.every(function(item) {
+ return item.label != "foo3";
+ }), "autocomplete results do not contain foo3");
+ ok(newItems.every(function(item) {
+ return item.label != "foo3Obj";
+ }), "autocomplete results do not contain foo3Obj");
+
+ // Test if 'foo1Obj.' gives 'prop1' and 'prop2'
+ input.value = "foo1Obj.";
+ input.setSelectionRange(8, 8);
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+ yield undefined;
+
+ newItems = popup.getItems();
+ ok(!newItems.every(function(item) {
+ return item.label != "prop1";
+ }), "autocomplete results do contain prop1");
+ ok(!newItems.every(function(item) {
+ return item.label != "prop2";
+ }), "autocomplete results do contain prop2");
+
+ // Test if 'foo1Obj.prop2.' gives 'prop21'
+ input.value = "foo1Obj.prop2.";
+ input.setSelectionRange(14, 14);
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+ yield undefined;
+
+ newItems = popup.getItems();
+ ok(!newItems.every(function(item) {
+ return item.label != "prop21";
+ }), "autocomplete results do contain prop21");
+
+ info("openDebugger");
+ executeSoon(() => openDebugger().then(debuggerOpened));
+ yield undefined;
+
+ // From this point on the
+ // Test if 'f' gives 'foo3' and 'foo1' but not 'foo2'
+ input.value = "f";
+ input.setSelectionRange(1, 1);
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+ yield undefined;
+
+ newItems = popup.getItems();
+ ok(newItems.length > 0, "'f' gave a list of suggestions");
+ ok(!newItems.every(function(item) {
+ return item.label != "foo3";
+ }), "autocomplete results do contain foo3");
+ ok(!newItems.every(function(item) {
+ return item.label != "foo3Obj";
+ }), "autocomplete results do contain foo3Obj");
+ ok(!newItems.every(function(item) {
+ return item.label != "foo1";
+ }), "autocomplete results do contain foo1");
+ ok(!newItems.every(function(item) {
+ return item.label != "foo1Obj";
+ }), "autocomplete results do contain foo1Obj");
+ ok(newItems.every(function(item) {
+ return item.label != "foo2";
+ }), "autocomplete results do not contain foo2");
+ ok(newItems.every(function(item) {
+ return item.label != "foo2Obj";
+ }), "autocomplete results do not contain foo2Obj");
+
+ openDebugger().then(() => {
+ gStackframes.selectFrame(1);
+
+ info("openConsole");
+ executeSoon(() => openConsole().then(() => testDriver.next()));
+ });
+ yield undefined;
+
+ // Test if 'f' gives 'foo2' and 'foo1' but not 'foo3'
+ input.value = "f";
+ input.setSelectionRange(1, 1);
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+ yield undefined;
+
+ newItems = popup.getItems();
+ ok(newItems.length > 0, "'f' gave a list of suggestions");
+ ok(!newItems.every(function(item) {
+ return item.label != "foo2";
+ }), "autocomplete results do contain foo2");
+ ok(!newItems.every(function(item) {
+ return item.label != "foo2Obj";
+ }), "autocomplete results do contain foo2Obj");
+ ok(!newItems.every(function(item) {
+ return item.label != "foo1";
+ }), "autocomplete results do contain foo1");
+ ok(!newItems.every(function(item) {
+ return item.label != "foo1Obj";
+ }), "autocomplete results do contain foo1Obj");
+ ok(newItems.every(function(item) {
+ return item.label != "foo3";
+ }), "autocomplete results do not contain foo3");
+ ok(newItems.every(function(item) {
+ return item.label != "foo3Obj";
+ }), "autocomplete results do not contain foo3Obj");
+
+ // Test if 'foo2Obj.' gives 'prop1'
+ input.value = "foo2Obj.";
+ input.setSelectionRange(8, 8);
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+ yield undefined;
+
+ newItems = popup.getItems();
+ ok(!newItems.every(function(item) {
+ return item.label != "prop1";
+ }), "autocomplete results do contain prop1");
+
+ // Test if 'foo2Obj.prop1.' gives 'prop11'
+ input.value = "foo2Obj.prop1.";
+ input.setSelectionRange(14, 14);
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+ yield undefined;
+
+ newItems = popup.getItems();
+ ok(!newItems.every(function(item) {
+ return item.label != "prop11";
+ }), "autocomplete results do contain prop11");
+
+ // Test if 'foo2Obj.prop1.prop11.' gives suggestions for a string i.e. 'length'
+ input.value = "foo2Obj.prop1.prop11.";
+ input.setSelectionRange(21, 21);
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+ yield undefined;
+
+ newItems = popup.getItems();
+ ok(!newItems.every(function(item) {
+ return item.label != "length";
+ }), "autocomplete results do contain length");
+
+ // Test if 'foo1Obj[0].' throws no errors.
+ input.value = "foo2Obj[0].";
+ input.setSelectionRange(11, 11);
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+ yield undefined;
+
+ newItems = popup.getItems();
+ is(newItems.length, 0, "no items for foo2Obj[0]");
+
+ testDriver = null;
+ executeSoon(finishUp);
+ yield undefined;
+}
+
+function debuggerOpened(aResult)
+{
+ let debuggerWin = aResult.panelWin;
+ let debuggerController = debuggerWin.DebuggerController;
+ let thread = debuggerController.activeThread;
+ gStackframes = debuggerController.StackFrames;
+
+ executeSoon(() => {
+ thread.addOneTimeListener("framesadded", onFramesAdded);
+ info("firstCall()");
+ content.wrappedJSObject.firstCall();
+ });
+}
+
+function onFramesAdded()
+{
+ info("onFramesAdded, openConsole() now");
+ executeSoon(() => openConsole().then(testNext));
+}
+
+function finishUp() {
+ testDriver = gStackframes = null;
+ finishTest();
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_autocomplete_popup_close_on_tab_switch.js b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_popup_close_on_tab_switch.js
new file mode 100644
index 000000000..19c3ceb49
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_popup_close_on_tab_switch.js
@@ -0,0 +1,33 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Test that the autocomplete popup closes on switching tabs. See bug 900448.
+
+const TEST_URI = "data:text/html;charset=utf-8,<p>bug 900448 - autocomplete popup closes on tab switch";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ let popup = hud.jsterm.autocompletePopup;
+ let popupShown = onPopupShown(popup._panel);
+
+ hud.jsterm.setInputValue("sc");
+ EventUtils.synthesizeKey("r", {});
+
+ yield popupShown;
+
+ ok(!popup.isOpen, "Popup closes on tab switch");
+});
+
+function onPopupShown(panel) {
+ let finished = promise.defer();
+
+ panel.addEventListener("popupshown", function popupOpened() {
+ panel.removeEventListener("popupshown", popupOpened, false);
+ loadTab("data:text/html;charset=utf-8,<p>testing autocomplete closes").then(finished.resolve);
+ }, false);
+
+ return finished.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_basic_net_logging.js b/browser/devtools/webconsole/test/browser_webconsole_basic_net_logging.js
new file mode 100644
index 000000000..c3c8005d4
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_basic_net_logging.js
@@ -0,0 +1,42 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the page's resources are displayed in the console as they're
+// loaded
+
+"use strict";
+
+const TEST_NETWORK_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-network.html" + "?_date=" + Date.now();
+
+let test = asyncTest(function* () {
+ yield loadTab("data:text/html;charset=utf-8,Web Console basic network logging test");
+ let hud = yield openConsole();
+
+ content.location = TEST_NETWORK_URI;
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "running network console",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "test-network.html",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "testscript.js",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "test-image.png",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ }],
+ });
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_block_mixedcontent_securityerrors.js b/browser/devtools/webconsole/test/browser_webconsole_block_mixedcontent_securityerrors.js
new file mode 100644
index 000000000..47e5cc549
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_block_mixedcontent_securityerrors.js
@@ -0,0 +1,122 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// The test loads a web page with mixed active and display content
+// on it while the "block mixed content" settings are _on_.
+// It then checks that the blocked mixed content warning messages
+// are logged to the console and have the correct "Learn More"
+// url appended to them. After the first test finishes, it invokes
+// a second test that overrides the mixed content blocker settings
+// by clicking on the doorhanger shield and validates that the
+// appropriate messages are logged to console.
+// Bug 875456 - Log mixed content messages from the Mixed Content
+// Blocker to the Security Pane in the Web Console
+
+const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-mixedcontent-securityerrors.html";
+const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Security/MixedContent";
+
+
+let test = asyncTest(function* () {
+ yield pushPrefEnv();
+
+ let { browser } = yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ let results = yield waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "Logged blocking mixed active content",
+ text: "Blocked loading mixed active content \"http://example.com/\"",
+ category: CATEGORY_SECURITY,
+ severity: SEVERITY_ERROR,
+ objects: true,
+ },
+ {
+ name: "Logged blocking mixed passive content - image",
+ text: "Blocked loading mixed active content \"http://example.com/\"",
+ category: CATEGORY_SECURITY,
+ severity: SEVERITY_ERROR,
+ objects: true,
+ },
+ ],
+ });
+
+ yield testClickOpenNewTab(hud, results[0]);
+
+ let results2 = yield mixedContentOverrideTest2(hud, browser);
+
+ yield testClickOpenNewTab(hud, results2[0]);
+});
+
+function pushPrefEnv()
+{
+ let deferred = promise.defer();
+ let options = {"set": [["security.mixed_content.block_active_content", true],
+ ["security.mixed_content.block_display_content", true]]};
+ SpecialPowers.pushPrefEnv(options, deferred.resolve);
+ return deferred.promise;
+}
+
+function waitForNotificationShown(notification, callback)
+{
+ if (PopupNotifications.panel.state == "open") {
+ executeSoon(callback);
+ return;
+ }
+ PopupNotifications.panel.addEventListener("popupshown", function onShown(e) {
+ PopupNotifications.panel.removeEventListener("popupshown", onShown);
+ callback();
+ }, false);
+ notification.reshow();
+}
+
+function mixedContentOverrideTest2(hud, browser)
+{
+ var notification = PopupNotifications.getNotification("bad-content", browser);
+ ok(notification, "Mixed Content Doorhanger did appear");
+ let deferred = promise.defer();
+ waitForNotificationShown(notification, () => {
+ afterNotificationShown(hud, notification, deferred);
+ });
+ return deferred.promise;
+}
+
+function afterNotificationShown(hud, notification, deferred)
+{
+ ok(PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked");
+ // Click on the doorhanger.
+ PopupNotifications.panel.firstChild.disableMixedContentProtection();
+ notification.remove();
+
+ waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "Logged blocking mixed active content",
+ text: "Loading mixed (insecure) active content \"http://example.com/\"" +
+ " on a secure page",
+ category: CATEGORY_SECURITY,
+ severity: SEVERITY_WARNING,
+ objects: true,
+ },
+ {
+ name: "Logged blocking mixed passive content - image",
+ text: "Loading mixed (insecure) display content" +
+ " \"http://example.com/tests/image/test/mochitest/blue.png\"" +
+ " on a secure page",
+ category: CATEGORY_SECURITY,
+ severity: SEVERITY_WARNING,
+ objects: true,
+ },
+ ],
+ }).then(msgs => deferred.resolve(msgs), Cu.reportError);
+}
+
+function testClickOpenNewTab(hud, match) {
+ let warningNode = match.clickableElements[0];
+ ok(warningNode, "link element");
+ ok(warningNode.classList.contains("learn-more-link"), "link class name");
+ return simulateMessageLinkClick(warningNode, LEARN_MORE_URI);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_1006027_message_timestamps_incorrect.js b/browser/devtools/webconsole/test/browser_webconsole_bug_1006027_message_timestamps_incorrect.js
new file mode 100644
index 000000000..6dd85e939
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_1006027_message_timestamps_incorrect.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";
+
+function test() {
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ const {tab} = yield loadTab("data:text/html;charset=utf8,<title>Test for Bug 1006027");
+
+ const target = TargetFactory.forTab(tab);
+ const hud = yield openConsole(tab);
+
+ hud.jsterm.execute("console.log('bug1006027')");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "console.log",
+ text: "bug1006027",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ info('hud.outputNode.textContent:\n'+hud.outputNode.textContent);
+ let timestampNodes = hud.outputNode.querySelectorAll('span.timestamp');
+ let aTimestampMilliseconds = Array.prototype.map.call(timestampNodes,
+ function (value) {
+ // We are parsing timestamps as local time, relative to the begin of the epoch.
+ // This is not the correct value of the timestamp, but good enough for comparison.
+ return Date.parse('T'+String.trim(value.textContent));
+ });
+
+ let minTimestamp = Math.min.apply(null, aTimestampMilliseconds);
+ let maxTimestamp = Math.max.apply(null, aTimestampMilliseconds);
+ ok(Math.abs(maxTimestamp - minTimestamp) < 1000, "console.log message timestamp spread < 1000ms confirmed");
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_1010953_cspro.js b/browser/devtools/webconsole/test/browser_webconsole_bug_1010953_cspro.js
new file mode 100644
index 000000000..078f44b74
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_1010953_cspro.js
@@ -0,0 +1,47 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* We are loading:
+a script that is allowed by the CSP header but not by the CSPRO header
+an image which is allowed by the CSPRO header but not by the CSP header.
+
+So we expect a warning (image has been blocked) and a report
+ (script should not load and was reported)
+
+The expected console messages in the constants CSP_VIOLATION_MSG and CSP_REPORT_MSG are confirmed to be found in the console messages.
+*/
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf8,Web Console CSP report only test (bug 1010953)";
+const TEST_VIOLATION = "http://example.com/browser/browser/devtools/webconsole/test/test_bug_1010953_cspro.html";
+const CSP_VIOLATION_MSG = 'Content Security Policy: The page\'s settings blocked the loading of a resource at http://some.example.com/test.png ("img-src http://example.com").';
+const CSP_REPORT_MSG = 'Content Security Policy: The page\'s settings observed the loading of a resource at http://some.example.com/test_bug_1010953_cspro.js ("script-src http://example.com"). A CSP report is being sent.';
+
+let test = asyncTest(function* () {
+ let { browser } = yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ hud.jsterm.clearOutput();
+
+ let loaded = loadBrowser(browser);
+ content.location = TEST_VIOLATION;
+ yield loaded;
+
+ let aOutputNode = hud.outputNode;
+
+ yield waitForSuccess({
+ name: "Confirmed that CSP and CSP-Report-Only log different messages to the console.",
+ validator: function() {
+ console.log(hud.outputNode.textContent);
+ let success = false;
+ success = hud.outputNode.textContent.indexOf(CSP_VIOLATION_MSG) > -1 &&
+ hud.outputNode.textContent.indexOf(CSP_REPORT_MSG) > -1;
+ return success;
+ }
+ });
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_578437_page_reload.js b/browser/devtools/webconsole/test/browser_webconsole_bug_578437_page_reload.js
new file mode 100644
index 000000000..f396259a5
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_578437_page_reload.js
@@ -0,0 +1,39 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the console object still exists after a page reload.
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let browser;
+
+function test() {
+ loadTab(TEST_URI).then({
+ openConsole().then((tab) => {
+ browser = tab.browser;
+
+ browser.addEventListener("DOMContentLoaded", testPageReload, false);
+ content.location.reload();
+ });
+ });
+ browser.addEventListener("DOMContentLoaded", onLoad, false);
+}
+
+function testPageReload() {
+
+ browser.removeEventListener("DOMContentLoaded", testPageReload, false);
+
+ let console = browser.contentWindow.wrappedJSObject.console;
+
+ is(typeof console, "object", "window.console is an object, after page reload");
+ is(typeof console.log, "function", "console.log is a function");
+ is(typeof console.info, "function", "console.info is a function");
+ is(typeof console.warn, "function", "console.warn is a function");
+ is(typeof console.error, "function", "console.error is a function");
+ is(typeof console.exception, "function", "console.exception is a function");
+
+ browser = null;
+ finishTest();
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_579412_input_focus.js b/browser/devtools/webconsole/test/browser_webconsole_bug_579412_input_focus.js
new file mode 100644
index 000000000..e726a0595
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_579412_input_focus.js
@@ -0,0 +1,19 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the input field is focused when the console is opened.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ hud.jsterm.clearOutput();
+
+ let inputNode = hud.jsterm.inputNode;
+ ok(inputNode.getAttribute("focused"), "input node is focused");
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_580001_closing_after_completion.js b/browser/devtools/webconsole/test/browser_webconsole_bug_580001_closing_after_completion.js
new file mode 100644
index 000000000..b71d83bd4
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_580001_closing_after_completion.js
@@ -0,0 +1,48 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests to ensure that errors don't appear when the console is closed while a
+// completion is being performed.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+
+let test = asyncTest(function* () {
+ let { browser } = yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+ yield testClosingAfterCompletion(hud, browser);
+});
+
+function testClosingAfterCompletion(hud, browser) {
+ let deferred = promise.defer();
+
+ let inputNode = hud.jsterm.inputNode;
+
+ let errorWhileClosing = false;
+ function errorListener(evt) {
+ errorWhileClosing = true;
+ }
+
+ browser.addEventListener("error", errorListener, false);
+
+ // Focus the inputNode and perform the keycombo to close the WebConsole.
+ inputNode.focus();
+
+ gDevTools.once("toolbox-destroyed", function() {
+ browser.removeEventListener("error", errorListener, false);
+ is(errorWhileClosing, false, "no error while closing the WebConsole");
+ deferred.resolve();
+ });
+
+ if (Services.appinfo.OS == "Darwin") {
+ EventUtils.synthesizeKey("i", { accelKey: true, altKey: true });
+ } else {
+ EventUtils.synthesizeKey("i", { accelKey: true, shiftKey: true });
+ }
+
+ return deferred.promise;
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_580030_errors_after_page_reload.js b/browser/devtools/webconsole/test/browser_webconsole_bug_580030_errors_after_page_reload.js
new file mode 100644
index 000000000..de208ee06
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_580030_errors_after_page_reload.js
@@ -0,0 +1,42 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that errors still show up in the Web Console after a page reload.
+// See bug 580030: the error handler fails silently after page reload.
+// https://bugzilla.mozilla.org/show_bug.cgi?id=580030
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-error.html";
+
+function test() {
+ Task.spawn(function*() {
+ const {tab} = yield loadTab(TEST_URI);
+ const hud = yield openConsole(tab);
+ info("console opened");
+
+ executeSoon(() => {
+ hud.jsterm.clearOutput();
+ info("wait for reload");
+ content.location.reload();
+ });
+
+ yield hud.target.once("navigate");
+ info("target navigated");
+
+ let button = content.document.querySelector("button");
+ ok(button, "button found");
+
+ expectUncaughtException();
+ EventUtils.sendMouseEvent({type: "click"}, button, content);
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "fooBazBaz is not defined",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ }],
+ });
+ }).then(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_580454_timestamp_l10n.js b/browser/devtools/webconsole/test/browser_webconsole_bug_580454_timestamp_l10n.js
new file mode 100644
index 000000000..b2887ddae
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_580454_timestamp_l10n.js
@@ -0,0 +1,30 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Patrick Walton <pcwalton@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Tests that appropriately-localized timestamps are printed.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ const TEST_TIMESTAMP = 12345678;
+ let date = new Date(TEST_TIMESTAMP);
+ let localizedString = WCU_l10n.timestampString(TEST_TIMESTAMP);
+ isnot(localizedString.indexOf(date.getHours()), -1, "the localized " +
+ "timestamp contains the hours");
+ isnot(localizedString.indexOf(date.getMinutes()), -1, "the localized " +
+ "timestamp contains the minutes");
+ isnot(localizedString.indexOf(date.getSeconds()), -1, "the localized " +
+ "timestamp contains the seconds");
+ isnot(localizedString.indexOf(date.getMilliseconds()), -1, "the localized " +
+ "timestamp contains the milliseconds");
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_582201_duplicate_errors.js b/browser/devtools/webconsole/test/browser_webconsole_bug_582201_duplicate_errors.js
new file mode 100644
index 000000000..6032cb761
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_582201_duplicate_errors.js
@@ -0,0 +1,44 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that exceptions thrown by content don't show up twice in the Web
+// Console.
+
+"use strict";
+
+const INIT_URI = "data:text/html;charset=utf8,hello world";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-duplicate-error.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(INIT_URI);
+
+ let hud = yield openConsole();
+
+ expectUncaughtException();
+
+ content.location = TEST_URI;
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "fooDuplicateError1",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ },
+ {
+ text: "test-duplicate-error.html",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ let text = hud.outputNode.textContent;
+ let error1pos = text.indexOf("fooDuplicateError1");
+ ok(error1pos > -1, "found fooDuplicateError1");
+ if (error1pos > -1) {
+ ok(text.indexOf("fooDuplicateError1", error1pos + 1) == -1,
+ "no duplicate for fooDuplicateError1");
+ }
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js b/browser/devtools/webconsole/test/browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js
new file mode 100644
index 000000000..1f089ad2e
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js
@@ -0,0 +1,31 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/browser/test-console.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+ testCompletion(hud);
+});
+
+function testCompletion(hud) {
+ var jsterm = hud.jsterm;
+ var input = jsterm.inputNode;
+
+ jsterm.setInputValue("");
+ EventUtils.synthesizeKey("VK_TAB", {});
+ is(jsterm.completeNode.value, "<- no result", "<- no result - matched");
+ is(input.value, "", "inputnode is empty - matched")
+ is(input.getAttribute("focused"), "true", "input is still focused");
+
+ //Any thing which is not in property autocompleter
+ jsterm.setInputValue("window.Bug583816");
+ EventUtils.synthesizeKey("VK_TAB", {});
+ is(jsterm.completeNode.value, " <- no result", "completenode content - matched");
+ is(input.value, "window.Bug583816", "inputnode content - matched");
+ is(input.getAttribute("focused"), "true", "input is still focused");
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_585237_line_limit.js b/browser/devtools/webconsole/test/browser_webconsole_bug_585237_line_limit.js
new file mode 100644
index 000000000..9ec4291e3
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585237_line_limit.js
@@ -0,0 +1,87 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Patrick Walton <pcwalton@mozilla.com>
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Tests that the Web Console limits the number of lines displayed according to
+// the user's preferences.
+
+const TEST_URI = "data:text/html;charset=utf8,test for bug 585237";
+
+let outputNode;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ let console = content.console;
+ outputNode = hud.outputNode;
+
+ hud.jsterm.clearOutput();
+
+ let prefBranch = Services.prefs.getBranch("devtools.hud.loglimit.");
+ prefBranch.setIntPref("console", 20);
+
+ for (let i = 0; i < 30; i++) {
+ console.log("foo #" + i); // must change message to prevent repeats
+ }
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "foo #29",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ is(countMessageNodes(), 20, "there are 20 message nodes in the output " +
+ "when the log limit is set to 20");
+
+ console.log("bar bug585237");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "bar bug585237",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ is(countMessageNodes(), 20, "there are still 20 message nodes in the " +
+ "output when adding one more");
+
+ prefBranch.setIntPref("console", 30);
+ for (let i = 0; i < 20; i++) {
+ console.log("boo #" + i); // must change message to prevent repeats
+ }
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "boo #19",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ is(countMessageNodes(), 30, "there are 30 message nodes in the output " +
+ "when the log limit is set to 30");
+
+ prefBranch.clearUserPref("console");
+
+ outputNode = null;
+});
+
+function countMessageNodes() {
+ return outputNode.querySelectorAll(".message").length;
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_585956_console_trace.js b/browser/devtools/webconsole/test/browser_webconsole_bug_585956_console_trace.js
new file mode 100644
index 000000000..8945d2fa6
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585956_console_trace.js
@@ -0,0 +1,48 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-585956-console-trace.html";
+
+function test() {
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ let {tab} = yield loadTab("data:text/html;charset=utf8,<p>hello");
+ let hud = yield openConsole(tab);
+
+ content.location = TEST_URI;
+
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "console.trace output",
+ consoleTrace: {
+ file: "test-bug-585956-console-trace.html",
+ fn: "window.foobar585956c",
+ },
+ }],
+ });
+
+ let node = [...result.matched][0];
+ ok(node, "found trace log node");
+
+ let obj = node._messageObject;
+ ok(obj, "console.trace message object");
+
+ // The expected stack trace object.
+ let stacktrace = [
+ { columnNumber: 2, filename: TEST_URI, functionName: "window.foobar585956c", language: 2, lineNumber: 9 },
+ { columnNumber: 9, filename: TEST_URI, functionName: "foobar585956b", language: 2, lineNumber: 14 },
+ { columnNumber: 9, filename: TEST_URI, functionName: "foobar585956a", language: 2, lineNumber: 18 },
+ { columnNumber: 0, filename: TEST_URI, functionName: "", language: 2, lineNumber: 21 }
+ ];
+
+ ok(obj._stacktrace, "found stacktrace object");
+ is(obj._stacktrace.toSource(), stacktrace.toSource(), "stacktrace is correct");
+ isnot(node.textContent.indexOf("bug-585956"), -1, "found file name");
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
new file mode 100644
index 000000000..7704bd627
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
@@ -0,0 +1,376 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const TEST_URI = "data:text/html;charset=utf-8,<p>bug 585991 - autocomplete popup keyboard usage test";
+let HUD, popup, jsterm, inputNode, completeNode;
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+
+ yield consoleOpened(hud);
+ yield popupHideAfterTab();
+ yield testReturnKey();
+ yield dontShowArrayNumbers();
+ yield testReturnWithNoSelection();
+ yield popupHideAfterReturnWithNoSelection();
+ yield testCompletionInText();
+ yield popupHideAfterCompletionInText();
+
+ HUD = popup = jsterm = inputNode = completeNode = null;
+});
+
+let consoleOpened = Task.async(function*(aHud) {
+ let deferred = promise.defer();
+ HUD = aHud;
+ info("web console opened");
+
+ jsterm = HUD.jsterm;
+
+ yield jsterm.execute("window.foobarBug585991={" +
+ "'item0': 'value0'," +
+ "'item1': 'value1'," +
+ "'item2': 'value2'," +
+ "'item3': 'value3'" +
+ "}");
+ yield jsterm.execute("window.testBug873250a = 'hello world';"
+ + "window.testBug873250b = 'hello world 2';");
+ popup = jsterm.autocompletePopup;
+ completeNode = jsterm.completeNode;
+ inputNode = jsterm.inputNode;
+
+ ok(!popup.isOpen, "popup is not open");
+
+ popup._panel.addEventListener("popupshown", function onShown() {
+ popup._panel.removeEventListener("popupshown", onShown, false);
+
+ ok(popup.isOpen, "popup is open");
+
+ // 4 values, and the following properties:
+ // __defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__
+ // hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString
+ // toSource unwatch valueOf watch constructor.
+ is(popup.itemCount, 18, "popup.itemCount is correct");
+
+ let sameItems = popup.getItems().reverse().map(function(e) {return e.label;});
+ ok(sameItems.every(function(prop, index) {
+ return [
+ "__defineGetter__",
+ "__defineSetter__",
+ "__lookupGetter__",
+ "__lookupSetter__",
+ "constructor",
+ "hasOwnProperty",
+ "isPrototypeOf",
+ "item0",
+ "item1",
+ "item2",
+ "item3",
+ "propertyIsEnumerable",
+ "toLocaleString",
+ "toSource",
+ "toString",
+ "unwatch",
+ "valueOf",
+ "watch",
+ ][index] === prop}), "getItems returns the items we expect");
+
+ is(popup.selectedIndex, 17,
+ "Index of the first item from bottom is selected.");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
+
+ is(popup.selectedIndex, 0, "index 0 is selected");
+ is(popup.selectedItem.label, "watch", "watch is selected");
+ is(completeNode.value, prefix + "watch",
+ "completeNode.value holds watch");
+
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ is(popup.selectedIndex, 1, "index 1 is selected");
+ is(popup.selectedItem.label, "valueOf", "valueOf is selected");
+ is(completeNode.value, prefix + "valueOf",
+ "completeNode.value holds valueOf");
+
+ EventUtils.synthesizeKey("VK_UP", {});
+
+ is(popup.selectedIndex, 0, "index 0 is selected");
+ is(popup.selectedItem.label, "watch", "watch is selected");
+ is(completeNode.value, prefix + "watch",
+ "completeNode.value holds watch");
+
+ let currentSelectionIndex = popup.selectedIndex;
+
+ EventUtils.synthesizeKey("VK_PAGE_DOWN", {});
+
+ ok(popup.selectedIndex > currentSelectionIndex,
+ "Index is greater after PGDN");
+
+ currentSelectionIndex = popup.selectedIndex;
+ EventUtils.synthesizeKey("VK_PAGE_UP", {});
+
+ ok(popup.selectedIndex < currentSelectionIndex, "Index is less after Page UP");
+
+ EventUtils.synthesizeKey("VK_END", {});
+ is(popup.selectedIndex, 17, "index is last after End");
+
+ EventUtils.synthesizeKey("VK_HOME", {});
+ is(popup.selectedIndex, 0, "index is first after Home");
+
+ info("press Tab and wait for popup to hide");
+ popup._panel.addEventListener("popuphidden", function popupHidden() {
+ popup._panel.removeEventListener("popuphidden", popupHidden, false);
+ deferred.resolve();
+ }, false);
+ EventUtils.synthesizeKey("VK_TAB", {});
+ }, false);
+
+ info("wait for completion: window.foobarBug585991.");
+ jsterm.setInputValue("window.foobarBug585991");
+ EventUtils.synthesizeKey(".", {});
+
+ return deferred.promise;
+});
+
+function popupHideAfterTab()
+{
+ let deferred = promise.defer();
+
+ // At this point the completion suggestion should be accepted.
+ ok(!popup.isOpen, "popup is not open");
+
+ is(inputNode.value, "window.foobarBug585991.watch",
+ "completion was successful after VK_TAB");
+
+ ok(!completeNode.value, "completeNode is empty");
+
+ popup._panel.addEventListener("popupshown", function onShown() {
+ popup._panel.removeEventListener("popupshown", onShown, false);
+
+ ok(popup.isOpen, "popup is open");
+
+ is(popup.itemCount, 18, "popup.itemCount is correct");
+
+ is(popup.selectedIndex, 17, "First index from bottom is selected");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
+
+ is(popup.selectedIndex, 0, "index 0 is selected");
+ is(popup.selectedItem.label, "watch", "watch is selected");
+ is(completeNode.value, prefix + "watch",
+ "completeNode.value holds watch");
+
+ popup._panel.addEventListener("popuphidden", function onHidden() {
+ popup._panel.removeEventListener("popuphidden", onHidden, false);
+
+ ok(!popup.isOpen, "popup is not open after VK_ESCAPE");
+
+ is(inputNode.value, "window.foobarBug585991.",
+ "completion was cancelled");
+
+ ok(!completeNode.value, "completeNode is empty");
+
+ deferred.resolve();
+ }, false);
+
+ info("press Escape to close the popup");
+ executeSoon(function() {
+ EventUtils.synthesizeKey("VK_ESCAPE", {});
+ });
+ }, false);
+
+ info("wait for completion: window.foobarBug585991.");
+ executeSoon(function() {
+ jsterm.setInputValue("window.foobarBug585991");
+ EventUtils.synthesizeKey(".", {});
+ });
+
+ return deferred.promise;
+}
+
+function testReturnKey()
+{
+ let deferred = promise.defer();
+
+ popup._panel.addEventListener("popupshown", function onShown() {
+ popup._panel.removeEventListener("popupshown", onShown, false);
+
+ ok(popup.isOpen, "popup is open");
+
+ is(popup.itemCount, 18, "popup.itemCount is correct");
+
+ is(popup.selectedIndex, 17, "First index from bottom is selected");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
+
+ is(popup.selectedIndex, 0, "index 0 is selected");
+ is(popup.selectedItem.label, "watch", "watch is selected");
+ is(completeNode.value, prefix + "watch",
+ "completeNode.value holds watch");
+
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ is(popup.selectedIndex, 1, "index 1 is selected");
+ is(popup.selectedItem.label, "valueOf", "valueOf is selected");
+ is(completeNode.value, prefix + "valueOf",
+ "completeNode.value holds valueOf");
+
+ popup._panel.addEventListener("popuphidden", function onHidden() {
+ popup._panel.removeEventListener("popuphidden", onHidden, false);
+
+ ok(!popup.isOpen, "popup is not open after VK_RETURN");
+
+ is(inputNode.value, "window.foobarBug585991.valueOf",
+ "completion was successful after VK_RETURN");
+
+ ok(!completeNode.value, "completeNode is empty");
+
+ deferred.resolve();
+ }, false);
+
+ info("press Return to accept suggestion. wait for popup to hide");
+
+ executeSoon(() => EventUtils.synthesizeKey("VK_RETURN", {}));
+ }, false);
+
+ info("wait for completion suggestions: window.foobarBug585991.");
+
+ executeSoon(function() {
+ jsterm.setInputValue("window.foobarBug58599");
+ EventUtils.synthesizeKey("1", {});
+ EventUtils.synthesizeKey(".", {});
+ });
+
+ return deferred.promise;
+}
+
+function dontShowArrayNumbers()
+{
+ let deferred = promise.defer();
+
+ info("dontShowArrayNumbers");
+ content.wrappedJSObject.foobarBug585991 = ["Sherlock Holmes"];
+
+ let jsterm = HUD.jsterm;
+ let popup = jsterm.autocompletePopup;
+ let completeNode = jsterm.completeNode;
+
+ popup._panel.addEventListener("popupshown", function onShown() {
+ popup._panel.removeEventListener("popupshown", onShown, false);
+
+ let sameItems = popup.getItems().map(function(e) {return e.label;});
+ ok(!sameItems.some(function(prop, index) { prop === "0"; }),
+ "Completing on an array doesn't show numbers.");
+
+ popup._panel.addEventListener("popuphidden", function popupHidden() {
+ popup._panel.removeEventListener("popuphidden", popupHidden, false);
+ deferred.resolve();
+ }, false);
+
+ info("wait for popup to hide");
+ executeSoon(() => EventUtils.synthesizeKey("VK_ESCAPE", {}));
+ }, false);
+
+ info("wait for popup to show");
+ executeSoon(() => {
+ jsterm.setInputValue("window.foobarBug585991");
+ EventUtils.synthesizeKey(".", {});
+ });
+
+ return deferred.promise;
+}
+
+function testReturnWithNoSelection()
+{
+ let deferred = promise.defer();
+
+ info("test pressing return with open popup, but no selection, see bug 873250");
+
+ popup._panel.addEventListener("popupshown", function onShown() {
+ popup._panel.removeEventListener("popupshown", onShown);
+
+ ok(popup.isOpen, "popup is open");
+ is(popup.itemCount, 2, "popup.itemCount is correct");
+ isnot(popup.selectedIndex, -1, "popup.selectedIndex is correct");
+
+ info("press Return and wait for popup to hide");
+ popup._panel.addEventListener("popuphidden", function popupHidden() {
+ popup._panel.removeEventListener("popuphidden", popupHidden);
+ deferred.resolve();
+ });
+ executeSoon(() => EventUtils.synthesizeKey("VK_RETURN", {}));
+ });
+
+ executeSoon(() => {
+ info("wait for popup to show");
+ jsterm.setInputValue("window.testBu");
+ EventUtils.synthesizeKey("g", {});
+ });
+
+ return deferred.promise;
+}
+
+function popupHideAfterReturnWithNoSelection()
+{
+ ok(!popup.isOpen, "popup is not open after VK_RETURN");
+
+ is(inputNode.value, "", "inputNode is empty after VK_RETURN");
+ is(completeNode.value, "", "completeNode is empty");
+ is(jsterm.history[jsterm.history.length-1], "window.testBug",
+ "jsterm history is correct");
+
+ return promise.resolve();
+}
+
+function testCompletionInText()
+{
+ info("test that completion works inside text, see bug 812618");
+
+ let deferred = promise.defer();
+
+ popup._panel.addEventListener("popupshown", function onShown() {
+ popup._panel.removeEventListener("popupshown", onShown);
+
+ ok(popup.isOpen, "popup is open");
+ is(popup.itemCount, 2, "popup.itemCount is correct");
+
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ is(popup.selectedIndex, 0, "popup.selectedIndex is correct");
+ ok(!completeNode.value, "completeNode.value is empty");
+
+ let items = popup.getItems().reverse().map(e => e.label);
+ let sameItems = items.every((prop, index) =>
+ ["testBug873250a", "testBug873250b"][index] === prop);
+ ok(sameItems, "getItems returns the items we expect");
+
+ info("press Tab and wait for popup to hide");
+ popup._panel.addEventListener("popuphidden", function popupHidden() {
+ popup._panel.removeEventListener("popuphidden", popupHidden);
+ deferred.resolve();
+ });
+ EventUtils.synthesizeKey("VK_TAB", {});
+ });
+
+ jsterm.setInputValue("dump(window.testBu)");
+ inputNode.selectionStart = inputNode.selectionEnd = 18;
+ EventUtils.synthesizeKey("g", {});
+ return deferred.promise;
+}
+
+function popupHideAfterCompletionInText()
+{
+ // At this point the completion suggestion should be accepted.
+ ok(!popup.isOpen, "popup is not open");
+ is(inputNode.value, "dump(window.testBug873250b)",
+ "completion was successful after VK_TAB");
+ is(inputNode.selectionStart, 26, "cursor location is correct");
+ is(inputNode.selectionStart, inputNode.selectionEnd, "cursor location (confirmed)");
+ ok(!completeNode.value, "completeNode is empty");
+
+ return promise.resolve();
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_popup.js b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_popup.js
new file mode 100644
index 000000000..76fc5d324
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_popup.js
@@ -0,0 +1,119 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const TEST_URI = "data:text/html;charset=utf-8,<p>bug 585991 - autocomplete popup test";
+
+"use strict";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+
+ yield consoleOpened(hud);
+});
+
+function consoleOpened(HUD) {
+ let deferred = promise.defer();
+
+ let items = [
+ {label: "item0", value: "value0"},
+ {label: "item1", value: "value1"},
+ {label: "item2", value: "value2"},
+ ];
+
+ let popup = HUD.jsterm.autocompletePopup;
+
+ let input = popup._document.activeElement;
+ function getActiveDescendant() {
+ return input.ownerDocument.getElementById(
+ input.getAttribute("aria-activedescendant"));
+ }
+
+ ok(!popup.isOpen, "popup is not open");
+ ok(!input.hasAttribute("aria-activedescendant"), "no aria-activedescendant");
+
+ popup._panel.addEventListener("popupshown", function() {
+ popup._panel.removeEventListener("popupshown", arguments.callee, false);
+
+ ok(popup.isOpen, "popup is open");
+
+ is(popup.itemCount, 0, "no items");
+ ok(!input.hasAttribute("aria-activedescendant"),
+ "no aria-activedescendant");
+
+ popup.setItems(items);
+
+ is(popup.itemCount, items.length, "items added");
+
+ let sameItems = popup.getItems();
+ is(sameItems.every(function(aItem, aIndex) {
+ return aItem === items[aIndex];
+ }), true, "getItems returns back the same items");
+
+ is(popup.selectedIndex, 2,
+ "Index of the first item from bottom is selected.");
+ is(popup.selectedItem, items[2], "First item from bottom is selected");
+ ok(getActiveDescendant().selected, "aria-activedescendant is correct");
+
+ popup.selectedIndex = 1;
+
+ is(popup.selectedIndex, 1, "index 1 is selected");
+ is(popup.selectedItem, items[1], "item1 is selected");
+ ok(getActiveDescendant().selected, "aria-activedescendant is correct");
+
+ popup.selectedItem = items[2];
+
+ is(popup.selectedIndex, 2, "index 2 is selected");
+ is(popup.selectedItem, items[2], "item2 is selected");
+ ok(getActiveDescendant().selected, "aria-activedescendant is correct");
+
+ is(popup.selectPreviousItem(), items[1], "selectPreviousItem() works");
+
+ is(popup.selectedIndex, 1, "index 1 is selected");
+ is(popup.selectedItem, items[1], "item1 is selected");
+ ok(getActiveDescendant().selected, "aria-activedescendant is correct");
+
+ is(popup.selectNextItem(), items[2], "selectPreviousItem() works");
+
+ is(popup.selectedIndex, 2, "index 2 is selected");
+ is(popup.selectedItem, items[2], "item2 is selected");
+ ok(getActiveDescendant().selected, "aria-activedescendant is correct");
+
+ ok(popup.selectNextItem(), "selectPreviousItem() works");
+
+ is(popup.selectedIndex, 0, "index 0 is selected");
+ is(popup.selectedItem, items[0], "item0 is selected");
+ ok(getActiveDescendant().selected, "aria-activedescendant is correct");
+
+ items.push({label: "label3", value: "value3"});
+ popup.appendItem(items[3]);
+
+ is(popup.itemCount, items.length, "item3 appended");
+
+ popup.selectedIndex = 3;
+ is(popup.selectedItem, items[3], "item3 is selected");
+ ok(getActiveDescendant().selected, "aria-activedescendant is correct");
+
+ popup.removeItem(items[2]);
+
+ is(popup.selectedIndex, 2, "index2 is selected");
+ is(popup.selectedItem, items[3], "item3 is still selected");
+ ok(getActiveDescendant().selected, "aria-activedescendant is correct");
+ is(popup.itemCount, items.length - 1, "item2 removed");
+
+ popup.clearItems();
+ is(popup.itemCount, 0, "items cleared");
+ ok(!input.hasAttribute("aria-activedescendant"),
+ "no aria-activedescendant");
+
+ popup.hidePopup();
+ deferred.resolve();
+ }, false);
+
+ popup.openPopup();
+
+ return deferred.promise;
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js b/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js
new file mode 100644
index 000000000..5512201cf
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js
@@ -0,0 +1,91 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Patrick Walton <pcwalton@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "http://example.com/";
+
+"use strict";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+ yield testSelectionWhenMovingBetweenBoxes(hud);
+ performTestsAfterOutput(hud);
+})
+
+let testSelectionWhenMovingBetweenBoxes = Task.async(function *(aHud) {
+ let hud = aHud;
+ let jsterm = hud.jsterm;
+
+ // Fill the console with some output.
+ jsterm.clearOutput();
+ yield jsterm.execute("1 + 2");
+ yield jsterm.execute("3 + 4");
+ yield jsterm.execute("5 + 6");
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "3",
+ category: CATEGORY_OUTPUT,
+ },
+ {
+ text: "7",
+ category: CATEGORY_OUTPUT,
+ },
+ {
+ text: "11",
+ category: CATEGORY_OUTPUT,
+ }],
+ });
+});
+
+function performTestsAfterOutput(aHud) {
+ let hud = aHud;
+ let outputNode = hud.outputNode;
+
+ ok(outputNode.childNodes.length >= 3, "the output node has children after " +
+ "executing some JavaScript");
+
+ // Test that the global Firefox "Select All" functionality (e.g. Edit >
+ // Select All) works properly in the Web Console.
+ let commandController = hud.ui._commandController;
+ ok(commandController != null, "the window has a command controller object");
+
+ commandController.selectAll();
+
+ let selectedCount = hud.ui.output.getSelectedMessages().length;
+ is(selectedCount, outputNode.childNodes.length,
+ "all console messages are selected after performing a regular browser " +
+ "select-all operation");
+
+ hud.iframeWindow.getSelection().removeAllRanges();
+
+ // Test the context menu "Select All" (which has a different code path) works
+ // properly as well.
+ let contextMenuId = outputNode.parentNode.getAttribute("context");
+ let contextMenu = hud.ui.document.getElementById(contextMenuId);
+ ok(contextMenu != null, "the output node has a context menu");
+
+ let selectAllItem = contextMenu.querySelector("*[command='cmd_selectAll']");
+ ok(selectAllItem != null,
+ "the context menu on the output node has a \"Select All\" item");
+
+ outputNode.focus();
+
+ selectAllItem.doCommand();
+
+ selectedCount = hud.ui.output.getSelectedMessages().length;
+ is(selectedCount, outputNode.childNodes.length,
+ "all console messages are selected after performing a select-all " +
+ "operation from the context menu");
+
+ hud.iframeWindow.getSelection().removeAllRanges();
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_587617_output_copy.js b/browser/devtools/webconsole/test/browser_webconsole_bug_587617_output_copy.js
new file mode 100644
index 000000000..78a4221c4
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_587617_output_copy.js
@@ -0,0 +1,98 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ * Patrick Walton <pcwalton@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let HUD, outputNode;
+
+"use strict";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+ yield consoleOpened(hud);
+ yield testContextMenuCopy();
+
+ HUD = outputNode = null;
+});
+
+function consoleOpened(aHud) {
+ HUD = aHud;
+
+ let deferred = promise.defer();
+
+ // See bugs 574036, 586386 and 587617.
+ outputNode = HUD.outputNode;
+
+ HUD.jsterm.clearOutput();
+
+ let controller = top.document.commandDispatcher.
+ getControllerForCommand("cmd_copy");
+ is(controller.isCommandEnabled("cmd_copy"), false, "cmd_copy is disabled");
+
+ content.console.log("Hello world! bug587617");
+
+ waitForMessages({
+ webconsole: HUD,
+ messages: [{
+ text: "bug587617",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ }).then(([result]) => {
+ let msg = [...result.matched][0];
+ HUD.ui.output.selectMessage(msg);
+
+ outputNode.focus();
+
+ goUpdateCommand("cmd_copy");
+ controller = top.document.commandDispatcher.getControllerForCommand("cmd_copy");
+ is(controller.isCommandEnabled("cmd_copy"), true, "cmd_copy is enabled");
+
+ // Remove new lines since getSelection() includes one between message and line
+ // number, but the clipboard doesn't (see bug 1119503)
+ let selection = (HUD.iframeWindow.getSelection() + "").replace(/\r?\n|\r/g, " ");
+ isnot(selection.indexOf("bug587617"), -1,
+ "selection text includes 'bug587617'");
+
+ waitForClipboard((str) => { return selection.trim() == str.trim(); },
+ () => { goDoCommand("cmd_copy") },
+ deferred.resolve, deferred.resolve);
+ });
+ return deferred.promise;
+}
+
+// Test that the context menu "Copy" (which has a different code path) works
+// properly as well.
+function testContextMenuCopy() {
+ let deferred = promise.defer();
+
+ let contextMenuId = outputNode.parentNode.getAttribute("context");
+ let contextMenu = HUD.ui.document.getElementById(contextMenuId);
+ ok(contextMenu, "the output node has a context menu");
+
+ let copyItem = contextMenu.querySelector("*[command='cmd_copy']");
+ ok(copyItem, "the context menu on the output node has a \"Copy\" item");
+
+ // Remove new lines since getSelection() includes one between message and line
+ // number, but the clipboard doesn't (see bug 1119503)
+ let selection = (HUD.iframeWindow.getSelection() + "").replace(/\r?\n|\r/g, " ");
+
+ copyItem.doCommand();
+
+ waitForClipboard((str) => { return selection.trim() == str.trim(); },
+ () => { goDoCommand("cmd_copy") },
+ deferred.resolve, deferred.resolve);
+ HUD = outputNode = null;
+
+ return deferred.promise;
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_588342_document_focus.js b/browser/devtools/webconsole/test/browser_webconsole_bug_588342_document_focus.js
new file mode 100644
index 000000000..6e7fcc1f6
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_588342_document_focus.js
@@ -0,0 +1,39 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 588342";
+
+let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
+
+"use strict";
+
+let test = asyncTest(function* () {
+ let { browser } = yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+ yield consoleOpened(hud);
+
+ is(fm.focusedWindow, browser.contentWindow,
+ "content document has focus");
+
+ fm = null;
+});
+
+function consoleOpened(hud) {
+ let deferred = promise.defer();
+ waitForFocus(function() {
+ is(hud.jsterm.inputNode.getAttribute("focused"), "true",
+ "jsterm input is focused on web console open");
+ isnot(fm.focusedWindow, content, "content document has no focus");
+ closeConsole(null).then(deferred.resolve);
+ }, hud.iframeWindow);
+
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_588730_text_node_insertion.js b/browser/devtools/webconsole/test/browser_webconsole_bug_588730_text_node_insertion.js
new file mode 100644
index 000000000..ef1c3e5a2
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_588730_text_node_insertion.js
@@ -0,0 +1,53 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that adding text to one of the output labels doesn't cause errors.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+"use strict";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ yield testTextNodeInsertion(hud);
+});
+
+// Test for bug 588730: Adding a text node to an existing label element causes
+// warnings
+function testTextNodeInsertion(hud) {
+ let deferred = promise.defer();
+ let outputNode = hud.outputNode;
+
+ let label = document.createElementNS(
+ "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "label");
+ outputNode.appendChild(label);
+
+ let error = false;
+ let listener = {
+ observe: function(aMessage) {
+ let messageText = aMessage.message;
+ if (messageText.indexOf("JavaScript Warning") !== -1) {
+ error = true;
+ }
+ }
+ };
+
+ Services.console.registerListener(listener);
+
+ // This shouldn't fail.
+ label.appendChild(document.createTextNode("foo"));
+
+ executeSoon(function() {
+ Services.console.unregisterListener(listener);
+ ok(!error, "no error when adding text nodes as children of labels");
+
+ return deferred.resolve();
+ });
+ return deferred.promise;
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_588967_input_expansion.js b/browser/devtools/webconsole/test/browser_webconsole_bug_588967_input_expansion.js
new file mode 100644
index 000000000..9b9fb3168
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_588967_input_expansion.js
@@ -0,0 +1,45 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+"use strict";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ testInputExpansion(hud);
+});
+
+
+function testInputExpansion(hud) {
+ let input = hud.jsterm.inputNode;
+
+ input.focus();
+
+ is(input.getAttribute("multiline"), "true", "multiline is enabled");
+
+ let ordinaryHeight = input.clientHeight;
+
+ // Tests if the inputNode expands.
+ input.value = "hello\nworld\n";
+ let length = input.value.length;
+ input.selectionEnd = length;
+ input.selectionStart = length;
+ // Performs an "d". This will trigger/test for the input event that should
+ // change the height of the inputNode.
+ EventUtils.synthesizeKey("d", {});
+ ok(input.clientHeight > ordinaryHeight, "the input expanded");
+
+ // Test if the inputNode shrinks again.
+ input.value = "";
+ EventUtils.synthesizeKey("d", {});
+ is(input.clientHeight, ordinaryHeight, "the input's height is normal again");
+
+ input = length = null;
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_589162_css_filter.js b/browser/devtools/webconsole/test/browser_webconsole_bug_589162_css_filter.js
new file mode 100644
index 000000000..72fd295eb
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_589162_css_filter.js
@@ -0,0 +1,49 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ * Patrick Walton <pcwalton@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+"use strict"
+
+const TEST_URI = "data:text/html;charset=utf-8,<div style='font-size:3em;" +
+ "foobarCssParser:baz'>test CSS parser filter</div>";
+
+/**
+ * Unit test for bug 589162:
+ * CSS filtering on the console does not work
+ */
+function test() {
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ let {tab} = yield loadTab(TEST_URI);
+ let hud = yield openConsole(tab);
+
+ // CSS warnings are disabled by default.
+ hud.setFilterState("cssparser", true);
+ hud.jsterm.clearOutput();
+
+ content.location.reload();
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "foobarCssParser",
+ category: CATEGORY_CSS,
+ severity: SEVERITY_WARNING,
+ }],
+ });
+
+ hud.setFilterState("cssparser", false);
+
+ let msg = "the unknown CSS property warning is not displayed, " +
+ "after filtering";
+ testLogEntry(hud.outputNode, "foobarCssParser", msg, true, true);
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_592442_closing_brackets.js b/browser/devtools/webconsole/test/browser_webconsole_bug_592442_closing_brackets.js
new file mode 100644
index 000000000..c29e61b26
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_592442_closing_brackets.js
@@ -0,0 +1,37 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Julian Viereck <jviereck@mozilla.com>
+ * Patrick Walton <pcwalton@mozilla.com>
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Tests that, when the user types an extraneous closing bracket, no error
+// appears.
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf-8,test for bug 592442";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ hud.jsterm.clearOutput();
+ let jsterm = hud.jsterm;
+
+ jsterm.setInputValue("document.getElementById)");
+
+ let error = false;
+ try {
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY);
+ }
+ catch (ex) {
+ error = true;
+ }
+
+ ok(!error, "no error was thrown when an extraneous bracket was inserted");
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_593003_iframe_wrong_hud.js b/browser/devtools/webconsole/test/browser_webconsole_bug_593003_iframe_wrong_hud.js
new file mode 100644
index 000000000..ac526b502
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_593003_iframe_wrong_hud.js
@@ -0,0 +1,65 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud.html";
+
+const TEST_IFRAME_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud-iframe.html";
+
+const TEST_DUMMY_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let tab1, tab2;
+
+function test() {
+ loadTab(TEST_URI).then(({tab}) => {
+ tab1 = tab;
+
+ content.console.log("FOO");
+ openConsole().then(() => {
+ tab2 = gBrowser.addTab(TEST_DUMMY_URI);
+ gBrowser.selectedTab = tab2;
+ gBrowser.selectedBrowser.addEventListener("load", tab2Loaded, true);
+ });
+ });
+}
+
+function tab2Loaded(aEvent) {
+ tab2.linkedBrowser.removeEventListener(aEvent.type, tab2Loaded, true);
+
+ openConsole(gBrowser.selectedTab).then(() => {
+ tab1.linkedBrowser.addEventListener("load", tab1Reloaded, true);
+ tab1.linkedBrowser.contentWindow.location.reload();
+ });
+}
+
+function tab1Reloaded(aEvent) {
+ tab1.linkedBrowser.removeEventListener(aEvent.type, tab1Reloaded, true);
+
+ let hud1 = HUDService.getHudByWindow(tab1.linkedBrowser.contentWindow);
+ let outputNode1 = hud1.outputNode;
+
+ waitForMessages({
+ webconsole: hud1,
+ messages: [{
+ text: TEST_IFRAME_URI,
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ }],
+ }).then(() => {
+ let hud2 = HUDService.getHudByWindow(tab2.linkedBrowser.contentWindow);
+ let outputNode2 = hud2.outputNode;
+
+ isnot(outputNode1, outputNode2,
+ "the two HUD outputNodes must be different");
+
+ let msg = "Didn't find the iframe network request in tab2";
+ testLogEntry(outputNode2, TEST_IFRAME_URI, msg, true, true);
+
+ closeConsole(tab2).then(() => {
+ gBrowser.removeTab(tab2);
+ tab1 = tab2 = null;
+ executeSoon(finishTest);
+ });
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js b/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js
new file mode 100644
index 000000000..c6a983d6b
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js
@@ -0,0 +1,131 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+let HUD;
+let outputItem;
+let outputNode;
+
+"use strict";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ HUD = yield openConsole();
+ outputNode = HUD.outputNode;
+
+ // reload the tab
+ BrowserReload();
+ yield loadBrowser(gBrowser.selectedBrowser);
+
+ let event = yield clickEvents();
+ yield testClickAgain(event);
+ yield networkPanelHidden();
+
+ HUD = outputItem = outputNode = null;
+});
+
+function clickEvents() {
+ let deferred = promise.defer();
+
+ waitForMessages({
+ webconsole: HUD,
+ messages: [{
+ text: "test-console.html",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ }],
+ }).then(([result]) => {
+ let msg = [...result.matched][0];
+ outputItem = msg.querySelector(".message-body .url");
+ ok(outputItem, "found a network message");
+ document.addEventListener("popupshown", function onPanelShown(event) {
+ document.removeEventListener("popupshown", onPanelShown, false);
+ deferred.resolve(event);
+ }, false);
+
+ // Send the mousedown and click events such that the network panel opens.
+ EventUtils.sendMouseEvent({type: "mousedown"}, outputItem);
+ EventUtils.sendMouseEvent({type: "click"}, outputItem);
+ });
+
+ return deferred.promise;
+}
+
+function testClickAgain(event) {
+ info("testClickAgain");
+
+ let deferred = promise.defer();
+
+ document.addEventListener("popupshown", networkPanelShowFailure, false);
+
+ // The network panel should not open for the second time.
+ EventUtils.sendMouseEvent({type: "mousedown"}, outputItem);
+ EventUtils.sendMouseEvent({type: "click"}, outputItem);
+
+ executeSoon(function() {
+ document.addEventListener("popuphidden", function onHidden() {
+ document.removeEventListener("popuphidden", onHidden, false);
+ deferred.resolve();
+ }, false);
+ event.target.hidePopup();
+ });
+
+ return deferred.promise;
+}
+
+function networkPanelShowFailure() {
+ ok(false, "the network panel should not show");
+}
+
+function networkPanelHidden() {
+ let deferred = promise.defer();
+
+ info("networkPanelHidden");
+
+ // The network panel should not show because this is a mouse event that starts
+ // in a position and ends in another.
+ EventUtils.sendMouseEvent({type: "mousedown", clientX: 3, clientY: 4},
+ outputItem);
+ EventUtils.sendMouseEvent({type: "click", clientX: 5, clientY: 6},
+ outputItem);
+
+ // The network panel should not show because this is a middle-click.
+ EventUtils.sendMouseEvent({type: "mousedown", button: 1},
+ outputItem);
+ EventUtils.sendMouseEvent({type: "click", button: 1},
+ outputItem);
+
+ // The network panel should not show because this is a right-click.
+ EventUtils.sendMouseEvent({type: "mousedown", button: 2},
+ outputItem);
+ EventUtils.sendMouseEvent({type: "click", button: 2},
+ outputItem);
+
+ executeSoon(function() {
+ document.removeEventListener("popupshown", networkPanelShowFailure, false);
+
+ // Done with the network output. Now test the jsterm output and the property
+ // panel.
+ HUD.jsterm.execute("document").then((msg) => {
+ info("jsterm execute 'document' callback");
+
+ HUD.jsterm.once("variablesview-open", deferred.resolve);
+ let outputItem = msg.querySelector(".message-body a");
+ ok(outputItem, "jsterm output message found");
+
+ // Send the mousedown and click events such that the property panel opens.
+ EventUtils.sendMouseEvent({type: "mousedown"}, outputItem);
+ EventUtils.sendMouseEvent({type: "click"}, outputItem);
+ });
+ });
+
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_594497_history_arrow_keys.js b/browser/devtools/webconsole/test/browser_webconsole_bug_594497_history_arrow_keys.js
new file mode 100644
index 000000000..38210ebfb
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_594497_history_arrow_keys.js
@@ -0,0 +1,156 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+let inputNode, values;
+
+let TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 594497 and bug 619598";
+"use strict";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ setup(hud);
+ performTests();
+
+ inputNode = values = null;
+});
+
+function setup(HUD) {
+ inputNode = HUD.jsterm.inputNode;
+
+ inputNode.focus();
+
+ ok(!inputNode.value, "inputNode.value is empty");
+
+ values = ["document", "window", "document.body"];
+ values.push(values.join(";\n"), "document.location");
+
+ // Execute each of the values;
+ for (let i = 0; i < values.length; i++) {
+ HUD.jsterm.setInputValue(values[i]);
+ HUD.jsterm.execute();
+ }
+}
+
+function performTests() {
+ EventUtils.synthesizeKey("VK_UP", {});
+
+ is(inputNode.value, values[4],
+ "VK_UP: inputNode.value #4 is correct");
+
+ ok(inputNode.selectionStart == values[4].length &&
+ inputNode.selectionStart == inputNode.selectionEnd,
+ "caret location is correct");
+
+ EventUtils.synthesizeKey("VK_UP", {});
+
+ is(inputNode.value, values[3],
+ "VK_UP: inputNode.value #3 is correct");
+
+ ok(inputNode.selectionStart == values[3].length &&
+ inputNode.selectionStart == inputNode.selectionEnd,
+ "caret location is correct");
+
+ inputNode.setSelectionRange(values[3].length - 2, values[3].length - 2);
+
+ EventUtils.synthesizeKey("VK_UP", {});
+ EventUtils.synthesizeKey("VK_UP", {});
+
+ is(inputNode.value, values[3],
+ "VK_UP two times: inputNode.value #3 is correct");
+
+ ok(inputNode.selectionStart == inputNode.value.indexOf("\n") &&
+ inputNode.selectionStart == inputNode.selectionEnd,
+ "caret location is correct");
+
+ EventUtils.synthesizeKey("VK_UP", {});
+
+ is(inputNode.value, values[3],
+ "VK_UP again: inputNode.value #3 is correct");
+
+ ok(inputNode.selectionStart == 0 &&
+ inputNode.selectionStart == inputNode.selectionEnd,
+ "caret location is correct");
+
+ EventUtils.synthesizeKey("VK_UP", {});
+
+ is(inputNode.value, values[2],
+ "VK_UP: inputNode.value #2 is correct");
+
+ EventUtils.synthesizeKey("VK_UP", {});
+
+ is(inputNode.value, values[1],
+ "VK_UP: inputNode.value #1 is correct");
+
+ EventUtils.synthesizeKey("VK_UP", {});
+
+ is(inputNode.value, values[0],
+ "VK_UP: inputNode.value #0 is correct");
+
+ ok(inputNode.selectionStart == values[0].length &&
+ inputNode.selectionStart == inputNode.selectionEnd,
+ "caret location is correct");
+
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ is(inputNode.value, values[1],
+ "VK_DOWN: inputNode.value #1 is correct");
+
+ ok(inputNode.selectionStart == values[1].length &&
+ inputNode.selectionStart == inputNode.selectionEnd,
+ "caret location is correct");
+
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ is(inputNode.value, values[2],
+ "VK_DOWN: inputNode.value #2 is correct");
+
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ is(inputNode.value, values[3],
+ "VK_DOWN: inputNode.value #3 is correct");
+
+ ok(inputNode.selectionStart == values[3].length &&
+ inputNode.selectionStart == inputNode.selectionEnd,
+ "caret location is correct");
+
+ inputNode.setSelectionRange(2, 2);
+
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ is(inputNode.value, values[3],
+ "VK_DOWN two times: inputNode.value #3 is correct");
+
+ ok(inputNode.selectionStart > inputNode.value.lastIndexOf("\n") &&
+ inputNode.selectionStart == inputNode.selectionEnd,
+ "caret location is correct");
+
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ is(inputNode.value, values[3],
+ "VK_DOWN again: inputNode.value #3 is correct");
+
+ ok(inputNode.selectionStart == values[3].length &&
+ inputNode.selectionStart == inputNode.selectionEnd,
+ "caret location is correct");
+
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ is(inputNode.value, values[4],
+ "VK_DOWN: inputNode.value #4 is correct");
+
+ EventUtils.synthesizeKey("VK_DOWN", {});
+
+ ok(!inputNode.value,
+ "VK_DOWN: inputNode.value is empty");
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_595223_file_uri.js b/browser/devtools/webconsole/test/browser_webconsole_bug_595223_file_uri.js
new file mode 100644
index 000000000..fe8ff7b2c
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_595223_file_uri.js
@@ -0,0 +1,64 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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";
+
+const PREF = "devtools.webconsole.persistlog";
+const TEST_FILE = "test-network.html";
+const TEST_URI = "data:text/html;charset=utf8,<p>test file URI";
+
+let hud;
+
+let test = asyncTest(function* () {
+ Services.prefs.setBoolPref(PREF, true);
+
+ let jar = getJar(getRootDirectory(gTestPath));
+ let dir = jar ?
+ extractJarToTmp(jar) :
+ getChromeDir(getResolvedURI(gTestPath));
+
+ dir.append(TEST_FILE);
+ let uri = Services.io.newFileURI(dir);
+
+ let { browser } = yield loadTab(TEST_URI);
+
+ hud = yield openConsole();
+ hud.jsterm.clearOutput();
+
+ let loaded = loadBrowser(browser);
+ content.location = uri.spec;
+ yield loaded;
+
+ yield testMessages();
+
+ Services.prefs.clearUserPref(PREF);
+ hud = null;
+});
+
+function testMessages() {
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "running network console logging tests",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "test-network.html",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "test-image.png",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "testscript.js",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ }],
+ })
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_595350_multiple_windows_and_tabs.js b/browser/devtools/webconsole/test/browser_webconsole_bug_595350_multiple_windows_and_tabs.js
new file mode 100644
index 000000000..cefb3e377
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_595350_multiple_windows_and_tabs.js
@@ -0,0 +1,101 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Patrick Walton <pcwalton@mozilla.com>
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Tests that the Web Console doesn't leak when multiple tabs and windows are
+// opened and then closed.
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 595350";
+
+let win1 = window, win2;
+let openTabs = [];
+let loadedTabCount = 0;
+
+function test() {
+ requestLongerTimeout(3);
+
+ // Add two tabs in the main window.
+ addTabs(win1);
+
+ // Open a new window.
+ win2 = OpenBrowserWindow();
+ win2.addEventListener("load", onWindowLoad, true);
+}
+
+function onWindowLoad(aEvent) {
+ win2.removeEventListener(aEvent.type, onWindowLoad, true);
+
+ // Add two tabs in the new window.
+ addTabs(win2);
+}
+
+function addTabs(aWindow) {
+ for (let i = 0; i < 2; i++) {
+ let tab = aWindow.gBrowser.addTab(TEST_URI);
+ openTabs.push(tab);
+
+ tab.linkedBrowser.addEventListener("load", function onLoad(aEvent) {
+ tab.linkedBrowser.removeEventListener(aEvent.type, onLoad, true);
+
+ loadedTabCount++;
+ info("tabs loaded: " + loadedTabCount);
+ if (loadedTabCount >= 4) {
+ executeSoon(openConsoles);
+ }
+ }, true);
+ }
+}
+
+function openConsoles() {
+ // open the Web Console for each of the four tabs and log a message.
+ let consolesOpen = 0;
+ for (let i = 0; i < openTabs.length; i++) {
+ let tab = openTabs[i];
+ openConsole(tab).then(function(index, hud) {
+ ok(hud, "HUD is open for tab " + index);
+ let window = hud.target.tab.linkedBrowser.contentWindow;
+ window.console.log("message for tab " + index);
+ consolesOpen++;
+ if (consolesOpen == 4) {
+ // Use executeSoon() to allow the promise to resolve.
+ executeSoon(closeConsoles);
+ }
+ }.bind(null, i));
+ }
+}
+
+function closeConsoles() {
+ let consolesClosed = 0;
+
+ function onWebConsoleClose(aSubject, aTopic) {
+ if (aTopic == "web-console-destroyed") {
+ consolesClosed++;
+ info("consoles destroyed: " + consolesClosed);
+ if (consolesClosed == 4) {
+ // Use executeSoon() to allow all the observers to execute.
+ executeSoon(finishTest);
+ }
+ }
+ }
+
+ Services.obs.addObserver(onWebConsoleClose, "web-console-destroyed", false);
+
+ registerCleanupFunction(() => {
+ Services.obs.removeObserver(onWebConsoleClose, "web-console-destroyed");
+ });
+
+ win2.close();
+
+ win1.gBrowser.removeTab(openTabs[0]);
+ win1.gBrowser.removeTab(openTabs[1]);
+
+ openTabs = win1 = win2 = null;
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js b/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js
new file mode 100644
index 000000000..bfafa4423
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js
@@ -0,0 +1,203 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 595934 - message categories coverage.";
+const TESTS_PATH = "http://example.com/browser/browser/devtools/webconsole/test/";
+const TESTS = [
+ { // #0
+ file: "test-bug-595934-css-loader.html",
+ category: "CSS Loader",
+ matchString: "text/css",
+ },
+ { // #1
+ file: "test-bug-595934-imagemap.html",
+ category: "Layout: ImageMap",
+ matchString: "shape=\"rect\"",
+ },
+ { // #2
+ file: "test-bug-595934-html.html",
+ category: "HTML",
+ matchString: "multipart/form-data",
+ onload: function() {
+ let form = content.document.querySelector("form");
+ form.submit();
+ },
+ },
+ { // #3
+ file: "test-bug-595934-workers.html",
+ category: "Web Worker",
+ matchString: "fooBarWorker",
+ expectError: true,
+ },
+ { // #4
+ file: "test-bug-595934-malformedxml.xhtml",
+ category: "malformed-xml",
+ matchString: "no element found",
+ },
+ { // #5
+ file: "test-bug-595934-svg.xhtml",
+ category: "SVG",
+ matchString: "fooBarSVG",
+ },
+ { // #6
+ file: "test-bug-595934-css-parser.html",
+ category: "CSS Parser",
+ matchString: "foobarCssParser",
+ },
+ { // #7
+ file: "test-bug-595934-malformedxml-external.html",
+ category: "malformed-xml",
+ matchString: "</html>",
+ },
+ { // #8
+ file: "test-bug-595934-empty-getelementbyid.html",
+ category: "DOM",
+ matchString: "getElementById",
+ },
+ { // #9
+ file: "test-bug-595934-canvas-css.html",
+ category: "CSS Parser",
+ matchString: "foobarCanvasCssParser",
+ },
+ { // #10
+ file: "test-bug-595934-image.html",
+ category: "Image",
+ matchString: "corrupt",
+ },
+];
+
+let pos = -1;
+
+let foundCategory = false;
+let foundText = false;
+let pageLoaded = false;
+let pageError = false;
+let output = null;
+let jsterm = null;
+let hud = null;
+let testEnded = false;
+
+let TestObserver = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+
+ observe: function test_observe(aSubject)
+ {
+ if (testEnded || !(aSubject instanceof Ci.nsIScriptError)) {
+ return;
+ }
+
+ var expectedCategory = TESTS[pos].category;
+
+ info("test #" + pos + " console observer got " + aSubject.category +
+ ", is expecting " + expectedCategory);
+
+ if (aSubject.category == expectedCategory) {
+ foundCategory = true;
+ startNextTest();
+ }
+ else {
+ info("unexpected message was: " + aSubject.sourceName + ":" +
+ aSubject.lineNumber + "; " + aSubject.errorMessage);
+ }
+ }
+};
+
+function consoleOpened(aHud) {
+ hud = aHud;
+ output = hud.outputNode;
+ jsterm = hud.jsterm;
+
+ Services.console.registerListener(TestObserver);
+
+ registerCleanupFunction(testEnd);
+
+ testNext();
+}
+
+function testNext() {
+ jsterm.clearOutput();
+ foundCategory = false;
+ foundText = false;
+ pageLoaded = false;
+ pageError = false;
+
+ pos++;
+ info("testNext: #" + pos);
+ if (pos < TESTS.length) {
+ let test = TESTS[pos];
+
+ waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "message for test #" + pos + ": '" + test.matchString +"'",
+ text: test.matchString,
+ }],
+ }).then(() => {
+ foundText = true;
+ startNextTest();
+ });
+
+ let testLocation = TESTS_PATH + test.file;
+ gBrowser.selectedBrowser.addEventListener("load", function onLoad(aEvent) {
+ if (content.location.href != testLocation) {
+ return;
+ }
+ gBrowser.selectedBrowser.removeEventListener(aEvent.type, onLoad, true);
+
+ pageLoaded = true;
+ test.onload && test.onload(aEvent);
+
+ if (test.expectError) {
+ content.addEventListener("error", function _onError() {
+ content.removeEventListener("error", _onError);
+ pageError = true;
+ startNextTest();
+ });
+ expectUncaughtException();
+ }
+ else {
+ pageError = true;
+ }
+
+ startNextTest();
+ }, true);
+
+ content.location = testLocation;
+ }
+ else {
+ testEnded = true;
+ finishTest();
+ }
+}
+
+function testEnd() {
+ if (!testEnded) {
+ info("foundCategory " + foundCategory + " foundText " + foundText +
+ " pageLoaded " + pageLoaded + " pageError " + pageError);
+ }
+
+ Services.console.unregisterListener(TestObserver);
+ hud = TestObserver = output = jsterm = null;
+}
+
+function startNextTest() {
+ if (!testEnded && foundCategory && foundText && pageLoaded && pageError) {
+ testNext();
+ }
+}
+
+function test() {
+ requestLongerTimeout(2);
+
+ loadTab(TEST_URI).then(() => {
+ openConsole().then(consoleOpened);
+ });
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js b/browser/devtools/webconsole/test/browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js
new file mode 100644
index 000000000..6bc20ba1c
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js
@@ -0,0 +1,104 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let tab1, tab2, win1, win2;
+let noErrors = true;
+
+function tab1Loaded() {
+ win2 = OpenBrowserWindow();
+ whenDelayedStartupFinished(win2, win2Loaded);
+}
+
+function win2Loaded() {
+ tab2 = win2.gBrowser.addTab(TEST_URI);
+ win2.gBrowser.selectedTab = tab2;
+ tab2.linkedBrowser.addEventListener("load", tab2Loaded, true);
+}
+
+function tab2Loaded(aEvent) {
+ tab2.linkedBrowser.removeEventListener(aEvent.type, tab2Loaded, true);
+
+ let consolesOpened = 0;
+ function onWebConsoleOpen() {
+ consolesOpened++;
+ if (consolesOpened == 2) {
+ executeSoon(closeConsoles);
+ }
+ }
+
+ function openConsoles() {
+ try {
+ let target1 = TargetFactory.forTab(tab1);
+ gDevTools.showToolbox(target1, "webconsole").then(onWebConsoleOpen);
+ }
+ catch (ex) {
+ ok(false, "gDevTools.showToolbox(target1) exception: " + ex);
+ noErrors = false;
+ }
+
+ try {
+ let target2 = TargetFactory.forTab(tab2);
+ gDevTools.showToolbox(target2, "webconsole").then(onWebConsoleOpen);
+ }
+ catch (ex) {
+ ok(false, "gDevTools.showToolbox(target2) exception: " + ex);
+ noErrors = false;
+ }
+ }
+
+ function closeConsoles() {
+ try {
+ let target1 = TargetFactory.forTab(tab1);
+ gDevTools.closeToolbox(target1).then(function() {
+ try {
+ let target2 = TargetFactory.forTab(tab2);
+ gDevTools.closeToolbox(target2).then(testEnd);
+ }
+ catch (ex) {
+ ok(false, "gDevTools.closeToolbox(target2) exception: " + ex);
+ noErrors = false;
+ }
+ });
+ }
+ catch (ex) {
+ ok(false, "gDevTools.closeToolbox(target1) exception: " + ex);
+ noErrors = false;
+ }
+ }
+
+ function testEnd() {
+ ok(noErrors, "there were no errors");
+
+ win1.gBrowser.removeTab(tab1);
+
+ Array.forEach(win2.gBrowser.tabs, function(aTab) {
+ win2.gBrowser.removeTab(aTab);
+ });
+
+ executeSoon(function() {
+ win2.close();
+ tab1 = tab2 = win1 = win2 = null;
+ finishTest();
+ });
+ }
+
+ waitForFocus(openConsoles, tab2.linkedBrowser.contentWindow);
+}
+
+function test() {
+ loadTab(TEST_URI).then(() => {
+ tab1 = gBrowser.selectedTab;
+ win1 = window;
+ tab1Loaded();
+ });
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_597136_external_script_errors.js b/browser/devtools/webconsole/test/browser_webconsole_bug_597136_external_script_errors.js
new file mode 100644
index 000000000..fa8905af0
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_597136_external_script_errors.js
@@ -0,0 +1,36 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Patrick Walton <pcwalton@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/" +
+ "webconsole/test/test-bug-597136-external-script-" +
+ "errors.html";
+
+function test() {
+ Task.spawn(function* () {
+ const {tab} = yield loadTab(TEST_URI);
+ const hud = yield openConsole(tab);
+
+ let button = content.document.querySelector("button");
+
+ expectUncaughtException();
+ EventUtils.sendMouseEvent({ type: "click" }, button, content);
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "bogus is not defined",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ }],
+ });
+ }).then(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_597136_network_requests_from_chrome.js b/browser/devtools/webconsole/test/browser_webconsole_bug_597136_network_requests_from_chrome.js
new file mode 100644
index 000000000..bf745ac3d
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_597136_network_requests_from_chrome.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that network requests from chrome don't cause the Web Console to
+// throw exceptions.
+
+const TEST_URI = "http://example.com/";
+
+let good = true;
+let listener = {
+ QueryInterface: XPCOMUtils.generateQI([ Ci.nsIObserver ]),
+ observe: function(aSubject, aTopic, aData) {
+ if (aSubject instanceof Ci.nsIScriptError &&
+ aSubject.category === "XPConnect JavaScript" &&
+ aSubject.sourceName.contains("webconsole")) {
+ good = false;
+ }
+ }
+};
+
+let xhr;
+
+function test() {
+ Services.console.registerListener(listener);
+
+ HUDService; // trigger a lazy-load of the HUD Service
+
+ xhr = new XMLHttpRequest();
+ xhr.addEventListener("load", xhrComplete, false);
+ xhr.open("GET", TEST_URI, true);
+ xhr.send(null);
+}
+
+function xhrComplete() {
+ xhr.removeEventListener("load", xhrComplete, false);
+ window.setTimeout(checkForException, 0);
+}
+
+function checkForException() {
+ ok(good, "no exception was thrown when sending a network request from a " +
+ "chrome window");
+
+ Services.console.unregisterListener(listener);
+ listener = xhr = null;
+
+ finishTest();
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_597460_filter_scroll.js b/browser/devtools/webconsole/test/browser_webconsole_bug_597460_filter_scroll.js
new file mode 100644
index 000000000..f8fc821eb
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_597460_filter_scroll.js
@@ -0,0 +1,82 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-network.html";
+const PREF = "devtools.webconsole.persistlog";
+
+let test = asyncTest(function* () {
+ Services.prefs.setBoolPref(PREF, true);
+
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+
+ let results = yield consoleOpened(hud);
+
+ testScroll(results, hud);
+
+ Services.prefs.clearUserPref(PREF);
+});
+
+function consoleOpened(hud) {
+ let deferred = promise.defer();
+
+ for (let i = 0; i < 200; i++) {
+ content.console.log("test message " + i);
+ }
+
+ hud.setFilterState("network", false);
+ hud.setFilterState("networkinfo", false);
+
+ hud.ui.filterBox.value = "test message";
+ hud.ui.adjustVisibilityOnSearchStringChange();
+
+ waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "console messages displayed",
+ text: "test message 199",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ }).then(() => {
+ waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "test-network.html",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ }],
+ }).then(deferred.resolve);
+
+ content.location.reload();
+ });
+
+ return deferred.promise;
+}
+
+function testScroll([result], hud) {
+ let scrollNode = hud.outputNode.parentNode;
+ let msgNode = [...result.matched][0];
+ ok(msgNode.classList.contains("filtered-by-type"),
+ "network message is filtered by type");
+ ok(msgNode.classList.contains("filtered-by-string"),
+ "network message is filtered by string");
+
+ ok(scrollNode.scrollTop > 0, "scroll location is not at the top");
+
+ // Make sure the Web Console output is scrolled as near as possible to the
+ // bottom.
+ let nodeHeight = msgNode.clientHeight;
+ ok(scrollNode.scrollTop >= scrollNode.scrollHeight - scrollNode.clientHeight -
+ nodeHeight * 2, "scroll location is correct");
+
+ hud.setFilterState("network", true);
+ hud.setFilterState("networkinfo", true);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_597756_reopen_closed_tab.js b/browser/devtools/webconsole/test/browser_webconsole_bug_597756_reopen_closed_tab.js
new file mode 100644
index 000000000..ccaedc98e
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_597756_reopen_closed_tab.js
@@ -0,0 +1,62 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-597756-reopen-closed-tab.html";
+
+let HUD;
+
+let test = asyncTest(function* () {
+ expectUncaughtException();
+
+ let { browser } = yield loadTab(TEST_URI);
+ HUD = yield openConsole();
+
+ expectUncaughtException();
+
+ yield reload(browser);
+
+ yield testMessages();
+
+ yield closeConsole();
+
+ // Close and reopen
+ gBrowser.removeCurrentTab();
+
+ expectUncaughtException();
+
+ let tab = yield loadTab(TEST_URI);
+ HUD = yield openConsole();
+
+ expectUncaughtException();
+
+ yield reload(tab.browser);
+
+ yield testMessages();
+
+ HUD = null;
+});
+
+function reload(browser) {
+ let loaded = loadBrowser(browser);
+ content.location.reload();
+ return loaded;
+}
+
+function testMessages() {
+ return waitForMessages({
+ webconsole: HUD,
+ messages: [{
+ name: "error message displayed",
+ text: "fooBug597756_error",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ }],
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_599725_response_headers.js b/browser/devtools/webconsole/test/browser_webconsole_bug_599725_response_headers.js
new file mode 100644
index 000000000..eb3c26cf0
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_599725_response_headers.js
@@ -0,0 +1,87 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const INIT_URI = "data:text/plain;charset=utf8,hello world";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-599725-response-headers.sjs";
+
+let loads = 0;
+function performTest(aRequest, aConsole)
+{
+ let deferred = promise.defer();
+
+ let headers = null;
+
+ function readHeader(aName)
+ {
+ for (let header of headers) {
+ if (header.name == aName) {
+ return header.value;
+ }
+ }
+ return null;
+ }
+
+ aConsole.webConsoleClient.getResponseHeaders(aRequest.actor,
+ function (aResponse) {
+ headers = aResponse.headers;
+ ok(headers, "we have the response headers for reload");
+
+ let contentType = readHeader("Content-Type");
+ let contentLength = readHeader("Content-Length");
+
+ ok(!contentType, "we do not have the Content-Type header");
+ isnot(contentLength, 60, "Content-Length != 60");
+
+ if (contentType || contentLength == 60) {
+ console.debug("lastFinishedRequest", lastFinishedRequest,
+ "request", lastFinishedRequest.request,
+ "response", lastFinishedRequest.response,
+ "updates", lastFinishedRequest.updates,
+ "response headers", headers);
+ }
+
+ executeSoon(deferred.resolve);
+ });
+
+ HUDService.lastFinishedRequest.callback = null;
+
+ return deferred.promise;
+}
+
+function waitForRequest() {
+ let deferred = promise.defer();
+ HUDService.lastFinishedRequest.callback = (req, console) => {
+ loads++;
+ ok(req, "page load was logged");
+ if (loads != 2) {
+ return;
+ }
+ performTest(req, console).then(deferred.resolve);
+ };
+ return deferred.promise;
+}
+
+let test = asyncTest(function* () {
+ let { browser } = yield loadTab(INIT_URI);
+
+ let hud = yield openConsole();
+
+ let gotLastRequest = waitForRequest();
+
+ let loaded = loadBrowser(browser);
+ content.location = TEST_URI;
+ yield loaded;
+
+ let reloaded = loadBrowser(browser);
+ content.location.reload();
+ yield reloaded;
+
+ yield gotLastRequest;
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js b/browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js
new file mode 100644
index 000000000..bd224375f
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js
@@ -0,0 +1,66 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const INIT_URI = "data:text/html;charset=utf-8,Web Console - bug 600183 test";
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-600183-charset.html";
+
+function performTest(lastFinishedRequest, aConsole)
+{
+ let deferred = promise.defer();
+
+ ok(lastFinishedRequest, "charset test page was loaded and logged");
+ HUDService.lastFinishedRequest.callback = null;
+
+ executeSoon(() => {
+ aConsole.webConsoleClient.getResponseContent(lastFinishedRequest.actor,
+ (aResponse) => {
+ ok(!aResponse.contentDiscarded, "response body was not discarded");
+
+ let body = aResponse.content.text;
+ ok(body, "we have the response body");
+
+ let chars = "\u7684\u95ee\u5019!"; // 的问候!
+ isnot(body.indexOf("<p>" + chars + "</p>"), -1,
+ "found the chinese simplified string");
+
+ HUDService.lastFinishedRequest.callback = null;
+ executeSoon(deferred.resolve);
+ });
+ });
+
+ return deferred.promise;
+}
+
+function waitForRequest() {
+ let deferred = promise.defer();
+ HUDService.lastFinishedRequest.callback = (req, console) => {
+ performTest(req, console).then(deferred.resolve);
+ };
+ return deferred.promise;
+}
+
+let test = asyncTest(function* () {
+ let { browser } = yield loadTab(INIT_URI);
+
+ let hud = yield openConsole();
+
+ yield hud.ui.setSaveRequestAndResponseBodies(true);
+
+ ok(hud.ui._saveRequestAndResponseBodies,
+ "The saveRequestAndResponseBodies property was successfully set.");
+
+ let gotLastRequest = waitForRequest();
+
+ let loaded = loadBrowser(browser);
+ content.location = TEST_URI;
+ yield loaded;
+
+ yield gotLastRequest;
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_601177_log_levels.js b/browser/devtools/webconsole/test/browser_webconsole_bug_601177_log_levels.js
new file mode 100644
index 000000000..dbe21f32d
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_601177_log_levels.js
@@ -0,0 +1,73 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 601177: log levels";
+const TEST_URI2 = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-601177-log-levels.html";
+
+let test = asyncTest(function* () {
+ Services.prefs.setBoolPref("javascript.options.strict", true);
+
+ let { browser } = yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ expectUncaughtException();
+
+ yield testLogLevels(hud);
+
+ Services.prefs.clearUserPref("javascript.options.strict");
+});
+
+function testLogLevels(hud) {
+ content.location = TEST_URI2;
+
+ info("waiting for messages");
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ text: "test-bug-601177-log-levels.html",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "test-bug-601177-log-levels.js",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "test-image.png",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "foobar-known-to-fail.png",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_ERROR,
+ },
+ {
+ text: "foobarBug601177exception",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ },
+ {
+ text: "undefinedPropertyBug601177",
+ category: CATEGORY_JS,
+ severity: SEVERITY_WARNING,
+ },
+ {
+ text: "foobarBug601177strictError",
+ category: CATEGORY_JS,
+ severity: SEVERITY_WARNING,
+ },
+ ],
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_601352_scroll.js b/browser/devtools/webconsole/test/browser_webconsole_bug_601352_scroll.js
new file mode 100644
index 000000000..2ff267896
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_601352_scroll.js
@@ -0,0 +1,69 @@
+/* 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/. */
+
+// Test that the console output scrolls to JS eval results when there are many
+// messages displayed. See bug 601352.
+
+function test() {
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ let {tab} = yield loadTab("data:text/html;charset=utf-8,Web Console test for bug 601352");
+ let hud = yield openConsole(tab);
+ hud.jsterm.clearOutput();
+
+ let longMessage = "";
+ for (let i = 0; i < 50; i++) {
+ longMessage += "LongNonwrappingMessage";
+ }
+
+ for (let i = 0; i < 50; i++) {
+ content.console.log("test1 message " + i);
+ }
+
+ content.console.log(longMessage);
+
+ for (let i = 0; i < 50; i++) {
+ content.console.log("test2 message " + i);
+ }
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "test1 message 0",
+ }, {
+ text: "test1 message 49",
+ }, {
+ text: "LongNonwrappingMessage",
+ }, {
+ text: "test2 message 0",
+ }, {
+ text: "test2 message 49",
+ }],
+ });
+
+ let node = yield hud.jsterm.execute("1+1");
+
+ let scrollNode = hud.outputNode.parentNode;
+ let rectNode = node.getBoundingClientRect();
+ let rectOutput = scrollNode.getBoundingClientRect();
+ console.debug("rectNode", rectNode, "rectOutput", rectOutput);
+ console.log("scrollNode scrollHeight", scrollNode.scrollHeight, "scrollTop", scrollNode.scrollTop, "clientHeight", scrollNode.clientHeight);
+
+ isnot(scrollNode.scrollTop, 0, "scroll location is not at the top");
+
+ // The bounding client rect .top/left coordinates are relative to the
+ // console iframe.
+
+ // Visible scroll viewport.
+ let height = rectOutput.height;
+
+ // Top and bottom coordinates of the last message node, relative to the outputNode.
+ let top = rectNode.top - rectOutput.top;
+ let bottom = top + rectNode.height;
+ info("node top " + top + " node bottom " + bottom + " node clientHeight " + node.clientHeight);
+
+ ok(top >= 0 && bottom <= height, "last message is visible");
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_601667_filter_buttons.js b/browser/devtools/webconsole/test/browser_webconsole_bug_601667_filter_buttons.js
new file mode 100644
index 000000000..d00f2d2d9
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_601667_filter_buttons.js
@@ -0,0 +1,241 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the filter button UI logic works correctly.
+
+const TEST_URI = "http://example.com/";
+
+let hud, hudId, hudBox;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ hud = yield openConsole();
+ hudId = hud.hudId;
+ hudBox = hud.ui.rootElement;
+
+ testFilterButtons();
+
+ hud = hudId = hudBox = null;
+});
+
+function testFilterButtons() {
+ testMenuFilterButton("net");
+ testMenuFilterButton("css");
+ testMenuFilterButton("js");
+ testMenuFilterButton("logging");
+ testMenuFilterButton("security");
+
+ testIsolateFilterButton("net");
+ testIsolateFilterButton("css");
+ testIsolateFilterButton("js");
+ testIsolateFilterButton("logging");
+ testIsolateFilterButton("security");
+}
+
+function testMenuFilterButton(aCategory) {
+ let selector = ".webconsole-filter-button[category=\"" + aCategory + "\"]";
+ let button = hudBox.querySelector(selector);
+ ok(button, "we have the \"" + aCategory + "\" button");
+
+ let firstMenuItem = button.querySelector("menuitem");
+ ok(firstMenuItem, "we have the first menu item for the \"" + aCategory +
+ "\" button");
+
+ // Turn all the filters off, if they were on.
+ let menuItem = firstMenuItem;
+ while (menuItem != null) {
+ if (menuItem.hasAttribute("prefKey") && isChecked(menuItem)) {
+ chooseMenuItem(menuItem);
+ }
+ menuItem = menuItem.nextSibling;
+ }
+
+ // Turn all the filters on; make sure the button gets checked.
+ menuItem = firstMenuItem;
+ let prefKey;
+ while (menuItem) {
+ if (menuItem.hasAttribute("prefKey")) {
+ prefKey = menuItem.getAttribute("prefKey");
+ chooseMenuItem(menuItem);
+ ok(isChecked(menuItem), "menu item " + prefKey + " for category " +
+ aCategory + " is checked after clicking it");
+ ok(hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
+ "on after clicking the appropriate menu item");
+ }
+ menuItem = menuItem.nextSibling;
+ }
+ ok(isChecked(button), "the button for category " + aCategory + " is " +
+ "checked after turning on all its menu items");
+
+ // Turn one filter off; make sure the button is still checked.
+ prefKey = firstMenuItem.getAttribute("prefKey");
+ chooseMenuItem(firstMenuItem);
+ ok(!isChecked(firstMenuItem), "the first menu item for category " +
+ aCategory + " is no longer checked after clicking it");
+ ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
+ "turned off after clicking the appropriate menu item");
+ ok(isChecked(button), "the button for category " + aCategory + " is still " +
+ "checked after turning off its first menu item");
+
+ // Turn all the filters off by clicking the main part of the button.
+ let subbutton = getMainButton(button);
+ ok(subbutton, "we have the subbutton for category " + aCategory);
+
+ clickButton(subbutton);
+ ok(!isChecked(button), "the button for category " + aCategory + " is " +
+ "no longer checked after clicking its main part");
+
+ menuItem = firstMenuItem;
+ while (menuItem) {
+ let prefKey = menuItem.getAttribute("prefKey");
+ if (prefKey) {
+ ok(!isChecked(menuItem), "menu item " + prefKey + " for category " +
+ aCategory + " is no longer checked after clicking the button");
+ ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
+ "off after clicking the button");
+ }
+ menuItem = menuItem.nextSibling;
+ }
+
+ // Turn all the filters on by clicking the main part of the button.
+ clickButton(subbutton);
+
+ ok(isChecked(button), "the button for category " + aCategory + " is " +
+ "checked after clicking its main part");
+
+ menuItem = firstMenuItem;
+ while (menuItem) {
+ if (menuItem.hasAttribute("prefKey")) {
+ let prefKey = menuItem.getAttribute("prefKey");
+ // The CSS/Log menu item should not be checked. See bug 971798.
+ if (aCategory == "css" && prefKey == "csslog") {
+ ok(!isChecked(menuItem), "menu item " + prefKey + " for category " +
+ aCategory + " should not be checked after clicking the button");
+ ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
+ "off after clicking the button");
+ } else {
+ ok(isChecked(menuItem), "menu item " + prefKey + " for category " +
+ aCategory + " is checked after clicking the button");
+ ok(hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
+ "on after clicking the button");
+ }
+ }
+ menuItem = menuItem.nextSibling;
+ }
+
+ // Uncheck the main button by unchecking all the filters
+ menuItem = firstMenuItem;
+ while (menuItem) {
+ // The csslog menu item is already unchecked at this point.
+ // Make sure it is not selected. See bug 971798.
+ prefKey = menuItem.getAttribute("prefKey");
+ if (prefKey && prefKey != "csslog") {
+ chooseMenuItem(menuItem);
+ }
+ menuItem = menuItem.nextSibling;
+ }
+
+ ok(!isChecked(button), "the button for category " + aCategory + " is " +
+ "unchecked after unchecking all its filters");
+
+ // Turn all the filters on again by clicking the button.
+ clickButton(subbutton);
+}
+
+function testIsolateFilterButton(aCategory) {
+ let selector = ".webconsole-filter-button[category=\"" + aCategory + "\"]";
+ let targetButton = hudBox.querySelector(selector);
+ ok(targetButton, "we have the \"" + aCategory + "\" button");
+
+ // Get the main part of the filter button.
+ let subbutton = getMainButton(targetButton);
+ ok(subbutton, "we have the subbutton for category " + aCategory);
+
+ // Turn on all the filters by alt clicking the main part of the button.
+ altClickButton(subbutton);
+ ok(isChecked(targetButton), "the button for category " + aCategory +
+ " is checked after isolating for filter");
+
+ // Check if all the filters for the target button are on.
+ let menuItems = targetButton.querySelectorAll("menuitem");
+ Array.forEach(menuItems, (item) => {
+ let prefKey = item.getAttribute("prefKey");
+ // The CSS/Log filter should not be checked. See bug 971798.
+ if (aCategory == "css" && prefKey == "csslog") {
+ ok(!isChecked(item), "menu item " + prefKey + " for category " +
+ aCategory + " should not be checked after isolating for " + aCategory);
+ ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages should be " +
+ "turned off after isolating for " + aCategory);
+ } else if (prefKey) {
+ ok(isChecked(item), "menu item " + prefKey + " for category " +
+ aCategory + " is checked after isolating for " + aCategory);
+ ok(hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
+ "turned on after isolating for " + aCategory);
+ }
+ });
+
+ // Ensure all other filter buttons are toggled off and their
+ // associated filters are turned off
+ let buttons = hudBox.querySelectorAll(".webconsole-filter-button[category]");
+ Array.forEach(buttons, (filterButton) => {
+ if (filterButton !== targetButton) {
+ let category = filterButton.getAttribute("category");
+ ok(!isChecked(filterButton), "the button for category " +
+ category + " is unchecked after isolating for " + aCategory);
+
+ menuItems = filterButton.querySelectorAll("menuitem");
+ Array.forEach(menuItems, (item) => {
+ let prefKey = item.getAttribute("prefKey");
+ if (prefKey) {
+ ok(!isChecked(item), "menu item " + prefKey + " for category " +
+ aCategory + " is unchecked after isolating for " + aCategory);
+ ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
+ "turned off after isolating for " + aCategory);
+ }
+ });
+
+ // Turn all the filters on again by clicking the button.
+ let mainButton = getMainButton(filterButton);
+ clickButton(mainButton);
+ }
+ });
+}
+
+/**
+ * Return the main part of the target filter button.
+ */
+function getMainButton(aTargetButton) {
+ let anonymousNodes = hud.ui.document.getAnonymousNodes(aTargetButton);
+ let subbutton;
+
+ for (let i = 0; i < anonymousNodes.length; i++) {
+ let node = anonymousNodes[i];
+ if (node.classList.contains("toolbarbutton-menubutton-button")) {
+ subbutton = node;
+ break;
+ }
+ }
+
+ return subbutton;
+}
+
+function clickButton(aNode) {
+ EventUtils.sendMouseEvent({ type: "click" }, aNode);
+}
+
+function altClickButton(aNode) {
+ EventUtils.sendMouseEvent({ type: "click", altKey: true }, aNode);
+}
+
+function chooseMenuItem(aNode) {
+ let event = document.createEvent("XULCommandEvent");
+ event.initCommandEvent("command", true, true, window, 0, false, false, false,
+ false, null);
+ aNode.dispatchEvent(event);
+}
+
+function isChecked(aNode) {
+ return aNode.getAttribute("checked") === "true";
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js b/browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js
new file mode 100644
index 000000000..ae68ecda8
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js
@@ -0,0 +1,177 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+let menuitems = [], menupopups = [], huds = [], tabs = [], runCount = 0;
+
+const TEST_URI1 = "data:text/html;charset=utf-8,Web Console test for bug 602572: log bodies checkbox. tab 1";
+const TEST_URI2 = "data:text/html;charset=utf-8,Web Console test for bug 602572: log bodies checkbox. tab 2";
+
+function test()
+{
+ if (runCount == 0) {
+ requestLongerTimeout(2);
+ }
+
+ // open tab 1
+ loadTab(TEST_URI1).then((tab) => {
+ tabs.push(tab.tab);
+ openConsole().then((hud) => {
+ hud.iframeWindow.mozRequestAnimationFrame(() => {
+ info("iframe1 root height " + hud.ui.rootElement.clientHeight);
+
+ // open tab 2
+ loadTab(TEST_URI2).then((tab) => {
+ tabs.push(tab.tab);
+ openConsole().then((hud) => hud.iframeWindow.mozRequestAnimationFrame(startTest));
+ });
+ });
+ });
+ });
+}
+
+function startTest()
+{
+ // Find the relevant elements in the Web Console of tab 2.
+ let win2 = tabs[runCount*2 + 1].linkedBrowser.contentWindow;
+ huds[1] = HUDService.getHudByWindow(win2);
+ info("startTest: iframe2 root height " + huds[1].ui.rootElement.clientHeight);
+
+ if (runCount == 0) {
+ menuitems[1] = huds[1].ui.rootElement.querySelector("#saveBodies");
+ }
+ else {
+ menuitems[1] = huds[1].ui.rootElement.querySelector("#saveBodiesContextMenu");
+ }
+ menupopups[1] = menuitems[1].parentNode;
+
+ // Open the context menu from tab 2.
+ menupopups[1].addEventListener("popupshown", onpopupshown2, false);
+ executeSoon(function() {
+ menupopups[1].openPopup();
+ });
+}
+
+function onpopupshown2(aEvent)
+{
+ menupopups[1].removeEventListener(aEvent.type, onpopupshown2, false);
+
+ // By default bodies are not logged.
+ isnot(menuitems[1].getAttribute("checked"), "true",
+ "menuitems[1] is not checked");
+
+ ok(!huds[1].ui._saveRequestAndResponseBodies, "bodies are not logged");
+
+ // Enable body logging.
+ huds[1].ui.setSaveRequestAndResponseBodies(true).then(() => {
+ menupopups[1].hidePopup();
+ });
+
+ menupopups[1].addEventListener("popuphidden", function _onhidden(aEvent) {
+ menupopups[1].removeEventListener(aEvent.type, _onhidden, false);
+
+ info("menupopups[1] hidden");
+
+ // Reopen the context menu.
+ huds[1].ui.once("save-bodies-ui-toggled", () => testpopup2b(aEvent));
+ menupopups[1].openPopup();
+ }, false);
+}
+
+function testpopup2b(aEvent) {
+ is(menuitems[1].getAttribute("checked"), "true", "menuitems[1] is checked");
+
+ menupopups[1].addEventListener("popuphidden", function _onhidden(aEvent) {
+ menupopups[1].removeEventListener(aEvent.type, _onhidden, false);
+
+ info("menupopups[1] hidden");
+
+ // Switch to tab 1 and open the Web Console context menu from there.
+ gBrowser.selectedTab = tabs[runCount*2];
+ waitForFocus(function() {
+ // Find the relevant elements in the Web Console of tab 1.
+ let win1 = tabs[runCount*2].linkedBrowser.contentWindow;
+ huds[0] = HUDService.getHudByWindow(win1);
+
+ info("iframe1 root height " + huds[0].ui.rootElement.clientHeight);
+
+ menuitems[0] = huds[0].ui.rootElement.querySelector("#saveBodies");
+ menupopups[0] = huds[0].ui.rootElement.querySelector("menupopup");
+
+ menupopups[0].addEventListener("popupshown", onpopupshown1, false);
+ executeSoon(() => menupopups[0].openPopup());
+ }, tabs[runCount*2].linkedBrowser.contentWindow);
+ }, false);
+
+ executeSoon(function() {
+ menupopups[1].hidePopup();
+ });
+}
+
+function onpopupshown1(aEvent)
+{
+ menupopups[0].removeEventListener(aEvent.type, onpopupshown1, false);
+
+ // The menuitem checkbox must not be in sync with the other tabs.
+ isnot(menuitems[0].getAttribute("checked"), "true",
+ "menuitems[0] is not checked");
+
+ // Enable body logging for tab 1 as well.
+ huds[0].ui.setSaveRequestAndResponseBodies(true).then(() => {
+ menupopups[0].hidePopup();
+ });
+
+ // Close the menu, and switch back to tab 2.
+ menupopups[0].addEventListener("popuphidden", function _onhidden(aEvent) {
+ menupopups[0].removeEventListener(aEvent.type, _onhidden, false);
+
+ info("menupopups[0] hidden");
+
+ gBrowser.selectedTab = tabs[runCount*2 + 1];
+ waitForFocus(function() {
+ // Reopen the context menu from tab 2.
+ huds[1].ui.once("save-bodies-ui-toggled", () => testpopup2c(aEvent));
+ menupopups[1].openPopup();
+ }, tabs[runCount*2 + 1].linkedBrowser.contentWindow);
+ }, false);
+}
+
+function testpopup2c(aEvent) {
+ is(menuitems[1].getAttribute("checked"), "true", "menuitems[1] is checked");
+
+ menupopups[1].addEventListener("popuphidden", function _onhidden(aEvent) {
+ menupopups[1].removeEventListener(aEvent.type, _onhidden, false);
+
+ info("menupopups[1] hidden");
+
+ // Done if on second run
+ closeConsole(gBrowser.selectedTab).then(function() {
+ if (runCount == 0) {
+ runCount++;
+ info("start second run");
+ executeSoon(test);
+ }
+ else {
+ gBrowser.removeCurrentTab();
+ gBrowser.selectedTab = tabs[2];
+ gBrowser.removeCurrentTab();
+ gBrowser.selectedTab = tabs[1];
+ gBrowser.removeCurrentTab();
+ gBrowser.selectedTab = tabs[0];
+ gBrowser.removeCurrentTab();
+ huds = menuitems = menupopups = tabs = null;
+ executeSoon(finishTest);
+ }
+ });
+ }, false);
+
+ executeSoon(function() {
+ menupopups[1].hidePopup();
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_603750_websocket.js b/browser/devtools/webconsole/test/browser_webconsole_bug_603750_websocket.js
new file mode 100644
index 000000000..5bc9c3a12
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_603750_websocket.js
@@ -0,0 +1,37 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-603750-websocket.html";
+const TEST_URI2 = "data:text/html;charset=utf-8,Web Console test for bug 603750: Web Socket errors";
+
+let test = asyncTest(function* () {
+ let { browser } = yield loadTab(TEST_URI2);
+
+ let hud = yield openConsole();
+
+ content.location = TEST_URI;
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ text: "ws://0.0.0.0:81",
+ source: { url: "test-bug-603750-websocket.js" },
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ },
+ {
+ text: "ws://0.0.0.0:82",
+ source: { url: "test-bug-603750-websocket.js" },
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ },
+ ]});
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_611795.js b/browser/devtools/webconsole/test/browser_webconsole_bug_611795.js
new file mode 100644
index 000000000..cfc1c8c37
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_611795.js
@@ -0,0 +1,64 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_URI = 'data:text/html;charset=utf-8,<div style="-moz-opacity:0;">test repeated' +
+ ' css warnings</div><p style="-moz-opacity:0">hi</p>';
+let hud;
+
+"use strict";
+
+/**
+ * Unit test for bug 611795:
+ * Repeated CSS messages get collapsed into one.
+ */
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ hud = yield openConsole();
+ hud.jsterm.clearOutput(true);
+
+ BrowserReload();
+ yield loadBrowser(gBrowser.selectedBrowser);
+
+ yield onContentLoaded();
+ yield testConsoleLogRepeats();
+
+ hud = null;
+});
+
+function onContentLoaded()
+{
+ let cssWarning = "Unknown property '-moz-opacity'. Declaration dropped.";
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: cssWarning,
+ category: CATEGORY_CSS,
+ severity: SEVERITY_WARNING,
+ repeats: 2,
+ }],
+ });
+}
+
+function testConsoleLogRepeats()
+{
+ let jsterm = hud.jsterm;
+
+ jsterm.clearOutput();
+
+ jsterm.setInputValue("for (let i = 0; i < 10; ++i) console.log('this is a line of reasonably long text that I will use to verify that the repeated text node is of an appropriate size.');");
+ jsterm.execute();
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "this is a line of reasonably long text",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ repeats: 10,
+ }],
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_613013_console_api_iframe.js b/browser/devtools/webconsole/test/browser_webconsole_bug_613013_console_api_iframe.js
new file mode 100644
index 000000000..13a1057ec
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_613013_console_api_iframe.js
@@ -0,0 +1,29 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-613013-console-api-iframe.html";
+
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ BrowserReload();
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "foobarBug613013",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_613280_jsterm_copy.js b/browser/devtools/webconsole/test/browser_webconsole_bug_613280_jsterm_copy.js
new file mode 100644
index 000000000..d35559ab5
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_613280_jsterm_copy.js
@@ -0,0 +1,80 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ */
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 613280";
+
+function test() {
+ loadTab(TEST_URI).then(() => {
+ openConsole().then((HUD) => {
+ content.console.log("foobarBazBug613280");
+ waitForMessages({
+ webconsole: HUD,
+ messages: [{
+ text: "foobarBazBug613280",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ }).then(performTest.bind(null, HUD));
+ })
+ });
+}
+
+function performTest(HUD, [result]) {
+ let msg = [...result.matched][0];
+ let input = HUD.jsterm.inputNode;
+ let selection = getSelection();
+ let contentSelection = content.getSelection();
+
+ let clipboard_setup = function() {
+ goDoCommand("cmd_copy");
+ };
+
+ let clipboard_copy_done = function() {
+ finishTest();
+ };
+
+ // Check if we first need to clear any existing selections.
+ if (selection.rangeCount > 0 || contentSelection.rangeCount > 0 ||
+ input.selectionStart != input.selectionEnd) {
+ if (input.selectionStart != input.selectionEnd) {
+ input.selectionStart = input.selectionEnd = 0;
+ }
+
+ if (selection.rangeCount > 0) {
+ selection.removeAllRanges();
+ }
+
+ if (contentSelection.rangeCount > 0) {
+ contentSelection.removeAllRanges();
+ }
+
+ goUpdateCommand("cmd_copy");
+ }
+
+ let controller = top.document.commandDispatcher.
+ getControllerForCommand("cmd_copy");
+ is(controller.isCommandEnabled("cmd_copy"), false, "cmd_copy is disabled");
+
+ HUD.ui.output.selectMessage(msg);
+ HUD.outputNode.focus();
+
+ goUpdateCommand("cmd_copy");
+
+ controller = top.document.commandDispatcher.
+ getControllerForCommand("cmd_copy");
+ is(controller.isCommandEnabled("cmd_copy"), true, "cmd_copy is enabled");
+
+ // Remove new lines since getSelection() includes one between message and line
+ // number, but the clipboard doesn't (see bug 1119503)
+ let selectionText = (HUD.iframeWindow.getSelection() + "").replace(/\r?\n|\r/g, " ");
+ isnot(selectionText.indexOf("foobarBazBug613280"), -1,
+ "selection text includes 'foobarBazBug613280'");
+
+ waitForClipboard((str) => { return str.trim() == selectionText.trim(); },
+ clipboard_setup, clipboard_copy_done, clipboard_copy_done);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_613642_maintain_scroll.js b/browser/devtools/webconsole/test/browser_webconsole_bug_613642_maintain_scroll.js
new file mode 100644
index 000000000..c747ca0a8
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_613642_maintain_scroll.js
@@ -0,0 +1,116 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ */
+
+let TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 613642: remember scroll location";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ hud.jsterm.clearOutput();
+ let outputNode = hud.outputNode;
+ let scrollBox = outputNode.parentNode;
+
+ for (let i = 0; i < 150; i++) {
+ content.console.log("test message " + i);
+ }
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "test message 149",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ ok(scrollBox.scrollTop > 0, "scroll location is not at the top");
+
+ // scroll to the first node
+ outputNode.focus();
+
+ let scrolled = promise.defer();
+
+ scrollBox.onscroll = () => {
+ info("onscroll top " + scrollBox.scrollTop);
+ if (scrollBox.scrollTop != 0) {
+ // Wait for scroll to 0.
+ return;
+ }
+ scrollBox.onscroll = null;
+ is(scrollBox.scrollTop, 0, "scroll location updated (moved to top)");
+ scrolled.resolve();
+ };
+ EventUtils.synthesizeKey("VK_HOME", {}, hud.iframeWindow);
+
+ yield scrolled.promise;
+
+
+ // add a message and make sure scroll doesn't change
+ content.console.log("test message 150");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "test message 150",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ scrolled = promise.defer();
+ scrollBox.onscroll = () => {
+ if (scrollBox.scrollTop != 0) {
+ // Wait for scroll to stabilize at the top.
+ return;
+ }
+ scrollBox.onscroll = null;
+ is(scrollBox.scrollTop, 0, "scroll location is still at the top");
+ scrolled.resolve();
+ };
+
+ // Make sure that scroll stabilizes at the top. executeSoon() is needed for
+ // the yield to work.
+ executeSoon(scrollBox.onscroll);
+
+ yield scrolled.promise;
+
+ // scroll back to the bottom
+ outputNode.lastChild.focus();
+
+ scrolled = promise.defer();
+ scrollBox.onscroll = () => {
+ if (scrollBox.scrollTop == 0) {
+ // Wait for scroll to bottom.
+ return;
+ }
+ scrollBox.onscroll = null;
+ isnot(scrollBox.scrollTop, 0, "scroll location updated (moved to bottom)");
+ scrolled.resolve();
+ };
+ EventUtils.synthesizeKey("VK_END", {});
+ yield scrolled.promise;
+
+ let oldScrollTop = scrollBox.scrollTop;
+
+ content.console.log("test message 151");
+
+ scrolled = promise.defer();
+ scrollBox.onscroll = () => {
+ if (scrollBox.scrollTop == oldScrollTop) {
+ // Wait for scroll to change.
+ return;
+ }
+ scrollBox.onscroll = null;
+ isnot(scrollBox.scrollTop, oldScrollTop, "scroll location updated (moved to bottom again)");
+ scrolled.resolve();
+ };
+ yield scrolled.promise;
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_613642_prune_scroll.js b/browser/devtools/webconsole/test/browser_webconsole_bug_613642_prune_scroll.js
new file mode 100644
index 000000000..c11ca8878
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_613642_prune_scroll.js
@@ -0,0 +1,81 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ */
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 613642: maintain scroll with pruning of old messages";
+
+let hud;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ hud.jsterm.clearOutput();
+
+ let outputNode = hud.outputNode;
+
+ Services.prefs.setIntPref("devtools.hud.loglimit.console", 140);
+ let scrollBoxElement = outputNode.parentNode;
+
+ for (let i = 0; i < 150; i++) {
+ content.console.log("test message " + i);
+ }
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "test message 149",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ let oldScrollTop = scrollBoxElement.scrollTop;
+ isnot(oldScrollTop, 0, "scroll location is not at the top");
+
+ let firstNode = outputNode.firstChild;
+ ok(firstNode, "found the first message");
+
+ let msgNode = outputNode.children[80];
+ ok(msgNode, "found the 80th message");
+
+ // scroll to the middle message node
+ msgNode.scrollIntoView(false);
+
+ isnot(scrollBoxElement.scrollTop, oldScrollTop,
+ "scroll location updated (scrolled to message)");
+
+ oldScrollTop = scrollBoxElement.scrollTop;
+
+ // add a message
+ content.console.log("hello world");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "hello world",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ // Scroll location needs to change, because one message is also removed, and
+ // we need to scroll a bit towards the top, to keep the current view in sync.
+ isnot(scrollBoxElement.scrollTop, oldScrollTop,
+ "scroll location updated (added a message)");
+
+ isnot(outputNode.firstChild, firstNode,
+ "first message removed");
+
+ Services.prefs.clearUserPref("devtools.hud.loglimit.console");
+
+ hud = null;
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_614793_jsterm_scroll.js b/browser/devtools/webconsole/test/browser_webconsole_bug_614793_jsterm_scroll.js
new file mode 100644
index 000000000..05dcb76fa
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_614793_jsterm_scroll.js
@@ -0,0 +1,63 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ */
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 614793: jsterm result scroll";
+
+"use strict";
+
+let test = asyncTest(function* () {
+ let { browser } = yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ yield consoleOpened(hud);
+});
+
+function consoleOpened(hud) {
+ let deferred = promise.defer();
+
+ hud.jsterm.clearOutput();
+
+ let scrollNode = hud.outputNode.parentNode;
+
+ for (let i = 0; i < 150; i++) {
+ content.console.log("test message " + i);
+ }
+
+ let oldScrollTop = -1;
+
+ waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "test message 149",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ }).then(() => {
+ oldScrollTop = scrollNode.scrollTop;
+ isnot(oldScrollTop, 0, "scroll location is not at the top");
+
+ hud.jsterm.execute("'hello world'").then(onExecute);
+ });
+
+ function onExecute(msg)
+ {
+ isnot(scrollNode.scrollTop, oldScrollTop, "scroll location updated");
+
+ oldScrollTop = scrollNode.scrollTop;
+
+ msg.scrollIntoView(false);
+
+ is(scrollNode.scrollTop, oldScrollTop, "scroll location is the same");
+
+ deferred.resolve();
+ }
+
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_618078_network_exceptions.js b/browser/devtools/webconsole/test/browser_webconsole_bug_618078_network_exceptions.js
new file mode 100644
index 000000000..cb98e2c0d
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_618078_network_exceptions.js
@@ -0,0 +1,29 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that we report JS exceptions in event handlers coming from
+// network requests, like onreadystate for XHR. See bug 618078.
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 618078";
+const TEST_URI2 = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-618078-network-exceptions.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ expectUncaughtException();
+
+ content.location = TEST_URI2;
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "bug618078exception",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ }],
+ });
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_618311_close_panels.js b/browser/devtools/webconsole/test/browser_webconsole_bug_618311_close_panels.js
new file mode 100644
index 000000000..6d3c9e4e5
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_618311_close_panels.js
@@ -0,0 +1,90 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ BrowserReload();
+
+ let results = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "test-console.html",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ }],
+ })
+
+ yield performTest(hud, results);
+});
+
+
+function performTest(HUD, results) {
+ let deferred = promise.defer();
+
+ let networkMessage = [...results[0].matched][0];
+ ok(networkMessage, "network message element");
+
+ let networkLink = networkMessage.querySelector(".url");
+ ok(networkLink, "found network message link");
+
+ let popupset = document.getElementById("mainPopupSet");
+ ok(popupset, "found #mainPopupSet");
+
+ let popupsShown = 0;
+ let hiddenPopups = 0;
+
+ let onpopupshown = function() {
+ document.removeEventListener("popupshown", onpopupshown, false);
+ popupsShown++;
+
+ executeSoon(function() {
+ let popups = popupset.querySelectorAll("panel[hudId=" + HUD.hudId + "]");
+ is(popups.length, 1, "found one popup");
+
+ document.addEventListener("popuphidden", onpopuphidden, false);
+
+ registerCleanupFunction(function() {
+ is(hiddenPopups, 1, "correct number of popups hidden");
+ if (hiddenPopups != 1) {
+ document.removeEventListener("popuphidden", onpopuphidden, false);
+ }
+ });
+
+ executeSoon(closeConsole);
+ });
+ };
+
+ let onpopuphidden = function() {
+ document.removeEventListener("popuphidden", onpopuphidden, false);
+ hiddenPopups++;
+
+ executeSoon(function() {
+ let popups = popupset.querySelectorAll("panel[hudId=" + HUD.hudId + "]");
+ is(popups.length, 0, "no popups found");
+
+ executeSoon(deferred.resolve);
+ });
+ };
+
+ document.addEventListener("popupshown", onpopupshown, false);
+
+ registerCleanupFunction(function() {
+ is(popupsShown, 1, "correct number of popups shown");
+ if (popupsShown != 1) {
+ document.removeEventListener("popupshown", onpopupshown, false);
+ }
+ });
+
+ EventUtils.sendMouseEvent({ type: "mousedown" }, networkLink, HUD.iframeWindow);
+ EventUtils.sendMouseEvent({ type: "mouseup" }, networkLink, HUD.iframeWindow);
+ EventUtils.sendMouseEvent({ type: "click" }, networkLink, HUD.iframeWindow);
+
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_621644_jsterm_dollar.js b/browser/devtools/webconsole/test/browser_webconsole_bug_621644_jsterm_dollar.js
new file mode 100644
index 000000000..085887e69
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_621644_jsterm_dollar.js
@@ -0,0 +1,49 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Sucan <mihai.sucan@gmail.com>
+ */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-621644-jsterm-dollar.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ yield test$(hud);
+ yield test$$(hud);
+});
+
+
+function* test$(HUD) {
+ let deferred = promise.defer();
+
+ HUD.jsterm.clearOutput();
+
+ HUD.jsterm.execute("$(document.body)", (msg) => {
+ ok(msg.textContent.indexOf("<p>") > -1,
+ "jsterm output is correct for $()");
+ deferred.resolve();
+ });
+
+ return deferred.promise;
+}
+
+function test$$(HUD) {
+ let deferred = promise.defer();
+
+ HUD.jsterm.clearOutput();
+
+ HUD.jsterm.setInputValue();
+ HUD.jsterm.execute("$$(document)", (msg) => {
+ ok(msg.textContent.indexOf("621644") > -1,
+ "jsterm output is correct for $$()");
+ deferred.resolve();
+ });
+
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_622303_persistent_filters.js b/browser/devtools/webconsole/test/browser_webconsole_bug_622303_persistent_filters.js
new file mode 100644
index 000000000..80966a691
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_622303_persistent_filters.js
@@ -0,0 +1,139 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const prefs = {
+ "net": [
+ "network",
+ "netwarn",
+ "netxhr",
+ "networkinfo"
+ ],
+ "css": [
+ "csserror",
+ "cssparser",
+ "csslog"
+ ],
+ "js": [
+ "exception",
+ "jswarn",
+ "jslog",
+ ],
+ "logging": [
+ "error",
+ "warn",
+ "info",
+ "log"
+ ]
+};
+
+let test = asyncTest(function* () {
+ // Set all prefs to true
+ for (let category in prefs) {
+ prefs[category].forEach(function(pref) {
+ Services.prefs.setBoolPref("devtools.webconsole.filter." + pref, true);
+ });
+ }
+
+ yield loadTab("about:blank");
+
+ let hud = yield openConsole();
+
+ let hud2 = yield onConsoleOpen(hud);
+ let hud3 = yield onConsoleReopen1(hud2);
+ yield onConsoleReopen2(hud3);
+
+ // Clear prefs
+ for (let category in prefs) {
+ prefs[category].forEach(function(pref) {
+ Services.prefs.clearUserPref("devtools.webconsole.filter." + pref);
+ });
+ }
+});
+
+function onConsoleOpen(hud) {
+ let deferred = promise.defer();
+
+ let hudBox = hud.ui.rootElement;
+
+ // Check if the filters menuitems exists and are checked
+ for (let category in prefs) {
+ let button = hudBox.querySelector(".webconsole-filter-button[category=\""
+ + category + "\"]");
+ ok(isChecked(button), "main button for " + category + " category is checked");
+
+ prefs[category].forEach(function(pref) {
+ let menuitem = hudBox.querySelector("menuitem[prefKey=" + pref + "]");
+ ok(isChecked(menuitem), "menuitem for " + pref + " is checked");
+ });
+ }
+
+ // Set all prefs to false
+ for (let category in prefs) {
+ prefs[category].forEach(function(pref) {
+ hud.setFilterState(pref, false);
+ });
+ }
+
+ //Re-init the console
+ closeConsole().then(() => {
+ openConsole().then(deferred.resolve);
+ });
+
+ return deferred.promise;
+}
+
+function onConsoleReopen1(hud) {
+ info("testing after reopening once");
+ let deferred = promise.defer();
+
+ let hudBox = hud.ui.rootElement;
+
+ // Check if the filter button and menuitems are unchecked
+ for (let category in prefs) {
+ let button = hudBox.querySelector(".webconsole-filter-button[category=\""
+ + category + "\"]");
+ ok(isUnchecked(button), "main button for " + category + " category is not checked");
+
+ prefs[category].forEach(function(pref) {
+ let menuitem = hudBox.querySelector("menuitem[prefKey=" + pref + "]");
+ ok(isUnchecked(menuitem), "menuitem for " + pref + " is not checked");
+ });
+ }
+
+ // Set first pref in each category to true
+ for (let category in prefs) {
+ hud.setFilterState(prefs[category][0], true);
+ }
+
+ // Re-init the console
+ closeConsole().then(() => {
+ openConsole().then(deferred.resolve);
+ });
+
+ return deferred.promise;
+}
+
+function onConsoleReopen2(hud) {
+ info("testing after reopening again");
+
+ let hudBox = hud.ui.rootElement;
+
+ // Check the main category button is checked and first menuitem is checked
+ for (let category in prefs) {
+ let button = hudBox.querySelector(".webconsole-filter-button[category=\""
+ + category + "\"]");
+ ok(isChecked(button), category + " button is checked when first pref is true");
+
+ let pref = prefs[category][0];
+ let menuitem = hudBox.querySelector("menuitem[prefKey=" + pref + "]");
+ ok(isChecked(menuitem), "first " + category + " menuitem is checked");
+ }
+}
+
+function isChecked(aNode) {
+ return aNode.getAttribute("checked") === "true";
+}
+
+function isUnchecked(aNode) {
+ return aNode.getAttribute("checked") === "false";
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js b/browser/devtools/webconsole/test/browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js
new file mode 100644
index 000000000..84cd52c4a
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=623749
+// Map Control + A to Select All, In the web console input, on Windows
+
+const TEST_URI = "data:text/html;charset=utf-8,Test console for bug 623749";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ let jsterm = hud.jsterm;
+ jsterm.setInputValue("Ignore These Four Words");
+ let inputNode = jsterm.inputNode;
+
+ // Test select all with Control + A.
+ EventUtils.synthesizeKey("a", { ctrlKey: true });
+ let inputLength = inputNode.selectionEnd - inputNode.selectionStart;
+ is(inputLength, inputNode.value.length, "Select all of input");
+
+ // Test do nothing on Control + E.
+ jsterm.setInputValue("Ignore These Four Words");
+ inputNode.selectionStart = 0;
+ EventUtils.synthesizeKey("e", { ctrlKey: true });
+ is(inputNode.selectionStart, 0, "Control + E does not move to end of input");
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js b/browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js
new file mode 100644
index 000000000..88f771275
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js
@@ -0,0 +1,130 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Sucan <mihai.sucan@gmail.com>
+ */
+
+const TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for bug 630733";
+const TEST_URI2 = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-630733-response-redirect-headers.sjs";
+
+let lastFinishedRequests = {};
+let webConsoleClient;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ yield consoleOpened(hud);
+ yield getHeaders();
+ yield getContent();
+
+ performTest();
+});
+
+function consoleOpened(hud)
+{
+ let deferred = promise.defer();
+
+ webConsoleClient = hud.ui.webConsoleClient;
+ hud.ui.setSaveRequestAndResponseBodies(true).then(() => {
+ ok(hud.ui._saveRequestAndResponseBodies,
+ "The saveRequestAndResponseBodies property was successfully set.");
+
+ HUDService.lastFinishedRequest.callback = (aHttpRequest) => {
+ let status = aHttpRequest.response.status;
+ lastFinishedRequests[status] = aHttpRequest;
+ if ("301" in lastFinishedRequests &&
+ "404" in lastFinishedRequests) {
+ deferred.resolve();
+ }
+ }
+ content.location = TEST_URI2;
+ });
+
+ return deferred.promise;
+}
+
+function getHeaders()
+{
+ let deferred = promise.defer();
+
+ HUDService.lastFinishedRequest.callback = null;
+
+ ok("301" in lastFinishedRequests, "request 1: 301 Moved Permanently");
+ ok("404" in lastFinishedRequests, "request 2: 404 Not found");
+
+ webConsoleClient.getResponseHeaders(lastFinishedRequests["301"].actor,
+ function (aResponse) {
+ lastFinishedRequests["301"].response.headers = aResponse.headers;
+
+ webConsoleClient.getResponseHeaders(lastFinishedRequests["404"].actor,
+ function (aResponse) {
+ lastFinishedRequests["404"].response.headers = aResponse.headers;
+ executeSoon(deferred.resolve);
+ });
+ });
+ return deferred.promise;
+}
+
+function getContent()
+{
+ let deferred = promise.defer();
+
+ webConsoleClient.getResponseContent(lastFinishedRequests["301"].actor,
+ function (aResponse) {
+ lastFinishedRequests["301"].response.content = aResponse.content;
+ lastFinishedRequests["301"].discardResponseBody = aResponse.contentDiscarded;
+
+ webConsoleClient.getResponseContent(lastFinishedRequests["404"].actor,
+ function (aResponse) {
+ lastFinishedRequests["404"].response.content = aResponse.content;
+ lastFinishedRequests["404"].discardResponseBody =
+ aResponse.contentDiscarded;
+
+ webConsoleClient = null;
+ executeSoon(deferred.resolve);
+ });
+ });
+ return deferred.promise;
+}
+
+function performTest()
+{
+ function readHeader(aName)
+ {
+ for (let header of headers) {
+ if (header.name == aName) {
+ return header.value;
+ }
+ }
+ return null;
+ }
+
+ let headers = lastFinishedRequests["301"].response.headers;
+ is(readHeader("Content-Type"), "text/html",
+ "we do have the Content-Type header");
+ is(readHeader("Content-Length"), 71, "Content-Length is correct");
+ is(readHeader("Location"), "/redirect-from-bug-630733",
+ "Content-Length is correct");
+ is(readHeader("x-foobar-bug630733"), "bazbaz",
+ "X-Foobar-bug630733 is correct");
+
+ let body = lastFinishedRequests["301"].response.content;
+ ok(!body.text, "body discarded for request 1");
+ ok(lastFinishedRequests["301"].discardResponseBody,
+ "body discarded for request 1 (confirmed)");
+
+ headers = lastFinishedRequests["404"].response.headers;
+ ok(!readHeader("Location"), "no Location header");
+ ok(!readHeader("x-foobar-bug630733"), "no X-Foobar-bug630733 header");
+
+ body = lastFinishedRequests["404"].response.content.text;
+ isnot(body.indexOf("404"), -1,
+ "body is correct for request 2");
+
+ lastFinishedRequests = webConsoleClient = null;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_632275_getters_document_width.js b/browser/devtools/webconsole/test/browser_webconsole_bug_632275_getters_document_width.js
new file mode 100644
index 000000000..3ee086810
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_632275_getters_document_width.js
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-632275-getters.html";
+
+let getterValue = null;
+
+function test() {
+ loadTab(TEST_URI).then(() => {
+ openConsole().then(consoleOpened);
+ });
+}
+
+function consoleOpened(hud) {
+ let doc = content.wrappedJSObject.document;
+ getterValue = doc.foobar._val;
+ hud.jsterm.execute("console.dir(document)");
+
+ let onOpen = onViewOpened.bind(null, hud);
+ hud.jsterm.once("variablesview-fetched", onOpen);
+}
+
+function onViewOpened(hud, event, view)
+{
+ let doc = content.wrappedJSObject.document;
+
+ findVariableViewProperties(view, [
+ { name: /^(width|height)$/, dontMatch: 1 },
+ { name: "foobar._val", value: getterValue },
+ { name: "foobar.val", isGetter: true },
+ ], { webconsole: hud }).then(function() {
+ is(doc.foobar._val, getterValue, "getter did not execute");
+ is(doc.foobar.val, getterValue+1, "getter executed");
+ is(doc.foobar._val, getterValue+1, "getter executed (recheck)");
+
+ let textContent = hud.outputNode.textContent;
+ is(textContent.indexOf("document.body.client"), -1,
+ "no document.width/height warning displayed");
+
+ getterValue = null;
+ finishTest();
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js b/browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js
new file mode 100644
index 000000000..0410a6968
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js
@@ -0,0 +1,81 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-632347-iterators-generators.html";
+
+function test() {
+ requestLongerTimeout(6);
+
+ loadTab(TEST_URI).then(() => {
+ openConsole().then(consoleOpened);
+ });
+}
+
+function consoleOpened(HUD) {
+ let tools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
+ let JSPropertyProvider = tools.require("devtools/toolkit/webconsole/utils").JSPropertyProvider;
+
+ let tmp = Cu.import("resource://gre/modules/jsdebugger.jsm", {});
+ tmp.addDebuggerToGlobal(tmp);
+ let dbg = new tmp.Debugger;
+
+ let jsterm = HUD.jsterm;
+ let win = content.wrappedJSObject;
+ let dbgWindow = dbg.makeGlobalObjectReference(win);
+ let container = win._container;
+
+ // Make sure autocomplete does not walk through iterators and generators.
+ let result = container.gen1.next();
+ let completion = JSPropertyProvider(dbgWindow, null, "_container.gen1.");
+ isnot(completion.matches.length, 0, "Got matches for gen1");
+
+ is(result+1, container.gen1.next(), "gen1.next() did not execute");
+
+ result = container.gen2.next();
+
+ completion = JSPropertyProvider(dbgWindow, null, "_container.gen2.");
+ isnot(completion.matches.length, 0, "Got matches for gen2");
+
+ is((result/2+1)*2, container.gen2.next(),
+ "gen2.next() did not execute");
+
+ result = container.iter1.next();
+ is(result[0], "foo", "iter1.next() [0] is correct");
+ is(result[1], "bar", "iter1.next() [1] is correct");
+
+ completion = JSPropertyProvider(dbgWindow, null, "_container.iter1.");
+ isnot(completion.matches.length, 0, "Got matches for iter1");
+
+ result = container.iter1.next();
+ is(result[0], "baz", "iter1.next() [0] is correct");
+ is(result[1], "baaz", "iter1.next() [1] is correct");
+
+ let dbgContent = dbg.makeGlobalObjectReference(content);
+ completion = JSPropertyProvider(dbgContent, null, "_container.iter2.");
+ isnot(completion.matches.length, 0, "Got matches for iter2");
+
+ completion = JSPropertyProvider(dbgWindow, null, "window._container.");
+ ok(completion, "matches available for window._container");
+ ok(completion.matches.length, "matches available for window (length)");
+
+ jsterm.clearOutput();
+
+ jsterm.execute("window._container", (msg) => {
+ jsterm.once("variablesview-fetched", testVariablesView.bind(null, HUD));
+ let anchor = msg.querySelector(".message-body a");
+ EventUtils.synthesizeMouse(anchor, 2, 2, {}, HUD.iframeWindow);
+ });
+}
+
+function testVariablesView(aWebconsole, aEvent, aView) {
+ findVariableViewProperties(aView, [
+ { name: "gen1", isGenerator: true },
+ { name: "gen2", isGenerator: true },
+ { name: "iter1", isIterator: true },
+ { name: "iter2", isIterator: true },
+ ], { webconsole: aWebconsole }).then(function() {
+ executeSoon(finishTest);
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_632817.js b/browser/devtools/webconsole/test/browser_webconsole_bug_632817.js
new file mode 100644
index 000000000..d6dc79bbb
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_632817.js
@@ -0,0 +1,241 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that network log messages bring up the network panel.
+
+const TEST_NETWORK_REQUEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-network-request.html";
+
+const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/test/test-image.png";
+
+const TEST_DATA_JSON_CONTENT =
+ '{ id: "test JSON data", myArray: [ "foo", "bar", "baz", "biff" ] }';
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console network logging tests";
+
+let lastRequest = null;
+let requestCallback = null;
+let hud, browser;
+
+function test()
+{
+ const PREF = "devtools.webconsole.persistlog";
+ const NET_PREF = "devtools.webconsole.filter.networkinfo";
+ const NETXHR_PREF = "devtools.webconsole.filter.netxhr"
+ const MIXED_AC_PREF = "security.mixed_content.block_active_content"
+ let original = Services.prefs.getBoolPref(NET_PREF);
+ let originalXhr = Services.prefs.getBoolPref(NETXHR_PREF);
+ let originalMixedActive = Services.prefs.getBoolPref(MIXED_AC_PREF);
+ Services.prefs.setBoolPref(NET_PREF, true);
+ Services.prefs.setBoolPref(NETXHR_PREF, true);
+ Services.prefs.setBoolPref(MIXED_AC_PREF, false);
+ Services.prefs.setBoolPref(PREF, true);
+ registerCleanupFunction(() => {
+ Services.prefs.setBoolPref(NET_PREF, original);
+ Services.prefs.setBoolPref(NETXHR_PREF, originalXhr);
+ Services.prefs.setBoolPref(MIXED_AC_PREF, originalMixedActive);
+ Services.prefs.clearUserPref(PREF);
+ });
+
+ loadTab(TEST_URI).then((tab) => {
+ browser = tab.browser;
+ openConsole().then((aHud) => {
+ hud = aHud;
+
+ HUDService.lastFinishedRequest.callback = function(aRequest) {
+ lastRequest = aRequest;
+ if (requestCallback) {
+ requestCallback();
+ }
+ };
+
+ executeSoon(testPageLoad);
+ })
+ });
+}
+
+function testPageLoad()
+{
+ requestCallback = function() {
+ // Check if page load was logged correctly.
+ ok(lastRequest, "Page load was logged");
+ is(lastRequest.request.url, TEST_NETWORK_REQUEST_URI,
+ "Logged network entry is page load");
+ is(lastRequest.request.method, "GET", "Method is correct");
+ lastRequest = null;
+ requestCallback = null;
+ executeSoon(testPageLoadBody);
+ };
+
+ content.location = TEST_NETWORK_REQUEST_URI;
+}
+
+function testPageLoadBody()
+{
+ let loaded = false;
+ let requestCallbackInvoked = false;
+
+ // Turn off logging of request bodies and check again.
+ requestCallback = function() {
+ ok(lastRequest, "Page load was logged again");
+ lastRequest = null;
+ requestCallback = null;
+ requestCallbackInvoked = true;
+
+ if (loaded) {
+ executeSoon(testXhrGet);
+ }
+ };
+
+ browser.addEventListener("load", function onLoad() {
+ browser.removeEventListener("load", onLoad, true);
+ loaded = true;
+
+ if (requestCallbackInvoked) {
+ executeSoon(testXhrGet);
+ }
+ }, true);
+
+ content.location.reload();
+}
+
+function testXhrGet()
+{
+ requestCallback = function() {
+ ok(lastRequest, "testXhrGet() was logged");
+ is(lastRequest.request.method, "GET", "Method is correct");
+ lastRequest = null;
+ requestCallback = null;
+ executeSoon(testXhrWarn);
+ };
+
+ // Start the XMLHttpRequest() GET test.
+ content.wrappedJSObject.testXhrGet();
+}
+
+function testXhrWarn()
+{
+ requestCallback = function() {
+ ok(lastRequest, "testXhrWarn() was logged");
+ is(lastRequest.request.method, "GET", "Method is correct");
+ lastRequest = null;
+ requestCallback = null;
+ executeSoon(testXhrPost);
+ };
+
+ // Start the XMLHttpRequest() warn test.
+ content.wrappedJSObject.testXhrWarn();
+}
+
+function testXhrPost()
+{
+ requestCallback = function() {
+ ok(lastRequest, "testXhrPost() was logged");
+ is(lastRequest.request.method, "POST", "Method is correct");
+ lastRequest = null;
+ requestCallback = null;
+ executeSoon(testFormSubmission);
+ };
+
+ // Start the XMLHttpRequest() POST test.
+ content.wrappedJSObject.testXhrPost();
+}
+
+function testFormSubmission()
+{
+ // Start the form submission test. As the form is submitted, the page is
+ // loaded again. Bind to the load event to catch when this is done.
+ requestCallback = function() {
+ ok(lastRequest, "testFormSubmission() was logged");
+ is(lastRequest.request.method, "POST", "Method is correct");
+
+ // There should be 3 network requests pointing to the HTML file.
+ waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ text: "test-network-request.html",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ count: 3,
+ },
+ {
+ text: "test-data.json",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_INFO,
+ isXhr: true,
+ count: 2,
+ },
+ {
+ text: "http://example.com/",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_WARNING,
+ isXhr: true,
+ count: 1,
+ },
+ ],
+ }).then(testLiveFilteringOnSearchStrings);
+ };
+
+ let form = content.document.querySelector("form");
+ ok(form, "we have the HTML form");
+ form.submit();
+}
+
+function testLiveFilteringOnSearchStrings() {
+ setStringFilter("http");
+ isnot(countMessageNodes(), 0, "the log nodes are not hidden when the " +
+ "search string is set to \"http\"");
+
+ setStringFilter("HTTP");
+ isnot(countMessageNodes(), 0, "the log nodes are not hidden when the " +
+ "search string is set to \"HTTP\"");
+
+ setStringFilter("hxxp");
+ is(countMessageNodes(), 0, "the log nodes are hidden when the search " +
+ "string is set to \"hxxp\"");
+
+ setStringFilter("ht tp");
+ isnot(countMessageNodes(), 0, "the log nodes are not hidden when the " +
+ "search string is set to \"ht tp\"");
+
+ setStringFilter("");
+ isnot(countMessageNodes(), 0, "the log nodes are not hidden when the " +
+ "search string is removed");
+
+ setStringFilter("json");
+ is(countMessageNodes(), 2, "the log nodes show only the nodes with \"json\"");
+
+ setStringFilter("'foo'");
+ is(countMessageNodes(), 0, "the log nodes are hidden when searching for " +
+ "the string 'foo'");
+
+ setStringFilter("foo\"bar'baz\"boo'");
+ is(countMessageNodes(), 0, "the log nodes are hidden when searching for " +
+ "the string \"foo\"bar'baz\"boo'\"");
+
+ HUDService.lastFinishedRequest.callback = null;
+ lastRequest = null;
+ requestCallback = null;
+ hud = browser = null;
+ finishTest();
+}
+
+function countMessageNodes() {
+ let messageNodes = hud.outputNode.querySelectorAll(".message");
+ let displayedMessageNodes = 0;
+ let view = hud.iframeWindow;
+ for (let i = 0; i < messageNodes.length; i++) {
+ let computedStyle = view.getComputedStyle(messageNodes[i], null);
+ if (computedStyle.display !== "none")
+ displayedMessageNodes++;
+ }
+
+ return displayedMessageNodes;
+}
+
+function setStringFilter(aValue)
+{
+ hud.ui.filterBox.value = aValue;
+ hud.ui.adjustVisibilityOnSearchStringChange();
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_642108_pruneTest.js b/browser/devtools/webconsole/test/browser_webconsole_bug_642108_pruneTest.js
new file mode 100644
index 000000000..e269b3e99
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_642108_pruneTest.js
@@ -0,0 +1,80 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Tests that the Web Console limits the number of lines displayed according to
+// the user's preferences.
+
+const TEST_URI = "data:text/html;charset=utf-8,<p>test for bug 642108.";
+const LOG_LIMIT = 20;
+
+function test() {
+ let hud;
+
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ let {tab} = yield loadTab(TEST_URI);
+
+ Services.prefs.setIntPref("devtools.hud.loglimit.cssparser", LOG_LIMIT);
+ Services.prefs.setBoolPref("devtools.webconsole.filter.cssparser", true);
+
+ registerCleanupFunction(function() {
+ Services.prefs.clearUserPref("devtools.hud.loglimit.cssparser");
+ Services.prefs.clearUserPref("devtools.webconsole.filter.cssparser");
+ });
+
+ hud = yield openConsole(tab);
+
+ for (let i = 0; i < 5; i++) {
+ logCSSMessage("css log x");
+ }
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "css log x",
+ category: CATEGORY_CSS,
+ severity: SEVERITY_WARNING,
+ repeats: 5,
+ }],
+ });
+
+ for (let i = 0; i < LOG_LIMIT + 5; i++) {
+ logCSSMessage("css log " + i);
+ }
+
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "css log 5",
+ category: CATEGORY_CSS,
+ severity: SEVERITY_WARNING,
+ },
+ {
+ text: "css log 24", // LOG_LIMIT + 5
+ category: CATEGORY_CSS,
+ severity: SEVERITY_WARNING,
+ }],
+ });
+
+ is(hud.ui.outputNode.querySelectorAll(".message").length, LOG_LIMIT,
+ "number of messages");
+
+ is(Object.keys(hud.ui._repeatNodes).length, LOG_LIMIT,
+ "repeated nodes pruned from repeatNodes");
+
+ let msg = [...result.matched][0];
+ let repeats = msg.querySelector(".message-repeats");
+ is(repeats.getAttribute("value"), 1,
+ "repeated nodes pruned from repeatNodes (confirmed)");
+ }
+
+ function logCSSMessage(msg) {
+ let node = hud.ui.createMessageNode(CATEGORY_CSS, SEVERITY_WARNING, msg);
+ hud.ui.outputMessage(CATEGORY_CSS, node);
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_644419_log_limits.js b/browser/devtools/webconsole/test/browser_webconsole_bug_644419_log_limits.js
new file mode 100644
index 000000000..ac489ee42
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_644419_log_limits.js
@@ -0,0 +1,225 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that the Web Console limits the number of lines displayed according to
+// the limit set for each category.
+
+const INIT_URI = "data:text/html;charset=utf-8,Web Console test for bug 644419: Console should " +
+ "have user-settable log limits for each message category";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/" +
+ "webconsole/test/test-bug-644419-log-limits.html";
+
+let hud, outputNode;
+
+let test = asyncTest(function* () {
+ let { browser } = yield loadTab(INIT_URI);
+
+ hud = yield openConsole();
+
+ hud.jsterm.clearOutput();
+ outputNode = hud.outputNode;
+
+ let loaded = loadBrowser(browser);
+
+ expectUncaughtException();
+
+ content.location = TEST_URI;
+ yield loaded;
+
+ yield testWebDevLimits();
+ yield testWebDevLimits2();
+ yield testJsLimits();
+ yield testJsLimits2();
+
+ yield testNetLimits();
+ yield loadImage();
+ yield testCssLimits();
+ yield testCssLimits2();
+
+ hud = outputNode = null;
+});
+
+function testWebDevLimits() {
+ Services.prefs.setIntPref("devtools.hud.loglimit.console", 10);
+
+ // Find the sentinel entry.
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "bar is not defined",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ }],
+ })
+}
+
+function testWebDevLimits2() {
+ // Fill the log with Web Developer errors.
+ for (let i = 0; i < 11; i++) {
+ content.console.log("test message " + i);
+ }
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "test message 10",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ }).then(() => {
+ testLogEntry(outputNode, "test message 0", "first message is pruned", false, true);
+ findLogEntry("test message 1");
+ // Check if the sentinel entry is still there.
+ findLogEntry("bar is not defined");
+
+ Services.prefs.clearUserPref("devtools.hud.loglimit.console");
+ });
+}
+
+function testJsLimits() {
+ Services.prefs.setIntPref("devtools.hud.loglimit.exception", 10);
+
+ hud.jsterm.clearOutput();
+ content.console.log("testing JS limits");
+
+ // Find the sentinel entry.
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "testing JS limits",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+}
+
+function testJsLimits2() {
+ // Fill the log with JS errors.
+ let head = content.document.getElementsByTagName("head")[0];
+ for (let i = 0; i < 11; i++) {
+ var script = content.document.createElement("script");
+ script.text = "fubar" + i + ".bogus(6);";
+
+ expectUncaughtException();
+ head.insertBefore(script, head.firstChild);
+ }
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "fubar10 is not defined",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ }],
+ }).then(() => {
+ testLogEntry(outputNode, "fubar0 is not defined", "first message is pruned", false, true);
+ findLogEntry("fubar1 is not defined");
+ // Check if the sentinel entry is still there.
+ findLogEntry("testing JS limits");
+
+ Services.prefs.clearUserPref("devtools.hud.loglimit.exception");
+ });
+}
+
+var gCounter, gImage;
+
+function testNetLimits() {
+ Services.prefs.setIntPref("devtools.hud.loglimit.network", 10);
+
+ hud.jsterm.clearOutput();
+ content.console.log("testing Net limits");
+
+ // Find the sentinel entry.
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "testing Net limits",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ }).then(() => {
+ // Fill the log with network messages.
+ gCounter = 0;
+ });
+}
+
+function loadImage() {
+ if (gCounter < 11) {
+ let body = content.document.getElementsByTagName("body")[0];
+ gImage && gImage.removeEventListener("load", loadImage, true);
+ gImage = content.document.createElement("img");
+ gImage.src = "test-image.png?_fubar=" + gCounter;
+ body.insertBefore(gImage, body.firstChild);
+ gImage.addEventListener("load", loadImage, true);
+ gCounter++;
+ return;
+ }
+
+ is(gCounter, 11, "loaded 11 files");
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "test-image.png",
+ url: "test-image.png?_fubar=10",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ }],
+ }).then(() => {
+ let msgs = outputNode.querySelectorAll(".message[category=network]");
+ is(msgs.length, 10, "number of network messages");
+ isnot(msgs[0].url.indexOf("fubar=1"), -1, "first network message");
+ isnot(msgs[1].url.indexOf("fubar=2"), -1, "second network message");
+ findLogEntry("testing Net limits");
+
+ Services.prefs.clearUserPref("devtools.hud.loglimit.network");
+ });
+}
+
+function testCssLimits() {
+ Services.prefs.setIntPref("devtools.hud.loglimit.cssparser", 10);
+
+ hud.jsterm.clearOutput();
+ content.console.log("testing CSS limits");
+
+ // Find the sentinel entry.
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "testing CSS limits",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+}
+
+function testCssLimits2() {
+ // Fill the log with CSS errors.
+ let body = content.document.getElementsByTagName("body")[0];
+ for (let i = 0; i < 11; i++) {
+ var div = content.document.createElement("div");
+ div.setAttribute("style", "-moz-foobar" + i + ": 42;");
+ body.insertBefore(div, body.firstChild);
+ }
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "-moz-foobar10",
+ category: CATEGORY_CSS,
+ severity: SEVERITY_WARNING,
+ }],
+ }).then(() => {
+ testLogEntry(outputNode, "Unknown property '-moz-foobar0'",
+ "first message is pruned", false, true);
+ findLogEntry("Unknown property '-moz-foobar1'");
+ // Check if the sentinel entry is still there.
+ findLogEntry("testing CSS limits");
+
+ Services.prefs.clearUserPref("devtools.hud.loglimit.cssparser");
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_646025_console_file_location.js b/browser/devtools/webconsole/test/browser_webconsole_bug_646025_console_file_location.js
new file mode 100644
index 000000000..39be46e41
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_646025_console_file_location.js
@@ -0,0 +1,54 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that console logging methods display the method location along with
+// the output in the console.
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console file location display test";
+const TEST_URI2 = "http://example.com/browser/browser/devtools/" +
+ "webconsole/test/" +
+ "test-bug-646025-console-file-location.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ content.location = TEST_URI2;
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "message for level log",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ source: { url: "test-file-location.js", line: 5 },
+ },
+ {
+ text: "message for level info",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_INFO,
+ source: { url: "test-file-location.js", line: 6 },
+ },
+ {
+ text: "message for level warn",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_WARNING,
+ source: { url: "test-file-location.js", line: 7 },
+ },
+ {
+ text: "message for level error",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_ERROR,
+ source: { url: "test-file-location.js", line: 8 },
+ },
+ {
+ text: "message for level debug",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ source: { url: "test-file-location.js", line: 9 },
+ }],
+ });
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js b/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
new file mode 100644
index 000000000..9f2969214
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
@@ -0,0 +1,109 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that document.body autocompletes in the web console.
+const TEST_URI = "data:text/html;charset=utf-8,Web Console autocompletion bug in document.body";
+
+"use strict";
+
+let gHUD;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ gHUD = yield openConsole();
+
+ yield consoleOpened();
+ yield autocompletePopupHidden();
+ let view = yield testPropertyPanel();
+ yield onVariablesViewReady(view);
+
+ gHUD = null;
+});
+
+function consoleOpened(aHud) {
+ let deferred = promise.defer();
+
+ let jsterm = gHUD.jsterm;
+ let popup = jsterm.autocompletePopup;
+ let completeNode = jsterm.completeNode;
+
+ ok(!popup.isOpen, "popup is not open");
+
+ popup._panel.addEventListener("popupshown", function onShown() {
+ popup._panel.removeEventListener("popupshown", onShown, false);
+
+ ok(popup.isOpen, "popup is open");
+
+ is(popup.itemCount, jsterm._autocompleteCache.length,
+ "popup.itemCount is correct");
+ isnot(jsterm._autocompleteCache.indexOf("addEventListener"), -1,
+ "addEventListener is in the list of suggestions");
+ isnot(jsterm._autocompleteCache.indexOf("bgColor"), -1,
+ "bgColor is in the list of suggestions");
+ isnot(jsterm._autocompleteCache.indexOf("ATTRIBUTE_NODE"), -1,
+ "ATTRIBUTE_NODE is in the list of suggestions");
+
+ popup._panel.addEventListener("popuphidden", deferred.resolve, false);
+
+ EventUtils.synthesizeKey("VK_ESCAPE", {});
+ }, false);
+
+ jsterm.setInputValue("document.body");
+ EventUtils.synthesizeKey(".", {});
+
+ return deferred.promise;
+}
+
+function autocompletePopupHidden()
+{
+ let deferred = promise.defer();
+
+ let jsterm = gHUD.jsterm;
+ let popup = jsterm.autocompletePopup;
+ let completeNode = jsterm.completeNode;
+ let inputNode = jsterm.inputNode;
+
+ popup._panel.removeEventListener("popuphidden", autocompletePopupHidden, false);
+
+ ok(!popup.isOpen, "popup is not open");
+
+ jsterm.once("autocomplete-updated", function() {
+ is(completeNode.value, testStr + "dy", "autocomplete shows document.body");
+ deferred.resolve();
+ });
+
+ let inputStr = "document.b";
+ jsterm.setInputValue(inputStr);
+ EventUtils.synthesizeKey("o", {});
+ let testStr = inputStr.replace(/./g, " ") + " ";
+
+ return deferred.promise;
+}
+
+function testPropertyPanel()
+{
+ let deferred = promise.defer();
+
+ let jsterm = gHUD.jsterm;
+ jsterm.clearOutput();
+ jsterm.execute("document", (msg) => {
+ jsterm.once("variablesview-fetched", (aEvent, aView) => {
+ deferred.resolve(aView);
+ });
+ let anchor = msg.querySelector(".message-body a");
+ EventUtils.synthesizeMouse(anchor, 2, 2, {}, gHUD.iframeWindow);
+ });
+
+ return deferred.promise;
+}
+
+function onVariablesViewReady(aView)
+{
+ return findVariableViewProperties(aView, [
+ { name: "body", value: "<body>" },
+ ], { webconsole: gHUD });
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js b/browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js
new file mode 100644
index 000000000..a5191c831
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js
@@ -0,0 +1,107 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+// Tests that the $0 console helper works as intended.
+
+let inspector, h1, outputNode;
+
+function createDocument() {
+ let doc = content.document;
+ let div = doc.createElement("div");
+ h1 = doc.createElement("h1");
+ let p1 = doc.createElement("p");
+ let p2 = doc.createElement("p");
+ let div2 = doc.createElement("div");
+ let p3 = doc.createElement("p");
+ doc.title = "Inspector Tree Selection Test";
+ h1.textContent = "Inspector Tree Selection Test";
+ p1.textContent = "This is some example text";
+ p2.textContent = "Lorem ipsum dolor sit amet, consectetur adipisicing " +
+ "elit, sed do eiusmod tempor incididunt ut labore et dolore magna " +
+ "aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco " +
+ "laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure " +
+ "dolor in reprehenderit in voluptate velit esse cillum dolore eu " +
+ "fugiat nulla pariatur. Excepteur sint occaecat cupidatat non " +
+ "proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
+ p3.textContent = "Lorem ipsum dolor sit amet, consectetur adipisicing " +
+ "elit, sed do eiusmod tempor incididunt ut labore et dolore magna " +
+ "aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco " +
+ "laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure " +
+ "dolor in reprehenderit in voluptate velit esse cillum dolore eu " +
+ "fugiat nulla pariatur. Excepteur sint occaecat cupidatat non " +
+ "proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
+ div.appendChild(h1);
+ div.appendChild(p1);
+ div.appendChild(p2);
+ div2.appendChild(p3);
+ doc.body.appendChild(div);
+ doc.body.appendChild(div2);
+ setupHighlighterTests();
+}
+
+function setupHighlighterTests() {
+ ok(h1, "we have the header node");
+ openInspector().then(runSelectionTests);
+}
+
+let runSelectionTests = Task.async(function*(aInspector) {
+ inspector = aInspector;
+
+ let onPickerStarted = inspector.toolbox.once("picker-started");
+ inspector.toolbox.highlighterUtils.startPicker();
+ yield onPickerStarted;
+
+ info("Picker mode started, now clicking on H1 to select that node");
+ h1.scrollIntoView();
+ let onPickerStopped = inspector.toolbox.once("picker-stopped");
+ let onInspectorUpdated = inspector.once("inspector-updated");
+ EventUtils.synthesizeMouseAtCenter(h1, {}, content);
+ yield onPickerStopped;
+ yield onInspectorUpdated;
+
+ info("Picker mode stopped, H1 selected, now switching to the console");
+ let hud = yield openConsole(gBrowser.selectedTab);
+
+ performWebConsoleTests(hud);
+});
+
+function performWebConsoleTests(hud) {
+ let target = TargetFactory.forTab(gBrowser.selectedTab);
+ let jsterm = hud.jsterm;
+ outputNode = hud.outputNode;
+
+ jsterm.clearOutput();
+ jsterm.execute("$0", onNodeOutput);
+
+ function onNodeOutput(node) {
+ isnot(node.textContent.indexOf("<h1>"), -1, "correct output for $0");
+
+ jsterm.clearOutput();
+ jsterm.execute("$0.textContent = 'bug653531'", onNodeUpdate);
+ }
+
+ function onNodeUpdate(node) {
+ isnot(node.textContent.indexOf("bug653531"), -1,
+ "correct output for $0.textContent");
+ is(inspector.selection.node.textContent, "bug653531",
+ "node successfully updated");
+
+ inspector = h1 = outputNode = null;
+ gBrowser.removeCurrentTab();
+ finishTest();
+ }
+}
+
+function test() {
+ waitForExplicitFinish();
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
+ gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
+ waitForFocus(createDocument, content);
+ }, true);
+
+ content.location = "data:text/html;charset=utf-8,test for highlighter helper in web console";
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_658368_time_methods.js b/browser/devtools/webconsole/test/browser_webconsole_bug_658368_time_methods.js
new file mode 100644
index 000000000..8cb87324e
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_658368_time_methods.js
@@ -0,0 +1,66 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that the Console API implements the time() and timeEnd() methods.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" +
+ "test/test-bug-658368-time-methods.html";
+
+const TEST_URI2 = "data:text/html;charset=utf-8,<script>" +
+ "console.timeEnd('bTimer');</script>";
+
+const TEST_URI3 = "data:text/html;charset=utf-8,<script>" +
+ "console.time('bTimer');</script>";
+
+const TEST_URI4 = "data:text/html;charset=utf-8," +
+ "<script>console.timeEnd('bTimer');</script>";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud1 = yield openConsole();
+
+ yield waitForMessages({
+ webconsole: hud1,
+ messages: [{
+ name: "aTimer started",
+ consoleTime: "aTimer",
+ }, {
+ name: "aTimer end",
+ consoleTimeEnd: "aTimer",
+ }],
+ });
+
+ // The next test makes sure that timers with the same name but in separate
+ // tabs, do not contain the same value.
+ let { browser } = yield loadTab(TEST_URI2);
+ let hud2 = yield openConsole();
+
+ testLogEntry(hud2.outputNode, "bTimer: timer started",
+ "bTimer was not started", false, true);
+
+ // The next test makes sure that timers with the same name but in separate
+ // pages, do not contain the same value.
+ content.location = TEST_URI3;
+
+ yield waitForMessages({
+ webconsole: hud2,
+ messages: [{
+ name: "bTimer started",
+ consoleTime: "bTimer",
+ }],
+ });
+
+ hud2.jsterm.clearOutput();
+
+ // Now the following console.timeEnd() call shouldn't display anything,
+ // if the timers in different pages are not related.
+ content.location = TEST_URI4;
+ yield loadBrowser(browser);
+
+ testLogEntry(hud2.outputNode, "bTimer: timer started",
+ "bTimer was not started", false, true);
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_659907_console_dir.js b/browser/devtools/webconsole/test/browser_webconsole_bug_659907_console_dir.js
new file mode 100644
index 000000000..1569899a1
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_659907_console_dir.js
@@ -0,0 +1,28 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that console.dir works as intended.
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 659907: " +
+ "Expand console object with a dir method"
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ hud.jsterm.clearOutput();
+
+ hud.jsterm.execute("console.dir(document)");
+
+ let varView = yield hud.jsterm.once("variablesview-fetched");
+
+ yield findVariableViewProperties(varView, [
+ { name: "__proto__.__proto__.querySelectorAll", value: "querySelectorAll()" },
+ { name: "location", value: /Location \u2192 data:Web/ },
+ { name: "__proto__.write", value: "write()" },
+ ], { webconsole: hud });
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_660806_history_nav.js b/browser/devtools/webconsole/test/browser_webconsole_bug_660806_history_nav.js
new file mode 100644
index 000000000..2f057e4ca
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_660806_history_nav.js
@@ -0,0 +1,51 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_URI = "data:text/html;charset=utf-8,<p>bug 660806 - history navigation must not show the autocomplete popup";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ yield consoleOpened(hud);
+});
+
+function consoleOpened(HUD)
+{
+ let deferred = promise.defer();
+
+ let jsterm = HUD.jsterm;
+ let popup = jsterm.autocompletePopup;
+ let onShown = function() {
+ ok(false, "popup shown");
+ };
+
+ jsterm.execute("window.foobarBug660806 = {\
+ 'location': 'value0',\
+ 'locationbar': 'value1'\
+ }");
+
+ popup._panel.addEventListener("popupshown", onShown, false);
+
+ ok(!popup.isOpen, "popup is not open");
+
+ ok(!jsterm.lastInputValue, "no lastInputValue");
+ jsterm.setInputValue("window.foobarBug660806.location");
+ is(jsterm.lastInputValue, "window.foobarBug660806.location",
+ "lastInputValue is correct");
+
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ EventUtils.synthesizeKey("VK_UP", {});
+
+ is(jsterm.lastInputValue, "window.foobarBug660806.location",
+ "lastInputValue is correct, again");
+
+ executeSoon(function() {
+ ok(!popup.isOpen, "popup is not open");
+ popup._panel.removeEventListener("popupshown", onShown, false);
+ executeSoon(deferred.resolve);
+ });
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_664131_console_group.js b/browser/devtools/webconsole/test/browser_webconsole_bug_664131_console_group.js
new file mode 100644
index 000000000..ff719877c
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_664131_console_group.js
@@ -0,0 +1,77 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that console.group/groupEnd works as intended.
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 664131: Expand console object with group methods";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+ let jsterm = hud.jsterm;
+ let outputNode = hud.outputNode;
+
+ hud.jsterm.clearOutput();
+
+ yield jsterm.execute("console.group('bug664131a')")
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "bug664131a",
+ consoleGroup: 1,
+ }],
+ });
+
+ yield jsterm.execute("console.log('bug664131a-inside')")
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "bug664131a-inside",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ groupDepth: 1,
+ }],
+ });
+
+ yield jsterm.execute('console.groupEnd("bug664131a")');
+ yield jsterm.execute('console.log("bug664131-outside")');
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "bug664131-outside",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ groupDepth: 0,
+ }],
+ });
+
+ yield jsterm.execute('console.groupCollapsed("bug664131b")');
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "bug664131b",
+ consoleGroup: 1,
+ }],
+ });
+
+ // Test that clearing the console removes the indentation.
+ hud.jsterm.clearOutput();
+ yield jsterm.execute('console.log("bug664131-cleared")');
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "bug664131-cleared",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ groupDepth: 0,
+ }],
+ });
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_686937_autocomplete_JSTerm_helpers.js b/browser/devtools/webconsole/test/browser_webconsole_bug_686937_autocomplete_JSTerm_helpers.js
new file mode 100644
index 000000000..d2e45489d
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_686937_autocomplete_JSTerm_helpers.js
@@ -0,0 +1,60 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the autocompletion results contain the names of JSTerm helpers.
+
+const TEST_URI = "data:text/html;charset=utf8,<p>test JSTerm Helpers autocomplete";
+
+let jsterm;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ jsterm = hud.jsterm;
+ let input = jsterm.inputNode;
+ let popup = jsterm.autocompletePopup;
+
+ // Test if 'i' gives 'inspect'
+ input.value = "i";
+ input.setSelectionRange(1, 1);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ let newItems = popup.getItems().map(function(e) {return e.label;});
+ ok(newItems.indexOf("inspect") > -1, "autocomplete results contain helper 'inspect'");
+
+ // Test if 'window.' does not give 'inspect'.
+ input.value = "window.";
+ input.setSelectionRange(7, 7);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ newItems = popup.getItems().map(function(e) {return e.label;});
+ is(newItems.indexOf("inspect"), -1, "autocomplete results do not contain helper 'inspect'");
+
+ // Test if 'dump(i' gives 'inspect'
+ input.value = "dump(i";
+ input.setSelectionRange(6, 6);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ newItems = popup.getItems().map(function(e) {return e.label;});
+ ok(newItems.indexOf("inspect") > -1, "autocomplete results contain helper 'inspect'");
+
+ // Test if 'window.dump(i' gives 'inspect'
+ input.value = "window.dump(i";
+ input.setSelectionRange(13, 13);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ newItems = popup.getItems().map(function(e) {return e.label;});
+ ok(newItems.indexOf("inspect") > -1, "autocomplete results contain helper 'inspect'");
+
+ jsterm = null;
+});
+
+function complete(type) {
+ let updated = jsterm.once("autocomplete-updated");
+ jsterm.complete(type);
+ return updated;
+} \ No newline at end of file
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_704295.js b/browser/devtools/webconsole/test/browser_webconsole_bug_704295.js
new file mode 100644
index 000000000..14d4aeeab
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_704295.js
@@ -0,0 +1,39 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests for bug 704295
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ testCompletion(hud);
+});
+
+function testCompletion(hud) {
+ var jsterm = hud.jsterm;
+ var input = jsterm.inputNode;
+
+ // Test typing 'var d = 5;' and press RETURN
+ jsterm.setInputValue("var d = ");
+ EventUtils.synthesizeKey("5", {});
+ EventUtils.synthesizeKey(";", {});
+ is(input.value, "var d = 5;", "var d = 5;");
+ is(jsterm.completeNode.value, "", "no completion");
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ is(jsterm.completeNode.value, "", "clear completion on execute()");
+
+ // Test typing 'var a = d' and press RETURN
+ jsterm.setInputValue("var a = ");
+ EventUtils.synthesizeKey("d", {});
+ is(input.value, "var a = d", "var a = d");
+ is(jsterm.completeNode.value, "", "no completion");
+ EventUtils.synthesizeKey("VK_RETURN", {});
+ is(jsterm.completeNode.value, "", "clear completion on execute()");
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_734061_No_input_change_and_Tab_key_pressed.js b/browser/devtools/webconsole/test/browser_webconsole_bug_734061_No_input_change_and_Tab_key_pressed.js
new file mode 100644
index 000000000..9aff77a44
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_734061_No_input_change_and_Tab_key_pressed.js
@@ -0,0 +1,32 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/browser/test-console.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ var jsterm = hud.jsterm;
+ var input = jsterm.inputNode;
+
+ is(input.getAttribute("focused"), "true", "input has focus");
+ EventUtils.synthesizeKey("VK_TAB", {});
+ is(input.getAttribute("focused"), "", "focus moved away");
+
+ // Test user changed something
+ input.focus();
+ EventUtils.synthesizeKey("A", {});
+ EventUtils.synthesizeKey("VK_TAB", {});
+ is(input.getAttribute("focused"), "true", "input is still focused");
+
+ // Test non empty input but not changed since last focus
+ input.blur();
+ input.focus();
+ EventUtils.synthesizeKey("VK_RIGHT", {});
+ EventUtils.synthesizeKey("VK_TAB", {});
+ is(input.getAttribute("focused"), "", "input moved away");
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js b/browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js
new file mode 100644
index 000000000..bc2f70b37
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js
@@ -0,0 +1,60 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Tanvi Vyas <tanvi@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Tests that the Web Console Mixed Content messages are displayed
+
+const TEST_URI = "data:text/html;charset=utf8,Web Console mixed content test";
+const TEST_HTTPS_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html";
+const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Security/MixedContent";
+
+let test = asyncTest(function* () {
+ Services.prefs.setBoolPref("security.mixed_content.block_display_content", false);
+ Services.prefs.setBoolPref("security.mixed_content.block_active_content", false);
+
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ yield testMixedContent(hud);
+
+ Services.prefs.clearUserPref("security.mixed_content.block_display_content");
+ Services.prefs.clearUserPref("security.mixed_content.block_active_content");
+});
+
+let testMixedContent = Task.async(function*(hud) {
+ content.location = TEST_HTTPS_URI;
+
+ let results = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "example.com",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_WARNING,
+ }],
+ });
+
+ let msg = [...results[0].matched][0];
+ ok(msg, "page load logged");
+ ok(msg.classList.contains("mixed-content"), ".mixed-content element");
+
+ let link = msg.querySelector(".learn-more-link");
+ ok(link, "mixed content link element");
+ is(link.textContent, "[Mixed Content]", "link text is accurate");
+
+ yield simulateMessageLinkClick(link, LEARN_MORE_URI);
+
+ ok(!msg.classList.contains("filtered-by-type"), "message is not filtered");
+
+ hud.setFilterState("netwarn", false);
+
+ ok(msg.classList.contains("filtered-by-type"), "message is filtered");
+
+ hud.setFilterState("netwarn", true);
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_752559_ineffective_iframe_sandbox_warning.js b/browser/devtools/webconsole/test/browser_webconsole_bug_752559_ineffective_iframe_sandbox_warning.js
new file mode 100644
index 000000000..fac6f2cc2
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_752559_ineffective_iframe_sandbox_warning.js
@@ -0,0 +1,73 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that warnings about ineffective iframe sandboxing are logged to the
+// web console when necessary (and not otherwise).
+
+const TEST_URI_WARNING = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning0.html";
+const TEST_URI_NOWARNING = [
+ "http://example.com/browser/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning1.html",
+ "http://example.com/browser/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning2.html",
+ "http://example.com/browser/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning3.html",
+ "http://example.com/browser/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning4.html",
+ "http://example.com/browser/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning5.html"
+];
+
+const INEFFECTIVE_IFRAME_SANDBOXING_MSG = "An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can remove its sandboxing.";
+const SENTINEL_MSG = "testing ineffective sandboxing message";
+
+function test()
+{
+ loadTab(TEST_URI_WARNING).then(() => {
+ openConsole().then((hud) => {
+ content.console.log(SENTINEL_MSG)
+ waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "Ineffective iframe sandboxing warning displayed successfully",
+ text: INEFFECTIVE_IFRAME_SANDBOXING_MSG,
+ category: CATEGORY_SECURITY,
+ severity: SEVERITY_WARNING
+ },
+ {
+ text: SENTINEL_MSG,
+ severity: SEVERITY_LOG
+ }
+ ]
+ }).then(() => {
+ let msgs = hud.outputNode.querySelectorAll(".message[category=security]");
+ is(msgs.length, 1, "one security message");
+ testNoWarning(0);
+ });
+ })
+ });
+}
+
+function testNoWarning(id)
+{
+ loadTab(TEST_URI_NOWARNING[id]).then(() => {
+ openConsole().then((hud) => {
+ content.console.log(SENTINEL_MSG)
+ waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ text: SENTINEL_MSG,
+ severity: SEVERITY_LOG
+ }
+ ]
+ }).then(() => {
+ let msgs = hud.outputNode.querySelectorAll(".message[category=security]");
+ is(msgs.length, 0, "no security messages (case " + id + ")");
+
+ id += 1;
+ if (id < TEST_URI_NOWARNING.length) {
+ testNoWarning(id);
+ } else {
+ finishTest();
+ }
+ });
+ })
+ });
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_about_blank_web_console_warning.js b/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_about_blank_web_console_warning.js
new file mode 100644
index 000000000..d0322f6e9
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_about_blank_web_console_warning.js
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+/*
+ * Tests that errors about insecure passwords are logged
+ * to the web console
+ */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-762593-insecure-passwords-about-blank-web-console-warning.html";
+const INSECURE_PASSWORD_MSG = "Password fields present on an insecure (http://) page. This is a security risk that allows user login credentials to be stolen.";
+
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "Insecure password error displayed successfully",
+ text: INSECURE_PASSWORD_MSG,
+ category: CATEGORY_SECURITY,
+ severity: SEVERITY_WARNING
+ },
+ ],
+ });
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_web_console_warning.js b/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_web_console_warning.js
new file mode 100644
index 000000000..428add7d2
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_web_console_warning.js
@@ -0,0 +1,51 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+/*
+ * Tests that errors about insecure passwords are logged
+ * to the web console
+ */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-762593-insecure-passwords-web-console-warning.html";
+const INSECURE_PASSWORD_MSG = "Password fields present on an insecure (http://) page. This is a security risk that allows user login credentials to be stolen.";
+const INSECURE_FORM_ACTION_MSG = "Password fields present in a form with an insecure (http://) form action. This is a security risk that allows user login credentials to be stolen.";
+const INSECURE_IFRAME_MSG = "Password fields present on an insecure (http://) iframe. This is a security risk that allows user login credentials to be stolen.";
+const INSECURE_PASSWORDS_URI = "https://developer.mozilla.org/docs/Security/InsecurePasswords";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ let result = yield waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "Insecure password error displayed successfully",
+ text: INSECURE_PASSWORD_MSG,
+ category: CATEGORY_SECURITY,
+ severity: SEVERITY_WARNING
+ },
+ {
+ name: "Insecure iframe error displayed successfully",
+ text: INSECURE_IFRAME_MSG,
+ category: CATEGORY_SECURITY,
+ severity: SEVERITY_WARNING
+ },
+ {
+ name: "Insecure form action error displayed successfully",
+ text: INSECURE_FORM_ACTION_MSG,
+ category: CATEGORY_SECURITY,
+ severity: SEVERITY_WARNING
+ },
+ ],
+ });
+
+ yield testClickOpenNewTab(hud, result);
+});
+
+function testClickOpenNewTab(hud, [result]) {
+ let msg = [...result.matched][0];
+ let warningNode = msg.querySelector(".learn-more-link");
+ ok(warningNode, "learn more link");
+ return simulateMessageLinkClick(warningNode, INSECURE_PASSWORDS_URI);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_764572_output_open_url.js b/browser/devtools/webconsole/test/browser_webconsole_bug_764572_output_open_url.js
new file mode 100644
index 000000000..2517c8e94
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_764572_output_open_url.js
@@ -0,0 +1,137 @@
+/* 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/. */
+
+// This is a test for the Open URL context menu item
+// that is shown for network requests
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"
+const COMMAND_NAME = "consoleCmd_openURL";
+const CONTEXT_MENU_ID = "#menu_openURL";
+
+let HUD = null, outputNode = null, contextMenu = null;
+
+let test = asyncTest(function* () {
+ Services.prefs.setBoolPref("devtools.webconsole.filter.networkinfo", true);
+
+ yield loadTab(TEST_URI);
+ HUD = yield openConsole();
+
+ let results = yield consoleOpened();
+ yield onConsoleMessage(results);
+
+ let results2 = yield testOnNetActivity();
+ let msg = yield onNetworkMessage(results2);
+
+ yield testOnNetActivity_contextmenu(msg);
+
+ Services.prefs.clearUserPref("devtools.webconsole.filter.networkinfo");
+
+ HUD = null, outputNode = null, contextMenu = null;
+});
+
+function consoleOpened() {
+ outputNode = HUD.outputNode;
+ contextMenu = HUD.iframeWindow.document.getElementById("output-contextmenu");
+
+ HUD.jsterm.clearOutput();
+
+ content.console.log("bug 764572");
+
+ return waitForMessages({
+ webconsole: HUD,
+ messages: [{
+ text: "bug 764572",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+}
+
+function onConsoleMessage(aResults) {
+ outputNode.focus();
+ outputNode.selectedItem = [...aResults[0].matched][0];
+
+ // Check if the command is disabled non-network messages.
+ goUpdateCommand(COMMAND_NAME);
+ let controller = top.document.commandDispatcher
+ .getControllerForCommand(COMMAND_NAME);
+
+ let isDisabled = !controller || !controller.isCommandEnabled(COMMAND_NAME);
+ ok(isDisabled, COMMAND_NAME + " should be disabled.");
+
+ outputNode.selectedItem.scrollIntoView();
+ return waitForContextMenu(contextMenu, outputNode.selectedItem, () => {
+ let isHidden = contextMenu.querySelector(CONTEXT_MENU_ID).hidden;
+ ok(isHidden, CONTEXT_MENU_ID + " should be hidden.");
+ });
+}
+
+function testOnNetActivity() {
+ HUD.jsterm.clearOutput();
+
+ // Reload the url to show net activity in console.
+ content.location.reload();
+
+ return waitForMessages({
+ webconsole: HUD,
+ messages: [{
+ text: "test-console.html",
+ category: CATEGORY_NETWORK,
+ severity: SEVERITY_LOG,
+ }],
+ });
+}
+
+function onNetworkMessage(aResults) {
+ let deferred = promise.defer();
+
+ outputNode.focus();
+ let msg = [...aResults[0].matched][0];
+ ok(msg, "network message");
+ HUD.ui.output.selectMessage(msg);
+
+ let currentTab = gBrowser.selectedTab;
+ let newTab = null;
+
+ gBrowser.tabContainer.addEventListener("TabOpen", function onOpen(aEvent) {
+ gBrowser.tabContainer.removeEventListener("TabOpen", onOpen, true);
+ newTab = aEvent.target;
+ newTab.linkedBrowser.addEventListener("load", onTabLoaded, true);
+ }, true);
+
+ function onTabLoaded() {
+ newTab.linkedBrowser.removeEventListener("load", onTabLoaded, true);
+ gBrowser.removeTab(newTab);
+ gBrowser.selectedTab = currentTab;
+ executeSoon(deferred.resolve.bind(null, msg));
+ }
+
+ // Check if the command is enabled for a network message.
+ goUpdateCommand(COMMAND_NAME);
+ let controller = top.document.commandDispatcher
+ .getControllerForCommand(COMMAND_NAME);
+ ok(controller.isCommandEnabled(COMMAND_NAME),
+ COMMAND_NAME + " should be enabled.");
+
+ // Try to open the URL.
+ goDoCommand(COMMAND_NAME);
+
+ return deferred.promise;
+}
+
+function testOnNetActivity_contextmenu(msg) {
+ let deferred = promise.defer();
+
+ outputNode.focus();
+ HUD.ui.output.selectMessage(msg);
+ msg.scrollIntoView();
+
+ info("net activity context menu");
+
+ waitForContextMenu(contextMenu, msg, () => {
+ let isShown = !contextMenu.querySelector(CONTEXT_MENU_ID).hidden;
+ ok(isShown, CONTEXT_MENU_ID + " should be shown.");
+ }).then(deferred.resolve);
+
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_766001_JS_Console_in_Debugger.js b/browser/devtools/webconsole/test/browser_webconsole_bug_766001_JS_Console_in_Debugger.js
new file mode 100644
index 000000000..05580a7c3
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_766001_JS_Console_in_Debugger.js
@@ -0,0 +1,78 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that message source links for js errors and console API calls open in
+// the jsdebugger when clicked.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test" +
+ "/test-bug-766001-js-console-links.html";
+
+function test() {
+ let hud;
+
+ requestLongerTimeout(2);
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ expectUncaughtException();
+
+ let {tab} = yield loadTab(TEST_URI);
+ hud = yield openConsole(tab);
+
+ let [exceptionRule, consoleRule] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "document.bar",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ },
+ {
+ text: "Blah Blah",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ let exceptionMsg = [...exceptionRule.matched][0];
+ let consoleMsg = [...consoleRule.matched][0];
+ let nodes = [exceptionMsg.querySelector(".message-location"),
+ consoleMsg.querySelector(".message-location")];
+ ok(nodes[0], ".location node for the exception message");
+ ok(nodes[1], ".location node for the console message");
+
+ for (let i = 0; i < nodes.length; i++) {
+ yield checkClickOnNode(i, nodes[i]);
+ yield gDevTools.showToolbox(hud.target, "webconsole");
+ }
+
+ // check again the first node.
+ yield checkClickOnNode(0, nodes[0]);
+ }
+
+ function* checkClickOnNode(index, node) {
+ info("checking click on node index " + index);
+
+ let url = node.getAttribute("title");
+ ok(url, "source url found for index " + index);
+
+ let line = node.sourceLine;
+ ok(line, "found source line for index " + index);
+
+ executeSoon(() => {
+ EventUtils.sendMouseEvent({ type: "click" }, node);
+ });
+
+ yield hud.ui.once("source-in-debugger-opened");
+
+ let toolbox = yield gDevTools.getToolbox(hud.target);
+ let {panelWin: { DebuggerView: view }} = toolbox.getPanel("jsdebugger");
+ is(view.Sources.selectedValue,
+ getSourceActor(view.Sources, url),
+ "expected source url");
+ is(view.editor.getCursor().line, line - 1, "expected source line");
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js b/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js
new file mode 100644
index 000000000..6c0400492
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js
@@ -0,0 +1,31 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Tests that the Web Console CSP messages are displayed
+
+const TEST_URI = "data:text/html;charset=utf8,Web Console CSP violation test";
+const TEST_VIOLATION = "https://example.com/browser/browser/devtools/webconsole/test/test_bug_770099_violation.html";
+const CSP_VIOLATION_MSG = 'Content Security Policy: The page\'s settings blocked the loading of a resource at http://some.example.com/test.png ("default-src https://example.com").'
+
+let test = asyncTest(function* () {
+ let { browser } = yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ hud.jsterm.clearOutput();
+
+ let loaded = loadBrowser(browser);
+ content.location = TEST_VIOLATION;
+ yield loaded;
+
+ yield waitForSuccess({
+ name: "CSP policy URI warning displayed successfully",
+ validator: function() {
+ return hud.outputNode.textContent.indexOf(CSP_VIOLATION_MSG) > -1;
+ }
+ });
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js b/browser/devtools/webconsole/test/browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js
new file mode 100644
index 000000000..6cc5172c5
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js
@@ -0,0 +1,147 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test" +
+ "/test-bug-782653-css-errors.html";
+
+let nodes, hud, StyleEditorUI;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ hud = yield openConsole();
+
+ let styleEditor = yield testViewSource();
+ yield onStyleEditorReady(styleEditor);
+
+ nodes = hud = StyleEditorUI = null;
+});
+
+function testViewSource()
+{
+ let deferred = promise.defer();
+
+ waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "'font-weight'",
+ category: CATEGORY_CSS,
+ severity: SEVERITY_WARNING,
+ },
+ {
+ text: "'color'",
+ category: CATEGORY_CSS,
+ severity: SEVERITY_WARNING,
+ }],
+ }).then(([error1Rule, error2Rule]) => {
+ let error1Msg = [...error1Rule.matched][0];
+ let error2Msg = [...error2Rule.matched][0];
+ nodes = [error1Msg.querySelector(".message-location"),
+ error2Msg.querySelector(".message-location")];
+ ok(nodes[0], ".message-location node for the first error");
+ ok(nodes[1], ".message-location node for the second error");
+
+ let target = TargetFactory.forTab(gBrowser.selectedTab);
+ let toolbox = gDevTools.getToolbox(target);
+ toolbox.once("styleeditor-selected", (event, panel) => {
+ StyleEditorUI = panel.UI;
+
+ let count = 0;
+ StyleEditorUI.on("editor-added", function() {
+ if (++count == 2) {
+ deferred.resolve(panel);
+ }
+ });
+ });
+
+ EventUtils.sendMouseEvent({ type: "click" }, nodes[0]);
+ });
+
+ return deferred.promise;
+}
+
+function onStyleEditorReady(aPanel)
+{
+ let deferred = promise.defer();
+
+ let win = aPanel.panelWindow;
+ ok(win, "Style Editor Window is defined");
+ ok(StyleEditorUI, "Style Editor UI is defined");
+
+ waitForFocus(function() {
+ info("style editor window focused");
+
+ let href = nodes[0].getAttribute("title");
+ let line = nodes[0].sourceLine;
+ ok(line, "found source line");
+
+ checkStyleEditorForSheetAndLine(href, line - 1).then(function() {
+ info("first check done");
+
+ let target = TargetFactory.forTab(gBrowser.selectedTab);
+ let toolbox = gDevTools.getToolbox(target);
+
+ let href = nodes[1].getAttribute("title");
+ let line = nodes[1].sourceLine;
+ ok(line, "found source line");
+
+ toolbox.selectTool("webconsole").then(function() {
+ info("webconsole selected");
+
+ toolbox.once("styleeditor-selected", function(aEvent) {
+ info(aEvent + " event fired");
+
+ checkStyleEditorForSheetAndLine(href, line - 1).then(deferred.resolve);
+ });
+
+ EventUtils.sendMouseEvent({ type: "click" }, nodes[1]);
+ });
+ });
+ }, win);
+
+ return deferred.promise;
+}
+
+function checkStyleEditorForSheetAndLine(aHref, aLine)
+{
+ let foundEditor = null;
+ for (let editor of StyleEditorUI.editors) {
+ if (editor.styleSheet.href == aHref) {
+ foundEditor = editor;
+ break;
+ }
+ }
+
+ ok(foundEditor, "found style editor for " + aHref);
+ return performLineCheck(foundEditor, aLine);
+}
+
+function performLineCheck(aEditor, aLine)
+{
+ let deferred = promise.defer();
+
+ function checkForCorrectState()
+ {
+ is(aEditor.sourceEditor.getCursor().line, aLine,
+ "correct line is selected");
+ is(StyleEditorUI.selectedStyleSheetIndex, aEditor.styleSheet.styleSheetIndex,
+ "correct stylesheet is selected in the editor");
+
+ executeSoon(deferred.resolve);
+ }
+
+ info("wait for source editor to load");
+
+ // Get out of the styleeditor-selected event loop.
+ executeSoon(() => {
+ aEditor.getSourceEditor().then(() => {
+ // Get out of the editor's source-editor-load event loop.
+ executeSoon(checkForCorrectState);
+ });
+ });
+
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_804845_ctrl_key_nav.js b/browser/devtools/webconsole/test/browser_webconsole_bug_804845_ctrl_key_nav.js
new file mode 100644
index 000000000..f6a66572f
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_804845_ctrl_key_nav.js
@@ -0,0 +1,217 @@
+/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * zmgmoz <zmgmoz@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Test navigation of webconsole contents via ctrl-a, ctrl-e, ctrl-p, ctrl-n
+// see https://bugzilla.mozilla.org/show_bug.cgi?id=804845
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 804845 and bug 619598";
+
+let jsterm, inputNode;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ doTests(hud);
+
+ jsterm = inputNode = null;
+});
+
+function doTests(HUD) {
+ jsterm = HUD.jsterm;
+ inputNode = jsterm.inputNode;
+ ok(!jsterm.inputNode.value, "inputNode.value is empty");
+ is(jsterm.inputNode.selectionStart, 0);
+ is(jsterm.inputNode.selectionEnd, 0);
+
+ testSingleLineInputNavNoHistory();
+ testMultiLineInputNavNoHistory();
+ testNavWithHistory();
+}
+
+function testSingleLineInputNavNoHistory() {
+ // Single char input
+ EventUtils.synthesizeKey("1", {});
+ is(inputNode.selectionStart, 1, "caret location after single char input");
+
+ // nav to start/end with ctrl-a and ctrl-e;
+ EventUtils.synthesizeKey("a", { ctrlKey: true });
+ is(inputNode.selectionStart, 0, "caret location after single char input and ctrl-a");
+
+ EventUtils.synthesizeKey("e", { ctrlKey: true });
+ is(inputNode.selectionStart, 1, "caret location after single char input and ctrl-e");
+
+ // Second char input
+ EventUtils.synthesizeKey("2", {});
+ // nav to start/end with up/down keys; verify behaviour using ctrl-p/ctrl-n
+ EventUtils.synthesizeKey("VK_UP", {});
+ is(inputNode.selectionStart, 0, "caret location after two char input and VK_UP");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ is(inputNode.selectionStart, 2, "caret location after two char input and VK_DOWN");
+
+ EventUtils.synthesizeKey("a", { ctrlKey: true });
+ is(inputNode.selectionStart, 0, "move caret to beginning of 2 char input with ctrl-a");
+ EventUtils.synthesizeKey("a", { ctrlKey: true });
+ is(inputNode.selectionStart, 0, "no change of caret location on repeat ctrl-a");
+ EventUtils.synthesizeKey("p", { ctrlKey: true });
+ is(inputNode.selectionStart, 0, "no change of caret location on ctrl-p from beginning of line");
+
+ EventUtils.synthesizeKey("e", { ctrlKey: true });
+ is(inputNode.selectionStart, 2, "move caret to end of 2 char input with ctrl-e");
+ EventUtils.synthesizeKey("e", { ctrlKey: true });
+ is(inputNode.selectionStart, 2, "no change of caret location on repeat ctrl-e");
+ EventUtils.synthesizeKey("n", { ctrlKey: true });
+ is(inputNode.selectionStart, 2, "no change of caret location on ctrl-n from end of line");
+
+ EventUtils.synthesizeKey("p", { ctrlKey: true });
+ is(inputNode.selectionStart, 0, "ctrl-p moves to start of line");
+
+ EventUtils.synthesizeKey("n", { ctrlKey: true });
+ is(inputNode.selectionStart, 2, "ctrl-n moves to end of line");
+}
+
+function testMultiLineInputNavNoHistory() {
+ let lineValues = ["one", "2", "something longer", "", "", "three!"];
+ jsterm.setInputValue("");
+ // simulate shift-return
+ for (let i = 0; i < lineValues.length; i++) {
+ jsterm.setInputValue(inputNode.value + lineValues[i]);
+ EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true });
+ }
+ let inputValue = inputNode.value;
+ is(inputNode.selectionStart, inputNode.selectionEnd);
+ is(inputNode.selectionStart, inputValue.length, "caret at end of multiline input");
+
+ // possibility newline is represented by one ('\r', '\n') or two ('\r\n') chars
+ let newlineString = inputValue.match(/(\r\n?|\n\r?)$/)[0];
+
+ // Ok, test navigating within the multi-line string!
+ EventUtils.synthesizeKey("VK_UP", {});
+ let expectedStringAfterCarat = lineValues[5]+newlineString;
+ is(inputNode.value.slice(inputNode.selectionStart), expectedStringAfterCarat,
+ "up arrow from end of multiline");
+
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ is(inputNode.value.slice(inputNode.selectionStart), "",
+ "down arrow from within multiline");
+
+ // navigate up through input lines
+ EventUtils.synthesizeKey("p", { ctrlKey: true });
+ is(inputNode.value.slice(inputNode.selectionStart), expectedStringAfterCarat,
+ "ctrl-p from end of multiline");
+
+ for (let i = 4; i >= 0; i--) {
+ EventUtils.synthesizeKey("p", { ctrlKey: true });
+ expectedStringAfterCarat = lineValues[i] + newlineString + expectedStringAfterCarat;
+ is(inputNode.value.slice(inputNode.selectionStart), expectedStringAfterCarat,
+ "ctrl-p from within line " + i + " of multiline input");
+ }
+ EventUtils.synthesizeKey("p", { ctrlKey: true });
+ is(inputNode.selectionStart, 0, "reached start of input");
+ is(inputNode.value, inputValue,
+ "no change to multiline input on ctrl-p from beginning of multiline");
+
+ // navigate to end of first line
+ EventUtils.synthesizeKey("e", { ctrlKey: true });
+ let caretPos = inputNode.selectionStart;
+ let expectedStringBeforeCarat = lineValues[0];
+ is(inputNode.value.slice(0, caretPos), expectedStringBeforeCarat,
+ "ctrl-e into multiline input");
+ EventUtils.synthesizeKey("e", { ctrlKey: true });
+ is(inputNode.selectionStart, caretPos,
+ "repeat ctrl-e doesn't change caret position in multiline input");
+
+ // navigate down one line; ctrl-a to the beginning; ctrl-e to end
+ for (let i = 1; i < lineValues.length; i++) {
+ EventUtils.synthesizeKey("n", { ctrlKey: true });
+ EventUtils.synthesizeKey("a", { ctrlKey: true });
+ caretPos = inputNode.selectionStart;
+ expectedStringBeforeCarat += newlineString;
+ is(inputNode.value.slice(0, caretPos), expectedStringBeforeCarat,
+ "ctrl-a to beginning of line " + (i+1) + " in multiline input");
+
+ EventUtils.synthesizeKey("e", { ctrlKey: true });
+ caretPos = inputNode.selectionStart;
+ expectedStringBeforeCarat += lineValues[i];
+ is(inputNode.value.slice(0, caretPos), expectedStringBeforeCarat,
+ "ctrl-e to end of line " + (i+1) + "in multiline input");
+ }
+}
+
+function testNavWithHistory() {
+ // NOTE: Tests does NOT currently define behaviour for ctrl-p/ctrl-n with
+ // caret placed _within_ single line input
+ let values = ['"single line input"',
+ '"a longer single-line input to check caret repositioning"',
+ ['"multi-line"', '"input"', '"here!"'].join("\n"),
+ ];
+ // submit to history
+ for (let i = 0; i < values.length; i++) {
+ jsterm.setInputValue(values[i]);
+ jsterm.execute();
+ }
+ is(inputNode.selectionStart, 0, "caret location at start of empty line");
+
+ EventUtils.synthesizeKey("p", { ctrlKey: true });
+ is(inputNode.selectionStart, values[values.length-1].length,
+ "caret location correct at end of last history input");
+
+ // Navigate backwards history with ctrl-p
+ for (let i = values.length-1; i > 0; i--) {
+ let match = values[i].match(/(\n)/g);
+ if (match) {
+ // multi-line inputs won't update from history unless caret at beginning
+ EventUtils.synthesizeKey("a", { ctrlKey: true });
+ for (let i = 0; i < match.length; i++) {
+ EventUtils.synthesizeKey("p", { ctrlKey: true });
+ }
+ EventUtils.synthesizeKey("p", { ctrlKey: true });
+ } else {
+ // single-line inputs will update from history from end of line
+ EventUtils.synthesizeKey("p", { ctrlKey: true });
+ }
+ is(inputNode.value, values[i-1],
+ "ctrl-p updates inputNode from backwards history values[" + i-1 + "]");
+ }
+ let inputValue = inputNode.value;
+ EventUtils.synthesizeKey("p", { ctrlKey: true });
+ is(inputNode.selectionStart, 0,
+ "ctrl-p at beginning of history moves caret location to beginning of line");
+ is(inputNode.value, inputValue,
+ "no change to input value on ctrl-p from beginning of line");
+
+ // Navigate forwards history with ctrl-n
+ for (let i = 1; i<values.length; i++) {
+ EventUtils.synthesizeKey("n", { ctrlKey: true });
+ is(inputNode.value, values[i],
+ "ctrl-n updates inputNode from forwards history values[" + i + "]");
+ is(inputNode.selectionStart, values[i].length,
+ "caret location correct at end of history input for values[" + i + "]");
+ }
+ EventUtils.synthesizeKey("n", { ctrlKey: true });
+ ok(!inputNode.value, "ctrl-n at end of history updates to empty input");
+
+ // Simulate editing multi-line
+ inputValue = "one\nlinebreak";
+ jsterm.setInputValue(inputValue);
+
+ // Attempt nav within input
+ EventUtils.synthesizeKey("p", { ctrlKey: true });
+ is(inputNode.value, inputValue,
+ "ctrl-p from end of multi-line does not trigger history");
+
+ EventUtils.synthesizeKey("a", { ctrlKey: true });
+ EventUtils.synthesizeKey("p", { ctrlKey: true });
+ is(inputNode.value, values[values.length-1],
+ "ctrl-p from start of multi-line triggers history");
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_817834_add_edited_input_to_history.js b/browser/devtools/webconsole/test/browser_webconsole_bug_817834_add_edited_input_to_history.js
new file mode 100644
index 000000000..98633c327
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_817834_add_edited_input_to_history.js
@@ -0,0 +1,63 @@
+/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * zmgmoz <zmgmoz@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Test that user input that is not submitted in the command line input is not
+// lost after navigating in history.
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=817834
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 817834";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ testEditedInputHistory(hud);
+});
+
+function testEditedInputHistory(HUD) {
+ let jsterm = HUD.jsterm;
+ let inputNode = jsterm.inputNode;
+ ok(!inputNode.value, "inputNode.value is empty");
+ is(inputNode.selectionStart, 0);
+ is(inputNode.selectionEnd, 0);
+
+ jsterm.setInputValue('"first item"');
+ EventUtils.synthesizeKey("VK_UP", {});
+ is(inputNode.value, '"first item"', "null test history up");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ is(inputNode.value, '"first item"', "null test history down");
+
+ jsterm.execute();
+ is(inputNode.value, "", "cleared input line after submit");
+
+ jsterm.setInputValue('"editing input 1"');
+ EventUtils.synthesizeKey("VK_UP", {});
+ is(inputNode.value, '"first item"', "test history up");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ is(inputNode.value, '"editing input 1"',
+ "test history down restores in-progress input");
+
+ jsterm.setInputValue('"second item"');
+ jsterm.execute();
+ jsterm.setInputValue('"editing input 2"');
+ EventUtils.synthesizeKey("VK_UP", {});
+ is(inputNode.value, '"second item"', "test history up");
+ EventUtils.synthesizeKey("VK_UP", {});
+ is(inputNode.value, '"first item"', "test history up");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ is(inputNode.value, '"second item"', "test history down");
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ is(inputNode.value, '"editing input 2"',
+ "test history down restores new in-progress input again");
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_837351_securityerrors.js b/browser/devtools/webconsole/test/browser_webconsole_bug_837351_securityerrors.js
new file mode 100644
index 000000000..c5d8b22fb
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_837351_securityerrors.js
@@ -0,0 +1,36 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-bug-837351-security-errors.html";
+
+let test = asyncTest(function* () {
+ yield pushPrefEnv();
+
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ let button = hud.ui.rootElement.querySelector(".webconsole-filter-button[category=\"security\"]");
+ ok(button, "Found security button in the web console");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "Logged blocking mixed active content",
+ text: "Blocked loading mixed active content \"http://example.com/\"",
+ category: CATEGORY_SECURITY,
+ severity: SEVERITY_ERROR
+ },
+ ],
+ });
+});
+
+function pushPrefEnv()
+{
+ let deferred = promise.defer();
+ let options = {'set': [["security.mixed_content.block_active_content", true]]};
+ SpecialPowers.pushPrefEnv(options, deferred.resolve);
+ return deferred.promise;
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_846918_hsts_invalid-headers.js b/browser/devtools/webconsole/test/browser_webconsole_bug_846918_hsts_invalid-headers.js
new file mode 100644
index 000000000..a3911f4b4
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_846918_hsts_invalid-headers.js
@@ -0,0 +1,35 @@
+ /* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+/* Tests that errors about invalid HSTS security headers are logged
+ * to the web console */
+const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-bug-846918-hsts-invalid-headers.html";
+const HSTS_INVALID_HEADER_MSG = "The site specified an invalid Strict-Transport-Security header.";
+const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Security/HTTP_Strict_Transport_Security";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ let results = yield waitForMessages({
+ webconsole: hud,
+ messages: [
+ {
+ name: "Invalid HSTS header error displayed successfully",
+ text: HSTS_INVALID_HEADER_MSG,
+ category: CATEGORY_SECURITY,
+ severity: SEVERITY_WARNING,
+ objects: true,
+ },
+ ],
+ });
+
+ yield testClickOpenNewTab(hud, results);
+});
+
+function testClickOpenNewTab(hud, results) {
+ let warningNode = results[0].clickableElements[0];
+ ok(warningNode, "link element");
+ ok(warningNode.classList.contains("learn-more-link"), "link class name");
+ return simulateMessageLinkClick(warningNode, LEARN_MORE_URI);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js b/browser/devtools/webconsole/test/browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js
new file mode 100644
index 000000000..56b566654
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js
@@ -0,0 +1,113 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that the 'Log Request and Response Bodies' buttons can be toggled with keyboard.
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 915141: Toggle log response bodies with keyboard";
+let hud;
+
+function test() {
+ let saveBodiesMenuItem;
+ let saveBodiesContextMenuItem;
+
+ loadTab(TEST_URI).then(({tab: tab}) => {
+ return openConsole(tab);
+ })
+ .then((aHud) => {
+ hud = aHud;
+ saveBodiesMenuItem = hud.ui.rootElement.querySelector("#saveBodies");
+ saveBodiesContextMenuItem = hud.ui.rootElement.querySelector("#saveBodiesContextMenu");
+
+ // Test the context menu action.
+ info("Testing 'Log Request and Response Bodies' menuitem of right click context menu.");
+
+ return openPopup(saveBodiesContextMenuItem);
+ })
+ .then(() => {
+ is(saveBodiesContextMenuItem.getAttribute("checked"), "false",
+ "Context menu: 'log responses' is not checked before action.");
+ is(hud.ui._saveRequestAndResponseBodies, false,
+ "Context menu: Responses are not logged before action.");
+
+ EventUtils.synthesizeKey("VK_DOWN", {});
+ EventUtils.synthesizeKey("VK_RETURN", {});
+
+ return waitForUpdate(saveBodiesContextMenuItem);
+ })
+ .then(() => {
+ is(saveBodiesContextMenuItem.getAttribute("checked"), "true",
+ "Context menu: 'log responses' is checked after menuitem was selected with keyboard.");
+ is(hud.ui._saveRequestAndResponseBodies, true,
+ "Context menu: Responses are saved after menuitem was selected with keyboard.");
+
+ return openPopup(saveBodiesMenuItem);
+ })
+ .then(() => {
+ // Test the 'Net' menu item.
+ info("Testing 'Log Request and Response Bodies' menuitem of 'Net' menu in the console.");
+ // 'Log Request and Response Bodies' should be selected due to previous test.
+
+ is(saveBodiesMenuItem.getAttribute("checked"), "true",
+ "Console net menu: 'log responses' is checked before action.");
+ is(hud.ui._saveRequestAndResponseBodies, true,
+ "Console net menu: Responses are logged before action.");
+
+ // The correct item is the last one in the menu.
+ EventUtils.synthesizeKey("VK_UP", {});
+ EventUtils.synthesizeKey("VK_RETURN", {});
+
+ return waitForUpdate(saveBodiesMenuItem);
+ })
+ .then(() => {
+ is(saveBodiesMenuItem.getAttribute("checked"), "false",
+ "Console net menu: 'log responses' is NOT checked after menuitem was selected with keyboard.");
+ is(hud.ui._saveRequestAndResponseBodies, false,
+ "Responses are NOT saved after menuitem was selected with keyboard.");
+ hud = null;
+ })
+ .then(finishTest);
+}
+
+/**
+ * Opens and waits for the menu containing aMenuItem to open.
+ * @param aMenuItem MenuItem
+ * A MenuItem in a menu that should be opened.
+ * @return A promise that's resolved once menu is open.
+ */
+function openPopup(aMenuItem) {
+ let menu = aMenuItem.parentNode;
+
+ let menuOpened = promise.defer();
+ let uiUpdated = promise.defer();
+ // The checkbox menuitem is updated asynchronously on 'popupshowing' event so
+ // it's better to wait for both the update to happen and the menu to open
+ // before continuing or the test might fail due to a race between menu being
+ // shown and the item updated to have the correct state.
+ hud.ui.once("save-bodies-ui-toggled", uiUpdated.resolve);
+ menu.addEventListener("popupshown", function onPopup () {
+ menu.removeEventListener("popupshown", onPopup);
+ menuOpened.resolve();
+ });
+
+ menu.openPopup();
+ return Promise.all([menuOpened.promise, uiUpdated.promise]);
+}
+
+/**
+ * Waits for the settings and menu containing aMenuItem to update.
+ * @param aMenuItem MenuItem
+ * The menuitem that should be updated.
+ * @return A promise that's resolved once the settings and menus are updated.
+ */
+function waitForUpdate(aMenuItem) {
+ info("Waiting for settings update to complete.");
+ let deferred = promise.defer();
+ hud.ui.once("save-bodies-pref-reversed", function () {
+ hud.ui.once("save-bodies-ui-toggled", deferred.resolve);
+ // The checked state is only updated once the popup is shown.
+ aMenuItem.parentNode.openPopup();
+ });
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_cached_autocomplete.js b/browser/devtools/webconsole/test/browser_webconsole_cached_autocomplete.js
new file mode 100644
index 000000000..1c780a3fc
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_cached_autocomplete.js
@@ -0,0 +1,108 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the cached autocomplete results are used when the new
+// user input is a subset of the existing completion results.
+
+const TEST_URI = "data:text/html;charset=utf8,<p>test cached autocompletion results";
+
+let jsterm;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ jsterm = hud.jsterm;
+ let input = jsterm.inputNode;
+ let popup = jsterm.autocompletePopup;
+
+ // Test if 'doc' gives 'document'
+ input.value = "doc";
+ input.setSelectionRange(3, 3);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ is(input.value, "doc", "'docu' completion (input.value)");
+ is(jsterm.completeNode.value, " ument", "'docu' completion (completeNode)");
+
+ // Test typing 'window.'.
+ input.value = "window.";
+ input.setSelectionRange(7, 7);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ ok(popup.getItems().length > 0, "'window.' gave a list of suggestions")
+
+ yield jsterm.execute("window.docfoobar = true");
+
+ // Test typing 'window.doc'.
+ input.value = "window.doc";
+ input.setSelectionRange(10, 10);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ let newItems = popup.getItems();
+ ok(newItems.every(function(item) {
+ return item.label != "docfoobar";
+ }), "autocomplete cached results do not contain docfoobar. list has not been updated");
+
+ // Test that backspace does not cause a request to the server
+ input.value = "window.do";
+ input.setSelectionRange(9, 9);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ newItems = popup.getItems();
+ ok(newItems.every(function(item) {
+ return item.label != "docfoobar";
+ }), "autocomplete cached results do not contain docfoobar. list has not been updated");
+
+ yield jsterm.execute("delete window.docfoobar");
+
+ // Test if 'window.getC' gives 'getComputedStyle'
+ input.value = "window."
+ input.setSelectionRange(7, 7);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ input.value = "window.getC";
+ input.setSelectionRange(11, 11);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ newItems = popup.getItems();
+ ok(!newItems.every(function(item) {
+ return item.label != "getComputedStyle";
+ }), "autocomplete results do contain getComputedStyle");
+
+ // Test if 'dump(d' gives non-zero results
+ input.value = "dump(d";
+ input.setSelectionRange(6, 6);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ ok(popup.getItems().length > 0, "'dump(d' gives non-zero results");
+
+ // Test that 'dump(window.)' works.
+ input.value = "dump(window.)";
+ input.setSelectionRange(12, 12);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ yield jsterm.execute("window.docfoobar = true");
+
+ // Make sure 'dump(window.doc)' does not contain 'docfoobar'.
+ input.value = "dump(window.doc)";
+ input.setSelectionRange(15, 15);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ newItems = popup.getItems();
+ ok(newItems.every(function(item) {
+ return item.label != "docfoobar";
+ }), "autocomplete cached results do not contain docfoobar. list has not been updated");
+
+ yield jsterm.execute("delete window.docfoobar");
+
+ jsterm = null;
+});
+
+function complete(type) {
+ let updated = jsterm.once("autocomplete-updated");
+ jsterm.complete(type);
+ return updated;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_cd_iframe.js b/browser/devtools/webconsole/test/browser_webconsole_cd_iframe.js
new file mode 100644
index 000000000..bc919a258
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_cd_iframe.js
@@ -0,0 +1,110 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the cd() jsterm helper function works as expected. See bug 609872.
+
+function test() {
+ let hud;
+
+ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-609872-cd-iframe-parent.html";
+
+ const parentMessages = [{
+ name: "document.title in parent iframe",
+ text: "bug 609872 - iframe parent",
+ category: CATEGORY_OUTPUT,
+ }, {
+ name: "paragraph content",
+ text: "p: test for bug 609872 - iframe parent",
+ category: CATEGORY_OUTPUT,
+ }, {
+ name: "object content",
+ text: "obj: parent!",
+ category: CATEGORY_OUTPUT,
+ }];
+
+ const childMessages = [{
+ name: "document.title in child iframe",
+ text: "bug 609872 - iframe child",
+ category: CATEGORY_OUTPUT,
+ }, {
+ name: "paragraph content",
+ text: "p: test for bug 609872 - iframe child",
+ category: CATEGORY_OUTPUT,
+ }, {
+ name: "object content",
+ text: "obj: child!",
+ category: CATEGORY_OUTPUT,
+ }];
+
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ const {tab} = yield loadTab(TEST_URI);
+ hud = yield openConsole(tab);
+
+ yield executeWindowTest();
+
+ yield waitForMessages({ webconsole: hud, messages: parentMessages });
+
+ info("cd() into the iframe using a selector");
+ hud.jsterm.clearOutput();
+ yield hud.jsterm.execute("cd('iframe')");
+ yield executeWindowTest();
+
+ yield waitForMessages({ webconsole: hud, messages: childMessages });
+
+ info("cd() out of the iframe, reset to default window");
+ hud.jsterm.clearOutput();
+ yield hud.jsterm.execute("cd()");
+ yield executeWindowTest();
+
+ yield waitForMessages({ webconsole: hud, messages: parentMessages });
+
+ info("call cd() with unexpected arguments");
+ hud.jsterm.clearOutput();
+ yield hud.jsterm.execute("cd(document)");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "Cannot cd()",
+ category: CATEGORY_OUTPUT,
+ severity: SEVERITY_ERROR,
+ }],
+ });
+
+ hud.jsterm.clearOutput();
+ yield hud.jsterm.execute("cd('p')");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "Cannot cd()",
+ category: CATEGORY_OUTPUT,
+ severity: SEVERITY_ERROR,
+ }],
+ });
+
+ info("cd() into the iframe using an iframe DOM element");
+ hud.jsterm.clearOutput();
+ yield hud.jsterm.execute("cd($('iframe'))");
+ yield executeWindowTest();
+
+ yield waitForMessages({ webconsole: hud, messages: childMessages });
+
+ info("cd(window.parent)");
+ hud.jsterm.clearOutput();
+ yield hud.jsterm.execute("cd(window.parent)");
+ yield executeWindowTest();
+
+ yield waitForMessages({ webconsole: hud, messages: parentMessages });
+
+ yield closeConsole(tab);
+ }
+
+ function executeWindowTest() {
+ yield hud.jsterm.execute("document.title");
+ yield hud.jsterm.execute("'p: ' + document.querySelector('p').textContent");
+ yield hud.jsterm.execute("'obj: ' + window.foobarBug609872");
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_certificate_messages.js b/browser/devtools/webconsole/test/browser_webconsole_certificate_messages.js
new file mode 100644
index 000000000..8a90876c0
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_certificate_messages.js
@@ -0,0 +1,94 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the Web Console shows weak crypto warnings (SHA-1 Certificate, SSLv3, and RC4)
+
+const TEST_URI = "data:text/html;charset=utf8,Web Console weak crypto warnings test";
+const TEST_URI_PATH = "/browser/browser/devtools/webconsole/test/test-certificate-messages.html";
+
+let gWebconsoleTests = [
+ {url: "https://sha1ee.example.com" + TEST_URI_PATH,
+ name: "SHA1 warning displayed successfully",
+ warning: ["SHA-1"], nowarning: ["SSL 3.0", "RC4"]},
+ {url: "https://ssl3.example.com" + TEST_URI_PATH,
+ name: "SSL3 warning displayed successfully",
+ pref: [["security.tls.version.min", 0]],
+ warning: ["SSL 3.0"], nowarning: ["SHA-1", "RC4"]},
+ {url: "https://rc4.example.com" + TEST_URI_PATH,
+ name: "RC4 warning displayed successfully",
+ pref: [["security.tls.insecure_fallback_hosts", "rc4.example.com"]],
+ warning: ["RC4"], nowarning: ["SHA-1", "SSL 3.0"]},
+ {url: "https://rc4.example.com" + TEST_URI_PATH + "?",
+ name: "Unrestricted RC4 fallback worked",
+ pref: [["security.tls.unrestricted_rc4_fallback", true]],
+ warning: ["RC4"], nowarning: ["SHA-1", "SSL 3.0"]},
+ {url: "https://ssl3rc4.example.com" + TEST_URI_PATH,
+ name: "SSL3 and RC4 warning displayed successfully",
+ pref: [["security.tls.version.min", 0],
+ ["security.tls.insecure_fallback_hosts", "ssl3rc4.example.com"]],
+ warning: ["SSL 3.0", "RC4"], nowarning: ["SHA-1"]},
+ {url: "https://sha256ee.example.com" + TEST_URI_PATH,
+ name: "SSL warnings appropriately not present",
+ warning: [], nowarning: ["SHA-1", "SSL 3.0", "RC4"]},
+];
+const TRIGGER_MSG = "If you haven't seen ssl warnings yet, you won't";
+
+let gHud = undefined, gContentBrowser;
+let gCurrentTest;
+
+function test() {
+ registerCleanupFunction(function () {
+ gHud = gContentBrowser = null;
+ });
+
+ loadTab(TEST_URI).then(({browser}) => {
+ gContentBrowser = browser;
+ openConsole().then(runTestLoop);
+ });
+}
+
+function runTestLoop(theHud) {
+ gCurrentTest = gWebconsoleTests.shift();
+ if (!gCurrentTest) {
+ finishTest();
+ return;
+ }
+ if (!gHud) {
+ gHud = theHud;
+ }
+ gHud.jsterm.clearOutput();
+ gContentBrowser.addEventListener("load", onLoad, true);
+ if (gCurrentTest.pref) {
+ SpecialPowers.pushPrefEnv({"set": gCurrentTest.pref},
+ function() {
+ content.location = gCurrentTest.url;
+ });
+ } else {
+ content.location = gCurrentTest.url;
+ }
+}
+
+function onLoad(aEvent) {
+ gContentBrowser.removeEventListener("load", onLoad, true);
+ let aOutputNode = gHud.outputNode;
+
+ waitForSuccess({
+ name: gCurrentTest.name,
+ validator: function() {
+ if (gHud.outputNode.textContent.indexOf(TRIGGER_MSG) >= 0) {
+ for (let warning of gCurrentTest.warning) {
+ if (gHud.outputNode.textContent.indexOf(warning) < 0) {
+ return false;
+ }
+ }
+ for (let nowarning of gCurrentTest.nowarning) {
+ if (gHud.outputNode.textContent.indexOf(nowarning) >= 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ }).then(runTestLoop);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_change_font_size.js b/browser/devtools/webconsole/test/browser_webconsole_change_font_size.js
new file mode 100644
index 000000000..ab86bb49e
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_change_font_size.js
@@ -0,0 +1,39 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Jennifer Fong <jfong@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+"use strict";
+
+const TEST_URI = "http://example.com/";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ Services.prefs.setIntPref("devtools.webconsole.fontSize", 10);
+ let hud = yield HUDService.toggleBrowserConsole();
+
+ let inputNode = hud.jsterm.inputNode;
+ let outputNode = hud.jsterm.outputNode;
+ outputNode.focus();
+
+ EventUtils.synthesizeKey("-", { accelKey: true }, hud.iframeWindow);
+ is(inputNode.style.fontSize, "10px", "input font stays at same size with ctrl+-");
+ is(outputNode.style.fontSize, inputNode.style.fontSize, "output font stays at same size with ctrl+-");
+
+ EventUtils.synthesizeKey("=", { accelKey: true }, hud.iframeWindow);
+ is(inputNode.style.fontSize, "11px", "input font increased with ctrl+=");
+ is(outputNode.style.fontSize, inputNode.style.fontSize, "output font stays at same size with ctrl+=");
+
+ EventUtils.synthesizeKey("-", { accelKey: true }, hud.iframeWindow);
+ is(inputNode.style.fontSize, "10px", "font decreased with ctrl+-");
+ is(outputNode.style.fontSize, inputNode.style.fontSize, "output font stays at same size with ctrl+-");
+
+ EventUtils.synthesizeKey("0", { accelKey: true }, hud.iframeWindow);
+ is(inputNode.style.fontSize, "", "font reset with ctrl+0");
+ is(outputNode.style.fontSize, inputNode.style.fontSize, "output font stays at same size with ctrl+0");
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_chrome.js b/browser/devtools/webconsole/test/browser_webconsole_chrome.js
new file mode 100644
index 000000000..f7f3cd0e3
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_chrome.js
@@ -0,0 +1,38 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that code completion works properly in chrome tabs, like about:credits.
+
+"use strict";
+
+function test() {
+ Task.spawn(function*() {
+ const {tab} = yield loadTab("about:config");
+ ok(tab, "tab loaded");
+
+ const hud = yield openConsole(tab);
+ ok(hud, "we have a console");
+ ok(hud.iframeWindow, "we have the console UI window");
+
+ let jsterm = hud.jsterm;
+ ok(jsterm, "we have a jsterm");
+
+ let input = jsterm.inputNode;
+ ok(hud.outputNode, "we have an output node");
+
+ // Test typing 'docu'.
+ input.value = "docu";
+ input.setSelectionRange(4, 4);
+
+ let deferred = promise.defer();
+
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY, function() {
+ is(jsterm.completeNode.value, " ment", "'docu' completion");
+ deferred.resolve(null);
+ });
+
+ yield deferred.promise;
+ }).then(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_clickable_urls.js b/browser/devtools/webconsole/test/browser_webconsole_clickable_urls.js
new file mode 100644
index 000000000..05f1ee2c9
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_clickable_urls.js
@@ -0,0 +1,85 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// When strings containing URLs are entered into the webconsole,
+// check its output and ensure that the output can be clicked to open those URLs.
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf8,Bug 1005909 - Clickable URLS";
+
+let inputTests = [
+
+ // 0: URL opens page when clicked.
+ {
+ input: "'http://example.com'",
+ output: "http://example.com",
+ expectedTab: "http://example.com/",
+ },
+
+ // 1: URL opens page using https when clicked.
+ {
+ input: "'https://example.com'",
+ output: "https://example.com",
+ expectedTab: "https://example.com/",
+ },
+
+ // 2: URL with port opens page when clicked.
+ {
+ input: "'https://example.com:443'",
+ output: "https://example.com:443",
+ expectedTab: "https://example.com/",
+ },
+
+ // 3: URL containing non-empty path opens page when clicked.
+ {
+ input: "'http://example.com/foo'",
+ output: "http://example.com/foo",
+ expectedTab: "http://example.com/foo",
+ },
+
+ // 4: URL opens page when clicked, even when surrounded by non-URL tokens.
+ {
+ input: "'foo http://example.com bar'",
+ output: "foo http://example.com bar",
+ expectedTab: "http://example.com/",
+ },
+
+ // 5: URL opens page when clicked, and whitespace is be preserved.
+ {
+ input: "'foo\\nhttp://example.com\\nbar'",
+ output: "foo\nhttp://example.com\nbar",
+ expectedTab: "http://example.com/",
+ },
+
+ // 6: URL opens page when clicked when multiple links are present.
+ {
+ input: "'http://example.com http://example.com'",
+ output: "http://example.com http://example.com",
+ expectedTab: "http://example.com/",
+ },
+
+ // 7: URL without scheme does not open page when clicked.
+ {
+ input: "'example.com'",
+ output: "example.com",
+ },
+
+ // 8: URL with invalid scheme does not open page when clicked.
+ {
+ input: "'foo://example.com'",
+ output: "foo://example.com",
+ },
+
+];
+
+function test() {
+ Task.spawn(function*() {
+ let {tab} = yield loadTab(TEST_URI);
+ let hud = yield openConsole(tab);
+ yield checkOutputForInputs(hud, inputTests);
+ inputTests = null;
+ }).then(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_closure_inspection.js b/browser/devtools/webconsole/test/browser_webconsole_closure_inspection.js
new file mode 100644
index 000000000..537ef1a72
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_closure_inspection.js
@@ -0,0 +1,89 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that inspecting a closure in the variables view sidebar works when
+// execution is paused.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-closures.html";
+
+let gWebConsole, gJSTerm, gVariablesView;
+
+function test()
+{
+ registerCleanupFunction(() => {
+ gWebConsole = gJSTerm = gVariablesView = null;
+ });
+
+ loadTab(TEST_URI).then(() => {
+ openConsole().then((hud) => {
+ openDebugger().then(({ toolbox, panelWin }) => {
+ let deferred = promise.defer();
+ panelWin.gThreadClient.addOneTimeListener("resumed", (aEvent, aPacket) => {
+ ok(true, "Debugger resumed");
+ deferred.resolve({ toolbox: toolbox, panelWin: panelWin });
+ });
+ return deferred.promise;
+ }).then(({ toolbox, panelWin }) => {
+ let deferred = promise.defer();
+ panelWin.once(panelWin.EVENTS.FETCHED_SCOPES, (aEvent, aPacket) => {
+ ok(true, "Scopes were fetched");
+ toolbox.selectTool("webconsole").then(() => consoleOpened(hud));
+ deferred.resolve();
+ });
+
+ let button = content.document.querySelector("button");
+ ok(button, "button element found");
+ EventUtils.synthesizeMouseAtCenter(button, {}, content);
+
+ return deferred.promise;
+ });
+ })
+ });
+}
+
+function consoleOpened(hud)
+{
+ gWebConsole = hud;
+ gJSTerm = hud.jsterm;
+ gJSTerm.execute("window.george.getName");
+
+ waitForMessages({
+ webconsole: gWebConsole,
+ messages: [{
+ text: "function _pfactory/<.getName()",
+ category: CATEGORY_OUTPUT,
+ objects: true,
+ }],
+ }).then(onExecuteGetName);
+}
+
+function onExecuteGetName(aResults)
+{
+ let clickable = aResults[0].clickableElements[0];
+ ok(clickable, "clickable object found");
+
+ gJSTerm.once("variablesview-fetched", onGetNameFetch);
+ EventUtils.synthesizeMouse(clickable, 2, 2, {}, gWebConsole.iframeWindow);
+}
+
+function onGetNameFetch(aEvent, aVar)
+{
+ gVariablesView = aVar._variablesView;
+ ok(gVariablesView, "variables view object");
+
+ findVariableViewProperties(aVar, [
+ { name: /_pfactory/, value: "" },
+ ], { webconsole: gWebConsole }).then(onExpandClosure);
+}
+
+function onExpandClosure(aResults)
+{
+ let prop = aResults[0].matchedProp;
+ ok(prop, "matched the name property in the variables view");
+
+ gVariablesView.window.focus();
+ gJSTerm.once("sidebar-closed", finishTest);
+ EventUtils.synthesizeKey("VK_ESCAPE", {});
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_column_numbers.js b/browser/devtools/webconsole/test/browser_webconsole_column_numbers.js
new file mode 100644
index 000000000..bbc5dde81
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_column_numbers.js
@@ -0,0 +1,42 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+ // Check if console provides the right column number alongside line number
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-column.html";
+
+let hud;
+
+function test() {
+ loadTab(TEST_URI).then(() => {
+ openConsole().then(consoleOpened);
+ });
+}
+
+function consoleOpened(aHud) {
+ hud = aHud;
+
+ waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: 'Error Message',
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_ERROR
+ }]
+ }).then(testLocationColumn);
+}
+
+function testLocationColumn() {
+ let messages = hud.outputNode.children;
+ let expected = ['10:6', '10:38', '11:8', '12:10', '13:8', '14:6'];
+
+ for(let i = 0, len = messages.length; i < len; i++) {
+ let msg = messages[i].textContent;
+
+ is(msg.contains(expected[i]), true, 'Found expected line:column of ' + expected[i]);
+ }
+
+ finishTest();
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_completion.js b/browser/devtools/webconsole/test/browser_webconsole_completion.js
new file mode 100644
index 000000000..d68ae0ac3
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_completion.js
@@ -0,0 +1,101 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that code completion works properly.
+
+const TEST_URI = "data:text/html;charset=utf8,<p>test code completion";
+
+let jsterm;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ jsterm = hud.jsterm;
+ let input = jsterm.inputNode;
+
+ // Test typing 'docu'.
+ input.value = "docu";
+ input.setSelectionRange(4, 4);
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ is(input.value, "docu", "'docu' completion (input.value)");
+ is(jsterm.completeNode.value, " ment", "'docu' completion (completeNode)");
+
+ // Test typing 'docu' and press tab.
+ input.value = "docu";
+ input.setSelectionRange(4, 4);
+ yield complete(jsterm.COMPLETE_FORWARD);
+
+ is(input.value, "document", "'docu' tab completion");
+ is(input.selectionStart, 8, "start selection is alright");
+ is(input.selectionEnd, 8, "end selection is alright");
+ is(jsterm.completeNode.value.replace(/ /g, ""), "", "'docu' completed");
+
+ // Test typing 'window.Ob' and press tab. Just 'window.O' is
+ // ambiguous: could be window.Object, window.Option, etc.
+ input.value = "window.Ob";
+ input.setSelectionRange(9, 9);
+ yield complete(jsterm.COMPLETE_FORWARD);
+
+ is(input.value, "window.Object", "'window.Ob' tab completion");
+
+ // Test typing 'document.getElem'.
+ input.value = "document.getElem";
+ input.setSelectionRange(16, 16);
+ yield complete(jsterm.COMPLETE_FORWARD);
+
+ is(input.value, "document.getElem", "'document.getElem' completion");
+ is(jsterm.completeNode.value, " entsByTagNameNS", "'document.getElem' completion");
+
+ // Test pressing tab another time.
+ yield jsterm.complete(jsterm.COMPLETE_FORWARD);
+
+ is(input.value, "document.getElem", "'document.getElem' completion");
+ is(jsterm.completeNode.value, " entsByTagName", "'document.getElem' another tab completion");
+
+ // Test pressing shift_tab.
+ complete(jsterm.COMPLETE_BACKWARD);
+
+ is(input.value, "document.getElem", "'document.getElem' untab completion");
+ is(jsterm.completeNode.value, " entsByTagNameNS", "'document.getElem' completion");
+
+ jsterm.clearOutput();
+
+ input.value = "docu";
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ is(jsterm.completeNode.value, " ment", "'docu' completion");
+ yield jsterm.execute();
+ is(jsterm.completeNode.value, "", "clear completion on execute()");
+
+ // Test multi-line completion works
+ input.value = "console.log('one');\nconsol";
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ is(jsterm.completeNode.value, " \n e", "multi-line completion");
+
+ // Test non-object autocompletion.
+ input.value = "Object.name.sl";
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ is(jsterm.completeNode.value, " ice", "non-object completion");
+
+ // Test string literal autocompletion.
+ input.value = "'Asimov'.sl";
+ yield complete(jsterm.COMPLETE_HINT_ONLY);
+
+ is(jsterm.completeNode.value, " ice", "string literal completion");
+
+ jsterm = null;
+});
+
+
+function complete(type) {
+ let updated = jsterm.once("autocomplete-updated");
+ jsterm.complete(type);
+ return updated;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_console_api_stackframe.js b/browser/devtools/webconsole/test/browser_webconsole_console_api_stackframe.js
new file mode 100644
index 000000000..499a45d59
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_console_api_stackframe.js
@@ -0,0 +1,81 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the console API messages for console.error()/exception()/assert()
+// include a stackframe. See bug 920116.
+
+function test() {
+ let hud;
+
+ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-api-stackframe.html";
+ const TEST_FILE = TEST_URI.substr(TEST_URI.lastIndexOf("/"));
+
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ const {tab} = yield loadTab(TEST_URI);
+ hud = yield openConsole(tab);
+
+ const stack = [{
+ file: TEST_FILE,
+ fn: "thirdCall",
+ line: /\b2[123]\b/, // 21,22,23
+ }, {
+ file: TEST_FILE,
+ fn: "secondCall",
+ line: 16,
+ }, {
+ file: TEST_FILE,
+ fn: "firstCall",
+ line: 12,
+ }];
+
+ let results = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "foo-log",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ collapsible: false,
+ }, {
+ text: "foo-error",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_ERROR,
+ collapsible: true,
+ stacktrace: stack,
+ }, {
+ text: "foo-exception",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_ERROR,
+ collapsible: true,
+ stacktrace: stack,
+ }, {
+ text: "foo-assert",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_ERROR,
+ collapsible: true,
+ stacktrace: stack,
+ }],
+ });
+
+ let elem = [...results[1].matched][0];
+ ok(elem, "message element");
+
+ let msg = elem._messageObject;
+ ok(msg, "message object");
+
+ ok(msg.collapsed, "message is collapsed");
+
+ msg.toggleDetails();
+
+ ok(!msg.collapsed, "message is not collapsed");
+
+ msg.toggleDetails();
+
+ ok(msg.collapsed, "message is collapsed");
+
+ yield closeConsole(tab);
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_console_custom_styles.js b/browser/devtools/webconsole/test/browser_webconsole_console_custom_styles.js
new file mode 100644
index 000000000..a522fc47b
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_console_custom_styles.js
@@ -0,0 +1,79 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the '%c' modifier works with the console API. See bug 823097.
+
+function test() {
+ let hud;
+
+ const TEST_URI = "data:text/html;charset=utf8,<p>test for " +
+ "console.log('%ccustom styles', 'color:red')";
+
+ const checks = [{
+ // check the basics work
+ style: "color:red;font-size:1.3em",
+ props: { color: true, fontSize: true },
+ sameStyleExpected: true,
+ }, {
+ // check that the url() is not allowed
+ style: "color:blue;background-image:url('http://example.com/test')",
+ props: { color: true, fontSize: false, background: false,
+ backgroundImage: false },
+ sameStyleExpected: false,
+ }, {
+ // check that some properties are not allowed
+ style: "color:pink;position:absolute;top:10px",
+ props: { color: true, position: false, top: false },
+ sameStyleExpected: false,
+ }];
+
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ const {tab} = yield loadTab(TEST_URI);
+ hud = yield openConsole(tab);
+
+ for (let check of checks) {
+ yield checkStyle(check);
+ }
+
+ yield closeConsole(tab);
+ }
+
+ function* checkStyle(check) {
+ hud.jsterm.clearOutput();
+
+ info("checkStyle " + check.style);
+ hud.jsterm.execute("console.log('%cfoobar', \"" + check.style + "\")");
+
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "foobar",
+ category: CATEGORY_WEBDEV,
+ }],
+ });
+
+ let msg = [...result.matched][0];
+ ok(msg, "message element");
+
+ let span = msg.querySelector(".message-body span[style]");
+ ok(span, "span element");
+
+ info("span textContent is: " + span.textContent);
+ isnot(span.textContent.indexOf("foobar"), -1, "span textContent check");
+
+ let outputStyle = span.getAttribute("style").replace(/\s+|;+$/g, "");
+ if (check.sameStyleExpected) {
+ is(outputStyle, check.style, "span style is correct");
+ } else {
+ isnot(outputStyle, check.style, "span style is not the same");
+ }
+
+ for (let prop of Object.keys(check.props)) {
+ is(!!span.style[prop], check.props[prop], "property check for " + prop);
+ }
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_console_extras.js b/browser/devtools/webconsole/test/browser_webconsole_console_extras.js
new file mode 100644
index 000000000..b42437492
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_console_extras.js
@@ -0,0 +1,40 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Test that window.console functions that are not implemented yet do not
+// output anything in the web console and they do not throw any exceptions.
+// See bug 614350.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-extras.html";
+
+function test() {
+ loadTab(TEST_URI).then(() => {
+ openConsole().then(consoleOpened);
+ });
+}
+
+function consoleOpened(hud) {
+ waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "start",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ },
+ {
+ text: "end",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ }).then(() => {
+ let nodes = hud.outputNode.querySelectorAll(".message");
+ is(nodes.length, 2, "only two messages are displayed");
+ finishTest();
+ });
+
+ let button = content.document.querySelector("button");
+ ok(button, "we have the button");
+ EventUtils.sendMouseEvent({ type: "click" }, button, content);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_console_logging_api.js b/browser/devtools/webconsole/test/browser_webconsole_console_logging_api.js
new file mode 100644
index 000000000..aeb73c58e
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_console_logging_api.js
@@ -0,0 +1,101 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the basic console.log()-style APIs and filtering work.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ hud.jsterm.clearOutput();
+
+ let outputNode = hud.outputNode;
+
+ let methods = ["log", "info", "warn", "error", "exception", "debug"];
+ for (let method of methods) {
+ yield testMethod(method, hud, outputNode);
+ }
+});
+
+function* testMethod(aMethod, aHud, aOutputNode) {
+ let console = content.console;
+
+ aHud.jsterm.clearOutput();
+
+ console[aMethod]("foo-bar-baz");
+ console[aMethod]("baar-baz");
+
+ yield waitForMessages({
+ webconsole: aHud,
+ messages: [{
+ text: "foo-bar-baz",
+ }, {
+ text: "baar-baz",
+ }],
+ });
+
+ setStringFilter("foo", aHud);
+
+ is(aOutputNode.querySelectorAll(".filtered-by-string").length, 1,
+ "1 hidden " + aMethod + " node via string filtering")
+
+ aHud.jsterm.clearOutput();
+
+ // now toggle the current method off - make sure no visible message
+ // TODO: move all filtering tests into a separate test file: see bug 608135
+
+ console[aMethod]("foo-bar-baz");
+ yield waitForMessages({
+ webconsole: aHud,
+ messages: [{
+ text: "foo-bar-baz",
+ }],
+ });
+
+ setStringFilter("", aHud);
+ let filter;
+ switch(aMethod) {
+ case "debug":
+ filter = "log";
+ break;
+ case "exception":
+ filter = "error";
+ break;
+ default:
+ filter = aMethod;
+ break;
+ }
+
+ aHud.setFilterState(filter, false);
+
+ is(aOutputNode.querySelectorAll(".filtered-by-type").length, 1,
+ "1 message hidden for " + aMethod + " (logging turned off)")
+
+ aHud.setFilterState(filter, true);
+
+ is(aOutputNode.querySelectorAll(".message:not(.filtered-by-type)").length, 1,
+ "1 message shown for " + aMethod + " (logging turned on)")
+
+ aHud.jsterm.clearOutput();
+
+ // test for multiple arguments.
+ console[aMethod]("foo", "bar");
+
+ yield waitForMessages({
+ webconsole: aHud,
+ messages: [{
+ text: '"foo" "bar"',
+ category: CATEGORY_WEBDEV,
+ }],
+ })
+}
+
+function setStringFilter(aValue, aHud) {
+ aHud.ui.filterBox.value = aValue;
+ aHud.ui.adjustVisibilityOnSearchStringChange();
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_console_trace_duplicates.js b/browser/devtools/webconsole/test/browser_webconsole_console_trace_duplicates.js
new file mode 100644
index 000000000..76793c3c7
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_console_trace_duplicates.js
@@ -0,0 +1,46 @@
+/* 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/. */
+
+function test() {
+ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug_939783_console_trace_duplicates.html";
+
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ const {tab} = yield loadTab("data:text/html;charset=utf8,<p>hello");
+ const hud = yield openConsole(tab);
+
+ content.location = TEST_URI;
+
+ // NB: Now that stack frames include a column number multiple invocations
+ // on the same line are considered unique. ie:
+ // |foo(); foo();|
+ // will generate two distinct trace entries.
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "console.trace output for foo1()",
+ text: "foo1()",
+ consoleTrace: {
+ file: "test-bug_939783_console_trace_duplicates.html",
+ fn: "foo3()",
+ },
+ }, {
+ name: "console.trace output for foo1()",
+ text: "foo1()",
+ consoleTrace: {
+ file: "test-bug_939783_console_trace_duplicates.html",
+ fn: "foo3()",
+ },
+ }, {
+ name: "console.trace output for foo1b()",
+ text: "foo1b()",
+ consoleTrace: {
+ file: "test-bug_939783_console_trace_duplicates.html",
+ fn: "foo3()",
+ },
+ }],
+ });
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_count.js b/browser/devtools/webconsole/test/browser_webconsole_count.js
new file mode 100644
index 000000000..a4866baa4
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_count.js
@@ -0,0 +1,77 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that console.count() counts as expected. See bug 922208.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-count.html";
+
+function test() {
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ const {tab} = yield loadTab(TEST_URI);
+ const hud = yield openConsole(tab);
+
+ let button = content.document.querySelector("#local");
+ ok(button, "we have the local-tests button");
+ EventUtils.sendMouseEvent({ type: "click" }, button, content);
+ let messages = [];
+ [
+ "start",
+ "<no label>: 2",
+ "console.count() testcounter: 1",
+ "console.count() testcounter: 2",
+ "console.count() testcounter: 3",
+ "console.count() testcounter: 4",
+ "end"
+ ].forEach(function (msg) {
+ messages.push({
+ text: msg,
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG
+ });
+ });
+ messages.push({
+ name: "Three local counts with no label and count=1",
+ text: "<no label>: 1",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ count: 3
+ });
+ yield waitForMessages({
+ webconsole: hud,
+ messages: messages
+ });
+
+ hud.jsterm.clearOutput();
+
+ button = content.document.querySelector("#external");
+ ok(button, "we have the external-tests button");
+ EventUtils.sendMouseEvent({ type: "click" }, button, content);
+ messages = [];
+ [
+ "start",
+ "console.count() testcounter: 5",
+ "console.count() testcounter: 6",
+ "end"
+ ].forEach(function (msg) {
+ messages.push({
+ text: msg,
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG
+ });
+ });
+ messages.push({
+ name: "Two external counts with no label and count=1",
+ text: "<no label>: 1",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ count: 2
+ });
+ yield waitForMessages({
+ webconsole: hud,
+ messages: messages
+ });
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_dont_navigate_on_doubleclick.js b/browser/devtools/webconsole/test/browser_webconsole_dont_navigate_on_doubleclick.js
new file mode 100644
index 000000000..34eb87b00
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_dont_navigate_on_doubleclick.js
@@ -0,0 +1,50 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that if a link in console is double clicked, the console frame doesn't
+// navigate to that destination (bug 975707).
+
+"use strict";
+
+function test() {
+ let originalNetPref = Services.prefs.getBoolPref("devtools.webconsole.filter.networkinfo");
+ registerCleanupFunction(() => {
+ Services.prefs.setBoolPref("devtools.webconsole.filter.networkinfo", originalNetPref);
+ });
+ Services.prefs.setBoolPref("devtools.webconsole.filter.networkinfo", true);
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ const TEST_PAGE_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html" + "?_uniq=" + Date.now();
+
+ const {tab} = yield loadTab("data:text/html;charset=utf8,<p>hello</p>");
+ const hud = yield openConsole(tab);
+
+ content.location = TEST_PAGE_URI;
+
+ let messages = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "Network request message",
+ url: TEST_PAGE_URI,
+ category: CATEGORY_NETWORK
+ }]
+ });
+
+ let networkEventMessage = messages[0].matched.values().next().value;
+ let urlNode = networkEventMessage.querySelector(".url");
+
+ let deferred = promise.defer();
+ urlNode.addEventListener("click", function onClick(aEvent) {
+ urlNode.removeEventListener("click", onClick);
+ ok(aEvent.defaultPrevented, "The default action was prevented.");
+
+ deferred.resolve();
+ });
+
+ EventUtils.synthesizeMouseAtCenter(urlNode, {clickCount: 2}, hud.iframeWindow);
+
+ yield deferred.promise;
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_execution_scope.js b/browser/devtools/webconsole/test/browser_webconsole_execution_scope.js
new file mode 100644
index 000000000..338b17e16
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_execution_scope.js
@@ -0,0 +1,34 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that commands run by the user are executed in content space.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ hud.jsterm.clearOutput();
+ hud.jsterm.execute("window.location.href;");
+
+ let [input, output] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "window.location.href;",
+ category: CATEGORY_INPUT,
+ },
+ {
+ text: TEST_URI,
+ category: CATEGORY_OUTPUT,
+ }],
+ });
+
+ let inputNode = [...input.matched][0];
+ let outputNode = [...output.matched][0];
+ is(inputNode.getAttribute("category"), "input", "input node category is correct");
+ is(outputNode.getAttribute("category"), "output", "output node category is correct");
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_expandable_timestamps.js b/browser/devtools/webconsole/test/browser_webconsole_expandable_timestamps.js
new file mode 100644
index 000000000..efcdaa63c
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_expandable_timestamps.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test for the message timestamps option: check if the preference toggles the
+// display of messages in the console output. See bug 722267.
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 722267 - " +
+ "preference for toggling timestamps in messages";
+const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages";
+let hud;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ hud = yield openConsole();
+ let panel = yield consoleOpened();
+
+ yield onOptionsPanelSelected(panel);
+ onPrefChanged();
+
+ Services.prefs.clearUserPref(PREF_MESSAGE_TIMESTAMP);
+ hud = null;
+});
+
+function consoleOpened()
+{
+ info("console opened");
+ let prefValue = Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP);
+ ok(!prefValue, "messages have no timestamp by default (pref check)");
+ ok(hud.outputNode.classList.contains("hideTimestamps"),
+ "messages have no timestamp (class name check)");
+
+ let toolbox = gDevTools.getToolbox(hud.target);
+ return toolbox.selectTool("options");
+}
+
+function onOptionsPanelSelected(panel)
+{
+ info("options panel opened");
+
+ let prefChanged = gDevTools.once("pref-changed", onPrefChanged);
+
+ let checkbox = panel.panelDoc.getElementById("webconsole-timestamp-messages");
+ checkbox.click();
+
+ return prefChanged;
+}
+
+function onPrefChanged()
+{
+ info("pref changed");
+ let prefValue = Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP);
+ ok(prefValue, "messages have timestamps (pref check)");
+ ok(!hud.outputNode.classList.contains("hideTimestamps"),
+ "messages have timestamps (class name check)");
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_filter_buttons_contextmenu.js b/browser/devtools/webconsole/test/browser_webconsole_filter_buttons_contextmenu.js
new file mode 100644
index 000000000..058b52afa
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_filter_buttons_contextmenu.js
@@ -0,0 +1,91 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the filter button context menu logic works correctly.
+
+const TEST_URI = "http://example.com/";
+
+function test() {
+ loadTab(TEST_URI).then(() => {
+ openConsole().then(testFilterButtons);
+ })
+}
+
+function testFilterButtons(aHud) {
+ let hudBox = aHud.ui.rootElement;
+
+ testRightClick("net", hudBox, aHud)
+ .then(() => testRightClick("css", hudBox, aHud))
+ .then(() => testRightClick("js", hudBox, aHud))
+ .then(() => testRightClick("logging", hudBox, aHud))
+ .then(() => testRightClick("security", hudBox, aHud))
+ .then(finishTest);
+}
+
+function testRightClick(aCategory, hudBox, aHud) {
+ let deferred = promise.defer();
+ let selector = ".webconsole-filter-button[category=\"" + aCategory + "\"]";
+ let button = hudBox.querySelector(selector);
+ let mainButton = getMainButton(button, aHud);
+ let origCheckedState = button.getAttribute("aria-pressed");
+ let contextMenu = aHud.iframeWindow.document.getElementById(aCategory + "-contextmenu");
+
+ function verifyContextMenuIsClosed() {
+ info("verify the context menu is closed");
+ is(button.getAttribute("open"), false, "The context menu for the \"" + aCategory +
+ "\" button is closed");
+ }
+
+ function verifyOriginalCheckedState() {
+ info("verify the button has the original checked state");
+ is(button.getAttribute("aria-pressed"), origCheckedState,
+ "The button state should not have changed");
+ };
+
+ function verifyNewCheckedState() {
+ info("verify the button's checked state has changed");
+ isnot(button.getAttribute("aria-pressed"), origCheckedState,
+ "The button state should have changed");
+ };
+
+ function leftClickToClose() {
+ info("left click the button to close the contextMenu");
+ EventUtils.sendMouseEvent({type: "click"}, button);
+ executeSoon(() => {
+ verifyContextMenuIsClosed();
+ verifyOriginalCheckedState();
+ leftClickToChangeCheckedState();
+ });
+ }
+
+ function leftClickToChangeCheckedState() {
+ info("left click the mainbutton to change checked state");
+ EventUtils.sendMouseEvent({type: "click"}, mainButton);
+ executeSoon(() => {
+ verifyContextMenuIsClosed();
+ verifyNewCheckedState();
+ deferred.resolve();
+ });
+ }
+
+ verifyContextMenuIsClosed();
+ info("right click the button to open the context menu");
+ waitForContextMenu(contextMenu, mainButton, verifyOriginalCheckedState,
+ leftClickToClose);
+ return deferred.promise;
+}
+
+function getMainButton(aTargetButton, aHud) {
+ let anonymousNodes = aHud.ui.document.getAnonymousNodes(aTargetButton);
+ let subbutton;
+
+ for (let i = 0; i < anonymousNodes.length; i++) {
+ let node = anonymousNodes[i];
+ if (node.classList.contains("toolbarbutton-menubutton-button")) {
+ subbutton = node;
+ break;
+ }
+ }
+
+ return subbutton;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_for_of.js b/browser/devtools/webconsole/test/browser_webconsole_for_of.js
new file mode 100644
index 000000000..b5b6304f6
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_for_of.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// A for-of loop in Web Console code can loop over a content NodeList.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-for-of.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+ yield testForOf(hud);
+});
+
+function testForOf(hud) {
+ let deferred = promise.defer();
+
+ var jsterm = hud.jsterm;
+ jsterm.execute("{ [x.tagName for (x of document.body.childNodes) if (x.nodeType === 1)].join(' '); }",
+ (node) => {
+ ok(/H1 DIV H2 P/.test(node.textContent),
+ "for-of loop should find all top-level nodes");
+ deferred.resolve();
+ });
+
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_history.js b/browser/devtools/webconsole/test/browser_webconsole_history.js
new file mode 100644
index 000000000..42d957afb
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_history.js
@@ -0,0 +1,61 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests the console history feature accessed via the up and down arrow keys.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+// Constants used for defining the direction of JSTerm input history navigation.
+const HISTORY_BACK = -1;
+const HISTORY_FORWARD = 1;
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ hud.jsterm.clearOutput();
+
+ let jsterm = hud.jsterm;
+ let input = jsterm.inputNode;
+
+ let executeList = ["document", "window", "window.location"];
+
+ for each (var item in executeList) {
+ input.value = item;
+ yield jsterm.execute();
+ }
+
+ for (var i = executeList.length - 1; i != -1; i--) {
+ jsterm.historyPeruse(HISTORY_BACK);
+ is (input.value, executeList[i], "check history previous idx:" + i);
+ }
+
+ jsterm.historyPeruse(HISTORY_BACK);
+ is (input.value, executeList[0], "test that item is still index 0");
+
+ jsterm.historyPeruse(HISTORY_BACK);
+ is (input.value, executeList[0], "test that item is still still index 0");
+
+ for (var i = 1; i < executeList.length; i++) {
+ jsterm.historyPeruse(HISTORY_FORWARD);
+ is (input.value, executeList[i], "check history next idx:" + i);
+ }
+
+ jsterm.historyPeruse(HISTORY_FORWARD);
+ is (input.value, "", "check input is empty again");
+
+ // Simulate pressing Arrow_Down a few times and then if Arrow_Up shows
+ // the previous item from history again.
+ jsterm.historyPeruse(HISTORY_FORWARD);
+ jsterm.historyPeruse(HISTORY_FORWARD);
+ jsterm.historyPeruse(HISTORY_FORWARD);
+
+ is (input.value, "", "check input is still empty");
+
+ let idxLast = executeList.length - 1;
+ jsterm.historyPeruse(HISTORY_BACK);
+ is (input.value, executeList[idxLast], "check history next idx:" + idxLast);
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_input_field_focus_on_panel_select.js b/browser/devtools/webconsole/test/browser_webconsole_input_field_focus_on_panel_select.js
new file mode 100644
index 000000000..192fc5595
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_input_field_focus_on_panel_select.js
@@ -0,0 +1,33 @@
+/* Any copyright is dedicated to the Public Domain
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that the JS input field is focused when the user switches back to the
+// web console from other tools, see bug 891581.
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf8,<p>hello";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ hud.jsterm.clearOutput();
+
+ is(hud.jsterm.inputNode.hasAttribute("focused"), true,
+ "inputNode should be focused");
+
+ hud.ui.filterBox.focus();
+
+ is(hud.ui.filterBox.hasAttribute("focused"), true,
+ "filterBox should be focused");
+
+ is(hud.jsterm.inputNode.hasAttribute("focused"), false,
+ "inputNode shouldn't be focused");
+
+ yield openDebugger();
+ hud = yield openConsole();
+
+ is(hud.jsterm.inputNode.hasAttribute("focused"), true,
+ "inputNode should be focused");
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_inspect-parsed-documents.js b/browser/devtools/webconsole/test/browser_webconsole_inspect-parsed-documents.js
new file mode 100644
index 000000000..e55e021c2
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_inspect-parsed-documents.js
@@ -0,0 +1,34 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that dynamically created (HTML|XML|SVG)Documents can be inspected by
+// clicking on the object in console (bug 1035198).
+
+"use strict;"
+
+const TEST_CASES = [
+ {
+ input: '(new DOMParser()).parseFromString("<a />", "text/html")',
+ output: "HTMLDocument",
+ inspectable: true,
+ },
+ {
+ input: '(new DOMParser()).parseFromString("<a />", "application/xml")',
+ output: "XMLDocument",
+ inspectable: true,
+ },
+ {
+ input: '(new DOMParser()).parseFromString("<svg></svg>", "image/svg+xml")',
+ output: "SVGDocument",
+ inspectable: true,
+ },
+];
+
+const TEST_URI = "data:text/html;charset=utf8," +
+ "browser_webconsole_inspect-parsed-documents.js";
+add_task(function* () {
+ let {tab} = yield loadTab(TEST_URI);
+ let hud = yield openConsole(tab);
+ yield checkOutputForInputs(hud, TEST_CASES);
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_js_input_expansion.js b/browser/devtools/webconsole/test/browser_webconsole_js_input_expansion.js
new file mode 100644
index 000000000..fe0483233
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_js_input_expansion.js
@@ -0,0 +1,55 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the input box expands as the user types long lines.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ hud.jsterm.clearOutput();
+
+ let input = hud.jsterm.inputNode;
+ input.focus();
+
+ is(input.getAttribute("multiline"), "true", "multiline is enabled");
+ // Tests if the inputNode expands.
+ input.value = "hello\nworld\n";
+ let length = input.value.length;
+ input.selectionEnd = length;
+ input.selectionStart = length;
+ function getHeight()
+ {
+ return input.clientHeight;
+ }
+ let initialHeight = getHeight();
+ // Performs an "d". This will trigger/test for the input event that should
+ // change the "row" attribute of the inputNode.
+ EventUtils.synthesizeKey("d", {});
+ let newHeight = getHeight();
+ ok(initialHeight < newHeight, "Height changed: " + newHeight);
+
+ // Add some more rows. Tests for the 8 row limit.
+ input.value = "row1\nrow2\nrow3\nrow4\nrow5\nrow6\nrow7\nrow8\nrow9\nrow10\n";
+ length = input.value.length;
+ input.selectionEnd = length;
+ input.selectionStart = length;
+ EventUtils.synthesizeKey("d", {});
+ let newerHeight = getHeight();
+
+ ok(newerHeight > newHeight, "height changed: " + newerHeight);
+
+ // Test if the inputNode shrinks again.
+ input.value = "";
+ EventUtils.synthesizeKey("d", {});
+ let height = getHeight();
+ info("height: " + height);
+ info("initialHeight: " + initialHeight);
+ let finalHeightDifference = Math.abs(initialHeight - height);
+ ok(finalHeightDifference <= 1, "height shrank to original size within 1px");
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_jsterm.js b/browser/devtools/webconsole/test/browser_webconsole_jsterm.js
new file mode 100644
index 000000000..8b9100d0e
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_jsterm.js
@@ -0,0 +1,144 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let jsterm;
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ jsterm = hud.jsterm;
+ yield testJSTerm(hud);
+ jsterm = null;
+});
+
+function checkResult(msg, desc) {
+ let def = promise.defer();
+ waitForMessages({
+ webconsole: jsterm.hud.owner,
+ messages: [{
+ name: desc,
+ category: CATEGORY_OUTPUT,
+ }],
+ }).then(([result]) => {
+ let node = [...result.matched][0].querySelector(".message-body");
+ if (typeof msg == "string") {
+ is(node.textContent.trim(), msg,
+ "correct message shown for " + desc);
+ }
+ else if (typeof msg == "function") {
+ ok(msg(node), "correct message shown for " + desc);
+ }
+
+ def.resolve();
+ });
+ return def.promise;
+}
+
+function testJSTerm(hud)
+{
+ const HELP_URL = "https://developer.mozilla.org/docs/Tools/Web_Console/Helpers";
+
+ jsterm.clearOutput();
+ yield jsterm.execute("$('#header').getAttribute('id')");
+ yield checkResult('"header"', "$() worked");
+
+ jsterm.clearOutput();
+ yield jsterm.execute("$$('h1').length");
+ yield checkResult("1", "$$() worked");
+
+ jsterm.clearOutput();
+ yield jsterm.execute("$x('.//*', document.body)[0] == $$('h1')[0]");
+ yield checkResult("true", "$x() worked");
+
+ // no jsterm.clearOutput() here as we clear the output using the clear() fn.
+ yield jsterm.execute("clear()");
+
+ yield waitForSuccess({
+ name: "clear() worked",
+ validator: function()
+ {
+ return jsterm.outputNode.childNodes.length == 0;
+ }
+ });
+
+ jsterm.clearOutput();
+ yield jsterm.execute("keys({b:1})[0] == 'b'");
+ yield checkResult("true", "keys() worked", 1);
+
+ jsterm.clearOutput();
+ yield jsterm.execute("values({b:1})[0] == 1");
+ yield checkResult("true", "values() worked", 1);
+
+ jsterm.clearOutput();
+
+ let openedLinks = 0;
+ let oldOpenLink = hud.openLink;
+ hud.openLink = (url) => {
+ if (url == HELP_URL) {
+ openedLinks++;
+ }
+ };
+
+ yield jsterm.execute("help()");
+ yield jsterm.execute("help");
+ yield jsterm.execute("?");
+
+ let output = jsterm.outputNode.querySelector(".message[category='output']");
+ ok(!output, "no output for help() calls");
+ is(openedLinks, 3, "correct number of pages opened by the help calls");
+ hud.openLink = oldOpenLink;
+
+ jsterm.clearOutput();
+ yield jsterm.execute("pprint({b:2, a:1})");
+ yield checkResult("\" b: 2\n a: 1\"", "pprint()");
+
+ // check instanceof correctness, bug 599940
+ jsterm.clearOutput();
+ yield jsterm.execute("[] instanceof Array");
+ yield checkResult("true", "[] instanceof Array == true");
+
+ jsterm.clearOutput();
+ yield jsterm.execute("({}) instanceof Object");
+ yield checkResult("true", "({}) instanceof Object == true");
+
+ // check for occurrences of Object XRayWrapper, bug 604430
+ jsterm.clearOutput();
+ yield jsterm.execute("document");
+ yield checkResult(function(node) {
+ return node.textContent.search(/\[object xraywrapper/i) == -1;
+ }, "document - no XrayWrapper");
+
+ // check that pprint(window) and keys(window) don't throw, bug 608358
+ jsterm.clearOutput();
+ yield jsterm.execute("pprint(window)");
+ yield checkResult(null, "pprint(window)");
+
+ jsterm.clearOutput();
+ yield jsterm.execute("keys(window)");
+ yield checkResult(null, "keys(window)");
+
+ // bug 614561
+ jsterm.clearOutput();
+ yield jsterm.execute("pprint('hi')");
+ yield checkResult("\" 0: \"h\"\n 1: \"i\"\"", "pprint('hi')");
+
+ // check that pprint(function) shows function source, bug 618344
+ jsterm.clearOutput();
+ yield jsterm.execute("pprint(function() { var someCanaryValue = 42; })");
+ yield checkResult(function(node) {
+ return node.textContent.indexOf("someCanaryValue") > -1;
+ }, "pprint(function) shows source");
+
+ // check that an evaluated null produces "null", bug 650780
+ jsterm.clearOutput();
+ yield jsterm.execute("null");
+ yield checkResult("null", "null is null");
+
+ jsterm.clearOutput();
+ yield jsterm.execute("undefined");
+ yield checkResult("undefined", "undefined is printed");
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_live_filtering_of_message_types.js b/browser/devtools/webconsole/test/browser_webconsole_live_filtering_of_message_types.js
new file mode 100644
index 000000000..02b79b6e9
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_live_filtering_of_message_types.js
@@ -0,0 +1,55 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the message type filter checkboxes work.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ hud.jsterm.clearOutput();
+
+ let console = content.console;
+
+ for (let i = 0; i < 50; i++) {
+ console.log("foobarz #" + i);
+ }
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "foobarz #49",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ is(hud.outputNode.children.length, 50, "number of messages");
+
+ hud.setFilterState("log", false);
+ is(countMessageNodes(hud), 0, "the log nodes are hidden when the " +
+ "corresponding filter is switched off");
+
+ hud.setFilterState("log", true);
+ is(countMessageNodes(hud), 50, "the log nodes reappear when the " +
+ "corresponding filter is switched on");
+});
+
+function countMessageNodes(hud) {
+ let messageNodes = hud.outputNode.querySelectorAll(".message");
+ let displayedMessageNodes = 0;
+ let view = hud.iframeWindow;
+ for (let i = 0; i < messageNodes.length; i++) {
+ let computedStyle = view.getComputedStyle(messageNodes[i], null);
+ if (computedStyle.display !== "none") {
+ displayedMessageNodes++;
+ }
+ }
+
+ return displayedMessageNodes;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_live_filtering_on_search_strings.js b/browser/devtools/webconsole/test/browser_webconsole_live_filtering_on_search_strings.js
new file mode 100644
index 000000000..fb229075a
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_live_filtering_on_search_strings.js
@@ -0,0 +1,96 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the text filter box works.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ hud.jsterm.clearOutput();
+
+ let console = content.console;
+
+ for (let i = 0; i < 50; i++) {
+ console.log("http://www.example.com/ " + i);
+ }
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "http://www.example.com/ 49",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ })
+
+ is(hud.outputNode.children.length, 50, "number of messages");
+
+ setStringFilter(hud, "http");
+ isnot(countMessageNodes(hud), 0, "the log nodes are not hidden when the " +
+ "search string is set to \"http\"");
+
+ setStringFilter(hud, "hxxp");
+ is(countMessageNodes(hud), 0, "the log nodes are hidden when the search " +
+ "string is set to \"hxxp\"");
+
+ setStringFilter(hud, "ht tp");
+ isnot(countMessageNodes(hud), 0, "the log nodes are not hidden when the " +
+ "search string is set to \"ht tp\"");
+
+ setStringFilter(hud, " zzzz zzzz ");
+ is(countMessageNodes(hud), 0, "the log nodes are hidden when the search " +
+ "string is set to \" zzzz zzzz \"");
+
+ setStringFilter(hud, "");
+ isnot(countMessageNodes(hud), 0, "the log nodes are not hidden when the " +
+ "search string is removed");
+
+ setStringFilter(hud, "\u9f2c");
+ is(countMessageNodes(hud), 0, "the log nodes are hidden when searching " +
+ "for weasels");
+
+ setStringFilter(hud, "\u0007");
+ is(countMessageNodes(hud), 0, "the log nodes are hidden when searching for " +
+ "the bell character");
+
+ setStringFilter(hud, '"foo"');
+ is(countMessageNodes(hud), 0, "the log nodes are hidden when searching for " +
+ 'the string "foo"');
+
+ setStringFilter(hud, "'foo'");
+ is(countMessageNodes(hud), 0, "the log nodes are hidden when searching for " +
+ "the string 'foo'");
+
+ setStringFilter(hud, "foo\"bar'baz\"boo'");
+ is(countMessageNodes(hud), 0, "the log nodes are hidden when searching for " +
+ "the string \"foo\"bar'baz\"boo'\"");
+});
+
+function countMessageNodes(hud) {
+ let outputNode = hud.outputNode;
+
+ let messageNodes = outputNode.querySelectorAll(".message");
+ let displayedMessageNodes = 0;
+ let view = hud.iframeWindow;
+ for (let i = 0; i < messageNodes.length; i++) {
+ let computedStyle = view.getComputedStyle(messageNodes[i], null);
+ if (computedStyle.display !== "none") {
+ displayedMessageNodes++;
+ }
+ }
+
+ return displayedMessageNodes;
+}
+
+function setStringFilter(hud, aValue)
+{
+ hud.ui.filterBox.value = aValue;
+ hud.ui.adjustVisibilityOnSearchStringChange();
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_log_file_filter.js b/browser/devtools/webconsole/test/browser_webconsole_log_file_filter.js
new file mode 100644
index 000000000..906bb2b48
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_log_file_filter.js
@@ -0,0 +1,82 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the text filter box works to filter based on filenames
+// where the logs were generated.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug_923281_console_log_filter.html";
+
+let hud;
+
+"use strict";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ hud = yield openConsole();
+ yield consoleOpened();
+
+ testLiveFilteringOnSearchStrings();
+
+ hud = null;
+});
+
+function consoleOpened() {
+ let console = content.console;
+ console.log("sentinel log");
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "sentinel log",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG
+ }],
+ })
+}
+
+function testLiveFilteringOnSearchStrings() {
+ is(hud.outputNode.children.length, 4, "number of messages");
+
+ setStringFilter("random");
+ is(countMessageNodes(), 1, "the log nodes not containing string " +
+ "\"random\" are hidden");
+
+ setStringFilter("test2.js");
+ is(countMessageNodes(), 2, "show only log nodes containing string " +
+ "\"test2.js\" or log nodes created from files with filename " +
+ "containing \"test2.js\" as substring.");
+
+ setStringFilter("test1");
+ is(countMessageNodes(), 2, "show only log nodes containing string " +
+ "\"test1\" or log nodes created from files with filename " +
+ "containing \"test1\" as substring.");
+
+ setStringFilter("");
+ is(countMessageNodes(), 4, "show all log nodes on setting filter string " +
+ "as \"\".");
+}
+
+function countMessageNodes() {
+ let outputNode = hud.outputNode;
+
+ let messageNodes = outputNode.querySelectorAll(".message");
+ content.console.log(messageNodes.length);
+ let displayedMessageNodes = 0;
+ let view = hud.iframeWindow;
+ for (let i = 0; i < messageNodes.length; i++) {
+ let computedStyle = view.getComputedStyle(messageNodes[i], null);
+ if (computedStyle.display !== "none") {
+ displayedMessageNodes++;
+ }
+ }
+
+ return displayedMessageNodes;
+}
+
+function setStringFilter(aValue)
+{
+ hud.ui.filterBox.value = aValue;
+ hud.ui.adjustVisibilityOnSearchStringChange();
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_message_node_id.js b/browser/devtools/webconsole/test/browser_webconsole_message_node_id.js
new file mode 100644
index 000000000..0a94538e6
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_message_node_id.js
@@ -0,0 +1,27 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+
+ hud.jsterm.execute("console.log('a log message')");
+
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "a log message",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ let msg = [...result.matched][0];
+ ok(msg.getAttribute("id"), "log message has an ID");
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_netlogging.js b/browser/devtools/webconsole/test/browser_webconsole_netlogging.js
new file mode 100644
index 000000000..7cf95822e
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_netlogging.js
@@ -0,0 +1,213 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Julian Viereck <jviereck@mozilla.com>
+ * Patrick Walton <pcwalton@mozilla.com>
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Tests that network log messages bring up the network panel.
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console network logging tests";
+
+const TEST_NETWORK_REQUEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-network-request.html";
+
+const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/test/test-image.png";
+
+const TEST_DATA_JSON_CONTENT =
+ '{ id: "test JSON data", myArray: [ "foo", "bar", "baz", "biff" ] }';
+
+let lastRequest = null;
+let requestCallback = null;
+let browser, hud;
+
+function test()
+{
+ loadTab(TEST_URI).then((tab) => {
+ browser = tab.browser;
+
+ openConsole().then((aHud) => {
+ hud = aHud;
+
+ HUDService.lastFinishedRequest.callback = requestCallbackWrapper;
+
+ executeSoon(testPageLoad);
+ });
+ });
+}
+
+function requestCallbackWrapper(aRequest)
+{
+ lastRequest = aRequest;
+
+ hud.ui.webConsoleClient.getResponseContent(lastRequest.actor,
+ function(aResponse) {
+ lastRequest.response.content = aResponse.content;
+ lastRequest.discardResponseBody = aResponse.contentDiscarded;
+
+ hud.ui.webConsoleClient.getRequestPostData(lastRequest.actor,
+ function(aResponse) {
+ lastRequest.request.postData = aResponse.postData;
+ lastRequest.discardRequestBody = aResponse.postDataDiscarded;
+
+ if (requestCallback) {
+ requestCallback();
+ }
+ });
+ });
+}
+
+function testPageLoad()
+{
+ requestCallback = function() {
+ // Check if page load was logged correctly.
+ ok(lastRequest, "Page load was logged");
+
+ is(lastRequest.request.url, TEST_NETWORK_REQUEST_URI,
+ "Logged network entry is page load");
+ is(lastRequest.request.method, "GET", "Method is correct");
+ ok(!lastRequest.request.postData.text, "No request body was stored");
+ ok(lastRequest.discardRequestBody, "Request body was discarded");
+ ok(!lastRequest.response.content.text, "No response body was stored");
+ ok(lastRequest.discardResponseBody, "Response body was discarded");
+
+ lastRequest = null;
+ requestCallback = null;
+ executeSoon(testPageLoadBody);
+ };
+
+ content.location = TEST_NETWORK_REQUEST_URI;
+}
+
+function testPageLoadBody()
+{
+ // Turn on logging of request bodies and check again.
+ hud.ui.setSaveRequestAndResponseBodies(true).then(() => {
+ ok(hud.ui._saveRequestAndResponseBodies,
+ "The saveRequestAndResponseBodies property was successfully set.");
+
+ testPageLoadBodyAfterSettingUpdate();
+ });
+}
+
+function testPageLoadBodyAfterSettingUpdate()
+{
+ let loaded = false;
+ let requestCallbackInvoked = false;
+
+ requestCallback = function() {
+ ok(lastRequest, "Page load was logged again");
+ ok(!lastRequest.discardResponseBody, "Response body was not discarded");
+ is(lastRequest.response.content.text.indexOf("<!DOCTYPE HTML>"), 0,
+ "Response body's beginning is okay");
+
+ lastRequest = null;
+ requestCallback = null;
+ requestCallbackInvoked = true;
+
+ if (loaded) {
+ executeSoon(testXhrGet);
+ }
+ };
+
+ browser.addEventListener("load", function onLoad() {
+ browser.removeEventListener("load", onLoad, true);
+ loaded = true;
+
+ if (requestCallbackInvoked) {
+ executeSoon(testXhrGet);
+ }
+ }, true);
+
+ content.location.reload();
+}
+
+function testXhrGet()
+{
+ requestCallback = function() {
+ ok(lastRequest, "testXhrGet() was logged");
+ is(lastRequest.request.method, "GET", "Method is correct");
+ ok(!lastRequest.request.postData.text, "No request body was sent");
+ ok(!lastRequest.discardRequestBody, "Request body was not discarded");
+ is(lastRequest.response.content.text, TEST_DATA_JSON_CONTENT,
+ "Response is correct");
+
+ lastRequest = null;
+ requestCallback = null;
+ executeSoon(testXhrPost);
+ };
+
+ // Start the XMLHttpRequest() GET test.
+ content.wrappedJSObject.testXhrGet();
+}
+
+function testXhrPost()
+{
+ requestCallback = function() {
+ ok(lastRequest, "testXhrPost() was logged");
+ is(lastRequest.request.method, "POST", "Method is correct");
+ is(lastRequest.request.postData.text, "Hello world!",
+ "Request body was logged");
+ is(lastRequest.response.content.text, TEST_DATA_JSON_CONTENT,
+ "Response is correct");
+
+ lastRequest = null;
+ requestCallback = null;
+ executeSoon(testFormSubmission);
+ };
+
+ // Start the XMLHttpRequest() POST test.
+ content.wrappedJSObject.testXhrPost();
+}
+
+function testFormSubmission()
+{
+ // Start the form submission test. As the form is submitted, the page is
+ // loaded again. Bind to the load event to catch when this is done.
+ requestCallback = function() {
+ ok(lastRequest, "testFormSubmission() was logged");
+ is(lastRequest.request.method, "POST", "Method is correct");
+ isnot(lastRequest.request.postData.text.
+ indexOf("Content-Type: application/x-www-form-urlencoded"), -1,
+ "Content-Type is correct");
+ isnot(lastRequest.request.postData.text.
+ indexOf("Content-Length: 20"), -1, "Content-length is correct");
+ isnot(lastRequest.request.postData.text.
+ indexOf("name=foo+bar&age=144"), -1, "Form data is correct");
+ is(lastRequest.response.content.text.indexOf("<!DOCTYPE HTML>"), 0,
+ "Response body's beginning is okay");
+
+ executeSoon(testNetworkPanel);
+ };
+
+ let form = content.document.querySelector("form");
+ ok(form, "we have the HTML form");
+ form.submit();
+}
+
+function testNetworkPanel()
+{
+ // Open the NetworkPanel. The functionality of the NetworkPanel is tested
+ // within separate test files.
+ let networkPanel = hud.ui.openNetworkPanel(hud.ui.filterBox, lastRequest);
+
+ networkPanel.panel.addEventListener("popupshown", function onPopupShown() {
+ networkPanel.panel.removeEventListener("popupshown", onPopupShown, true);
+
+ is(hud.ui.filterBox._netPanel, networkPanel,
+ "Network panel stored on anchor node");
+ ok(true, "NetworkPanel was opened");
+
+ // All tests are done. Shutdown.
+ networkPanel.panel.hidePopup();
+ lastRequest = null;
+ HUDService.lastFinishedRequest.callback = null;
+ browser = requestCallback = hud = null;
+ executeSoon(finishTest);
+ }, true);
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_network_panel.js b/browser/devtools/webconsole/test/browser_webconsole_network_panel.js
new file mode 100644
index 000000000..0cea84fea
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_network_panel.js
@@ -0,0 +1,541 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the network panel works.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/test/test-image.png";
+const TEST_ENCODING_ISO_8859_1 = "http://example.com/browser/browser/devtools/webconsole/test/test-encoding-ISO-8859-1.html";
+
+const TEST_IMG_BASE64 =
+ "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAVRJREFU" +
+ "OI2lk7FLw0AUxr+YpC1CBqcMWfsvCCLdXFzqEJCgDl1EQRGxg9AhSBEJONhFhG52UCuFDjq5dxD8" +
+ "FwoO0qGDOBQkl7vLOeWa2EQDffDBvTu+373Hu1OEEJgntGgxGD6J+7fLXKbt5VNUyhsKAChRBQcP" +
+ "FVFeWskFGH694mZroCQqCLlAwPxcgJBP254CmAD5B7C7dgHLMLF3uzoL4DQEod+Z5sP1FizDxGgy" +
+ "BqfhLID9AahX29J89bwPFgMsSEAQglAf9WobhPpScbPXr4FQHyzIADTsDizDRMPuIOC+zEeTMZo9" +
+ "BwH3EfAMACccbtfGaDKGZZg423yUZrdrg3EqxQlPr0BTdTR7joREN2uqnlBmCwW1hIJagtev4f3z" +
+ "A16/JvfiigMSYyzqJXlw/XKUyOORMUaBor6YavgdjKa8xGOnidadmwtwsnMu18q83/kHSou+bFND" +
+ "Dr4AAAAASUVORK5CYII=";
+
+let testDriver, hud;
+
+function test() {
+ loadTab(TEST_URI).then(() => {
+ openConsole().then(testNetworkPanel);
+ });
+}
+
+function testNetworkPanel(aHud) {
+ hud = aHud;
+ testDriver = testGen();
+ testDriver.next();
+}
+
+function checkIsVisible(aPanel, aList) {
+ for (let id in aList) {
+ let node = aPanel.document.getElementById(id);
+ let isVisible = aList[id];
+ is(node.style.display, (isVisible ? "block" : "none"), id + " isVisible=" + isVisible);
+ }
+}
+
+function checkNodeContent(aPanel, aId, aContent) {
+ let node = aPanel.document.getElementById(aId);
+ if (node == null) {
+ ok(false, "Tried to access node " + aId + " that doesn't exist!");
+ }
+ else if (node.textContent.indexOf(aContent) != -1) {
+ ok(true, "checking content of " + aId);
+ }
+ else {
+ ok(false, "Got false value for " + aId + ": " + node.textContent + " doesn't have " + aContent);
+ }
+}
+
+function checkNodeKeyValue(aPanel, aId, aKey, aValue) {
+ let node = aPanel.document.getElementById(aId);
+
+ let headers = node.querySelectorAll("th");
+ for (let i = 0; i < headers.length; i++) {
+ if (headers[i].textContent == (aKey + ":")) {
+ is(headers[i].nextElementSibling.textContent, aValue,
+ "checking content of " + aId + " for key " + aKey);
+ return;
+ }
+ }
+
+ ok(false, "content check failed for " + aId + ", key " + aKey);
+}
+
+function testGen() {
+ let filterBox = hud.ui.filterBox;
+
+ let httpActivity = {
+ updates: [],
+ discardRequestBody: true,
+ discardResponseBody: true,
+ startedDateTime: (new Date()).toISOString(),
+ request: {
+ url: "http://www.testpage.com",
+ method: "GET",
+ cookies: [],
+ headers: [
+ { name: "foo", value: "bar" },
+ ],
+ },
+ response: {
+ headers: [],
+ content: {},
+ cookies: [],
+ },
+ timings: {},
+ };
+
+ let networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+
+ is(filterBox._netPanel, networkPanel,
+ "Network panel stored on the anchor object");
+
+ networkPanel._onUpdate = function() {
+ networkPanel._onUpdate = null;
+ executeSoon(function() {
+ testDriver.next();
+ });
+ };
+
+ yield undefined;
+
+ info("test 1");
+
+ checkIsVisible(networkPanel, {
+ requestCookie: false,
+ requestFormData: false,
+ requestBody: false,
+ responseContainer: false,
+ responseBody: false,
+ responseNoBody: false,
+ responseImage: false,
+ responseImageCached: false
+ });
+
+ checkNodeContent(networkPanel, "header", "http://www.testpage.com");
+ checkNodeContent(networkPanel, "header", "GET");
+ checkNodeKeyValue(networkPanel, "requestHeadersContent", "foo", "bar");
+
+ // Test request body.
+ info("test 2: request body");
+ httpActivity.discardRequestBody = false;
+ httpActivity.request.postData = { text: "hello world" };
+ networkPanel.update();
+
+ checkIsVisible(networkPanel, {
+ requestBody: true,
+ requestFormData: false,
+ requestCookie: false,
+ responseContainer: false,
+ responseBody: false,
+ responseNoBody: false,
+ responseImage: false,
+ responseImageCached: false
+ });
+ checkNodeContent(networkPanel, "requestBodyContent", "hello world");
+
+ // Test response header.
+ info("test 3: response header");
+ httpActivity.timings.wait = 10;
+ httpActivity.response.httpVersion = "HTTP/3.14";
+ httpActivity.response.status = 999;
+ httpActivity.response.statusText = "earthquake win";
+ httpActivity.response.content.mimeType = "text/html";
+ httpActivity.response.headers.push(
+ { name: "Content-Type", value: "text/html" },
+ { name: "leaveHouses", value: "true" }
+ );
+
+ networkPanel.update();
+
+ checkIsVisible(networkPanel, {
+ requestBody: true,
+ requestFormData: false,
+ requestCookie: false,
+ responseContainer: true,
+ responseBody: false,
+ responseNoBody: false,
+ responseImage: false,
+ responseImageCached: false
+ });
+
+ checkNodeContent(networkPanel, "header", "HTTP/3.14 999 earthquake win");
+ checkNodeKeyValue(networkPanel, "responseHeadersContent", "leaveHouses", "true");
+ checkNodeContent(networkPanel, "responseHeadersInfo", "10ms");
+
+ info("test 4");
+
+ httpActivity.discardResponseBody = false;
+ httpActivity.timings.receive = 2;
+ networkPanel.update();
+
+ checkIsVisible(networkPanel, {
+ requestBody: true,
+ requestCookie: false,
+ requestFormData: false,
+ responseContainer: true,
+ responseBody: false,
+ responseNoBody: false,
+ responseImage: false,
+ responseImageCached: false
+ });
+
+ info("test 5");
+
+ httpActivity.updates.push("responseContent", "eventTimings");
+ networkPanel.update();
+
+ checkNodeContent(networkPanel, "responseNoBodyInfo", "2ms");
+ checkIsVisible(networkPanel, {
+ requestBody: true,
+ requestCookie: false,
+ responseContainer: true,
+ responseBody: false,
+ responseNoBody: true,
+ responseImage: false,
+ responseImageCached: false
+ });
+
+ networkPanel.panel.hidePopup();
+
+ // Second run: Test for cookies and response body.
+ info("test 6: cookies and response body");
+ httpActivity.request.cookies.push(
+ { name: "foo", value: "bar" },
+ { name: "hello", value: "world" }
+ );
+ httpActivity.response.content.text = "get out here";
+
+ networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+ is(filterBox._netPanel, networkPanel,
+ "Network panel stored on httpActivity object");
+
+ networkPanel._onUpdate = function() {
+ networkPanel._onUpdate = null;
+ executeSoon(function() {
+ testDriver.next();
+ });
+ };
+
+ yield undefined;
+
+ checkIsVisible(networkPanel, {
+ requestBody: true,
+ requestFormData: false,
+ requestCookie: true,
+ responseContainer: true,
+ responseCookie: false,
+ responseBody: true,
+ responseNoBody: false,
+ responseImage: false,
+ responseImageCached: false
+ });
+
+ checkNodeKeyValue(networkPanel, "requestCookieContent", "foo", "bar");
+ checkNodeKeyValue(networkPanel, "requestCookieContent", "hello", "world");
+ checkNodeContent(networkPanel, "responseBodyContent", "get out here");
+ checkNodeContent(networkPanel, "responseBodyInfo", "2ms");
+
+ networkPanel.panel.hidePopup();
+
+ // Third run: Test for response cookies.
+ info("test 6b: response cookies");
+ httpActivity.response.cookies.push(
+ { name: "foobar", value: "boom" },
+ { name: "foobaz", value: "omg" }
+ );
+
+ networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+ is(filterBox._netPanel, networkPanel,
+ "Network panel stored on httpActivity object");
+
+ networkPanel._onUpdate = function() {
+ networkPanel._onUpdate = null;
+ executeSoon(function() {
+ testDriver.next();
+ });
+ };
+
+ yield undefined;
+
+ checkIsVisible(networkPanel, {
+ requestBody: true,
+ requestFormData: false,
+ requestCookie: true,
+ responseContainer: true,
+ responseCookie: true,
+ responseBody: true,
+ responseNoBody: false,
+ responseImage: false,
+ responseImageCached: false,
+ responseBodyFetchLink: false,
+ });
+
+ checkNodeKeyValue(networkPanel, "responseCookieContent", "foobar", "boom");
+ checkNodeKeyValue(networkPanel, "responseCookieContent", "foobaz", "omg");
+
+ networkPanel.panel.hidePopup();
+
+ // Check image request.
+ info("test 7: image request");
+ httpActivity.response.headers[1].value = "image/png";
+ httpActivity.response.content.mimeType = "image/png";
+ httpActivity.response.content.text = TEST_IMG_BASE64;
+ httpActivity.request.url = TEST_IMG;
+
+ networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+ networkPanel._onUpdate = function() {
+ networkPanel._onUpdate = null;
+ executeSoon(function() {
+ testDriver.next();
+ });
+ };
+
+ yield undefined;
+
+ checkIsVisible(networkPanel, {
+ requestBody: true,
+ requestFormData: false,
+ requestCookie: true,
+ responseContainer: true,
+ responseBody: false,
+ responseNoBody: false,
+ responseImage: true,
+ responseImageCached: false,
+ responseBodyFetchLink: false,
+ });
+
+ let imgNode = networkPanel.document.getElementById("responseImageNode");
+ is(imgNode.getAttribute("src"), "data:image/png;base64," + TEST_IMG_BASE64,
+ "Displayed image is correct");
+
+ function checkImageResponseInfo() {
+ checkNodeContent(networkPanel, "responseImageInfo", "2ms");
+ checkNodeContent(networkPanel, "responseImageInfo", "16x16px");
+ }
+
+ // Check if the image is loaded already.
+ imgNode.addEventListener("load", function onLoad() {
+ imgNode.removeEventListener("load", onLoad, false);
+ checkImageResponseInfo();
+ networkPanel.panel.hidePopup();
+ testDriver.next();
+ }, false);
+ yield undefined;
+
+ // Check cached image request.
+ info("test 8: cached image request");
+ httpActivity.response.httpVersion = "HTTP/1.1";
+ httpActivity.response.status = 304;
+ httpActivity.response.statusText = "Not Modified";
+
+ networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+ networkPanel._onUpdate = function() {
+ networkPanel._onUpdate = null;
+ executeSoon(function() {
+ testDriver.next();
+ });
+ };
+
+ yield undefined;
+
+ checkIsVisible(networkPanel, {
+ requestBody: true,
+ requestFormData: false,
+ requestCookie: true,
+ responseContainer: true,
+ responseBody: false,
+ responseNoBody: false,
+ responseImage: false,
+ responseImageCached: true
+ });
+
+ imgNode = networkPanel.document.getElementById("responseImageCachedNode");
+ is(imgNode.getAttribute("src"), "data:image/png;base64," + TEST_IMG_BASE64,
+ "Displayed image is correct");
+
+ networkPanel.panel.hidePopup();
+
+ // Test sent form data.
+ info("test 9: sent form data");
+ httpActivity.request.postData.text = [
+ "Content-Type: application/x-www-form-urlencoded",
+ "Content-Length: 59",
+ "name=rob&age=20"
+ ].join("\n");
+
+ networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+ networkPanel._onUpdate = function() {
+ networkPanel._onUpdate = null;
+ executeSoon(function() {
+ testDriver.next();
+ });
+ };
+
+ yield undefined;
+
+ checkIsVisible(networkPanel, {
+ requestBody: false,
+ requestFormData: true,
+ requestCookie: true,
+ responseContainer: true,
+ responseBody: false,
+ responseNoBody: false,
+ responseImage: false,
+ responseImageCached: true
+ });
+
+ checkNodeKeyValue(networkPanel, "requestFormDataContent", "name", "rob");
+ checkNodeKeyValue(networkPanel, "requestFormDataContent", "age", "20");
+ networkPanel.panel.hidePopup();
+
+ // Test no space after Content-Type:
+ info("test 10: no space after Content-Type header in post data");
+ httpActivity.request.postData.text = "Content-Type:application/x-www-form-urlencoded\n";
+
+ networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+ networkPanel._onUpdate = function() {
+ networkPanel._onUpdate = null;
+ executeSoon(function() {
+ testDriver.next();
+ });
+ };
+
+ yield undefined;
+
+ checkIsVisible(networkPanel, {
+ requestBody: false,
+ requestFormData: true,
+ requestCookie: true,
+ responseContainer: true,
+ responseBody: false,
+ responseNoBody: false,
+ responseImage: false,
+ responseImageCached: true
+ });
+
+ networkPanel.panel.hidePopup();
+
+ // Test cached data.
+
+ info("test 11: cached data");
+
+ httpActivity.request.url = TEST_ENCODING_ISO_8859_1;
+ httpActivity.response.headers[1].value = "application/json";
+ httpActivity.response.content.mimeType = "application/json";
+ httpActivity.response.content.text = "my cached data is here!";
+
+ networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+ networkPanel._onUpdate = function() {
+ networkPanel._onUpdate = null;
+ executeSoon(function() {
+ testDriver.next();
+ });
+ };
+
+ yield undefined;
+
+ checkIsVisible(networkPanel, {
+ requestBody: false,
+ requestFormData: true,
+ requestCookie: true,
+ responseContainer: true,
+ responseBody: false,
+ responseBodyCached: true,
+ responseNoBody: false,
+ responseImage: false,
+ responseImageCached: false
+ });
+
+ checkNodeContent(networkPanel, "responseBodyCachedContent",
+ "my cached data is here!");
+
+ networkPanel.panel.hidePopup();
+
+ // Test a response with a content type that can't be displayed in the
+ // NetworkPanel.
+ info("test 12: unknown content type");
+ httpActivity.response.headers[1].value = "application/x-shockwave-flash";
+ httpActivity.response.content.mimeType = "application/x-shockwave-flash";
+
+ networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+ networkPanel._onUpdate = function() {
+ networkPanel._onUpdate = null;
+ executeSoon(function() {
+ testDriver.next();
+ });
+ };
+
+ yield undefined;
+
+ checkIsVisible(networkPanel, {
+ requestBody: false,
+ requestFormData: true,
+ requestCookie: true,
+ responseContainer: true,
+ responseBody: false,
+ responseBodyCached: false,
+ responseBodyUnknownType: true,
+ responseNoBody: false,
+ responseImage: false,
+ responseImageCached: false
+ });
+
+ let responseString =
+ WCU_l10n.getFormatStr("NetworkPanel.responseBodyUnableToDisplay.content",
+ ["application/x-shockwave-flash"]);
+ checkNodeContent(networkPanel, "responseBodyUnknownTypeContent", responseString);
+ networkPanel.panel.hidePopup();
+
+ /*
+
+ // This test disabled. See bug 603620.
+
+ // Test if the NetworkPanel figures out the content type based on an URL as
+ // well.
+ delete httpActivity.response.header["Content-Type"];
+ httpActivity.url = "http://www.test.com/someCrazyFile.swf?done=right&ending=txt";
+
+ networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+ networkPanel.isDoneCallback = function NP_doneCallback() {
+ networkPanel.isDoneCallback = null;
+ testDriver.next();
+ }
+
+ yield undefined;
+
+ checkIsVisible(networkPanel, {
+ requestBody: false,
+ requestFormData: true,
+ requestCookie: true,
+ responseContainer: true,
+ responseBody: false,
+ responseBodyCached: false,
+ responseBodyUnknownType: true,
+ responseNoBody: false,
+ responseImage: false,
+ responseImageCached: false
+ });
+
+ // Systems without Flash installed will return an empty string here. Ignore.
+ if (networkPanel.document.getElementById("responseBodyUnknownTypeContent").textContent !== "")
+ checkNodeContent(networkPanel, "responseBodyUnknownTypeContent", responseString);
+ else
+ ok(true, "Flash not installed");
+
+ networkPanel.panel.hidePopup(); */
+
+ // All done!
+ testDriver = hud = null;
+ executeSoon(finishTest);
+
+ yield undefined;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_notifications.js b/browser/devtools/webconsole/test/browser_webconsole_notifications.js
new file mode 100644
index 000000000..c2be3ab8f
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_notifications.js
@@ -0,0 +1,77 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for notifications";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let consoleOpened = promise.defer();
+ let gotEvents = waitForEvents(consoleOpened.promise);
+ let hud = yield openConsole().then(() => consoleOpened.resolve());
+
+ yield gotEvents;
+});
+
+function waitForEvents(onConsoleOpened) {
+ let deferred = promise.defer();
+
+ function webConsoleCreated(aID)
+ {
+ Services.obs.removeObserver(observer, "web-console-created");
+ ok(HUDService.getHudReferenceById(aID), "We have a hud reference");
+ content.wrappedJSObject.console.log("adding a log message");
+ }
+
+ function webConsoleDestroyed(aID)
+ {
+ Services.obs.removeObserver(observer, "web-console-destroyed");
+ ok(!HUDService.getHudReferenceById(aID), "We do not have a hud reference");
+ executeSoon(deferred.resolve);
+ }
+
+ function webConsoleMessage(aID, aNodeID)
+ {
+ Services.obs.removeObserver(observer, "web-console-message-created");
+ ok(aID, "we have a console ID");
+ is(typeof aNodeID, "string", "message node id is a string");
+ onConsoleOpened.then(closeConsole);
+ }
+
+ let observer = {
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+
+ observe: function observe(aSubject, aTopic, aData)
+ {
+ aSubject = aSubject.QueryInterface(Ci.nsISupportsString);
+
+ switch(aTopic) {
+ case "web-console-created":
+ webConsoleCreated(aSubject.data);
+ break;
+ case "web-console-destroyed":
+ webConsoleDestroyed(aSubject.data);
+ break;
+ case "web-console-message-created":
+ webConsoleMessage(aSubject, aData);
+ break;
+ default:
+ break;
+ }
+ },
+
+ init: function init()
+ {
+ Services.obs.addObserver(this, "web-console-created", false);
+ Services.obs.addObserver(this, "web-console-destroyed", false);
+ Services.obs.addObserver(this, "web-console-message-created", false);
+ }
+ }
+
+ observer.init();
+
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_open-links-without-callback.js b/browser/devtools/webconsole/test/browser_webconsole_open-links-without-callback.js
new file mode 100644
index 000000000..225a340ef
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_open-links-without-callback.js
@@ -0,0 +1,52 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that if a link without an onclick callback is clicked the link is
+// opened in a new tab and no exception occurs (bug 999236).
+
+"use strict";
+
+function test() {
+ function* runner() {
+ const TEST_EVAL_STRING = "document";
+ const TEST_PAGE_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+ const {tab} = yield loadTab(TEST_PAGE_URI);
+ const hud = yield openConsole(tab);
+
+ hud.jsterm.execute(TEST_EVAL_STRING);
+
+ const EXPECTED_OUTPUT = new RegExp("HTMLDocument \.+");
+
+ let messages = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "JS eval output",
+ text: EXPECTED_OUTPUT,
+ category: CATEGORY_OUTPUT,
+ }],
+ });
+
+ let messageNode = messages[0].matched.values().next().value;
+
+ // The correct anchor is second in the message node; the first anchor has
+ // class .cm-variable. Ignore the first one by not matching anchors that
+ // have the class .cm-variable.
+ let urlNode = messageNode.querySelector("a:not(.cm-variable)");
+
+ let linkOpened = false;
+ let oldOpenUILinkIn = window.openUILinkIn;
+ window.openUILinkIn = function(aLink) {
+ if (aLink == TEST_PAGE_URI) {
+ linkOpened = true;
+ }
+ }
+
+ EventUtils.synthesizeMouseAtCenter(urlNode, {}, hud.iframeWindow);
+
+ ok(linkOpened, "Clicking the URL opens the desired page");
+ window.openUILinkIn = oldOpenUILinkIn;
+ }
+
+ Task.spawn(runner).then(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_01.js b/browser/devtools/webconsole/test/browser_webconsole_output_01.js
new file mode 100644
index 000000000..f9ec8ff38
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_01.js
@@ -0,0 +1,125 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+///////////////////
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("null");
+
+// Test the webconsole output for various types of objects.
+
+const TEST_URI = "data:text/html;charset=utf8,test for console output - 01";
+
+let {DebuggerServer} = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
+
+let LONG_STRING_LENGTH = DebuggerServer.LONG_STRING_LENGTH;
+let LONG_STRING_INITIAL_LENGTH = DebuggerServer.LONG_STRING_INITIAL_LENGTH;
+DebuggerServer.LONG_STRING_LENGTH = 100;
+DebuggerServer.LONG_STRING_INITIAL_LENGTH = 50;
+
+let longString = (new Array(DebuggerServer.LONG_STRING_LENGTH + 4)).join("a");
+let initialString = longString.substring(0, DebuggerServer.LONG_STRING_INITIAL_LENGTH);
+
+let inputTests = [
+ // 0
+ {
+ input: "'hello \\nfrom \\rthe \\\"string world!'",
+ output: "\"hello \nfrom \rthe \"string world!\"",
+ },
+
+ // 1
+ {
+ // unicode test
+ input: "'\xFA\u1E47\u0129\xE7\xF6d\xEA \u021B\u0115\u0219\u0165'",
+ output: "\"\xFA\u1E47\u0129\xE7\xF6d\xEA \u021B\u0115\u0219\u0165\"",
+ },
+
+ // 2
+ {
+ input: "'" + longString + "'",
+ output: '"' + initialString + "\"[\u2026]",
+ printOutput: initialString,
+ },
+
+ // 3
+ {
+ input: "''",
+ output: '""',
+ printOutput: '""',
+ },
+
+ // 4
+ {
+ input: "0",
+ output: "0",
+ },
+
+ // 5
+ {
+ input: "'0'",
+ output: '"0"',
+ },
+
+ // 6
+ {
+ input: "42",
+ output: "42",
+ },
+
+ // 7
+ {
+ input: "'42'",
+ output: '"42"',
+ },
+
+ // 8
+ {
+ input: "/foobar/",
+ output: "/foobar/",
+ inspectable: true,
+ },
+
+ // 9
+ {
+ input: "Symbol()",
+ output: "Symbol()"
+ },
+
+ // 10
+ {
+ input: "Symbol('foo')",
+ output: "Symbol(foo)"
+ },
+
+ // 11
+ {
+ input: "Symbol.iterator",
+ output: "Symbol(Symbol.iterator)"
+ },
+];
+
+longString = initialString = null;
+
+function test() {
+ requestLongerTimeout(2);
+
+ registerCleanupFunction(() => {
+ DebuggerServer.LONG_STRING_LENGTH = LONG_STRING_LENGTH;
+ DebuggerServer.LONG_STRING_INITIAL_LENGTH = LONG_STRING_INITIAL_LENGTH;
+ });
+
+ Task.spawn(function*() {
+ let {tab} = yield loadTab(TEST_URI);
+ let hud = yield openConsole(tab);
+ return checkOutputForInputs(hud, inputTests);
+ }).then(finishUp);
+}
+
+function finishUp() {
+ longString = initialString = inputTests = null;
+ finishTest();
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_02.js b/browser/devtools/webconsole/test/browser_webconsole_output_02.js
new file mode 100644
index 000000000..88c4df245
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_02.js
@@ -0,0 +1,160 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test the webconsole output for various types of objects.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-02.html";
+
+let inputTests = [
+ // 0 - native named function
+ {
+ input: "document.getElementById",
+ output: "function getElementById()",
+ printOutput: "function getElementById() {\n [native code]\n}",
+ inspectable: true,
+ variablesViewLabel: "getElementById()",
+ },
+
+ // 1 - anonymous function
+ {
+ input: "(function() { return 42; })",
+ output: "function ()",
+ printOutput: "function () { return 42; }",
+ inspectable: true,
+ },
+
+ // 2 - named function
+ {
+ input: "window.testfn1",
+ output: "function testfn1()",
+ printOutput: "function testfn1() { return 42; }",
+ inspectable: true,
+ variablesViewLabel: "testfn1()",
+ },
+
+ // 3 - anonymous function, but spidermonkey gives us an inferred name.
+ {
+ input: "testobj1.testfn2",
+ output: "function testobj1.testfn2()",
+ printOutput: "function () { return 42; }",
+ inspectable: true,
+ variablesViewLabel: "testobj1.testfn2()",
+ },
+
+ // 4 - named function with custom display name
+ {
+ input: "window.testfn3",
+ output: "function testfn3DisplayName()",
+ printOutput: "function testfn3() { return 42; }",
+ inspectable: true,
+ variablesViewLabel: "testfn3DisplayName()",
+ },
+
+ // 5 - basic array
+ {
+ input: "window.array1",
+ output: 'Array [ 1, 2, 3, "a", "b", "c", "4", "5" ]',
+ printOutput: "1,2,3,a,b,c,4,5",
+ inspectable: true,
+ variablesViewLabel: "Array[8]",
+ },
+
+ // 6 - array with objects
+ {
+ input: "window.array2",
+ output: 'Array [ "a", HTMLDocument \u2192 test-console-output-02.html, <body>, ' +
+ "DOMStringMap[0], DOMTokenList[0] ]",
+ printOutput: '"a,[object HTMLDocument],[object HTMLBodyElement],' +
+ '[object DOMStringMap],"',
+ inspectable: true,
+ variablesViewLabel: "Array[5]",
+ },
+
+ // 7 - array with more than 10 elements
+ {
+ input: "window.array3",
+ output: 'Array [ 1, Window \u2192 test-console-output-02.html, null, "a", "b", ' +
+ 'undefined, false, "", -Infinity, testfn3DisplayName(), 3 more\u2026 ]',
+ printOutput: '"1,[object Window],,a,b,,false,,-Infinity,' +
+ 'function testfn3() { return 42; },[object Object],foo,bar"',
+ inspectable: true,
+ variablesViewLabel: "Array[13]",
+ },
+
+ // 8 - array with holes and a cyclic reference
+ {
+ input: "window.array4",
+ output: 'Array [ <5 empty slots>, "test", Array[7] ]',
+ printOutput: '",,,,,test,"',
+ inspectable: true,
+ variablesViewLabel: "Array[7]",
+ },
+
+ // 9
+ {
+ input: "window.typedarray1",
+ output: 'Int32Array [ 1, 287, 8651, 40983, 8754 ]',
+ printOutput: "[object Int32Array]",
+ inspectable: true,
+ variablesViewLabel: "Int32Array[5]",
+ },
+
+ // 10 - Set with cyclic reference
+ {
+ input: "window.set1",
+ output: 'Set [ 1, 2, null, Array[13], "a", "b", undefined, <head>, Set[9] ]',
+ printOutput: "[object Set]",
+ inspectable: true,
+ variablesViewLabel: "Set[9]",
+ },
+
+ // 11 - Object with cyclic reference and a getter
+ {
+ input: "window.testobj2",
+ output: 'Object { a: "b", c: "d", e: 1, f: "2", foo: Object, bar: Object, ' +
+ "getterTest: Getter }",
+ printOutput: "[object Object]",
+ inspectable: true,
+ variablesViewLabel: "Object",
+ },
+
+ // 12 - Object with more than 10 properties
+ {
+ input: "window.testobj3",
+ output: 'Object { a: "b", c: "d", e: 1, f: "2", g: true, h: null, i: undefined, ' +
+ 'j: "", k: StyleSheetList[0], l: NodeList[5], 2 more\u2026 }',
+ printOutput: "[object Object]",
+ inspectable: true,
+ variablesViewLabel: "Object",
+ },
+
+ // 13 - Object with a non-enumerable property that we do not show
+ {
+ input: "window.testobj4",
+ output: 'Object { a: "b", c: "d", 1 more\u2026 }',
+ printOutput: "[object Object]",
+ inspectable: true,
+ variablesViewLabel: "Object",
+ },
+
+ // 14 - Map with cyclic references
+ {
+ input: "window.map1",
+ output: 'Map { a: "b", HTMLCollection[2]: Object, Map[3]: Set[9] }',
+ printOutput: "[object Map]",
+ inspectable: true,
+ variablesViewLabel: "Map[3]",
+ },
+];
+
+function test() {
+ requestLongerTimeout(2);
+ Task.spawn(function*() {
+ const {tab} = yield loadTab(TEST_URI);
+ const hud = yield openConsole(tab);
+ yield checkOutputForInputs(hud, inputTests);
+ inputTests = null;
+ }).then(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_03.js b/browser/devtools/webconsole/test/browser_webconsole_output_03.js
new file mode 100644
index 000000000..40f8cf334
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_03.js
@@ -0,0 +1,165 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test the webconsole output for various types of objects.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-03.html";
+
+let inputTests = [
+
+ // 0
+ {
+ input: "document",
+ output: "HTMLDocument \u2192 " + TEST_URI,
+ printOutput: "[object HTMLDocument]",
+ inspectable: true,
+ noClick: true,
+ },
+
+ // 1
+ {
+ input: "window",
+ output: "Window \u2192 " + TEST_URI,
+ printOutput: "[object Window",
+ inspectable: true,
+ noClick: true,
+ },
+
+ // 2
+ {
+ input: "document.body",
+ output: "<body>",
+ printOutput: "[object HTMLBodyElement]",
+ inspectable: true,
+ noClick: true,
+ },
+
+ // 3
+ {
+ input: "document.body.dataset",
+ output: "DOMStringMap { }",
+ printOutput: "[object DOMStringMap]",
+ inspectable: true,
+ variablesViewLabel: "DOMStringMap[0]",
+ },
+
+ // 4
+ {
+ input: "document.body.classList",
+ output: "DOMTokenList [ ]",
+ printOutput: '""',
+ inspectable: true,
+ variablesViewLabel: "DOMTokenList[0]",
+ },
+
+ // 5
+ {
+ input: "window.location.href",
+ output: '"' + TEST_URI + '"',
+ noClick: true,
+ },
+
+ // 6
+ {
+ input: "window.location",
+ output: "Location \u2192 " + TEST_URI,
+ printOutput: TEST_URI,
+ inspectable: true,
+ variablesViewLabel: "Location \u2192 test-console-output-03.html",
+ },
+
+ // 7
+ {
+ input: "document.body.attributes",
+ output: "NamedNodeMap [ ]",
+ printOutput: "[object NamedNodeMap]",
+ inspectable: true,
+ variablesViewLabel: "NamedNodeMap[0]",
+ },
+
+ // 8
+ {
+ input: "document.styleSheets",
+ output: "StyleSheetList [ ]",
+ printOutput: "[object StyleSheetList",
+ inspectable: true,
+ variablesViewLabel: "StyleSheetList[0]",
+ },
+
+ // 9
+ {
+ input: "testBodyClassName()",
+ output: '<body class="test1 tezt2">',
+ printOutput: "[object HTMLBodyElement]",
+ inspectable: true,
+ noClick: true,
+ },
+
+ // 10
+ {
+ input: "testBodyID()",
+ output: '<body class="test1 tezt2" id="foobarid">',
+ printOutput: "[object HTMLBodyElement]",
+ inspectable: true,
+ noClick: true,
+ },
+
+ // 11
+ {
+ input: "document.body.classList",
+ output: 'DOMTokenList [ "test1", "tezt2" ]',
+ printOutput: '"test1 tezt2"',
+ inspectable: true,
+ variablesViewLabel: "DOMTokenList[2]",
+ },
+
+ // 12
+ {
+ input: "testBodyDataset()",
+ output: '<body class="test1 tezt2" id="foobarid"' +
+ ' data-preview="zuzu&quot;&lt;a&gt;foo">',
+ printOutput: "[object HTMLBodyElement]",
+ inspectable: true,
+ noClick: true,
+ },
+
+ // 13
+ {
+ input: "document.body.dataset",
+ output: 'DOMStringMap { preview: "zuzu"<a>foo" }',
+ printOutput: "[object DOMStringMap]",
+ inspectable: true,
+ variablesViewLabel: "DOMStringMap[1]",
+ },
+
+ // 14
+ {
+ input: "document.body.attributes",
+ output: 'NamedNodeMap [ class="test1 tezt2", id="foobarid", ' +
+ 'data-preview="zuzu&quot;&lt;a&gt;foo" ]',
+ printOutput: "[object NamedNodeMap]",
+ inspectable: true,
+ variablesViewLabel: "NamedNodeMap[3]",
+ },
+
+ // 15
+ {
+ input: "document.body.attributes[0]",
+ output: 'class="test1 tezt2"',
+ printOutput: "[object Attr]",
+ inspectable: true,
+ variablesViewLabel: 'class="test1 tezt2"',
+ },
+];
+
+function test() {
+ requestLongerTimeout(2);
+ Task.spawn(function*() {
+ const {tab} = yield loadTab(TEST_URI);
+ const hud = yield openConsole(tab);
+ yield checkOutputForInputs(hud, inputTests);
+ inputTests = null;
+ }).then(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_04.js b/browser/devtools/webconsole/test/browser_webconsole_output_04.js
new file mode 100644
index 000000000..f50f4d073
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_04.js
@@ -0,0 +1,127 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+///////////////////
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("null");
+
+// Test the webconsole output for various types of objects.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-04.html";
+
+let inputTests = [
+ // 0
+ {
+ input: "testTextNode()",
+ output: '#text "hello world!"',
+ printOutput: "[object Text]",
+ inspectable: true,
+ noClick: true,
+ },
+
+ // 1
+ {
+ input: "testCommentNode()",
+ output: /<!--\s+- Any copyright /,
+ printOutput: "[object Comment]",
+ inspectable: true,
+ noClick: true,
+ },
+
+ // 2
+ {
+ input: "testDocumentFragment()",
+ output: 'DocumentFragment [ <div#foo1.bar>, <div#foo3> ]',
+ printOutput: "[object DocumentFragment]",
+ inspectable: true,
+ variablesViewLabel: "DocumentFragment[2]",
+ },
+
+ // 3
+ {
+ input: "testError()",
+ output: "TypeError: window.foobar is not a function\n" +
+ "Stack trace:\n" +
+ "testError@" + TEST_URI + ":44",
+ printOutput: '"TypeError: window.foobar is not a function"',
+ inspectable: true,
+ variablesViewLabel: "TypeError",
+ },
+
+ // 4
+ {
+ input: "testDOMException()",
+ output: 'DOMException [SyntaxError: "An invalid or illegal string was specified"',
+ printOutput: '"SyntaxError: An invalid or illegal string was specified"',
+ inspectable: true,
+ variablesViewLabel: "SyntaxError",
+ },
+
+ // 5
+ {
+ input: "testCSSStyleDeclaration()",
+ output: 'CSS2Properties { color: "green", font-size: "2em" }',
+ printOutput: "[object CSS2Properties]",
+ inspectable: true,
+ noClick: true,
+ },
+
+ // 6
+ {
+ input: "testStyleSheetList()",
+ output: "StyleSheetList [ CSSStyleSheet ]",
+ printOutput: "[object StyleSheetList",
+ inspectable: true,
+ variablesViewLabel: "StyleSheetList[1]",
+ },
+
+ // 7
+ {
+ input: "document.styleSheets[0]",
+ output: "CSSStyleSheet",
+ printOutput: "[object CSSStyleSheet]",
+ inspectable: true,
+ },
+
+ // 8
+ {
+ input: "document.styleSheets[0].cssRules",
+ output: "CSSRuleList [ CSSStyleRule, CSSMediaRule ]",
+ printOutput: "[object CSSRuleList",
+ inspectable: true,
+ variablesViewLabel: "CSSRuleList[2]",
+ },
+
+ // 9
+ {
+ input: "document.styleSheets[0].cssRules[0]",
+ output: 'CSSStyleRule "p, div"',
+ printOutput: "[object CSSStyleRule",
+ inspectable: true,
+ variablesViewLabel: "CSSStyleRule",
+ },
+
+ // 10
+ {
+ input: "document.styleSheets[0].cssRules[1]",
+ output: 'CSSMediaRule "print"',
+ printOutput: "[object CSSMediaRule",
+ inspectable: true,
+ variablesViewLabel: "CSSMediaRule",
+ },
+];
+
+function test() {
+ requestLongerTimeout(2);
+ Task.spawn(function*() {
+ const {tab} = yield loadTab(TEST_URI);
+ const hud = yield openConsole(tab);
+ yield checkOutputForInputs(hud, inputTests);
+ inputTests = null;
+ }).then(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_05.js b/browser/devtools/webconsole/test/browser_webconsole_output_05.js
new file mode 100644
index 000000000..c985b7b34
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_05.js
@@ -0,0 +1,130 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test the webconsole output for various types of objects.
+
+const TEST_URI = "data:text/html;charset=utf8,test for console output - 05";
+const ELLIPSIS = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
+
+let dateNow = Date.now();
+
+let inputTests = [
+ // 0
+ {
+ input: "/foo?b*\\s\"ar/igym",
+ output: "/foo?b*\\s\"ar/gimy",
+ printOutput: "/foo?b*\\s\"ar/gimy",
+ inspectable: true,
+ },
+
+ // 1
+ {
+ input: "null",
+ output: "null",
+ },
+
+ // 2
+ {
+ input: "undefined",
+ output: "undefined",
+ },
+
+ // 3
+ {
+ input: "true",
+ output: "true",
+ },
+
+ // 4
+ {
+ input: "new Boolean(false)",
+ output: "false",
+ inspectable: true,
+ },
+
+ // 5
+ {
+ input: "new Date(" + dateNow + ")",
+ output: "Date " + (new Date(dateNow)).toISOString(),
+ printOutput: (new Date(dateNow)).toString(),
+ inspectable: true,
+ },
+
+ // 6
+ {
+ input: "new Date('test')",
+ output: "Invalid Date",
+ printOutput: "Invalid Date",
+ inspectable: true,
+ variablesViewLabel: "Invalid Date",
+ },
+
+ // 7
+ {
+ input: "Date.prototype",
+ output: "Date",
+ printOutput: "Invalid Date",
+ inspectable: true,
+ variablesViewLabel: "Date",
+ },
+
+ // 8
+ {
+ input: "new Number(43)",
+ output: "43",
+ inspectable: true,
+ },
+
+ // 9
+ {
+ input: "new String('hello')",
+ output: 'String [ "h", "e", "l", "l", "o" ]',
+ printOutput: "hello",
+ inspectable: true,
+ variablesViewLabel: "String[5]"
+ },
+
+ // 9
+ {
+ // XXX: Can't test fulfilled and rejected promises, because promises get
+ // settled on the next tick of the event loop.
+ input: "new Promise(function () {})",
+ output: 'Promise { <state>: "pending" }',
+ printOutput: "[object Promise]",
+ inspectable: true,
+ variablesViewLabel: "Promise"
+ },
+
+ // 10
+ {
+ input: "(function () { var p = new Promise(function () {}); p.foo = 1; return p; }())",
+ output: 'Promise { <state>: "pending", foo: 1 }',
+ printOutput: "[object Promise]",
+ inspectable: true,
+ variablesViewLabel: "Promise"
+ },
+
+ //11
+ {
+ input: "new Object({1: 'this\\nis\\nsupposed\\nto\\nbe\\na\\nvery\\nlong\\nstring\\n,shown\\non\\na\\nsingle\\nline', 2: 'a shorter string', 3: 100})",
+ output: 'Object { 1: "this is supposed to be a very long ' + ELLIPSIS + '", 2: "a shorter string", 3: 100 }',
+ printOutput: "[object Object]",
+ inspectable: false,
+ }
+];
+
+function test() {
+ requestLongerTimeout(2);
+ Task.spawn(function*() {
+ let {tab} = yield loadTab(TEST_URI);
+ let hud = yield openConsole(tab);
+ return checkOutputForInputs(hud, inputTests);
+ }).then(finishUp);
+}
+
+function finishUp() {
+ inputTests = dateNow = null;
+ finishTest();
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_06.js b/browser/devtools/webconsole/test/browser_webconsole_output_06.js
new file mode 100644
index 000000000..082b53dcc
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_06.js
@@ -0,0 +1,127 @@
+ /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+ /* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+ "use strict";
+
+// Test the webconsole output for various arrays.
+
+const TEST_URI = "data:text/html;charset=utf8,test for console output - 06";
+const ELLIPSIS = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
+const test_str_in = "SHOW\\nALL\\nOF\\nTHIS\\nON\\nA\\nSINGLE\\nLINE ONLY. ESCAPE ALL NEWLINE";
+const test_str_out = "SHOW ALL OF THIS ON A SINGLE LINE O" + ELLIPSIS;
+
+let inputTests = [
+ // 1 - array with empty slots only
+ {
+ input: 'Array(5)',
+ output: 'Array [ <5 empty slots> ]',
+ printOutput: ',,,,',
+ inspectable: true,
+ variablesViewLabel: "Array[5]",
+ },
+ // 2 - array with one empty slot at the beginning
+ {
+ input: '[,1,2,3]',
+ output: 'Array [ <1 empty slot>, 1, 2, 3 ]',
+ printOutput: ",1,2,3",
+ inspectable: true,
+ variablesViewLabel: "Array[4]",
+ },
+ // 3 - array with multiple consecutive empty slots at the beginning
+ {
+ input: '[,,,3,4,5]',
+ output: 'Array [ <3 empty slots>, 3, 4, 5 ]',
+ printOutput: ",,,3,4,5",
+ inspectable: true,
+ variablesViewLabel: "Array[6]",
+ },
+ // 4 - array with one empty slot at the middle
+ {
+ input: '[0,1,,3,4,5]',
+ output: 'Array [ 0, 1, <1 empty slot>, 3, 4, 5 ]',
+ printOutput: "0,1,,3,4,5",
+ inspectable: true,
+ variablesViewLabel: "Array[6]",
+ },
+ // 5 - array with multiple successive empty slots at the middle
+ {
+ input: '[0,1,,,,5]',
+ output: 'Array [ 0, 1, <3 empty slots>, 5 ]',
+ printOutput: "0,1,,,,5",
+ inspectable: true,
+ variablesViewLabel: "Array[6]",
+ },
+ // 6 - array with multiple non successive single empty slots
+ {
+ input: '[0,,2,,4,5]',
+ output: 'Array [ 0, <1 empty slot>, 2, <1 empty slot>, 4, 5 ]',
+ printOutput: "0,,2,,4,5",
+ inspectable: true,
+ variablesViewLabel: "Array[6]",
+ },
+ // 7 - array with multiple multi-slot holes
+ {
+ input: '[0,,,3,,,,7,8]',
+ output: 'Array [ 0, <2 empty slots>, 3, <3 empty slots>, 7, 8 ]',
+ printOutput: "0,,,3,,,,7,8",
+ inspectable: true,
+ variablesViewLabel: "Array[9]",
+ },
+ // 8 - array with a single slot hole at the end
+ {
+ input: '[0,1,2,3,4,,]',
+ output: 'Array [ 0, 1, 2, 3, 4, <1 empty slot> ]',
+ printOutput: "0,1,2,3,4,",
+ inspectable: true,
+ variablesViewLabel: "Array[6]",
+ },
+ // 9 - array with multiple consecutive empty slots at the end
+ {
+ input: '[0,1,2,,,,]',
+ output: 'Array [ 0, 1, 2, <3 empty slots> ]',
+ printOutput: "0,1,2,,,",
+ inspectable: true,
+ variablesViewLabel: "Array[6]",
+ },
+
+ // 10 - array with members explicitly set to null
+ {
+ input: '[0,null,null,3,4,5]',
+ output: 'Array [ 0, null, null, 3, 4, 5 ]',
+ printOutput: "0,,,3,4,5",
+ inspectable: true,
+ variablesViewLabel: "Array[6]"
+ },
+
+ // 11 - array with members explicitly set to undefined
+ {
+ input: '[0,undefined,undefined,3,4,5]',
+ output: 'Array [ 0, undefined, undefined, 3, 4, 5 ]',
+ printOutput: "0,,,3,4,5",
+ inspectable: true,
+ variablesViewLabel: "Array[6]"
+ },
+
+ //12 - array with long strings as elements
+ {
+ input: '["' + test_str_in + '", "' + test_str_in + '", "' + test_str_in + '"]',
+ output: 'Array [ "' + test_str_out + '", "' + test_str_out + '", "' + test_str_out + '" ]',
+ inspectable: false,
+ printOutput: "SHOW\nALL\nOF\nTHIS\nON\nA\nSINGLE\nLINE ONLY. ESCAPE ALL NEWLINE,SHOW\nALL\nOF\nTHIS\nON\nA\nSINGLE\nLINE ONLY. ESCAPE ALL NEWLINE,SHOW\nALL\nOF\nTHIS\nON\nA\nSINGLE\nLINE ONLY. ESCAPE ALL NEWLINE",
+ variablesViewLabel: "Array[3]"
+ }
+];
+
+function test() {
+ requestLongerTimeout(2);
+ Task.spawn(function*() {
+ let {tab} = yield loadTab(TEST_URI);
+ let hud = yield openConsole(tab);
+ return checkOutputForInputs(hud, inputTests);
+ }).then(finishUp);
+}
+
+function finishUp() {
+ inputTests = null;
+ finishTest();
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_copy_newlines.js b/browser/devtools/webconsole/test/browser_webconsole_output_copy_newlines.js
new file mode 100644
index 000000000..376099661
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_copy_newlines.js
@@ -0,0 +1,67 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that multiple messages are copied into the clipboard and that they are
+// separated by new lines. See bug 916997.
+
+"use strict";
+
+let test = asyncTest(function*() {
+ const TEST_URI = "data:text/html;charset=utf8,<p>hello world, bug 916997";
+ let clipboardValue = "";
+
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+ hud.jsterm.clearOutput();
+
+ let controller = top.document.commandDispatcher.
+ getControllerForCommand("cmd_copy");
+ is(controller.isCommandEnabled("cmd_copy"), false, "cmd_copy is disabled");
+
+ content.console.log("Hello world! bug916997a");
+ content.console.log("Hello world 2! bug916997b");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "Hello world! bug916997a",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }, {
+ text: "Hello world 2! bug916997b",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ hud.ui.output.selectAllMessages();
+ hud.outputNode.focus();
+
+ goUpdateCommand("cmd_copy");
+ controller = top.document.commandDispatcher.getControllerForCommand("cmd_copy");
+ is(controller.isCommandEnabled("cmd_copy"), true, "cmd_copy is enabled");
+
+ let selection = hud.iframeWindow.getSelection() + "";
+ info("selection '" + selection + "'");
+
+ waitForClipboard((str) => {
+ clipboardValue = str;
+ return str.indexOf("bug916997a") > -1 && str.indexOf("bug916997b") > -1;
+ },
+ () => { goDoCommand("cmd_copy"); },
+ () => {
+ info("clipboard value '" + clipboardValue + "'");
+ let lines = clipboardValue.trim().split("\n");
+ is(hud.outputNode.children.length, 2, "number of messages");
+ is(lines.length, hud.outputNode.children.length, "number of lines");
+ isnot(lines[0].indexOf("bug916997a"), -1,
+ "first message text includes 'bug916997a'");
+ isnot(lines[1].indexOf("bug916997b"), -1,
+ "second message text includes 'bug916997b'");
+ is(lines[0].indexOf("bug916997b"), -1,
+ "first message text does not include 'bug916997b'");
+ },
+ () => {
+ info("last clipboard value: '" + clipboardValue + "'");
+ });
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_01.js b/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_01.js
new file mode 100644
index 000000000..e7cc49369
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_01.js
@@ -0,0 +1,108 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+///////////////////
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejections should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed(null);
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.toolbox is null");
+
+// Test the webconsole output for various types of DOM Nodes.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-dom-elements.html";
+
+let inputTests = [
+ {
+ input: "testBodyNode()",
+ output: '<body id="body-id" class="body-class">',
+ printOutput: "[object HTMLBodyElement]",
+ inspectable: true,
+ noClick: true,
+ inspectorIcon: true
+ },
+
+ {
+ input: "testDocumentElement()",
+ output: '<html lang="en-US" dir="ltr">',
+ printOutput: "[object HTMLHtmlElement]",
+ inspectable: true,
+ noClick: true,
+ inspectorIcon: true
+ },
+
+ {
+ input: "testDocument()",
+ output: 'HTMLDocument \u2192 ' + TEST_URI,
+ printOutput: "[object HTMLDocument]",
+ inspectable: true,
+ noClick: true,
+ inspectorIcon: false
+ },
+
+ {
+ input: "testNode()",
+ output: '<p some-attribute="some-value">',
+ printOutput: "[object HTMLParagraphElement]",
+ inspectable: true,
+ noClick: true,
+ inspectorIcon: true
+ },
+
+ {
+ input: "testNodeList()",
+ output: 'NodeList [ <html>, <head>, <meta>, <title>, <body#body-id.body-class>, <p>, <iframe>, <div.some.classname.here.with.more.classnames.here>, <script> ]',
+ printOutput: "[object NodeList]",
+ inspectable: true,
+ noClick: true,
+ inspectorIcon: true
+ },
+
+ {
+ input: "testNodeInIframe()",
+ output: '<p>',
+ printOutput: "[object HTMLParagraphElement]",
+ inspectable: true,
+ noClick: true,
+ inspectorIcon: true
+ },
+
+ {
+ input: "testDocumentFragment()",
+ output: 'DocumentFragment [ <span.foo>, <div#fragdiv> ]',
+ printOutput: "[object DocumentFragment]",
+ inspectable: true,
+ noClick: true,
+ inspectorIcon: false
+ },
+
+ {
+ input: "testNodeInDocumentFragment()",
+ output: '<span class="foo" data-lolz="hehe">',
+ printOutput: "[object HTMLSpanElement]",
+ inspectable: true,
+ noClick: true,
+ inspectorIcon: false
+ },
+
+ {
+ input: "testUnattachedNode()",
+ output: '<p class="such-class" data-data="such-data">',
+ printOutput: "[object HTMLParagraphElement]",
+ inspectable: true,
+ noClick: true,
+ inspectorIcon: false
+ }
+];
+
+function test() {
+ requestLongerTimeout(2);
+ Task.spawn(function*() {
+ let {tab} = yield loadTab(TEST_URI);
+ let hud = yield openConsole(tab);
+ yield checkOutputForInputs(hud, inputTests);
+ }).then(finishTest);
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_02.js b/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_02.js
new file mode 100644
index 000000000..d6db04ea1
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_02.js
@@ -0,0 +1,111 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test the inspector links in the webconsole output for DOM Nodes actually
+// open the inspector and select the right node
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-dom-elements.html";
+
+const TEST_DATA = [
+ {
+ // The first test shouldn't be returning the body element as this is the
+ // default selected node, so re-selecting it won't fire the inspector-updated
+ // event
+ input: "testNode()",
+ output: '<p some-attribute="some-value">',
+ tagName: 'P',
+ attrs: [{name: "some-attribute", value: "some-value"}]
+ },
+ {
+ input: "testBodyNode()",
+ output: '<body id="body-id" class="body-class">',
+ tagName: 'BODY',
+ attrs: [{name: "id", value: "body-id"}, {name: "class", value: "body-class"}]
+ },
+ {
+ input: "testNodeInIframe()",
+ output: '<p>',
+ tagName: 'P',
+ attrs: []
+ },
+ {
+ input: "testDocumentElement()",
+ output: '<html lang="en-US" dir="ltr">',
+ tagName: 'HTML',
+ attrs: [{name: "lang", value: "en-US"}, {name: "dir", value: "ltr"}]
+ }
+];
+
+function test() {
+ Task.spawn(function*() {
+ let {tab} = yield loadTab(TEST_URI);
+ let hud = yield openConsole(tab);
+ let toolbox = gDevTools.getToolbox(hud.target);
+
+ // Loading the inspector panel at first, to make it possible to listen for
+ // new node selections
+ yield toolbox.selectTool("inspector");
+ let inspector = toolbox.getCurrentPanel();
+ yield toolbox.selectTool("webconsole");
+
+ info("Iterating over the test data");
+ for (let data of TEST_DATA) {
+ let [result] = yield jsEval(data.input, hud, {text: data.output});
+ let {widget, msg} = yield getWidgetAndMessage(result);
+
+ let inspectorIcon = msg.querySelector(".open-inspector");
+ ok(inspectorIcon, "Inspector icon found in the ElementNode widget");
+
+ info("Clicking on the inspector icon and waiting for the inspector to be selected");
+ let onInspectorSelected = toolbox.once("inspector-selected");
+ let onInspectorUpdated = inspector.once("inspector-updated");
+ let onNewNode = toolbox.selection.once("new-node-front");
+
+ EventUtils.synthesizeMouseAtCenter(inspectorIcon, {},
+ inspectorIcon.ownerDocument.defaultView);
+ yield onInspectorSelected;
+ yield onInspectorUpdated;
+ let nodeFront = yield onNewNode;
+
+ ok(true, "Inspector selected and new node got selected");
+
+ is(nodeFront.tagName, data.tagName, "The correct node was highlighted");
+
+ let attrs = nodeFront.attributes;
+ for (let i in data.attrs) {
+ is(attrs[i].name, data.attrs[i].name, "The correct node was highlighted");
+ is(attrs[i].value, data.attrs[i].value, "The correct node was highlighted");
+ }
+
+ info("Switching back to the console");
+ yield toolbox.selectTool("webconsole");
+ }
+ }).then(finishTest);
+}
+
+function jsEval(input, hud, message) {
+ info("Executing '" + input + "' in the web console");
+
+ hud.jsterm.clearOutput();
+ hud.jsterm.execute(input);
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [message]
+ });
+}
+
+function* getWidgetAndMessage(result) {
+ info("Getting the output ElementNode widget");
+
+ let msg = [...result.matched][0];
+ let widget = [...msg._messageObject.widgets][0];
+ ok(widget, "ElementNode widget found in the output");
+
+ info("Waiting for the ElementNode widget to be linked to the inspector");
+ yield widget.linkToInspector();
+
+ return {widget: widget, msg: msg};
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_03.js b/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_03.js
new file mode 100644
index 000000000..cc420d492
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_03.js
@@ -0,0 +1,67 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that inspector links in webconsole outputs for DOM Nodes highlight
+// the actual DOM Nodes on hover
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-dom-elements.html";
+
+function test() {
+ Task.spawn(function*() {
+ let {tab} = yield loadTab(TEST_URI);
+ let hud = yield openConsole(tab);
+ let toolbox = gDevTools.getToolbox(hud.target);
+
+ // Loading the inspector panel at first, to make it possible to listen for
+ // new node selections
+ yield toolbox.loadTool("inspector");
+ let inspector = toolbox.getPanel("inspector");
+
+ info("Executing 'testNode()' in the web console to output a DOM Node");
+ let [result] = yield jsEval("testNode()", hud, {
+ text: '<p some-attribute="some-value">'
+ });
+
+ let elementNodeWidget = yield getWidget(result);
+
+ let nodeFront = yield hoverOverWidget(elementNodeWidget, toolbox);
+ let attrs = nodeFront.attributes;
+ is(nodeFront.tagName, "P", "The correct node was highlighted");
+ is(attrs[0].name, "some-attribute", "The correct node was highlighted");
+ is(attrs[0].value, "some-value", "The correct node was highlighted");
+ }).then(finishTest);
+}
+
+function jsEval(input, hud, message) {
+ hud.jsterm.execute(input);
+ return waitForMessages({
+ webconsole: hud,
+ messages: [message]
+ });
+}
+
+function* getWidget(result) {
+ info("Getting the output ElementNode widget");
+
+ let msg = [...result.matched][0];
+ let elementNodeWidget = [...msg._messageObject.widgets][0];
+ ok(elementNodeWidget, "ElementNode widget found in the output");
+
+ info("Waiting for the ElementNode widget to be linked to the inspector");
+ yield elementNodeWidget.linkToInspector();
+
+ return elementNodeWidget;
+}
+
+function* hoverOverWidget(widget, toolbox) {
+ info("Hovering over the output to highlight the node");
+
+ let onHighlight = toolbox.once("node-highlight");
+ EventUtils.sendMouseEvent({type: "mouseover"}, widget.element,
+ widget.element.ownerDocument.defaultView);
+ let nodeFront = yield onHighlight;
+ ok(true, "The highlighter was shown on a node");
+ return nodeFront;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_04.js b/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_04.js
new file mode 100644
index 000000000..7cb0847e7
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_04.js
@@ -0,0 +1,106 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that inspector links in the webconsole output for DOM Nodes do not try
+// to highlight or select nodes once they have been detached
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-dom-elements.html";
+
+const TEST_DATA = [
+ {
+ // The first test shouldn't be returning the body element as this is the
+ // default selected node, so re-selecting it won't fire the inspector-updated
+ // event
+ input: "testNode()",
+ output: '<p some-attribute="some-value">'
+ },
+ {
+ input: "testBodyNode()",
+ output: '<body id="body-id" class="body-class">'
+ },
+ {
+ input: "testNodeInIframe()",
+ output: '<p>'
+ },
+ {
+ input: "testDocumentElement()",
+ output: '<html lang="en-US" dir="ltr">'
+ }
+];
+
+const PREF = "devtools.webconsole.persistlog";
+
+function test() {
+ Services.prefs.setBoolPref(PREF, true);
+ registerCleanupFunction(() => Services.prefs.clearUserPref(PREF));
+
+ Task.spawn(function*() {
+ let {tab} = yield loadTab(TEST_URI);
+ let hud = yield openConsole(tab);
+ let toolbox = gDevTools.getToolbox(hud.target);
+
+ info("Executing the test data");
+ let widgets = [];
+ for (let data of TEST_DATA) {
+ let [result] = yield jsEval(data.input, hud, {text: data.output});
+ let {widget} = yield getWidgetAndMessage(result);
+ widgets.push(widget);
+ }
+
+ info("Reloading the page");
+ yield reloadPage();
+
+ info("Iterating over the ElementNode widgets");
+ for (let widget of widgets) {
+ // Verify that openNodeInInspector rejects since the associated dom node
+ // doesn't exist anymore
+ yield widget.openNodeInInspector().then(() => {
+ ok(false, "The openNodeInInspector promise resolved");
+ }, () => {
+ ok(true, "The openNodeInInspector promise rejected as expected");
+ });
+ yield toolbox.selectTool("webconsole");
+
+ // Verify that highlightDomNode rejects too, for the same reason
+ yield widget.highlightDomNode().then(() => {
+ ok(false, "The highlightDomNode promise resolved");
+ }, () => {
+ ok(true, "The highlightDomNode promise rejected as expected");
+ });
+ }
+ }).then(finishTest);
+}
+
+function jsEval(input, hud, message) {
+ info("Executing '" + input + "' in the web console");
+ hud.jsterm.execute(input);
+ return waitForMessages({
+ webconsole: hud,
+ messages: [message]
+ });
+}
+
+function* getWidgetAndMessage(result) {
+ info("Getting the output ElementNode widget");
+
+ let msg = [...result.matched][0];
+ let widget = [...msg._messageObject.widgets][0];
+ ok(widget, "ElementNode widget found in the output");
+
+ info("Waiting for the ElementNode widget to be linked to the inspector");
+ yield widget.linkToInspector();
+
+ return {widget: widget, msg: msg};
+}
+
+function reloadPage() {
+ let def = promise.defer();
+ gBrowser.selectedBrowser.addEventListener("load", function onload() {
+ gBrowser.selectedBrowser.removeEventListener("load", onload, true);
+ def.resolve();
+ }, true);
+ content.location.reload();
+ return def.promise;
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_events.js b/browser/devtools/webconsole/test/browser_webconsole_output_events.js
new file mode 100644
index 000000000..72b2ec93d
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_events.js
@@ -0,0 +1,53 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+///////////////////
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("null");
+
+// Test the webconsole output for DOM events.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-events.html";
+
+let test = asyncTest(function* () {
+ yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ hud.jsterm.clearOutput();
+ hud.jsterm.execute("testDOMEvents()");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "testDOMEvents() output",
+ text: "undefined",
+ category: CATEGORY_OUTPUT,
+ }],
+ });
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "console.log() output for mousemove",
+ text: /"eventLogger" mousemove { target: .+, buttons: 0, clientX: \d+, clientY: \d+, layerX: \d+, layerY: \d+ }/,
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "console.log() output for keypress",
+ text: /"eventLogger" keypress Shift { target: .+, key: .+, charCode: \d+, keyCode: \d+ }/,
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+}); \ No newline at end of file
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_order.js b/browser/devtools/webconsole/test/browser_webconsole_output_order.js
new file mode 100644
index 000000000..4a2a9f6be
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_order.js
@@ -0,0 +1,47 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that any output created from calls to the console API comes after the
+// echoed JavaScript.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+
+let test = asyncTest(function*() {
+ yield loadTab(TEST_URI);
+ let hud = yield openConsole();
+
+ let jsterm = hud.jsterm;
+ let outputNode = jsterm.outputNode;
+
+ jsterm.clearOutput();
+ jsterm.execute("console.log('foo', 'bar');");
+
+ let [function_call, result, console_message] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "console.log('foo', 'bar');",
+ category: CATEGORY_INPUT,
+ },
+ {
+ text: "undefined",
+ category: CATEGORY_OUTPUT,
+ },
+ {
+ text: '"foo" "bar"',
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ let fncall_node = [...function_call.matched][0];
+ let result_node = [...result.matched][0];
+ let console_message_node = [...console_message.matched][0];
+ is(fncall_node.nextElementSibling, result_node,
+ "console.log() is followed by undefined");
+ is(result_node.nextElementSibling, console_message_node,
+ "undefined is followed by 'foo' 'bar'");
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_table.js b/browser/devtools/webconsole/test/browser_webconsole_output_table.js
new file mode 100644
index 000000000..512a3bc8f
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_table.js
@@ -0,0 +1,158 @@
+ /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+ /* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that console.table() works as intended.
+
+ "use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-table.html";
+
+const TEST_DATA = [
+ {
+ command: "console.table(languages1)",
+ data: [
+ { _index: 0, name: "\"JavaScript\"", fileExtension: "Array[1]" },
+ { _index: 1, name: "Object", fileExtension: "\".ts\"" },
+ { _index: 2, name: "\"CoffeeScript\"", fileExtension: "\".coffee\"" }
+ ],
+ columns: { _index: "(index)", name: "name", fileExtension: "fileExtension" }
+ },
+ {
+ command: "console.table(languages1, 'name')",
+ data: [
+ { _index: 0, name: "\"JavaScript\"", fileExtension: "Array[1]" },
+ { _index: 1, name: "Object", fileExtension: "\".ts\"" },
+ { _index: 2, name: "\"CoffeeScript\"", fileExtension: "\".coffee\"" }
+ ],
+ columns: { _index: "(index)", name: "name" }
+ },
+ {
+ command: "console.table(languages1, ['name'])",
+ data: [
+ { _index: 0, name: "\"JavaScript\"", fileExtension: "Array[1]" },
+ { _index: 1, name: "Object", fileExtension: "\".ts\"" },
+ { _index: 2, name: "\"CoffeeScript\"", fileExtension: "\".coffee\"" }
+ ],
+ columns: { _index: "(index)", name: "name" }
+ },
+ {
+ command: "console.table(languages2)",
+ data: [
+ { _index: "csharp", name: "\"C#\"", paradigm: "\"object-oriented\"" },
+ { _index: "fsharp", name: "\"F#\"", paradigm: "\"functional\"" }
+ ],
+ columns: { _index: "(index)", name: "name", paradigm: "paradigm" }
+ },
+ {
+ command: "console.table([[1, 2], [3, 4]])",
+ data: [
+ { _index: 0, 0: "1", 1: "2" },
+ { _index: 1, 0: "3", 1: "4" }
+ ],
+ columns: { _index: "(index)", 0: "0", 1: "1" }
+ },
+ {
+ command: "console.table({a: [1, 2], b: [3, 4]})",
+ data: [
+ { _index: "a", 0: "1", 1: "2" },
+ { _index: "b", 0: "3", 1: "4" }
+ ],
+ columns: { _index: "(index)", 0: "0", 1: "1" }
+ },
+ {
+ command: "console.table(family)",
+ data: [
+ { _index: "mother", firstName: "\"Susan\"", lastName: "\"Doyle\"", age: "32" },
+ { _index: "father", firstName: "\"John\"", lastName: "\"Doyle\"", age: "33" },
+ { _index: "daughter", firstName: "\"Lily\"", lastName: "\"Doyle\"", age: "5" },
+ { _index: "son", firstName: "\"Mike\"", lastName: "\"Doyle\"", age: "8" },
+ ],
+ columns: { _index: "(index)", firstName: "firstName", lastName: "lastName", age: "age" }
+ },
+ {
+ command: "console.table(family, [])",
+ data: [
+ { _index: "mother", firstName: "\"Susan\"", lastName: "\"Doyle\"", age: "32" },
+ { _index: "father", firstName: "\"John\"", lastName: "\"Doyle\"", age: "33" },
+ { _index: "daughter", firstName: "\"Lily\"", lastName: "\"Doyle\"", age: "5" },
+ { _index: "son", firstName: "\"Mike\"", lastName: "\"Doyle\"", age: "8" },
+ ],
+ columns: { _index: "(index)" }
+ },
+ {
+ command: "console.table(family, ['firstName', 'lastName'])",
+ data: [
+ { _index: "mother", firstName: "\"Susan\"", lastName: "\"Doyle\"", age: "32" },
+ { _index: "father", firstName: "\"John\"", lastName: "\"Doyle\"", age: "33" },
+ { _index: "daughter", firstName: "\"Lily\"", lastName: "\"Doyle\"", age: "5" },
+ { _index: "son", firstName: "\"Mike\"", lastName: "\"Doyle\"", age: "8" },
+ ],
+ columns: { _index: "(index)", firstName: "firstName", lastName: "lastName" }
+ },
+ {
+ command: "console.table(mySet)",
+ data: [
+ { _index: 0, _value: "1" },
+ { _index: 1, _value: "5" },
+ { _index: 2, _value: "\"some text\"" },
+ { _index: 3, _value: "null" },
+ { _index: 4, _value: "undefined" }
+ ],
+ columns: { _index: "(iteration index)", _value: "Values" }
+ },
+ {
+ command: "console.table(myMap)",
+ data: [
+ { _index: 0, _key: "\"a string\"", _value: "\"value associated with 'a string'\"" },
+ { _index: 1, _key: "5", _value: "\"value associated with 5\"" },
+ ],
+ columns: { _index: "(iteration index)", _key: "Key", _value: "Values" }
+ }
+];
+
+add_task(function*() {
+ const {tab} = yield loadTab(TEST_URI);
+ let hud = yield openConsole(tab);
+
+ for (let testdata of TEST_DATA) {
+ hud.jsterm.clearOutput();
+
+ info("Executing " + testdata.command);
+
+ let onTableRender = once(hud.ui, "messages-table-rendered");
+ hud.jsterm.execute(testdata.command);
+ yield onTableRender;
+
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: testdata.command + " output",
+ consoleTable: true
+ }],
+ });
+
+ let node = [...result.matched][0];
+ ok(node, "found trace log node");
+
+ let obj = node._messageObject;
+ ok(obj, "console.trace message object");
+
+ ok(obj._data, "found table data object");
+
+ let data = obj._data.map(entries => {
+ let result = {};
+
+ for (let key of Object.keys(entries)) {
+ result[key] = entries[key] instanceof HTMLElement ?
+ entries[key].textContent : entries[key];
+ }
+
+ return result;
+ });
+
+ is(data.toSource(), testdata.data.toSource(), "table data is correct");
+ ok(obj._columns, "found table column object");
+ is(obj._columns.toSource(), testdata.columns.toSource(), "table column is correct");
+ }
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_property_provider.js b/browser/devtools/webconsole/test/browser_webconsole_property_provider.js
new file mode 100644
index 000000000..14c054d36
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_property_provider.js
@@ -0,0 +1,45 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests the property provider, which is part of the code completion
+// infrastructure.
+
+const TEST_URI = "data:text/html;charset=utf8,<p>test the JS property provider";
+
+function test() {
+ loadTab(TEST_URI).then(testPropertyProvider);
+}
+
+function testPropertyProvider({browser}) {
+ browser.removeEventListener("load", testPropertyProvider, true);
+ let tools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
+ let JSPropertyProvider = tools.require("devtools/toolkit/webconsole/utils").JSPropertyProvider;
+
+ let tmp = Cu.import("resource://gre/modules/jsdebugger.jsm", {});
+ tmp.addDebuggerToGlobal(tmp);
+ let dbg = new tmp.Debugger;
+ let dbgWindow = dbg.makeGlobalObjectReference(content);
+
+ let completion = JSPropertyProvider(dbgWindow, null, "thisIsNotDefined");
+ is (completion.matches.length, 0, "no match for 'thisIsNotDefined");
+
+ // This is a case the PropertyProvider can't handle. Should return null.
+ completion = JSPropertyProvider(dbgWindow, null, "window[1].acb");
+ is (completion, null, "no match for 'window[1].acb");
+
+ // A very advanced completion case.
+ var strComplete =
+ 'function a() { }document;document.getElementById(window.locatio';
+ completion = JSPropertyProvider(dbgWindow, null, strComplete);
+ ok(completion.matches.length == 2, "two matches found");
+ ok(completion.matchProp == "locatio", "matching part is 'test'");
+ var matches = completion.matches;
+ matches.sort();
+ ok(matches[0] == "location", "the first match is 'location'");
+ ok(matches[1] == "locationbar", "the second match is 'locationbar'");
+
+ finishTest();
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_reflow.js b/browser/devtools/webconsole/test/browser_webconsole_reflow.js
new file mode 100644
index 000000000..328b296de
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_reflow.js
@@ -0,0 +1,32 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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";
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for reflow activity";
+
+let test = asyncTest(function* () {
+ let { browser } = yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ function onReflowListenersReady(aType, aPacket) {
+ browser.contentDocument.body.style.display = "none";
+ browser.contentDocument.body.clientTop;
+ }
+
+ Services.prefs.setBoolPref("devtools.webconsole.filter.csslog", true);
+ hud.ui._updateReflowActivityListener(onReflowListenersReady);
+ Services.prefs.clearUserPref("devtools.webconsole.filter.csslog");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: /reflow: /,
+ category: CATEGORY_CSS,
+ severity: SEVERITY_LOG,
+ }],
+ })
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_scratchpad_panel_link.js b/browser/devtools/webconsole/test/browser_webconsole_scratchpad_panel_link.js
new file mode 100644
index 000000000..c0899d868
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_scratchpad_panel_link.js
@@ -0,0 +1,63 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_URI = "data:text/html;charset=utf8,<p>test Scratchpad panel linking</p>";
+
+let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
+let { Tools } = require("main");
+let { isTargetSupported } = Tools.scratchpad;
+
+Tools.scratchpad.isTargetSupported = () => true;
+
+add_task(function*() {
+ waitForExplicitFinish();
+ yield loadTab(TEST_URI);
+
+ info("Opening toolbox with Scratchpad panel");
+
+ let target = TargetFactory.forTab(gBrowser.selectedTab);
+ let toolbox = yield gDevTools.showToolbox(target, "scratchpad", "window");
+
+ let scratchpadPanel = toolbox.getPanel("scratchpad");
+ let { scratchpad } = scratchpadPanel;
+ is(toolbox.getCurrentPanel(), scratchpadPanel,
+ "Scratchpad is currently selected panel");
+
+ info("Switching to webconsole panel");
+
+ let webconsolePanel = yield toolbox.selectTool("webconsole");
+ let { hud } = webconsolePanel;
+ is(toolbox.getCurrentPanel(), webconsolePanel,
+ "Webconsole is currently selected panel");
+
+ info("console.log()ing from Scratchpad");
+
+ scratchpad.setText("console.log('foobar-from-scratchpad')");
+ scratchpad.run();
+ let messages = yield waitForMessages({
+ webconsole: hud,
+ messages: [{ text: "foobar-from-scratchpad" }]
+ });
+
+ info("Clicking link to switch to and focus Scratchpad");
+
+ let [matched] = [...messages[0].matched];
+ ok(matched, "Found logged message from Scratchpad");
+ let anchor = matched.querySelector("a.message-location");
+
+ toolbox.on("scratchpad-selected", function selected() {
+ toolbox.off("scratchpad-selected", selected);
+
+ is(toolbox.getCurrentPanel(), scratchpadPanel,
+ "Clicking link switches to Scratchpad panel");
+
+ is(Services.ww.activeWindow, toolbox.frame.ownerGlobal,
+ "Scratchpad's toolbox is focused");
+
+ Tools.scratchpad.isTargetSupported = isTargetSupported;
+ finish();
+ });
+
+ EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow);
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_show_subresource_security_errors.js b/browser/devtools/webconsole/test/browser_webconsole_show_subresource_security_errors.js
new file mode 100644
index 000000000..282c8aab1
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_show_subresource_security_errors.js
@@ -0,0 +1,30 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Ensure non-toplevel security errors are displayed
+
+const TEST_URI = "data:text/html;charset=utf8,Web Console subresource STS warning test";
+const TEST_DOC = "https://example.com/browser/browser/devtools/webconsole/test/test_bug1092055_shouldwarn.html";
+const SAMPLE_MSG = 'invalid Strict-Transport-Security header'
+
+let test = asyncTest(function* () {
+ let { browser } = yield loadTab(TEST_URI);
+
+ let hud = yield openConsole();
+
+ hud.jsterm.clearOutput();
+
+ let loaded = loadBrowser(browser);
+ content.location = TEST_DOC;
+ yield loaded;
+
+ yield waitForSuccess({
+ name: "Subresource STS warning displayed successfully",
+ validator: function() {
+ return hud.outputNode.textContent.indexOf(SAMPLE_MSG) > -1;
+ }
+ });
+});
diff --git a/browser/devtools/webconsole/test/browser_webconsole_split.js b/browser/devtools/webconsole/test/browser_webconsole_split.js
new file mode 100644
index 000000000..9501cd238
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_split.js
@@ -0,0 +1,247 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const TEST_URI = "data:text/html;charset=utf-8,Web Console test for splitting";
+
+function test()
+{
+ // Test is slow on Linux EC2 instances - Bug 962931
+ requestLongerTimeout(2);
+
+ let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+ let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
+ let Toolbox = devtools.Toolbox;
+ let toolbox;
+
+ loadTab(TEST_URI).then(testConsoleLoadOnDifferentPanel);
+
+ function testConsoleLoadOnDifferentPanel()
+ {
+ info("About to check console loads even when non-webconsole panel is open");
+
+ openPanel("inspector").then(() => {
+ toolbox.on("webconsole-ready", () => {
+ ok(true, "Webconsole has been triggered as loaded while another tool is active");
+ testKeyboardShortcuts();
+ });
+
+ // Opens split console.
+ toolbox.toggleSplitConsole();
+ });
+ }
+
+ function testKeyboardShortcuts()
+ {
+ info("About to check that panel responds to ESCAPE keyboard shortcut");
+
+ toolbox.once("split-console", () => {
+ ok(true, "Split console has been triggered via ESCAPE keypress");
+ checkAllTools();
+ });
+
+ // Closes split console.
+ EventUtils.sendKey("ESCAPE", toolbox.frame.contentWindow);
+ }
+
+ function checkAllTools()
+ {
+ info("About to check split console with each panel individually.");
+
+ Task.spawn(function() {
+ yield openAndCheckPanel("jsdebugger");
+ yield openAndCheckPanel("inspector");
+ yield openAndCheckPanel("styleeditor");
+ yield openAndCheckPanel("jsprofiler");
+ yield openAndCheckPanel("netmonitor");
+
+ yield checkWebconsolePanelOpened();
+ testBottomHost();
+ });
+ }
+
+ function getCurrentUIState()
+ {
+ let win = toolbox.doc.defaultView;
+ let deck = toolbox.doc.querySelector("#toolbox-deck");
+ let webconsolePanel = toolbox.webconsolePanel;
+ let splitter = toolbox.doc.querySelector("#toolbox-console-splitter");
+
+ let containerHeight = parseFloat(win.getComputedStyle(deck.parentNode).getPropertyValue("height"));
+ let deckHeight = parseFloat(win.getComputedStyle(deck).getPropertyValue("height"));
+ let webconsoleHeight = parseFloat(win.getComputedStyle(webconsolePanel).getPropertyValue("height"));
+ let splitterVisibility = !splitter.getAttribute("hidden");
+ let openedConsolePanel = toolbox.currentToolId === "webconsole";
+ let cmdButton = toolbox.doc.querySelector("#command-button-splitconsole");
+
+ return {
+ deckHeight: deckHeight,
+ containerHeight: containerHeight,
+ webconsoleHeight: webconsoleHeight,
+ splitterVisibility: splitterVisibility,
+ openedConsolePanel: openedConsolePanel,
+ buttonSelected: cmdButton.hasAttribute("checked")
+ };
+ }
+
+ function checkWebconsolePanelOpened()
+ {
+ info("About to check special cases when webconsole panel is open.");
+
+ let deferred = promise.defer();
+
+ // Start with console split, so we can test for transition to main panel.
+ toolbox.toggleSplitConsole();
+
+ let currentUIState = getCurrentUIState();
+
+ ok (currentUIState.splitterVisibility, "Splitter is visible when console is split");
+ ok (currentUIState.deckHeight > 0, "Deck has a height > 0 when console is split");
+ ok (currentUIState.webconsoleHeight > 0, "Web console has a height > 0 when console is split");
+ ok (!currentUIState.openedConsolePanel, "The console panel is not the current tool");
+ ok (currentUIState.buttonSelected, "The command button is selected");
+
+ openPanel("webconsole").then(() => {
+
+ let currentUIState = getCurrentUIState();
+
+ ok (!currentUIState.splitterVisibility, "Splitter is hidden when console is opened.");
+ is (currentUIState.deckHeight, 0, "Deck has a height == 0 when console is opened.");
+ is (currentUIState.webconsoleHeight, currentUIState.containerHeight, "Web console is full height.");
+ ok (currentUIState.openedConsolePanel, "The console panel is the current tool");
+ ok (currentUIState.buttonSelected, "The command button is still selected.");
+
+ // Make sure splitting console does nothing while webconsole is opened
+ toolbox.toggleSplitConsole();
+
+ currentUIState = getCurrentUIState();
+
+ ok (!currentUIState.splitterVisibility, "Splitter is hidden when console is opened.");
+ is (currentUIState.deckHeight, 0, "Deck has a height == 0 when console is opened.");
+ is (currentUIState.webconsoleHeight, currentUIState.containerHeight, "Web console is full height.");
+ ok (currentUIState.openedConsolePanel, "The console panel is the current tool");
+ ok (currentUIState.buttonSelected, "The command button is still selected.");
+
+ // Make sure that split state is saved after opening another panel
+ openPanel("inspector").then(() => {
+ let currentUIState = getCurrentUIState();
+ ok (currentUIState.splitterVisibility, "Splitter is visible when console is split");
+ ok (currentUIState.deckHeight > 0, "Deck has a height > 0 when console is split");
+ ok (currentUIState.webconsoleHeight > 0, "Web console has a height > 0 when console is split");
+ ok (!currentUIState.openedConsolePanel, "The console panel is not the current tool");
+ ok (currentUIState.buttonSelected, "The command button is still selected.");
+
+ toolbox.toggleSplitConsole();
+ deferred.resolve();
+
+ });
+ });
+ return deferred.promise;
+ }
+
+ function openPanel(toolId, callback)
+ {
+ let deferred = promise.defer();
+ let target = TargetFactory.forTab(gBrowser.selectedTab);
+ gDevTools.showToolbox(target, toolId).then(function(box) {
+ toolbox = box;
+ deferred.resolve();
+ }).then(null, console.error);
+ return deferred.promise;
+ }
+
+ function openAndCheckPanel(toolId)
+ {
+ let deferred = promise.defer();
+ openPanel(toolId).then(() => {
+ info ("Checking toolbox for " + toolId);
+ checkToolboxUI(toolbox.getCurrentPanel());
+ deferred.resolve();
+ });
+ return deferred.promise;
+ }
+
+ function checkToolboxUI()
+ {
+ let currentUIState = getCurrentUIState();
+
+ ok (!currentUIState.splitterVisibility, "Splitter is hidden by default");
+ is (currentUIState.deckHeight, currentUIState.containerHeight, "Deck has a height > 0 by default");
+ is (currentUIState.webconsoleHeight, 0, "Web console is collapsed by default");
+ ok (!currentUIState.openedConsolePanel, "The console panel is not the current tool");
+ ok (!currentUIState.buttonSelected, "The command button is not selected.");
+
+ toolbox.toggleSplitConsole();
+
+ currentUIState = getCurrentUIState();
+
+ ok (currentUIState.splitterVisibility, "Splitter is visible when console is split");
+ ok (currentUIState.deckHeight > 0, "Deck has a height > 0 when console is split");
+ ok (currentUIState.webconsoleHeight > 0, "Web console has a height > 0 when console is split");
+ is (Math.round(currentUIState.deckHeight + currentUIState.webconsoleHeight),
+ currentUIState.containerHeight,
+ "Everything adds up to container height");
+ ok (!currentUIState.openedConsolePanel, "The console panel is not the current tool");
+ ok (currentUIState.buttonSelected, "The command button is selected.");
+
+ toolbox.toggleSplitConsole();
+
+ currentUIState = getCurrentUIState();
+
+ ok (!currentUIState.splitterVisibility, "Splitter is hidden after toggling");
+ is (currentUIState.deckHeight, currentUIState.containerHeight, "Deck has a height > 0 after toggling");
+ is (currentUIState.webconsoleHeight, 0, "Web console is collapsed after toggling");
+ ok (!currentUIState.openedConsolePanel, "The console panel is not the current tool");
+ ok (!currentUIState.buttonSelected, "The command button is not selected.");
+ }
+
+ function testBottomHost()
+ {
+ checkHostType(Toolbox.HostType.BOTTOM);
+
+ checkToolboxUI();
+
+ toolbox.switchHost(Toolbox.HostType.SIDE).then(testSidebarHost);
+ }
+
+ function testSidebarHost()
+ {
+ checkHostType(Toolbox.HostType.SIDE);
+
+ checkToolboxUI();
+
+ toolbox.switchHost(Toolbox.HostType.WINDOW).then(testWindowHost);
+ }
+
+ function testWindowHost()
+ {
+ checkHostType(Toolbox.HostType.WINDOW);
+
+ checkToolboxUI();
+
+ toolbox.switchHost(Toolbox.HostType.BOTTOM).then(testDestroy);
+ }
+
+ function checkHostType(hostType)
+ {
+ is(toolbox.hostType, hostType, "host type is " + hostType);
+
+ let pref = Services.prefs.getCharPref("devtools.toolbox.host");
+ is(pref, hostType, "host pref is " + hostType);
+ }
+
+ function testDestroy()
+ {
+ toolbox.destroy().then(function() {
+ let target = TargetFactory.forTab(gBrowser.selectedTab);
+ gDevTools.showToolbox(target).then(finish);
+ });
+ }
+
+ function finish()
+ {
+ toolbox = null;
+ finishTest();
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_split_escape_key.js b/browser/devtools/webconsole/test/browser_webconsole_split_escape_key.js
new file mode 100644
index 000000000..2b8b8e4e7
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_split_escape_key.js
@@ -0,0 +1,171 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function test() {
+ info("Test various cases where the escape key should hide the split console.");
+
+ let toolbox;
+ let hud;
+ let jsterm;
+ let hudMessages;
+ let variablesView;
+
+ Task.spawn(runner).then(finish);
+
+ function* runner() {
+ let {tab} = yield loadTab("data:text/html;charset=utf-8,<p>Web Console test for splitting");
+ let target = TargetFactory.forTab(tab);
+ toolbox = yield gDevTools.showToolbox(target, "inspector");
+
+ yield testCreateSplitConsoleAfterEscape();
+
+ yield showAutoCompletePopoup();
+
+ yield testHideAutoCompletePopupAfterEscape();
+
+ yield executeJS();
+ yield clickMessageAndShowVariablesView();
+ jsterm.inputNode.focus();
+
+ yield testHideVariablesViewAfterEscape();
+
+ yield clickMessageAndShowVariablesView();
+ yield startPropertyEditor();
+
+ yield testCancelPropertyEditorAfterEscape();
+ yield testHideVariablesViewAfterEscape();
+ yield testHideSplitConsoleAfterEscape();
+ }
+
+ function testCreateSplitConsoleAfterEscape() {
+ let result = toolbox.once("webconsole-ready", () => {
+ hud = toolbox.getPanel("webconsole").hud;
+ jsterm = hud.jsterm;
+ ok(toolbox.splitConsole, "Split console is created.");
+ });
+
+ let contentWindow = toolbox.frame.contentWindow;
+ contentWindow.focus();
+ EventUtils.sendKey("ESCAPE", contentWindow);
+
+ return result;
+ }
+
+ function testShowSplitConsoleAfterEscape() {
+ let result = toolbox.once("split-console", () => {
+ ok(toolbox.splitConsole, "Split console is shown.");
+ });
+ EventUtils.sendKey("ESCAPE", toolbox.frame.contentWindow);
+
+ return result;
+ }
+
+ function testHideSplitConsoleAfterEscape() {
+ let result = toolbox.once("split-console", () => {
+ ok(!toolbox.splitConsole, "Split console is hidden.");
+ });
+ EventUtils.sendKey("ESCAPE", toolbox.frame.contentWindow);
+
+ return result;
+ }
+
+ function testHideVariablesViewAfterEscape() {
+ let result = jsterm.once("sidebar-closed", () => {
+ ok(!hud.ui.jsterm.sidebar,
+ "Variables view is hidden.");
+ ok(toolbox.splitConsole,
+ "Split console is open after hiding the variables view.");
+ });
+ EventUtils.sendKey("ESCAPE", toolbox.frame.contentWindow);
+
+ return result;
+ }
+
+ function testHideAutoCompletePopupAfterEscape() {
+ let deferred = promise.defer();
+ let popup = jsterm.autocompletePopup;
+
+ popup._panel.addEventListener("popuphidden", function popupHidden() {
+ popup._panel.removeEventListener("popuphidden", popupHidden, false);
+ ok(!popup.isOpen,
+ "Auto complete popup is hidden.");
+ ok(toolbox.splitConsole,
+ "Split console is open after hiding the autocomplete popup.");
+
+ deferred.resolve();
+ }, false);
+
+ EventUtils.sendKey("ESCAPE", toolbox.frame.contentWindow);
+
+ return deferred.promise;
+ }
+
+ function testCancelPropertyEditorAfterEscape() {
+ EventUtils.sendKey("ESCAPE", variablesView.window);
+ ok(hud.ui.jsterm.sidebar,
+ "Variables view is open after canceling property editor.");
+ ok(toolbox.splitConsole,
+ "Split console is open after editing.");
+ }
+
+ function executeJS() {
+ jsterm.execute("var foo = { bar: \"baz\" }; foo;");
+ hudMessages = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "Object { bar: \"baz\" }",
+ category: CATEGORY_OUTPUT,
+ objects: true
+ }],
+ });
+ }
+
+ function clickMessageAndShowVariablesView() {
+ let result = jsterm.once("variablesview-fetched", (event, vview) => {
+ variablesView = vview;
+ });
+
+ let clickable = hudMessages[0].clickableElements[0];
+ EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow);
+
+ return result;
+ }
+
+ function startPropertyEditor() {
+ let results = yield findVariableViewProperties(variablesView, [
+ {name: "bar", value: "baz"}
+ ], {webconsole: hud});
+ results[0].matchedProp.focus();
+ EventUtils.synthesizeKey("VK_RETURN", variablesView.window);
+ }
+
+ function showAutoCompletePopoup() {
+ let deferred = promise.defer();
+ let popupPanel = jsterm.autocompletePopup._panel;
+
+ popupPanel.addEventListener("popupshown", function popupShown() {
+ popupPanel.removeEventListener("popupshown", popupShown, false);
+ deferred.resolve();
+ }, false);
+
+ jsterm.inputNode.focus();
+ jsterm.setInputValue("document.location.");
+ EventUtils.sendKey("TAB", hud.iframeWindow);
+
+ return deferred.promise;
+ }
+
+ function finish() {
+ toolbox.destroy().then(() => {
+ toolbox = null;
+ hud = null;
+ jsterm = null;
+ hudMessages = null;
+ variablesView = null;
+
+ finishTest();
+ });
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_split_focus.js b/browser/devtools/webconsole/test/browser_webconsole_split_focus.js
new file mode 100644
index 000000000..51d7b9a79
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_split_focus.js
@@ -0,0 +1,74 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function test() {
+ info("Test that the split console state is persisted");
+
+ let toolbox;
+ let TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for splitting</p>";
+
+ Task.spawn(runner).then(finish);
+
+ function* runner() {
+ info("Opening a tab while there is no user setting on split console pref");
+ let {tab} = yield loadTab(TEST_URI);
+ let target = TargetFactory.forTab(tab);
+ toolbox = yield gDevTools.showToolbox(target, "inspector");
+
+ ok(!toolbox.splitConsole, "Split console is hidden by default");
+
+ info ("Focusing the search box before opening the split console");
+ let inspector = toolbox.getPanel("inspector");
+ inspector.searchBox.focus();
+
+ // Use the binding element since inspector.searchBox is a XUL element.
+ let activeElement = getActiveElement(inspector.panelDoc);
+ activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
+ is (activeElement, inspector.searchBox, "Search box is focused");
+
+ yield toolbox.openSplitConsole();
+
+ ok(toolbox.splitConsole, "Split console is now visible");
+
+ // Use the binding element since jsterm.inputNode is a XUL textarea element.
+ activeElement = getActiveElement(toolbox.doc);
+ activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
+ let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
+ is(activeElement, inputNode, "Split console input is focused by default");
+
+ yield toolbox.closeSplitConsole();
+
+ info ("Making sure that the search box is refocused after closing the split console");
+ // Use the binding element since inspector.searchBox is a XUL element.
+ activeElement = getActiveElement(inspector.panelDoc);
+ activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
+ is (activeElement, inspector.searchBox, "Search box is focused");
+
+ yield toolbox.destroy();
+ }
+
+ function getActiveElement(doc) {
+ let activeElement = doc.activeElement;
+ while (activeElement && activeElement.contentDocument) {
+ activeElement = activeElement.contentDocument.activeElement;
+ }
+ return activeElement;
+ }
+
+ function toggleSplitConsoleWithEscape() {
+ let onceSplitConsole = toolbox.once("split-console");
+ let contentWindow = toolbox.frame.contentWindow;
+ contentWindow.focus();
+ EventUtils.sendKey("ESCAPE", contentWindow);
+ return onceSplitConsole;
+ }
+
+ function finish() {
+ toolbox = TEST_URI = null;
+ Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled");
+ Services.prefs.clearUserPref("devtools.toolbox.splitconsoleHeight");
+ finishTest();
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_split_persist.js b/browser/devtools/webconsole/test/browser_webconsole_split_persist.js
new file mode 100644
index 000000000..d9116f2b1
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_split_persist.js
@@ -0,0 +1,111 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function test() {
+ info("Test that the split console state is persisted");
+
+ let toolbox;
+ let TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for splitting</p>";
+
+ Task.spawn(runner).then(finish);
+
+ function* runner() {
+ info("Opening a tab while there is no user setting on split console pref");
+ let {tab} = yield loadTab(TEST_URI);
+ let target = TargetFactory.forTab(tab);
+ toolbox = yield gDevTools.showToolbox(target, "inspector");
+
+ ok(!toolbox.splitConsole, "Split console is hidden by default.");
+ ok(!isCommandButtonChecked(), "Split console button is unchecked by default.");
+ yield toggleSplitConsoleWithEscape();
+ ok(toolbox.splitConsole, "Split console is now visible.");
+ ok(isCommandButtonChecked(), "Split console button is now checked.");
+ ok(getVisiblePrefValue(), "Visibility pref is true");
+
+ is(getHeightPrefValue(), toolbox.webconsolePanel.height, "Panel height matches the pref");
+ toolbox.webconsolePanel.height = 200;
+
+ yield toolbox.destroy();
+
+ info("Opening a tab while there is a true user setting on split console pref");
+ ({tab} = yield loadTab(TEST_URI));
+ target = TargetFactory.forTab(tab);
+ toolbox = yield gDevTools.showToolbox(target, "inspector");
+
+ ok(toolbox.splitConsole, "Split console is visible by default.");
+ ok(isCommandButtonChecked(), "Split console button is checked by default.");
+ is(getHeightPrefValue(), 200, "Height is set based on panel height after closing");
+
+ // Use the binding element since jsterm.inputNode is a XUL textarea element.
+ let activeElement = getActiveElement(toolbox.doc);
+ activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
+ let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
+ is(activeElement, inputNode, "Split console input is focused by default");
+
+ toolbox.webconsolePanel.height = 1;
+ ok (toolbox.webconsolePanel.clientHeight > 1,
+ "The actual height of the console is bound with a min height");
+
+ toolbox.webconsolePanel.height = 10000;
+ ok (toolbox.webconsolePanel.clientHeight < 10000,
+ "The actual height of the console is bound with a max height");
+
+ yield toggleSplitConsoleWithEscape();
+ ok(!toolbox.splitConsole, "Split console is now hidden.");
+ ok(!isCommandButtonChecked(), "Split console button is now unchecked.");
+ ok(!getVisiblePrefValue(), "Visibility pref is false");
+
+ yield toolbox.destroy();
+
+ is(getHeightPrefValue(), 10000, "Height is set based on panel height after closing");
+
+
+ info("Opening a tab while there is a false user setting on split console pref");
+ ({tab} = yield loadTab(TEST_URI));
+ target = TargetFactory.forTab(tab);
+ toolbox = yield gDevTools.showToolbox(target, "inspector");
+
+ ok(!toolbox.splitConsole, "Split console is hidden by default.");
+ ok(!getVisiblePrefValue(), "Visibility pref is false");
+
+ yield toolbox.destroy();
+ }
+
+ function getActiveElement(doc) {
+ let activeElement = doc.activeElement;
+ while (activeElement && activeElement.contentDocument) {
+ activeElement = activeElement.contentDocument.activeElement;
+ }
+ return activeElement;
+ }
+
+ function getVisiblePrefValue() {
+ return Services.prefs.getBoolPref("devtools.toolbox.splitconsoleEnabled");
+ }
+
+ function getHeightPrefValue() {
+ return Services.prefs.getIntPref("devtools.toolbox.splitconsoleHeight");
+ }
+
+ function isCommandButtonChecked() {
+ return toolbox.doc.querySelector("#command-button-splitconsole").
+ hasAttribute("checked");
+ }
+
+ function toggleSplitConsoleWithEscape() {
+ let onceSplitConsole = toolbox.once("split-console");
+ let contentWindow = toolbox.frame.contentWindow;
+ contentWindow.focus();
+ EventUtils.sendKey("ESCAPE", contentWindow);
+ return onceSplitConsole;
+ }
+
+ function finish() {
+ toolbox = TEST_URI = null;
+ Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled");
+ Services.prefs.clearUserPref("devtools.toolbox.splitconsoleHeight");
+ finishTest();
+ }
+}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_start_netmon_first.js b/browser/devtools/webconsole/test/browser_webconsole_start_netmon_first.js
new file mode 100644
index 000000000..b648da021
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_start_netmon_first.js
@@ -0,0 +1,37 @@
+/* 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/. */
+
+// Check that the webconsole works if the network monitor is first opened, then
+// the user switches to the webconsole. See bug 970914.
+
+function test() {
+ Task.spawn(runner).then(finishTest);
+
+ function* runner() {
+ const {tab} = yield loadTab("data:text/html;charset=utf8,<p>hello");
+
+ const target = TargetFactory.forTab(tab);
+ const toolbox = yield gDevTools.showToolbox(target, "netmonitor");
+
+ const hud = yield openConsole(tab);
+
+ hud.jsterm.execute("console.log('foobar bug970914')");
+
+ yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "console.log",
+ text: "foobar bug970914",
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ let text = hud.outputNode.textContent;
+ isnot(text.indexOf("foobar bug970914"), -1, "console.log message confirmed");
+ ok(!/logging API|disabled by a script/i.test(text),
+ "no warning about disabled console API");
+ }
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_view_source.js b/browser/devtools/webconsole/test/browser_webconsole_view_source.js
new file mode 100644
index 000000000..ad008478d
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_view_source.js
@@ -0,0 +1,82 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that source URLs in the Web Console can be clicked to display the
+// standard View Source window.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-error.html";
+
+let getItemForAttachment;
+let Sources;
+let getItemInvoked = false;
+
+function test() {
+ loadTab(TEST_URI).then(() => {
+ openConsole(null).then(testViewSource);
+ });
+}
+
+function testViewSource(hud) {
+ info("console opened");
+
+ let button = content.document.querySelector("button");
+ ok(button, "we have the button on the page");
+
+ expectUncaughtException();
+ EventUtils.sendMouseEvent({ type: "click" }, button, content);
+
+ openDebugger().then(({panelWin: { DebuggerView }}) => {
+ info("debugger opened");
+ Sources = DebuggerView.Sources;
+ openConsole().then((hud) => {
+ info("console opened again");
+
+ waitForMessages({
+ webconsole: hud,
+ messages: [{
+ text: "fooBazBaz is not defined",
+ category: CATEGORY_JS,
+ severity: SEVERITY_ERROR,
+ }],
+ }).then(onMessage);
+ });
+ });
+
+ function onMessage([result]) {
+ let msg = [...result.matched][0];
+ ok(msg, "error message");
+ let locationNode = msg.querySelector(".message-location");
+ ok(locationNode, "location node");
+
+ Services.ww.registerNotification(observer);
+
+ getItemForAttachment = Sources.getItemForAttachment;
+ Sources.getItemForAttachment = () => {
+ getItemInvoked = true;
+ return false;
+ };
+
+ EventUtils.sendMouseEvent({ type: "click" }, locationNode);
+ }
+}
+
+let observer = {
+ observe: function(aSubject, aTopic, aData) {
+ if (aTopic != "domwindowopened") {
+ return;
+ }
+
+ ok(true, "the view source window was opened in response to clicking " +
+ "the location node");
+
+ aSubject.close();
+ ok(getItemInvoked, "custom getItemForAttachment() was invoked");
+ Sources.getItemForAttachment = getItemForAttachment;
+ Sources = getItemForAttachment = null;
+ finishTest();
+ }
+};
+
+registerCleanupFunction(function() {
+ Services.ww.unregisterNotification(observer);
+});
diff --git a/browser/devtools/webconsole/test/head.js b/browser/devtools/webconsole/test/head.js
new file mode 100644
index 000000000..c49badb40
--- /dev/null
+++ b/browser/devtools/webconsole/test/head.js
@@ -0,0 +1,1677 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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";
+
+let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
+let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
+let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
+let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
+let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+let {require, TargetFactory} = devtools;
+let {Utils: WebConsoleUtils} = require("devtools/toolkit/webconsole/utils");
+let {Messages} = require("devtools/webconsole/console-output");
+
+// promise._reportErrors = true; // please never leave me.
+//Services.prefs.setBoolPref("devtools.debugger.log", true);
+
+let gPendingOutputTest = 0;
+
+// The various categories of messages.
+const CATEGORY_NETWORK = 0;
+const CATEGORY_CSS = 1;
+const CATEGORY_JS = 2;
+const CATEGORY_WEBDEV = 3;
+const CATEGORY_INPUT = 4;
+const CATEGORY_OUTPUT = 5;
+const CATEGORY_SECURITY = 6;
+
+// The possible message severities.
+const SEVERITY_ERROR = 0;
+const SEVERITY_WARNING = 1;
+const SEVERITY_INFO = 2;
+const SEVERITY_LOG = 3;
+
+// The indent of a console group in pixels.
+const GROUP_INDENT = 12;
+
+const WEBCONSOLE_STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
+let WCU_l10n = new WebConsoleUtils.l10n(WEBCONSOLE_STRINGS_URI);
+
+gDevTools.testing = true;
+
+function asyncTest(generator) {
+ return () => {
+ Task.spawn(generator).then(finishTest);
+ };
+}
+
+
+function loadTab(url) {
+ let deferred = promise.defer();
+
+ let tab = gBrowser.selectedTab = gBrowser.addTab(url);
+ let browser = gBrowser.getBrowserForTab(tab);
+
+ browser.addEventListener("load", function onLoad() {
+ browser.removeEventListener("load", onLoad, true);
+ deferred.resolve({tab: tab, browser: browser});
+ }, true);
+
+ return deferred.promise;
+}
+
+function loadBrowser(browser) {
+ let deferred = promise.defer();
+
+ browser.addEventListener("load", function onLoad() {
+ browser.removeEventListener("load", onLoad, true);
+ deferred.resolve(null);
+ }, true);
+
+ return deferred.promise;
+}
+
+function closeTab(tab) {
+ let deferred = promise.defer();
+
+ let container = gBrowser.tabContainer;
+
+ container.addEventListener("TabClose", function onTabClose() {
+ container.removeEventListener("TabClose", onTabClose, true);
+ deferred.resolve(null);
+ }, true);
+
+ gBrowser.removeTab(tab);
+
+ return deferred.promise;
+}
+
+function afterAllTabsLoaded(callback, win) {
+ win = win || window;
+
+ let stillToLoad = 0;
+
+ function onLoad() {
+ this.removeEventListener("load", onLoad, true);
+ stillToLoad--;
+ if (!stillToLoad)
+ callback();
+ }
+
+ for (let a = 0; a < win.gBrowser.tabs.length; a++) {
+ let browser = win.gBrowser.tabs[a].linkedBrowser;
+ if (browser.webProgress.isLoadingDocument) {
+ stillToLoad++;
+ browser.addEventListener("load", onLoad, true);
+ }
+ }
+
+ if (!stillToLoad)
+ callback();
+}
+
+/**
+ * Check if a log entry exists in the HUD output node.
+ *
+ * @param {Element} aOutputNode
+ * the HUD output node.
+ * @param {string} aMatchString
+ * the string you want to check if it exists in the output node.
+ * @param {string} aMsg
+ * the message describing the test
+ * @param {boolean} [aOnlyVisible=false]
+ * find only messages that are visible, not hidden by the filter.
+ * @param {boolean} [aFailIfFound=false]
+ * fail the test if the string is found in the output node.
+ * @param {string} aClass [optional]
+ * find only messages with the given CSS class.
+ */
+function testLogEntry(aOutputNode, aMatchString, aMsg, aOnlyVisible,
+ aFailIfFound, aClass)
+{
+ let selector = ".message";
+ // Skip entries that are hidden by the filter.
+ if (aOnlyVisible) {
+ selector += ":not(.filtered-by-type):not(.filtered-by-string)";
+ }
+ if (aClass) {
+ selector += "." + aClass;
+ }
+
+ let msgs = aOutputNode.querySelectorAll(selector);
+ let found = false;
+ for (let i = 0, n = msgs.length; i < n; i++) {
+ let message = msgs[i].textContent.indexOf(aMatchString);
+ if (message > -1) {
+ found = true;
+ break;
+ }
+ }
+
+ is(found, !aFailIfFound, aMsg);
+}
+
+/**
+ * A convenience method to call testLogEntry().
+ *
+ * @param string aString
+ * The string to find.
+ */
+function findLogEntry(aString)
+{
+ testLogEntry(outputNode, aString, "found " + aString);
+}
+
+/**
+ * Open the Web Console for the given tab.
+ *
+ * @param nsIDOMElement [aTab]
+ * Optional tab element for which you want open the Web Console. The
+ * default tab is taken from the global variable |tab|.
+ * @param function [aCallback]
+ * Optional function to invoke after the Web Console completes
+ * initialization (web-console-created).
+ * @return object
+ * A promise that is resolved once the web console is open.
+ */
+let openConsole = function(aTab) {
+ let webconsoleOpened = promise.defer();
+ let target = TargetFactory.forTab(aTab || gBrowser.selectedTab);
+ gDevTools.showToolbox(target, "webconsole").then(toolbox => {
+ let hud = toolbox.getCurrentPanel().hud;
+ hud.jsterm._lazyVariablesView = false;
+ webconsoleOpened.resolve(hud);
+ });
+ return webconsoleOpened.promise;
+};
+
+/**
+ * Close the Web Console for the given tab.
+ *
+ * @param nsIDOMElement [aTab]
+ * Optional tab element for which you want close the Web Console. The
+ * default tab is taken from the global variable |tab|.
+ * @param function [aCallback]
+ * Optional function to invoke after the Web Console completes
+ * closing (web-console-destroyed).
+ * @return object
+ * A promise that is resolved once the web console is closed.
+ */
+let closeConsole = Task.async(function* (aTab) {
+ let target = TargetFactory.forTab(aTab || gBrowser.selectedTab);
+ let toolbox = gDevTools.getToolbox(target);
+ if (toolbox) {
+ yield toolbox.destroy();
+ }
+});
+
+/**
+ * Wait for a context menu popup to open.
+ *
+ * @param nsIDOMElement aPopup
+ * The XUL popup you expect to open.
+ * @param nsIDOMElement aButton
+ * The button/element that receives the contextmenu event. This is
+ * expected to open the popup.
+ * @param function aOnShown
+ * Function to invoke on popupshown event.
+ * @param function aOnHidden
+ * Function to invoke on popuphidden event.
+ * @return object
+ * A Promise object that is resolved after the popuphidden event
+ * callback is invoked.
+ */
+function waitForContextMenu(aPopup, aButton, aOnShown, aOnHidden)
+{
+ function onPopupShown() {
+ info("onPopupShown");
+ aPopup.removeEventListener("popupshown", onPopupShown);
+
+ aOnShown && aOnShown();
+
+ // Use executeSoon() to get out of the popupshown event.
+ aPopup.addEventListener("popuphidden", onPopupHidden);
+ executeSoon(() => aPopup.hidePopup());
+ }
+ function onPopupHidden() {
+ info("onPopupHidden");
+ aPopup.removeEventListener("popuphidden", onPopupHidden);
+
+ aOnHidden && aOnHidden();
+
+ deferred.resolve(aPopup);
+ }
+
+ let deferred = promise.defer();
+ aPopup.addEventListener("popupshown", onPopupShown);
+
+ info("wait for the context menu to open");
+ let eventDetails = { type: "contextmenu", button: 2};
+ EventUtils.synthesizeMouse(aButton, 2, 2, eventDetails,
+ aButton.ownerDocument.defaultView);
+ return deferred.promise;
+}
+
+/**
+ * Dump the output of all open Web Consoles - used only for debugging purposes.
+ */
+function dumpConsoles()
+{
+ if (gPendingOutputTest) {
+ console.log("dumpConsoles start");
+ for (let [, hud] of HUDService.consoles) {
+ if (!hud.outputNode) {
+ console.debug("no output content for", hud.hudId);
+ continue;
+ }
+
+ console.debug("output content for", hud.hudId);
+ for (let elem of hud.outputNode.childNodes) {
+ dumpMessageElement(elem);
+ }
+ }
+ console.log("dumpConsoles end");
+
+ gPendingOutputTest = 0;
+ }
+}
+
+/**
+ * Dump to output debug information for the given webconsole message.
+ *
+ * @param nsIDOMNode aMessage
+ * The message element you want to display.
+ */
+function dumpMessageElement(aMessage)
+{
+ let text = aMessage.textContent;
+ let repeats = aMessage.querySelector(".message-repeats");
+ if (repeats) {
+ repeats = repeats.getAttribute("value");
+ }
+ console.debug("id", aMessage.getAttribute("id"),
+ "date", aMessage.timestamp,
+ "class", aMessage.className,
+ "category", aMessage.category,
+ "severity", aMessage.severity,
+ "repeats", repeats,
+ "clipboardText", aMessage.clipboardText,
+ "text", text);
+}
+
+let finishTest = Task.async(function* () {
+ dumpConsoles();
+
+ let browserConsole = HUDService.getBrowserConsole();
+ if (browserConsole) {
+ if (browserConsole.jsterm) {
+ browserConsole.jsterm.clearOutput(true);
+ }
+ yield HUDService.toggleBrowserConsole();
+ }
+
+ let target = TargetFactory.forTab(gBrowser.selectedTab);
+ yield gDevTools.closeToolbox(target);
+
+ finish();
+});
+
+registerCleanupFunction(function*() {
+ gDevTools.testing = false;
+
+ dumpConsoles();
+
+ if (HUDService.getBrowserConsole()) {
+ HUDService.toggleBrowserConsole();
+ }
+
+ let target = TargetFactory.forTab(gBrowser.selectedTab);
+ yield gDevTools.closeToolbox(target);
+
+ while (gBrowser.tabs.length > 1) {
+ gBrowser.removeCurrentTab();
+ }
+});
+
+waitForExplicitFinish();
+
+/**
+ * Polls a given function waiting for it to become true.
+ *
+ * @param object aOptions
+ * Options object with the following properties:
+ * - validator
+ * A validator function that returns a boolean. This is called every few
+ * milliseconds to check if the result is true. When it is true, the
+ * promise is resolved and polling stops. If validator never returns
+ * true, then polling timeouts after several tries and the promise is
+ * rejected.
+ * - name
+ * Name of test. This is used to generate the success and failure
+ * messages.
+ * - timeout
+ * Timeout for validator function, in milliseconds. Default is 5000.
+ * @return object
+ * A Promise object that is resolved based on the validator function.
+ */
+function waitForSuccess(aOptions)
+{
+ let deferred = promise.defer();
+ let start = Date.now();
+ let timeout = aOptions.timeout || 5000;
+ let {validator} = aOptions;
+
+
+ function wait()
+ {
+ if ((Date.now() - start) > timeout) {
+ // Log the failure.
+ ok(false, "Timed out while waiting for: " + aOptions.name);
+ deferred.reject(null);
+ return;
+ }
+
+ if (validator(aOptions)) {
+ ok(true, aOptions.name);
+ deferred.resolve(null);
+ }
+ else {
+ setTimeout(wait, 100);
+ }
+ }
+
+ setTimeout(wait, 100);
+
+ return deferred.promise;
+}
+
+let openInspector = Task.async(function* (aTab = gBrowser.selectedTab) {
+ let target = TargetFactory.forTab(aTab);
+ let toolbox = yield gDevTools.showToolbox(target, "inspector");
+ return toolbox.getCurrentPanel();
+});
+
+/**
+ * Find variables or properties in a VariablesView instance.
+ *
+ * @param object aView
+ * The VariablesView instance.
+ * @param array aRules
+ * The array of rules you want to match. Each rule is an object with:
+ * - name (string|regexp): property name to match.
+ * - value (string|regexp): property value to match.
+ * - isIterator (boolean): check if the property is an iterator.
+ * - isGetter (boolean): check if the property is a getter.
+ * - isGenerator (boolean): check if the property is a generator.
+ * - dontMatch (boolean): make sure the rule doesn't match any property.
+ * @param object aOptions
+ * Options for matching:
+ * - webconsole: the WebConsole instance we work with.
+ * @return object
+ * A promise object that is resolved when all the rules complete
+ * matching. The resolved callback is given an array of all the rules
+ * you wanted to check. Each rule has a new property: |matchedProp|
+ * which holds a reference to the Property object instance from the
+ * VariablesView. If the rule did not match, then |matchedProp| is
+ * undefined.
+ */
+function findVariableViewProperties(aView, aRules, aOptions)
+{
+ // Initialize the search.
+ function init()
+ {
+ // Separate out the rules that require expanding properties throughout the
+ // view.
+ let expandRules = [];
+ let rules = aRules.filter((aRule) => {
+ if (typeof aRule.name == "string" && aRule.name.indexOf(".") > -1) {
+ expandRules.push(aRule);
+ return false;
+ }
+ return true;
+ });
+
+ // Search through the view those rules that do not require any properties to
+ // be expanded. Build the array of matchers, outstanding promises to be
+ // resolved.
+ let outstanding = [];
+ finder(rules, aView, outstanding);
+
+ // Process the rules that need to expand properties.
+ let lastStep = processExpandRules.bind(null, expandRules);
+
+ // Return the results - a promise resolved to hold the updated aRules array.
+ let returnResults = onAllRulesMatched.bind(null, aRules);
+
+ return promise.all(outstanding).then(lastStep).then(returnResults);
+ }
+
+ function onMatch(aProp, aRule, aMatched)
+ {
+ if (aMatched && !aRule.matchedProp) {
+ aRule.matchedProp = aProp;
+ }
+ }
+
+ function finder(aRules, aVar, aPromises)
+ {
+ for (let [id, prop] of aVar) {
+ for (let rule of aRules) {
+ let matcher = matchVariablesViewProperty(prop, rule, aOptions);
+ aPromises.push(matcher.then(onMatch.bind(null, prop, rule)));
+ }
+ }
+ }
+
+ function processExpandRules(aRules)
+ {
+ let rule = aRules.shift();
+ if (!rule) {
+ return promise.resolve(null);
+ }
+
+ let deferred = promise.defer();
+ let expandOptions = {
+ rootVariable: aView,
+ expandTo: rule.name,
+ webconsole: aOptions.webconsole,
+ };
+
+ variablesViewExpandTo(expandOptions).then(function onSuccess(aProp) {
+ let name = rule.name;
+ let lastName = name.split(".").pop();
+ rule.name = lastName;
+
+ let matched = matchVariablesViewProperty(aProp, rule, aOptions);
+ return matched.then(onMatch.bind(null, aProp, rule)).then(function() {
+ rule.name = name;
+ });
+ }, function onFailure() {
+ return promise.resolve(null);
+ }).then(processExpandRules.bind(null, aRules)).then(function() {
+ deferred.resolve(null);
+ });
+
+ return deferred.promise;
+ }
+
+ function onAllRulesMatched(aRules)
+ {
+ for (let rule of aRules) {
+ let matched = rule.matchedProp;
+ if (matched && !rule.dontMatch) {
+ ok(true, "rule " + rule.name + " matched for property " + matched.name);
+ }
+ else if (matched && rule.dontMatch) {
+ ok(false, "rule " + rule.name + " should not match property " +
+ matched.name);
+ }
+ else {
+ ok(rule.dontMatch, "rule " + rule.name + " did not match any property");
+ }
+ }
+ return aRules;
+ }
+
+ return init();
+}
+
+/**
+ * Check if a given Property object from the variables view matches the given
+ * rule.
+ *
+ * @param object aProp
+ * The variable's view Property instance.
+ * @param object aRule
+ * Rules for matching the property. See findVariableViewProperties() for
+ * details.
+ * @param object aOptions
+ * Options for matching. See findVariableViewProperties().
+ * @return object
+ * A promise that is resolved when all the checks complete. Resolution
+ * result is a boolean that tells your promise callback the match
+ * result: true or false.
+ */
+function matchVariablesViewProperty(aProp, aRule, aOptions)
+{
+ function resolve(aResult) {
+ return promise.resolve(aResult);
+ }
+
+ if (aRule.name) {
+ let match = aRule.name instanceof RegExp ?
+ aRule.name.test(aProp.name) :
+ aProp.name == aRule.name;
+ if (!match) {
+ return resolve(false);
+ }
+ }
+
+ if (aRule.value) {
+ let displayValue = aProp.displayValue;
+ if (aProp.displayValueClassName == "token-string") {
+ displayValue = displayValue.substring(1, displayValue.length - 1);
+ }
+
+ let match = aRule.value instanceof RegExp ?
+ aRule.value.test(displayValue) :
+ displayValue == aRule.value;
+ if (!match) {
+ info("rule " + aRule.name + " did not match value, expected '" +
+ aRule.value + "', found '" + displayValue + "'");
+ return resolve(false);
+ }
+ }
+
+ if ("isGetter" in aRule) {
+ let isGetter = !!(aProp.getter && aProp.get("get"));
+ if (aRule.isGetter != isGetter) {
+ info("rule " + aRule.name + " getter test failed");
+ return resolve(false);
+ }
+ }
+
+ if ("isGenerator" in aRule) {
+ let isGenerator = aProp.displayValue == "Generator";
+ if (aRule.isGenerator != isGenerator) {
+ info("rule " + aRule.name + " generator test failed");
+ return resolve(false);
+ }
+ }
+
+ let outstanding = [];
+
+ if ("isIterator" in aRule) {
+ let isIterator = isVariableViewPropertyIterator(aProp, aOptions.webconsole);
+ outstanding.push(isIterator.then((aResult) => {
+ if (aResult != aRule.isIterator) {
+ info("rule " + aRule.name + " iterator test failed");
+ }
+ return aResult == aRule.isIterator;
+ }));
+ }
+
+ outstanding.push(promise.resolve(true));
+
+ return promise.all(outstanding).then(function _onMatchDone(aResults) {
+ let ruleMatched = aResults.indexOf(false) == -1;
+ return resolve(ruleMatched);
+ });
+}
+
+/**
+ * Check if the given variables view property is an iterator.
+ *
+ * @param object aProp
+ * The Property instance you want to check.
+ * @param object aWebConsole
+ * The WebConsole instance to work with.
+ * @return object
+ * A promise that is resolved when the check completes. The resolved
+ * callback is given a boolean: true if the property is an iterator, or
+ * false otherwise.
+ */
+function isVariableViewPropertyIterator(aProp, aWebConsole)
+{
+ if (aProp.displayValue == "Iterator") {
+ return promise.resolve(true);
+ }
+
+ let deferred = promise.defer();
+
+ variablesViewExpandTo({
+ rootVariable: aProp,
+ expandTo: "__proto__.__iterator__",
+ webconsole: aWebConsole,
+ }).then(function onSuccess(aProp) {
+ deferred.resolve(true);
+ }, function onFailure() {
+ deferred.resolve(false);
+ });
+
+ return deferred.promise;
+}
+
+
+/**
+ * Recursively expand the variables view up to a given property.
+ *
+ * @param aOptions
+ * Options for view expansion:
+ * - rootVariable: start from the given scope/variable/property.
+ * - expandTo: string made up of property names you want to expand.
+ * For example: "body.firstChild.nextSibling" given |rootVariable:
+ * document|.
+ * - webconsole: a WebConsole instance. If this is not provided all
+ * property expand() calls will be considered sync. Things may fail!
+ * @return object
+ * A promise that is resolved only when the last property in |expandTo|
+ * is found, and rejected otherwise. Resolution reason is always the
+ * last property - |nextSibling| in the example above. Rejection is
+ * always the last property that was found.
+ */
+function variablesViewExpandTo(aOptions)
+{
+ let root = aOptions.rootVariable;
+ let expandTo = aOptions.expandTo.split(".");
+ let jsterm = (aOptions.webconsole || {}).jsterm;
+ let lastDeferred = promise.defer();
+
+ function fetch(aProp)
+ {
+ if (!aProp.onexpand) {
+ ok(false, "property " + aProp.name + " cannot be expanded: !onexpand");
+ return promise.reject(aProp);
+ }
+
+ let deferred = promise.defer();
+
+ if (aProp._fetched || !jsterm) {
+ executeSoon(function() {
+ deferred.resolve(aProp);
+ });
+ }
+ else {
+ jsterm.once("variablesview-fetched", function _onFetchProp() {
+ executeSoon(() => deferred.resolve(aProp));
+ });
+ }
+
+ aProp.expand();
+
+ return deferred.promise;
+ }
+
+ function getNext(aProp)
+ {
+ let name = expandTo.shift();
+ let newProp = aProp.get(name);
+
+ if (expandTo.length > 0) {
+ ok(newProp, "found property " + name);
+ if (newProp) {
+ fetch(newProp).then(getNext, fetchError);
+ }
+ else {
+ lastDeferred.reject(aProp);
+ }
+ }
+ else {
+ if (newProp) {
+ lastDeferred.resolve(newProp);
+ }
+ else {
+ lastDeferred.reject(aProp);
+ }
+ }
+ }
+
+ function fetchError(aProp)
+ {
+ lastDeferred.reject(aProp);
+ }
+
+ if (!root._fetched) {
+ fetch(root).then(getNext, fetchError);
+ }
+ else {
+ getNext(root);
+ }
+
+ return lastDeferred.promise;
+}
+
+
+/**
+ * Update the content of a property in the variables view.
+ *
+ * @param object aOptions
+ * Options for the property update:
+ * - property: the property you want to change.
+ * - field: string that tells what you want to change:
+ * - use "name" to change the property name,
+ * - or "value" to change the property value.
+ * - string: the new string to write into the field.
+ * - webconsole: reference to the Web Console instance we work with.
+ * @return object
+ * A Promise object that is resolved once the property is updated.
+ */
+let updateVariablesViewProperty = Task.async(function* (aOptions) {
+ let view = aOptions.property._variablesView;
+ view.window.focus();
+ aOptions.property.focus();
+
+ switch (aOptions.field) {
+ case "name":
+ EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true }, view.window);
+ break;
+ case "value":
+ EventUtils.synthesizeKey("VK_RETURN", {}, view.window);
+ break;
+ default:
+ throw new Error("options.field is incorrect");
+ }
+
+ let deferred = promise.defer();
+
+ executeSoon(() => {
+ EventUtils.synthesizeKey("A", { accelKey: true }, view.window);
+
+ for (let c of aOptions.string) {
+ EventUtils.synthesizeKey(c, {}, view.window);
+ }
+
+ if (aOptions.webconsole) {
+ aOptions.webconsole.jsterm.once("variablesview-fetched").then((varView) => {
+ deferred.resolve(varView);
+ });
+ }
+
+ EventUtils.synthesizeKey("VK_RETURN", {}, view.window);
+
+ if (!aOptions.webconsole) {
+ executeSoon(() => {
+ deferred.resolve(null);
+ });
+ }
+ });
+
+ return deferred.promise;
+});
+
+/**
+ * Open the JavaScript debugger.
+ *
+ * @param object aOptions
+ * Options for opening the debugger:
+ * - tab: the tab you want to open the debugger for.
+ * @return object
+ * A promise that is resolved once the debugger opens, or rejected if
+ * the open fails. The resolution callback is given one argument, an
+ * object that holds the following properties:
+ * - target: the Target object for the Tab.
+ * - toolbox: the Toolbox instance.
+ * - panel: the jsdebugger panel instance.
+ * - panelWin: the window object of the panel iframe.
+ */
+function openDebugger(aOptions = {})
+{
+ if (!aOptions.tab) {
+ aOptions.tab = gBrowser.selectedTab;
+ }
+
+ let deferred = promise.defer();
+
+ let target = TargetFactory.forTab(aOptions.tab);
+ let toolbox = gDevTools.getToolbox(target);
+ let dbgPanelAlreadyOpen = toolbox.getPanel("jsdebugger");
+
+ gDevTools.showToolbox(target, "jsdebugger").then(function onSuccess(aToolbox) {
+ let panel = aToolbox.getCurrentPanel();
+ let panelWin = panel.panelWin;
+
+ panel._view.Variables.lazyEmpty = false;
+
+ let resolveObject = {
+ target: target,
+ toolbox: aToolbox,
+ panel: panel,
+ panelWin: panelWin,
+ };
+
+ if (dbgPanelAlreadyOpen) {
+ deferred.resolve(resolveObject);
+ }
+ else {
+ panelWin.once(panelWin.EVENTS.SOURCES_ADDED, () => {
+ deferred.resolve(resolveObject);
+ });
+ }
+ }, function onFailure(aReason) {
+ console.debug("failed to open the toolbox for 'jsdebugger'", aReason);
+ deferred.reject(aReason);
+ });
+
+ return deferred.promise;
+}
+
+/**
+ * Wait for messages in the Web Console output.
+ *
+ * @param object aOptions
+ * Options for what you want to wait for:
+ * - webconsole: the webconsole instance you work with.
+ * - matchCondition: "any" or "all". Default: "all". The promise
+ * returned by this function resolves when all of the messages are
+ * matched, if the |matchCondition| is "all". If you set the condition to
+ * "any" then the promise is resolved by any message rule that matches,
+ * irrespective of order - waiting for messages stops whenever any rule
+ * matches.
+ * - messages: an array of objects that tells which messages to wait for.
+ * Properties:
+ * - text: string or RegExp to match the textContent of each new
+ * message.
+ * - noText: string or RegExp that must not match in the message
+ * textContent.
+ * - repeats: the number of message repeats, as displayed by the Web
+ * Console.
+ * - category: match message category. See CATEGORY_* constants at
+ * the top of this file.
+ * - severity: match message severity. See SEVERITY_* constants at
+ * the top of this file.
+ * - count: how many unique web console messages should be matched by
+ * this rule.
+ * - consoleTrace: boolean, set to |true| to match a console.trace()
+ * message. Optionally this can be an object of the form
+ * { file, fn, line } that can match the specified file, function
+ * and/or line number in the trace message.
+ * - consoleTime: string that matches a console.time() timer name.
+ * Provide this if you want to match a console.time() message.
+ * - consoleTimeEnd: same as above, but for console.timeEnd().
+ * - consoleDir: boolean, set to |true| to match a console.dir()
+ * message.
+ * - consoleGroup: boolean, set to |true| to match a console.group()
+ * message.
+ * - consoleTable: boolean, set to |true| to match a console.table()
+ * message.
+ * - longString: boolean, set to |true} to match long strings in the
+ * message.
+ * - collapsible: boolean, set to |true| to match messages that can
+ * be collapsed/expanded.
+ * - type: match messages that are instances of the given object. For
+ * example, you can point to Messages.NavigationMarker to match any
+ * such message.
+ * - objects: boolean, set to |true| if you expect inspectable
+ * objects in the message.
+ * - source: object of the shape { url, line }. This is used to
+ * match the source URL and line number of the error message or
+ * console API call.
+ * - stacktrace: array of objects of the form { file, fn, line } that
+ * can match frames in the stacktrace associated with the message.
+ * - groupDepth: number used to check the depth of the message in
+ * a group.
+ * - url: URL to match for network requests.
+ * @return object
+ * A promise object is returned once the messages you want are found.
+ * The promise is resolved with the array of rule objects you give in
+ * the |messages| property. Each objects is the same as provided, with
+ * additional properties:
+ * - matched: a Set of web console messages that matched the rule.
+ * - clickableElements: a list of inspectable objects. This is available
+ * if any of the following properties are present in the rule:
+ * |consoleTrace| or |objects|.
+ * - longStrings: a list of long string ellipsis elements you can click
+ * in the message element, to expand a long string. This is available
+ * only if |longString| is present in the matching rule.
+ */
+function waitForMessages(aOptions)
+{
+ info("Waiting for messages...");
+
+ gPendingOutputTest++;
+ let webconsole = aOptions.webconsole;
+ let rules = WebConsoleUtils.cloneObject(aOptions.messages, true);
+ let rulesMatched = 0;
+ let listenerAdded = false;
+ let deferred = promise.defer();
+ aOptions.matchCondition = aOptions.matchCondition || "all";
+
+ function checkText(aRule, aText)
+ {
+ let result = false;
+ if (Array.isArray(aRule)) {
+ result = aRule.every((s) => checkText(s, aText));
+ }
+ else if (typeof aRule == "string") {
+ result = aText.indexOf(aRule) > -1;
+ }
+ else if (aRule instanceof RegExp) {
+ result = aRule.test(aText);
+ }
+ else {
+ result = aRule == aText;
+ }
+ return result;
+ }
+
+ function checkConsoleTable(aRule, aElement)
+ {
+ let elemText = aElement.textContent;
+ let table = aRule.consoleTable;
+
+ if (!checkText("console.table():", elemText)) {
+ return false;
+ }
+
+ aRule.category = CATEGORY_WEBDEV;
+ aRule.severity = SEVERITY_LOG;
+ aRule.type = Messages.ConsoleTable;
+
+ return true;
+ }
+
+ function checkConsoleTrace(aRule, aElement)
+ {
+ let elemText = aElement.textContent;
+ let trace = aRule.consoleTrace;
+
+ if (!checkText("console.trace():", elemText)) {
+ return false;
+ }
+
+ aRule.category = CATEGORY_WEBDEV;
+ aRule.severity = SEVERITY_LOG;
+ aRule.type = Messages.ConsoleTrace;
+
+ if (!aRule.stacktrace && typeof trace == "object" && trace !== true) {
+ if (Array.isArray(trace)) {
+ aRule.stacktrace = trace;
+ } else {
+ aRule.stacktrace = [trace];
+ }
+ }
+
+ return true;
+ }
+
+ function checkConsoleTime(aRule, aElement)
+ {
+ let elemText = aElement.textContent;
+ let time = aRule.consoleTime;
+
+ if (!checkText(time + ": timer started", elemText)) {
+ return false;
+ }
+
+ aRule.category = CATEGORY_WEBDEV;
+ aRule.severity = SEVERITY_LOG;
+
+ return true;
+ }
+
+ function checkConsoleTimeEnd(aRule, aElement)
+ {
+ let elemText = aElement.textContent;
+ let time = aRule.consoleTimeEnd;
+ let regex = new RegExp(time + ": -?\\d+([,.]\\d+)?ms");
+
+ if (!checkText(regex, elemText)) {
+ return false;
+ }
+
+ aRule.category = CATEGORY_WEBDEV;
+ aRule.severity = SEVERITY_LOG;
+
+ return true;
+ }
+
+ function checkConsoleDir(aRule, aElement)
+ {
+ if (!aElement.classList.contains("inlined-variables-view")) {
+ return false;
+ }
+
+ let elemText = aElement.textContent;
+ if (!checkText(aRule.consoleDir, elemText)) {
+ return false;
+ }
+
+ let iframe = aElement.querySelector("iframe");
+ if (!iframe) {
+ ok(false, "console.dir message has no iframe");
+ return false;
+ }
+
+ return true;
+ }
+
+ function checkConsoleGroup(aRule, aElement)
+ {
+ if (!isNaN(parseInt(aRule.consoleGroup))) {
+ aRule.groupDepth = aRule.consoleGroup;
+ }
+ aRule.category = CATEGORY_WEBDEV;
+ aRule.severity = SEVERITY_LOG;
+
+ return true;
+ }
+
+ function checkSource(aRule, aElement)
+ {
+ let location = aElement.querySelector(".message-location");
+ if (!location) {
+ return false;
+ }
+
+ if (!checkText(aRule.source.url, location.getAttribute("title"))) {
+ return false;
+ }
+
+ if ("line" in aRule.source && location.sourceLine != aRule.source.line) {
+ return false;
+ }
+
+ return true;
+ }
+
+ function checkCollapsible(aRule, aElement)
+ {
+ let msg = aElement._messageObject;
+ if (!msg || !!msg.collapsible != aRule.collapsible) {
+ return false;
+ }
+
+ return true;
+ }
+
+ function checkStacktrace(aRule, aElement)
+ {
+ let stack = aRule.stacktrace;
+ let frames = aElement.querySelectorAll(".stacktrace > li");
+ if (!frames.length) {
+ return false;
+ }
+
+ for (let i = 0; i < stack.length; i++) {
+ let frame = frames[i];
+ let expected = stack[i];
+ if (!frame) {
+ ok(false, "expected frame #" + i + " but didnt find it");
+ return false;
+ }
+
+ if (expected.file) {
+ let file = frame.querySelector(".message-location").title;
+ if (!checkText(expected.file, file)) {
+ ok(false, "frame #" + i + " does not match file name: " +
+ expected.file);
+ displayErrorContext(aRule, aElement);
+ return false;
+ }
+ }
+
+ if (expected.fn) {
+ let fn = frame.querySelector(".function").textContent;
+ if (!checkText(expected.fn, fn)) {
+ ok(false, "frame #" + i + " does not match the function name: " +
+ expected.fn);
+ displayErrorContext(aRule, aElement);
+ return false;
+ }
+ }
+
+ if (expected.line) {
+ let line = frame.querySelector(".message-location").sourceLine;
+ if (!checkText(expected.line, line)) {
+ ok(false, "frame #" + i + " does not match the line number: " +
+ expected.line);
+ displayErrorContext(aRule, aElement);
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ function hasXhrLabel(aElement) {
+ let xhr = aElement.querySelector('.xhr');
+ if (!xhr) {
+ return false;
+ }
+ return true;
+ }
+
+ function checkMessage(aRule, aElement)
+ {
+ let elemText = aElement.textContent;
+
+ if (aRule.text && !checkText(aRule.text, elemText)) {
+ return false;
+ }
+
+ if (aRule.noText && checkText(aRule.noText, elemText)) {
+ return false;
+ }
+
+ if (aRule.consoleTable && !checkConsoleTable(aRule, aElement)) {
+ return false;
+ }
+
+ if (aRule.consoleTrace && !checkConsoleTrace(aRule, aElement)) {
+ return false;
+ }
+
+ if (aRule.consoleTime && !checkConsoleTime(aRule, aElement)) {
+ return false;
+ }
+
+ if (aRule.consoleTimeEnd && !checkConsoleTimeEnd(aRule, aElement)) {
+ return false;
+ }
+
+ if (aRule.consoleDir && !checkConsoleDir(aRule, aElement)) {
+ return false;
+ }
+
+ if (aRule.consoleGroup && !checkConsoleGroup(aRule, aElement)) {
+ return false;
+ }
+
+ if (aRule.source && !checkSource(aRule, aElement)) {
+ return false;
+ }
+
+ if ("collapsible" in aRule && !checkCollapsible(aRule, aElement)) {
+ return false;
+ }
+
+ if (aRule.isXhr && !hasXhrLabel(aElement)) {
+ return false;
+ }
+
+ if (!aRule.isXhr && hasXhrLabel(aElement)) {
+ return false;
+ }
+
+ let partialMatch = !!(aRule.consoleTrace || aRule.consoleTime ||
+ aRule.consoleTimeEnd);
+
+ // The rule tries to match the newer types of messages, based on their
+ // object constructor.
+ if (aRule.type) {
+ if (!aElement._messageObject ||
+ !(aElement._messageObject instanceof aRule.type)) {
+ if (partialMatch) {
+ ok(false, "message type for rule: " + displayRule(aRule));
+ displayErrorContext(aRule, aElement);
+ }
+ return false;
+ }
+ partialMatch = true;
+ }
+
+ if ("category" in aRule && aElement.category != aRule.category) {
+ if (partialMatch) {
+ is(aElement.category, aRule.category,
+ "message category for rule: " + displayRule(aRule));
+ displayErrorContext(aRule, aElement);
+ }
+ return false;
+ }
+
+ if ("severity" in aRule && aElement.severity != aRule.severity) {
+ if (partialMatch) {
+ is(aElement.severity, aRule.severity,
+ "message severity for rule: " + displayRule(aRule));
+ displayErrorContext(aRule, aElement);
+ }
+ return false;
+ }
+
+ if (aRule.text) {
+ partialMatch = true;
+ }
+
+ if (aRule.stacktrace && !checkStacktrace(aRule, aElement)) {
+ if (partialMatch) {
+ ok(false, "failed to match stacktrace for rule: " + displayRule(aRule));
+ displayErrorContext(aRule, aElement);
+ }
+ return false;
+ }
+
+ if (aRule.category == CATEGORY_NETWORK && "url" in aRule &&
+ !checkText(aRule.url, aElement.url)) {
+ return false;
+ }
+
+ if ("repeats" in aRule) {
+ let repeats = aElement.querySelector(".message-repeats");
+ if (!repeats || repeats.getAttribute("value") != aRule.repeats) {
+ return false;
+ }
+ }
+
+ if ("groupDepth" in aRule) {
+ let indentNode = aElement.querySelector(".indent");
+ let indent = (GROUP_INDENT * aRule.groupDepth) + "px";
+ if (!indentNode || indentNode.style.width != indent) {
+ is(indentNode.style.width, indent,
+ "group depth check failed for message rule: " + displayRule(aRule));
+ return false;
+ }
+ }
+
+ if ("longString" in aRule) {
+ let longStrings = aElement.querySelectorAll(".longStringEllipsis");
+ if (aRule.longString != !!longStrings[0]) {
+ if (partialMatch) {
+ is(!!longStrings[0], aRule.longString,
+ "long string existence check failed for message rule: " +
+ displayRule(aRule));
+ displayErrorContext(aRule, aElement);
+ }
+ return false;
+ }
+ aRule.longStrings = longStrings;
+ }
+
+ if ("objects" in aRule) {
+ let clickables = aElement.querySelectorAll(".message-body a");
+ if (aRule.objects != !!clickables[0]) {
+ if (partialMatch) {
+ is(!!clickables[0], aRule.objects,
+ "objects existence check failed for message rule: " +
+ displayRule(aRule));
+ displayErrorContext(aRule, aElement);
+ }
+ return false;
+ }
+ aRule.clickableElements = clickables;
+ }
+
+ let count = aRule.count || 1;
+ if (!aRule.matched) {
+ aRule.matched = new Set();
+ }
+ aRule.matched.add(aElement);
+
+ return aRule.matched.size == count;
+ }
+
+ function onMessagesAdded(aEvent, aNewMessages)
+ {
+ for (let msg of aNewMessages) {
+ let elem = msg.node;
+ let location = elem.querySelector(".message-location");
+ if (location) {
+ let url = location.title;
+ // Prevent recursion with the browser console and any potential
+ // messages coming from head.js.
+ if (url.indexOf("browser/devtools/webconsole/test/head.js") != -1) {
+ continue;
+ }
+ }
+
+ for (let rule of rules) {
+ if (rule._ruleMatched) {
+ continue;
+ }
+
+ let matched = checkMessage(rule, elem);
+ if (matched) {
+ rule._ruleMatched = true;
+ rulesMatched++;
+ ok(1, "matched rule: " + displayRule(rule));
+ if (maybeDone()) {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ function allRulesMatched()
+ {
+ return aOptions.matchCondition == "all" && rulesMatched == rules.length ||
+ aOptions.matchCondition == "any" && rulesMatched > 0;
+ }
+
+ function maybeDone()
+ {
+ if (allRulesMatched()) {
+ if (listenerAdded) {
+ webconsole.ui.off("new-messages", onMessagesAdded);
+ }
+ gPendingOutputTest--;
+ deferred.resolve(rules);
+ return true;
+ }
+ return false;
+ }
+
+ function testCleanup() {
+ if (allRulesMatched()) {
+ return;
+ }
+
+ if (webconsole.ui) {
+ webconsole.ui.off("new-messages", onMessagesAdded);
+ }
+
+ for (let rule of rules) {
+ if (!rule._ruleMatched) {
+ ok(false, "failed to match rule: " + displayRule(rule));
+ }
+ }
+ }
+
+ function displayRule(aRule)
+ {
+ return aRule.name || aRule.text;
+ }
+
+ function displayErrorContext(aRule, aElement)
+ {
+ console.log("error occured during rule " + displayRule(aRule));
+ console.log("while checking the following message");
+ dumpMessageElement(aElement);
+ }
+
+ executeSoon(() => {
+
+ let messages = [];
+ for (let elem of webconsole.outputNode.childNodes) {
+ messages.push({
+ node: elem,
+ update: false,
+ });
+ }
+
+ onMessagesAdded("new-messages", messages);
+
+ if (!allRulesMatched()) {
+ listenerAdded = true;
+ registerCleanupFunction(testCleanup);
+ webconsole.ui.on("new-messages", onMessagesAdded);
+ }
+ });
+
+ return deferred.promise;
+}
+
+function whenDelayedStartupFinished(aWindow, aCallback)
+{
+ Services.obs.addObserver(function observer(aSubject, aTopic) {
+ if (aWindow == aSubject) {
+ Services.obs.removeObserver(observer, aTopic);
+ executeSoon(aCallback);
+ }
+ }, "browser-delayed-startup-finished", false);
+}
+
+/**
+ * Check the web console output for the given inputs. Each input is checked for
+ * the expected JS eval result, the result of calling print(), the result of
+ * console.log(). The JS eval result is also checked if it opens the variables
+ * view on click.
+ *
+ * @param object hud
+ * The web console instance to work with.
+ * @param array inputTests
+ * An array of input tests. An input test element is an object. Each
+ * object has the following properties:
+ * - input: string, JS input value to execute.
+ *
+ * - output: string|RegExp, expected JS eval result.
+ *
+ * - inspectable: boolean, when true, the test runner expects the JS eval
+ * result is an object that can be clicked for inspection.
+ *
+ * - noClick: boolean, when true, the test runner does not click the JS
+ * eval result. Some objects, like |window|, have a lot of properties and
+ * opening vview for them is very slow (they can cause timeouts in debug
+ * builds).
+ *
+ * - printOutput: string|RegExp, optional, expected output for
+ * |print(input)|. If this is not provided, printOutput = output.
+ *
+ * - variablesViewLabel: string|RegExp, optional, the expected variables
+ * view label when the object is inspected. If this is not provided, then
+ * |output| is used.
+ *
+ * - inspectorIcon: boolean, when true, the test runner expects the
+ * result widget to contain an inspectorIcon element (className
+ * open-inspector).
+ *
+ * - expectedTab: string, optional, the full URL of the new tab which must
+ * open. If this is not provided, any new tabs that open will cause a test
+ * failure.
+ */
+function checkOutputForInputs(hud, inputTests)
+{
+ let container = gBrowser.tabContainer;
+
+ function* runner()
+ {
+ for (let [i, entry] of inputTests.entries()) {
+ info("checkInput(" + i + "): " + entry.input);
+ yield checkInput(entry);
+ }
+ container = null;
+ }
+
+ function* checkInput(entry)
+ {
+ yield checkConsoleLog(entry);
+ yield checkPrintOutput(entry);
+ yield checkJSEval(entry);
+ }
+
+ function* checkConsoleLog(entry)
+ {
+ info("Logging: " + entry.input);
+ hud.jsterm.clearOutput();
+ hud.jsterm.execute("console.log(" + entry.input + ")");
+
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "console.log() output: " + entry.output,
+ text: entry.output,
+ category: CATEGORY_WEBDEV,
+ severity: SEVERITY_LOG,
+ }],
+ });
+
+ if (typeof entry.inspectorIcon == "boolean") {
+ let msg = [...result.matched][0];
+ yield checkLinkToInspector(entry, msg);
+ }
+ }
+
+ function checkPrintOutput(entry)
+ {
+ info("Printing: " + entry.input);
+ hud.jsterm.clearOutput();
+ hud.jsterm.execute("print(" + entry.input + ")");
+
+ let printOutput = entry.printOutput || entry.output;
+
+ return waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "print() output: " + printOutput,
+ text: printOutput,
+ category: CATEGORY_OUTPUT,
+ }],
+ });
+ }
+
+ function* checkJSEval(entry)
+ {
+ info("Evaluating: " + entry.input);
+ hud.jsterm.clearOutput();
+ hud.jsterm.execute(entry.input);
+
+ let [result] = yield waitForMessages({
+ webconsole: hud,
+ messages: [{
+ name: "JS eval output: " + entry.output,
+ text: entry.output,
+ category: CATEGORY_OUTPUT,
+ }],
+ });
+
+ let msg = [...result.matched][0];
+ if (!entry.noClick) {
+ yield checkObjectClick(entry, msg);
+ }
+ if (typeof entry.inspectorIcon == "boolean") {
+ yield checkLinkToInspector(entry, msg);
+ }
+ }
+
+ function* checkObjectClick(entry, msg)
+ {
+ info("Clicking: " + entry.input);
+ let body = msg.querySelector(".message-body a") ||
+ msg.querySelector(".message-body");
+ ok(body, "the message body");
+
+ let deferredVariablesView = promise.defer();
+ entry._onVariablesViewOpen = onVariablesViewOpen.bind(null, entry, deferredVariablesView);
+ hud.jsterm.on("variablesview-open", entry._onVariablesViewOpen);
+
+ let deferredTab = promise.defer();
+ entry._onTabOpen = onTabOpen.bind(null, entry, deferredTab);
+ container.addEventListener("TabOpen", entry._onTabOpen, true);
+
+ body.scrollIntoView();
+ EventUtils.synthesizeMouse(body, 2, 2, {}, hud.iframeWindow);
+
+ if (entry.inspectable) {
+ info("message body tagName '" + body.tagName + "' className '" + body.className + "'");
+ yield deferredVariablesView.promise;
+ } else {
+ hud.jsterm.off("variablesview-open", entry._onVariablesView);
+ entry._onVariablesView = null;
+ }
+
+ if (entry.expectedTab) {
+ yield deferredTab.promise;
+ } else {
+ container.removeEventListener("TabOpen", entry._onTabOpen, true);
+ entry._onTabOpen = null;
+ }
+
+ yield promise.resolve(null);
+ }
+
+ function checkLinkToInspector(entry, msg)
+ {
+ info("Checking Inspector Link: " + entry.input);
+ let elementNodeWidget = [...msg._messageObject.widgets][0];
+ if (!elementNodeWidget) {
+ ok(!entry.inspectorIcon, "The message has no ElementNode widget");
+ return;
+ }
+
+ return elementNodeWidget.linkToInspector().then(() => {
+ // linkToInspector resolved, check for the .open-inspector element
+ if (entry.inspectorIcon) {
+ ok(msg.querySelectorAll(".open-inspector").length,
+ "The ElementNode widget is linked to the inspector");
+ } else {
+ ok(!msg.querySelectorAll(".open-inspector").length,
+ "The ElementNode widget isn't linked to the inspector");
+ }
+ }, () => {
+ // linkToInspector promise rejected, node not linked to inspector
+ ok(!entry.inspectorIcon, "The ElementNode widget isn't linked to the inspector");
+ });
+ }
+
+ function onVariablesViewOpen(entry, {resolve, reject}, event, view, options)
+ {
+ info("Variables view opened: " + entry.input);
+ let label = entry.variablesViewLabel || entry.output;
+ if (typeof label == "string" && options.label != label) {
+ return;
+ }
+ if (label instanceof RegExp && !label.test(options.label)) {
+ return;
+ }
+
+ hud.jsterm.off("variablesview-open", entry._onVariablesViewOpen);
+ entry._onVariablesViewOpen = null;
+ ok(entry.inspectable, "variables view was shown");
+
+ resolve(null);
+ }
+
+ function onTabOpen(entry, {resolve, reject}, event)
+ {
+ container.removeEventListener("TabOpen", entry._onTabOpen, true);
+ entry._onTabOpen = null;
+
+ let tab = event.target;
+ let browser = gBrowser.getBrowserForTab(tab);
+ loadBrowser(browser).then(() => {
+ let uri = content.location.href;
+ ok(entry.expectedTab && entry.expectedTab == uri,
+ "opened tab '" + uri + "', expected tab '" + entry.expectedTab + "'");
+ return closeTab(tab);
+ }).then(resolve, reject);
+ }
+
+ return Task.spawn(runner);
+}
+
+/**
+ * Wait for eventName on target.
+ * @param {Object} target An observable object that either supports on/off or
+ * addEventListener/removeEventListener
+ * @param {String} eventName
+ * @param {Boolean} useCapture Optional, for addEventListener/removeEventListener
+ * @return A promise that resolves when the event has been handled
+ */
+function once(target, eventName, useCapture=false) {
+ info("Waiting for event: '" + eventName + "' on " + target + ".");
+
+ let deferred = promise.defer();
+
+ for (let [add, remove] of [
+ ["addEventListener", "removeEventListener"],
+ ["addListener", "removeListener"],
+ ["on", "off"]
+ ]) {
+ if ((add in target) && (remove in target)) {
+ target[add](eventName, function onEvent(...aArgs) {
+ target[remove](eventName, onEvent, useCapture);
+ deferred.resolve.apply(deferred, aArgs);
+ }, useCapture);
+ break;
+ }
+ }
+
+ return deferred.promise;
+}
+
+function getSourceActor(aSources, aURL) {
+ let item = aSources.getItemForAttachment(a => a.source.url === aURL);
+ return item && item.value;
+}
+
+/**
+ * Verify that clicking on a link from a popup notification message tries to
+ * open the expected URL.
+ */
+function simulateMessageLinkClick(element, expectedLink) {
+ let deferred = promise.defer();
+
+ // Invoke the click event and check if a new tab would
+ // open to the correct page.
+ let oldOpenUILinkIn = window.openUILinkIn;
+ window.openUILinkIn = function(link) {
+ if (link == expectedLink) {
+ ok(true, "Clicking the message link opens the desired page");
+ window.openUILinkIn = oldOpenUILinkIn;
+ deferred.resolve();
+ }
+ };
+
+ let event = new MouseEvent("click", {
+ detail: 1,
+ button: 0,
+ bubbles: true,
+ cancelable: true
+ });
+ element.dispatchEvent(event);
+
+ return deferred.promise;
+}
diff --git a/browser/devtools/webconsole/test/test-autocomplete-in-stackframe.html b/browser/devtools/webconsole/test/test-autocomplete-in-stackframe.html
new file mode 100644
index 000000000..ba5212de3
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-autocomplete-in-stackframe.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html dir="ltr" lang="en">
+ <head>
+ <meta charset="utf8">
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ <title>Test for bug 842682 - use the debugger API for web console autocomplete</title>
+ <script>
+ var foo1 = "globalFoo";
+
+ var foo1Obj = {
+ prop1: "111",
+ prop2: {
+ prop21: "212121"
+ }
+ };
+
+ function firstCall()
+ {
+ var foo2 = "fooFirstCall";
+
+ var foo2Obj = {
+ prop1: {
+ prop11: "111111"
+ }
+ };
+
+ secondCall();
+ }
+
+ function secondCall()
+ {
+ var foo3 = "fooSecondCall";
+
+ var foo3Obj = {
+ prop1: {
+ prop11: "313131"
+ }
+ };
+
+ debugger;
+ }
+ </script>
+ </head>
+ <body>
+ <p>Hello world!</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-585956-console-trace.html b/browser/devtools/webconsole/test/test-bug-585956-console-trace.html
new file mode 100644
index 000000000..e658ba633
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-585956-console-trace.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head><meta charset="utf-8">
+ <title>Web Console test for bug 585956 - console.trace()</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<script type="application/javascript">
+window.foobar585956c = function(a) {
+ console.trace();
+ return a+"c";
+};
+
+function foobar585956b(a) {
+ return foobar585956c(a+"b");
+}
+
+function foobar585956a(omg) {
+ return foobar585956b(omg + "a");
+}
+
+foobar585956a("omg");
+</script>
+ </head>
+ <body>
+ <p>Web Console test for bug 585956 - console.trace().</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud-iframe.html b/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud-iframe.html
new file mode 100644
index 000000000..ebf9c515f
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud-iframe.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>WebConsole test: iframe associated to the wrong HUD</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>WebConsole test: iframe associated to the wrong HUD.</p>
+ <p>This is the iframe!</p>
+ </body>
+ </html>
diff --git a/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud.html b/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud.html
new file mode 100644
index 000000000..5b12278d1
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>WebConsole test: iframe associated to the wrong HUD</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>WebConsole test: iframe associated to the wrong HUD.</p>
+ <iframe
+ src="http://example.com/browser/browser/devtools/webconsole/test/test-bug-593003-iframe-wrong-hud-iframe.html"></iframe>
+ </body>
+ </html>
diff --git a/browser/devtools/webconsole/test/test-bug-595934-canvas-css.html b/browser/devtools/webconsole/test/test-bug-595934-canvas-css.html
new file mode 100644
index 000000000..3c9cf03a5
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-canvas-css.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 595934 - category: CSS Parser (with
+ Canvas)</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <script type="text/javascript"
+ src="test-bug-595934-canvas-css.js"></script>
+ </head>
+ <body>
+ <p>Web Console test for bug 595934 - category "CSS Parser" (with
+ Canvas).</p>
+ <p><canvas width="200" height="200">Canvas support is required!</canvas></p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-595934-canvas-css.js b/browser/devtools/webconsole/test/test-bug-595934-canvas-css.js
new file mode 100644
index 000000000..cc364d6a3
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-canvas-css.js
@@ -0,0 +1,10 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+window.addEventListener("DOMContentLoaded", function() {
+ var canvas = document.querySelector("canvas");
+ var context = canvas.getContext("2d");
+ context.strokeStyle = "foobarCanvasCssParser";
+}, false);
diff --git a/browser/devtools/webconsole/test/test-bug-595934-css-loader.css b/browser/devtools/webconsole/test/test-bug-595934-css-loader.css
new file mode 100644
index 000000000..b4224430f
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-css-loader.css
@@ -0,0 +1,10 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+body {
+ color: #0f0;
+ font-weight: bold;
+}
+
diff --git a/browser/devtools/webconsole/test/test-bug-595934-css-loader.css^headers^ b/browser/devtools/webconsole/test/test-bug-595934-css-loader.css^headers^
new file mode 100644
index 000000000..e7be84a71
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-css-loader.css^headers^
@@ -0,0 +1 @@
+Content-Type: image/png
diff --git a/browser/devtools/webconsole/test/test-bug-595934-css-loader.html b/browser/devtools/webconsole/test/test-bug-595934-css-loader.html
new file mode 100644
index 000000000..6bb0d54c5
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-css-loader.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 595934 - category: CSS Loader</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <link rel="stylesheet" href="test-bug-595934-css-loader.css">
+ </head>
+ <body>
+ <p>Web Console test for bug 595934 - category "CSS Loader".</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-595934-css-parser.css b/browser/devtools/webconsole/test/test-bug-595934-css-parser.css
new file mode 100644
index 000000000..f6db82398
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-css-parser.css
@@ -0,0 +1,10 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+p {
+ color: #0f0;
+ foobarCssParser: failure;
+}
+
diff --git a/browser/devtools/webconsole/test/test-bug-595934-css-parser.html b/browser/devtools/webconsole/test/test-bug-595934-css-parser.html
new file mode 100644
index 000000000..a4ea74ba3
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-css-parser.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 595934 - category: CSS Parser</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <link rel="stylesheet" type="text/css"
+ href="test-bug-595934-css-parser.css">
+ </head>
+ <body>
+ <p>Web Console test for bug 595934 - category "CSS Parser".</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-595934-empty-getelementbyid.html b/browser/devtools/webconsole/test/test-bug-595934-empty-getelementbyid.html
new file mode 100644
index 000000000..a70f9011b
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-empty-getelementbyid.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 595934 - category: DOM.
+ (empty getElementById())</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <script type="text/javascript"
+ src="test-bug-595934-empty-getelementbyid.js"></script>
+ </head>
+ <body>
+ <p>Web Console test for bug 595934 - category "DOM"
+ (empty getElementById()).</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-595934-empty-getelementbyid.js b/browser/devtools/webconsole/test/test-bug-595934-empty-getelementbyid.js
new file mode 100644
index 000000000..dd94d716d
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-empty-getelementbyid.js
@@ -0,0 +1,8 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+window.addEventListener("load", function() {
+ document.getElementById("");
+}, false);
diff --git a/browser/devtools/webconsole/test/test-bug-595934-html.html b/browser/devtools/webconsole/test/test-bug-595934-html.html
new file mode 100644
index 000000000..fe35afef6
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-html.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 595934 - category: HTML</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>Web Console test for bug 595934 - category "HTML".</p>
+ <form action="?" enctype="multipart/form-data">
+ <p><label>Input <input type="text" value="test value"></label></p>
+ </form>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test-bug-595934-image.html b/browser/devtools/webconsole/test/test-bug-595934-image.html
new file mode 100644
index 000000000..312ecd49f
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-image.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 595934 - category: Image</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>Web Console test for bug 595934 - category Image.</p>
+ <p><img src="test-bug-595934-image.jpg" alt="corrupted image"></p>
+ </body>
+</html>
+
+
diff --git a/browser/devtools/webconsole/test/test-bug-595934-image.jpg b/browser/devtools/webconsole/test/test-bug-595934-image.jpg
new file mode 100644
index 000000000..947e5f11b
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-image.jpg
Binary files differ
diff --git a/browser/devtools/webconsole/test/test-bug-595934-imagemap.html b/browser/devtools/webconsole/test/test-bug-595934-imagemap.html
new file mode 100644
index 000000000..007c3c01b
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-imagemap.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 595934 - category: ImageMap</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>Web Console test for bug 595934 - category "ImageMap".</p>
+ <p><img src="test-image.png" usemap="#testMap" alt="Test image"></p>
+ <map name="testMap">
+ <area shape="rect" coords="0,0,10,10,5" href="#" alt="Test area" />
+ </map>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test-bug-595934-malformedxml-external.html b/browser/devtools/webconsole/test/test-bug-595934-malformedxml-external.html
new file mode 100644
index 000000000..2fd8beac5
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-malformedxml-external.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 595934 - category: malformed-xml.
+ (external file)</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <script type="text/javascript"><!--
+ var req = new XMLHttpRequest();
+ req.open("GET", "test-bug-595934-malformedxml-external.xml", true);
+ req.send(null);
+ // --></script>
+ </head>
+ <body>
+ <p>Web Console test for bug 595934 - category "malformed-xml"
+ (external file).</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-595934-malformedxml-external.xml b/browser/devtools/webconsole/test/test-bug-595934-malformedxml-external.xml
new file mode 100644
index 000000000..4812786f1
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-malformedxml-external.xml
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>Web Console test for bug 595934 - category "malformed-xml".</p>
+ </body>
diff --git a/browser/devtools/webconsole/test/test-bug-595934-malformedxml.xhtml b/browser/devtools/webconsole/test/test-bug-595934-malformedxml.xhtml
new file mode 100644
index 000000000..62689c567
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-malformedxml.xhtml
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <title>Web Console test for bug 595934 - category: malformed-xml</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>Web Console test for bug 595934 - category "malformed-xml".</p>
+ </body>
diff --git a/browser/devtools/webconsole/test/test-bug-595934-svg.xhtml b/browser/devtools/webconsole/test/test-bug-595934-svg.xhtml
new file mode 100644
index 000000000..572382c64
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-svg.xhtml
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <title>Web Console test for bug 595934 - category: SVG</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>Web Console test for bug 595934 - category "SVG".</p>
+ <svg version="1.1" width="120" height="fooBarSVG"
+ xmlns="http://www.w3.org/2000/svg">
+ <ellipse fill="#0f0" stroke="#000" cx="50%"
+ cy="50%" rx="50%" ry="50%" />
+ </svg>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test-bug-595934-workers.html b/browser/devtools/webconsole/test/test-bug-595934-workers.html
new file mode 100644
index 000000000..baf5a6215
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-workers.html
@@ -0,0 +1,18 @@
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 595934 - category: DOM Worker
+ javascript</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p id="foobar">Web Console test for bug 595934 - category "DOM Worker
+ javascript".</p>
+ <script type="text/javascript">
+ var myWorker = new Worker("test-bug-595934-workers.js");
+ myWorker.postMessage("hello world");
+ </script>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test-bug-595934-workers.js b/browser/devtools/webconsole/test/test-bug-595934-workers.js
new file mode 100644
index 000000000..4e93c967b
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-595934-workers.js
@@ -0,0 +1,9 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+onmessage = function() {
+ fooBarWorker();
+}
+
diff --git a/browser/devtools/webconsole/test/test-bug-597136-external-script-errors.html b/browser/devtools/webconsole/test/test-bug-597136-external-script-errors.html
new file mode 100644
index 000000000..25bdeecc5
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-597136-external-script-errors.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+<!--
+ ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Patrick Walton <pcwalton@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK *****
+ -->
+ <title>Test for bug 597136: external script errors</title>
+ </head>
+ <body>
+ <h1>Test for bug 597136: external script errors</h1>
+ <p><button onclick="f()">Click me</button</p>
+
+ <script type="text/javascript"
+ src="test-bug-597136-external-script-errors.js"></script>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test-bug-597136-external-script-errors.js b/browser/devtools/webconsole/test/test-bug-597136-external-script-errors.js
new file mode 100644
index 000000000..87c0aff8e
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-597136-external-script-errors.js
@@ -0,0 +1,14 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Patrick Walton <pcwalton@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+function f() {
+ bogus.g();
+}
+
diff --git a/browser/devtools/webconsole/test/test-bug-597756-reopen-closed-tab.html b/browser/devtools/webconsole/test/test-bug-597756-reopen-closed-tab.html
new file mode 100644
index 000000000..68e19e677
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-597756-reopen-closed-tab.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <meta charset="utf-8">
+ <title>Bug 597756: test error logging after tab close and reopen</title>
+ <!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ </head>
+ <body>
+ <h1>Bug 597756: test error logging after tab close and reopen.</h1>
+
+ <script type="text/javascript"><!--
+ fooBug597756_error.bar();
+ // --></script>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-599725-response-headers.sjs b/browser/devtools/webconsole/test/test-bug-599725-response-headers.sjs
new file mode 100644
index 000000000..2e78d6b7b
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-599725-response-headers.sjs
@@ -0,0 +1,25 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function handleRequest(request, response)
+{
+ var Etag = '"4c881ab-b03-435f0a0f9ef00"';
+ var IfNoneMatch = request.hasHeader("If-None-Match")
+ ? request.getHeader("If-None-Match")
+ : "";
+
+ var page = "<!DOCTYPE html><html><body><p>hello world!</p></body></html>";
+
+ response.setHeader("Etag", Etag, false);
+
+ if (IfNoneMatch == Etag) {
+ response.setStatusLine(request.httpVersion, "304", "Not Modified");
+ }
+ else {
+ response.setHeader("Content-Type", "text/html", false);
+ response.setHeader("Content-Length", page.length + "", false);
+ response.write(page);
+ }
+}
diff --git a/browser/devtools/webconsole/test/test-bug-600183-charset.html b/browser/devtools/webconsole/test/test-bug-600183-charset.html
new file mode 100644
index 000000000..040490a6b
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-600183-charset.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+ <meta charset="gb2312">
+ <title>Console HTTP test page (chinese)</title>
+ </head>
+ <body>
+ <p>µÄÎʺò!</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-600183-charset.html^headers^ b/browser/devtools/webconsole/test/test-bug-600183-charset.html^headers^
new file mode 100644
index 000000000..9f3e2302f
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-600183-charset.html^headers^
@@ -0,0 +1 @@
+Content-Type: text/html; charset=gb2312
diff --git a/browser/devtools/webconsole/test/test-bug-601177-log-levels.html b/browser/devtools/webconsole/test/test-bug-601177-log-levels.html
new file mode 100644
index 000000000..a59213907
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-601177-log-levels.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 601177: log levels</title>
+ <script src="test-bug-601177-log-levels.js" type="text/javascript"></script>
+ <script type="text/javascript"><!--
+ window.undefinedPropertyBug601177;
+ // --></script>
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ </head>
+ <body>
+ <h1>Web Console test for bug 601177: log levels</h1>
+ <img src="test-image.png?bug601177">
+ <img src="foobar-known-to-fail.png?bug601177">
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-601177-log-levels.js b/browser/devtools/webconsole/test/test-bug-601177-log-levels.js
new file mode 100644
index 000000000..ea37f533d
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-601177-log-levels.js
@@ -0,0 +1,8 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+foobarBug601177strictError = "strict error";
+
+window.foobarBug601177exception();
diff --git a/browser/devtools/webconsole/test/test-bug-603750-websocket.html b/browser/devtools/webconsole/test/test-bug-603750-websocket.html
new file mode 100644
index 000000000..f0097dd77
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-603750-websocket.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 603750 - Web Socket errors</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>Web Console test for bug 595934 - Web Socket errors.</p>
+ <iframe src="data:text/html;charset=utf-8,hello world!"></iframe>
+ <script type="text/javascript" src="test-bug-603750-websocket.js"></script>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-603750-websocket.js b/browser/devtools/webconsole/test/test-bug-603750-websocket.js
new file mode 100644
index 000000000..3746424cc
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-603750-websocket.js
@@ -0,0 +1,18 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+window.addEventListener("load", function () {
+ var ws1 = new WebSocket("ws://0.0.0.0:81");
+ ws1.onopen = function() {
+ ws1.send("test 1");
+ ws1.close();
+ };
+
+ var ws2 = new window.frames[0].WebSocket("ws://0.0.0.0:82");
+ ws2.onopen = function() {
+ ws2.send("test 2");
+ ws2.close();
+ };
+}, false);
diff --git a/browser/devtools/webconsole/test/test-bug-609872-cd-iframe-child.html b/browser/devtools/webconsole/test/test-bug-609872-cd-iframe-child.html
new file mode 100644
index 000000000..451eba21e
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-609872-cd-iframe-child.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>test for bug 609872 - iframe child</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>test for bug 609872 - iframe child</p>
+ <script>window.foobarBug609872 = 'child!';</script>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-609872-cd-iframe-parent.html b/browser/devtools/webconsole/test/test-bug-609872-cd-iframe-parent.html
new file mode 100644
index 000000000..fdb636b97
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-609872-cd-iframe-parent.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>test for bug 609872 - iframe parent</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>test for bug 609872 - iframe parent</p>
+ <script>window.foobarBug609872 = 'parent!';</script>
+ <iframe src="test-bug-609872-cd-iframe-child.html"></iframe>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-613013-console-api-iframe.html b/browser/devtools/webconsole/test/test-bug-613013-console-api-iframe.html
new file mode 100644
index 000000000..edf40e80e
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-613013-console-api-iframe.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>test for bug 613013</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>test for bug 613013</p>
+ <script type="text/javascript"><!--
+ (function () {
+ var iframe = document.createElement('iframe');
+ iframe.src = 'data:text/html;charset=utf-8,little iframe';
+ document.body.appendChild(iframe);
+
+ console.log("foobarBug613013");
+ })();
+ // --></script>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-618078-network-exceptions.html b/browser/devtools/webconsole/test/test-bug-618078-network-exceptions.html
new file mode 100644
index 000000000..ac755e1b9
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-618078-network-exceptions.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 618078 - exception in async network request
+ callback</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <script type="text/javascript">
+ var req = new XMLHttpRequest();
+ req.open('GET', 'http://example.com', true);
+ req.onreadystatechange = function() {
+ if (req.readyState == 4) {
+ bug618078exception();
+ }
+ };
+ req.send(null);
+ </script>
+ </head>
+ <body>
+ <p>Web Console test for bug 618078 - exception in async network request
+ callback.</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-621644-jsterm-dollar.html b/browser/devtools/webconsole/test/test-bug-621644-jsterm-dollar.html
new file mode 100644
index 000000000..09c986703
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-621644-jsterm-dollar.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 621644</title>
+ <script>
+ function $(elem) {
+ return elem.innerHTML;
+ }
+ function $$(doc) {
+ return doc.title;
+ }
+ </script>
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ </head>
+ <body>
+ <h1>Web Console test for bug 621644</h1>
+ <p>hello world!</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-630733-response-redirect-headers.sjs b/browser/devtools/webconsole/test/test-bug-630733-response-redirect-headers.sjs
new file mode 100644
index 000000000..f92e0fe65
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-630733-response-redirect-headers.sjs
@@ -0,0 +1,16 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function handleRequest(request, response)
+{
+ var page = "<!DOCTYPE html><html><body><p>hello world! bug 630733</p></body></html>";
+
+ response.setStatusLine(request.httpVersion, "301", "Moved Permanently");
+ response.setHeader("Content-Type", "text/html", false);
+ response.setHeader("Content-Length", page.length + "", false);
+ response.setHeader("x-foobar-bug630733", "bazbaz", false);
+ response.setHeader("Location", "/redirect-from-bug-630733", false);
+ response.write(page);
+}
diff --git a/browser/devtools/webconsole/test/test-bug-632275-getters.html b/browser/devtools/webconsole/test/test-bug-632275-getters.html
new file mode 100644
index 000000000..349c301f3
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-632275-getters.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 632275 - getters</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<script type="application/javascript;version=1.8">
+ document.foobar = {
+ _val: 5,
+ get val() { return ++this._val; }
+ };
+</script>
+
+ </head>
+ <body>
+ <p>Web Console test for bug 632275 - getters.</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-632347-iterators-generators.html b/browser/devtools/webconsole/test/test-bug-632347-iterators-generators.html
new file mode 100644
index 000000000..a6080c642
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-632347-iterators-generators.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 632347 - iterators and generators</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<script type="application/javascript;version=1.8">
+(function(){
+function genFunc() {
+ var a = 5;
+ while (a < 10) {
+ yield a++;
+ }
+}
+
+window._container = {};
+
+_container.gen1 = genFunc();
+_container.gen1.next();
+
+var obj = { foo: "bar", baz: "baaz", hay: "stack" };
+_container.iter1 = Iterator(obj);
+
+function Range(low, high) {
+ this.low = low;
+ this.high = high;
+}
+
+function RangeIterator(range) {
+ this.range = range;
+ this.current = this.range.low;
+}
+
+RangeIterator.prototype.next = function() {
+ if (this.current > this.range.high) {
+ throw StopIteration;
+ } else {
+ return this.current++;
+ }
+}
+
+Range.prototype.__iterator__ = function() {
+ return new RangeIterator(this);
+}
+
+_container.iter2 = new Range(3, 15);
+
+_container.gen2 = (i * 2 for (i in _container.iter2));
+})();
+</script>
+ </head>
+ <body>
+ <p>Web Console test for bug 632347 - iterators and generators.</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-644419-log-limits.html b/browser/devtools/webconsole/test/test-bug-644419-log-limits.html
new file mode 100644
index 000000000..21d99ba14
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-644419-log-limits.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for bug 644419: console log limits</title>
+ </head>
+ <body>
+ <h1>Test for bug 644419: Console should have user-settable log limits for
+ each message category</h1>
+
+ <script type="text/javascript">
+ function foo() {
+ bar.baz();
+ }
+ foo();
+ </script>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test-bug-646025-console-file-location.html b/browser/devtools/webconsole/test/test-bug-646025-console-file-location.html
new file mode 100644
index 000000000..7c80f1446
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-646025-console-file-location.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+ <meta charset="utf-8">
+ <title>Console file location test</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <script src="test-file-location.js"></script>
+ </head>
+ <body>
+ <h1>Web Console File Location Test Page</h1>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-658368-time-methods.html b/browser/devtools/webconsole/test/test-bug-658368-time-methods.html
new file mode 100644
index 000000000..cc50b6313
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-658368-time-methods.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for bug 658368: Expand console object with time and timeEnd
+ methods</title>
+ </head>
+ <body>
+ <h1>Test for bug 658368: Expand console object with time and timeEnd
+ methods</h1>
+
+ <script type="text/javascript">
+ function foo() {
+ console.timeEnd("aTimer");
+ }
+ console.time("aTimer");
+ foo();
+ console.time("bTimer");
+ </script>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html b/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html
new file mode 100644
index 000000000..db83274f0
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+ <meta charset="utf8">
+ <title>Mixed Content test - http on https</title>
+ <script src="testscript.js"></script>
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ </head>
+ <body>
+ <iframe src = "http://example.com"></iframe>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-inner.html b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-inner.html
new file mode 100644
index 000000000..ccb363ed9
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-inner.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 752559 - print warning to error console when iframe sandbox
+ is being used ineffectively</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>I am sandboxed and want to escape.</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-nested1.html b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-nested1.html
new file mode 100644
index 000000000..273e1a4e5
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-nested1.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 752559 - print warning to error console when iframe sandbox
+ is being used ineffectively</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <iframe
+src="http://www.example.com/browser/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-inner.html"></iframe>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-nested2.html b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-nested2.html
new file mode 100644
index 000000000..21f5dd672
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-nested2.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 752559 - print warning to error console when iframe sandbox
+ is being used ineffectively</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <iframe
+src="http://www.example.com/browser/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-inner.html" sandbox="allow-scripts allow-same-origin"></iframe>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning0.html b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning0.html
new file mode 100644
index 000000000..233a6cb70
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning0.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 752559 - print warning to error console when iframe sandbox
+ is being used ineffectively (allow-scripts, allow-same-origin)</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <iframe src="test-bug-752559-ineffective-iframe-sandbox-warning-inner.html" sandbox="allow-scripts allow-same-origin"></iframe>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning1.html b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning1.html
new file mode 100644
index 000000000..da0d58819
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning1.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 752559 - print warning to error console when iframe sandbox
+ is being used ineffectively (allow-scripts, no allow-same-origin)</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <iframe src="test-bug-752559-ineffective-iframe-sandbox-warning-inner.html" sandbox="allow-scripts"></iframe>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning2.html b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning2.html
new file mode 100644
index 000000000..f33f0a6dc
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning2.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 752559 - print warning to error console when iframe sandbox
+ is being used ineffectively (no allow-scripts, allow-same-origin)</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <iframe src="test-bug-752559-ineffective-iframe-sandbox-warning-inner.html" sandbox="allow-same-origin"></iframe>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning3.html b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning3.html
new file mode 100644
index 000000000..1d8f5ac47
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning3.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 752559 - print warning to error console when iframe sandbox
+ is being used ineffectively (allow-scripts, allow-same-origin)</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <iframe
+src="http://www.example.com/browser/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-inner.html" sandbox="allow-scripts allow-same-origin"></iframe>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning4.html b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning4.html
new file mode 100644
index 000000000..7c749b8c7
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning4.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 752559 - print warning to error console when iframe sandbox
+ is being used ineffectively (allow-scripts, allow-same-origin, nested)</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <iframe
+src="http://www.example.com/browser/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-nested1.html" sandbox="allow-scripts allow-same-origin"></iframe>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning5.html b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning5.html
new file mode 100644
index 000000000..7aad0b2c5
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning5.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 752559 - print warning to error console when iframe sandbox
+ is being used ineffectively (nested, allow-scripts, allow-same-origin)</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <iframe
+src="http://www.example.com/browser/browser/devtools/webconsole/test/test-bug-752559-ineffective-iframe-sandbox-warning-nested2.html"></iframe>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-762593-insecure-passwords-about-blank-web-console-warning.html b/browser/devtools/webconsole/test/test-bug-762593-insecure-passwords-about-blank-web-console-warning.html
new file mode 100644
index 000000000..d7bcd45d6
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-762593-insecure-passwords-about-blank-web-console-warning.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 762593 - Add warning/error Message to Web Console when the
+ page includes Insecure Password fields</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+ <!-- This test tests the scenario where a javascript adds password fields to
+ an about:blank iframe inside an insecure web page. It ensures that
+ insecure password fields like those are detected and a warning is sent to
+ the web console. -->
+ </head>
+ <body>
+ <p>This insecure page is served with an about:blank iframe. A script then adds a
+ password field to it.</p>
+ <iframe id = "myiframe" width = "300" height="300" >
+ </iframe>
+ <script>
+ var doc = window.document;
+ var myIframe = doc.getElementById("myiframe");
+ myIframe.contentDocument.open();
+ myIframe.contentDocument.write("<form><input type = 'password' name='pwd' value='test'> </form>");
+ myIframe.contentDocument.close();
+ </script>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-762593-insecure-passwords-web-console-warning.html b/browser/devtools/webconsole/test/test-bug-762593-insecure-passwords-web-console-warning.html
new file mode 100644
index 000000000..a4d0d7843
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-762593-insecure-passwords-web-console-warning.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 762593 - Add warning/error Message to Web Console when the
+ page includes Insecure Password fields</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>This page is served with an iframe with insecure password field.</p>
+ <iframe src
+ ="http://example.com/browser/browser/devtools/webconsole/test/test-iframe-762593-insecure-frame.html">
+ </iframe>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-766001-console-log.js b/browser/devtools/webconsole/test/test-bug-766001-console-log.js
new file mode 100644
index 000000000..8f6a3bb9c
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-766001-console-log.js
@@ -0,0 +1,10 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function onLoad123() {
+ console.log("Blah Blah");
+}
+
+window.addEventListener("load", onLoad123, false);
diff --git a/browser/devtools/webconsole/test/test-bug-766001-js-console-links.html b/browser/devtools/webconsole/test/test-bug-766001-js-console-links.html
new file mode 100644
index 000000000..6a6ac6008
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-766001-js-console-links.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 766001 : Open JS/Console call Links in Debugger</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <script type="text/javascript" src="test-bug-766001-js-errors.js"></script>
+ <script type="text/javascript" src="test-bug-766001-console-log.js"></script>
+ </head>
+ <body>
+ <p>Web Console test for bug 766001 : Open JS/Console call Links in Debugger.</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-766001-js-errors.js b/browser/devtools/webconsole/test/test-bug-766001-js-errors.js
new file mode 100644
index 000000000..932204395
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-766001-js-errors.js
@@ -0,0 +1,7 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+window.addEventListener("load", function() {
+ document.bar();
+}, false);
diff --git a/browser/devtools/webconsole/test/test-bug-782653-css-errors-1.css b/browser/devtools/webconsole/test/test-bug-782653-css-errors-1.css
new file mode 100644
index 000000000..ad7fd1999
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-782653-css-errors-1.css
@@ -0,0 +1,10 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+body {
+ color: #0f0;
+ font-weight: green;
+}
+
diff --git a/browser/devtools/webconsole/test/test-bug-782653-css-errors-2.css b/browser/devtools/webconsole/test/test-bug-782653-css-errors-2.css
new file mode 100644
index 000000000..91b14137a
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-782653-css-errors-2.css
@@ -0,0 +1,10 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+body {
+ color: #0fl;
+ font-weight: bold;
+}
+
diff --git a/browser/devtools/webconsole/test/test-bug-782653-css-errors.html b/browser/devtools/webconsole/test/test-bug-782653-css-errors.html
new file mode 100644
index 000000000..7ca11fc34
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-782653-css-errors.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 782653 : Open CSS Links in Style Editor</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <link rel="stylesheet" href="test-bug-782653-css-errors-1.css">
+ <link rel="stylesheet" href="test-bug-782653-css-errors-2.css">
+ </head>
+ <body>
+ <p>Web Console test for bug 782653 : Open CSS Links in Style Editor.</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-837351-security-errors.html b/browser/devtools/webconsole/test/test-bug-837351-security-errors.html
new file mode 100644
index 000000000..db83274f0
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-837351-security-errors.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+ <meta charset="utf8">
+ <title>Mixed Content test - http on https</title>
+ <script src="testscript.js"></script>
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ </head>
+ <body>
+ <iframe src = "http://example.com"></iframe>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test-bug-846918-hsts-invalid-headers.html b/browser/devtools/webconsole/test/test-bug-846918-hsts-invalid-headers.html
new file mode 100644
index 000000000..a2353354d
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-846918-hsts-invalid-headers.html
@@ -0,0 +1,13 @@
+<!doctype html>
+ <html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 846918 - Report invalid strict-transport-security
+ headers to the web console</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>This page is served with an invalid STS header.</p>
+ </body>
+ </html>
diff --git a/browser/devtools/webconsole/test/test-bug-846918-hsts-invalid-headers.html^headers^ b/browser/devtools/webconsole/test/test-bug-846918-hsts-invalid-headers.html^headers^
new file mode 100644
index 000000000..9778993d7
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-846918-hsts-invalid-headers.html^headers^
@@ -0,0 +1 @@
+Strict-Transport-Security: max-age444 \ No newline at end of file
diff --git a/browser/devtools/webconsole/test/test-bug-859170-longstring-hang.html b/browser/devtools/webconsole/test/test-bug-859170-longstring-hang.html
new file mode 100644
index 000000000..51bc0de28
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-859170-longstring-hang.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head><meta charset="utf-8">
+ <title>Web Console test for bug 859170 - very long strings hang the browser</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<script type="application/javascript">
+(function() {
+var longString = "abbababazomglolztest";
+for (var i = 0; i < 10; i++) {
+ longString += longString + longString;
+}
+
+longString = "foobar" + (new Array(9000)).join("a") + "foobaz" +
+ longString + "boom!";
+console.log(longString);
+})();
+</script>
+ </head>
+ <body>
+ <p>Web Console test for bug 859170 - very long strings hang the browser.</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-869003-iframe.html b/browser/devtools/webconsole/test/test-bug-869003-iframe.html
new file mode 100644
index 000000000..5a29728e5
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-869003-iframe.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 869003</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <script type="text/javascript"><!--
+ window.onload = function testConsoleLogging()
+ {
+ var o = { hello: "world!", bug: 869003 };
+ console.log("foobar", o);
+ };
+ // --></script>
+ </head>
+ <body>
+ <p>Make sure users can inspect objects from cross-domain iframes.</p>
+ <p>Iframe window.</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-869003-top-window.html b/browser/devtools/webconsole/test/test-bug-869003-top-window.html
new file mode 100644
index 000000000..ab3b87542
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-869003-top-window.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 869003</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>Make sure users can inspect objects from cross-domain iframes.</p>
+ <p>Top window.</p>
+ <iframe src="http://example.org/browser/browser/devtools/webconsole/test/test-bug-869003-iframe.html"></iframe>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug-952277-highlight-nodes-in-vview.html b/browser/devtools/webconsole/test/test-bug-952277-highlight-nodes-in-vview.html
new file mode 100644
index 000000000..de297d9b5
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-952277-highlight-nodes-in-vview.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 952277 - Highlighting and selecting nodes from the variablesview</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>Web Console test for bug 952277 - Highlighting and selecting nodes from the variablesview</p>
+ <p>Web Console test for bug 952277 - Highlighting and selecting nodes from the variablesview</p>
+ <p>Web Console test for bug 952277 - Highlighting and selecting nodes from the variablesview</p>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test-bug-989025-iframe-parent.html b/browser/devtools/webconsole/test/test-bug-989025-iframe-parent.html
new file mode 100644
index 000000000..e9a8553dd
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-989025-iframe-parent.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>test for bug 989025 - iframe parent</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>test for bug 989025 - iframe parent</p>
+ <iframe src="http://mochi.test:8888/browser/browser/devtools/webconsole/test/test-bug-609872-cd-iframe-child.html"></iframe>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug_923281_console_log_filter.html b/browser/devtools/webconsole/test/test-bug_923281_console_log_filter.html
new file mode 100644
index 000000000..f2d650a5d
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug_923281_console_log_filter.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <meta charset="utf-8">
+ <title>Console test</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <script type="text/javascript" src="test-bug_923281_test1.js"></script>
+ <script type="text/javascript" src="test-bug_923281_test2.js"></script>
+ </head>
+ <body></body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-bug_923281_test1.js b/browser/devtools/webconsole/test/test-bug_923281_test1.js
new file mode 100644
index 000000000..81342a437
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug_923281_test1.js
@@ -0,0 +1,5 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+console.log("Sample log.");
+console.log("This log should be filtered when filtered for test2.js.");
diff --git a/browser/devtools/webconsole/test/test-bug_923281_test2.js b/browser/devtools/webconsole/test/test-bug_923281_test2.js
new file mode 100644
index 000000000..f523103cd
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug_923281_test2.js
@@ -0,0 +1,4 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+console.log("This is a random text.");
diff --git a/browser/devtools/webconsole/test/test-bug_939783_console_trace_duplicates.html b/browser/devtools/webconsole/test/test-bug_939783_console_trace_duplicates.html
new file mode 100644
index 000000000..ab44de09f
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug_939783_console_trace_duplicates.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test for bug 939783 - different console.trace() calls
+ wrongly filtered as duplicates</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<script type="application/javascript">
+function foo1() {
+ foo2();
+}
+
+function foo1b() {
+ foo2();
+}
+
+function foo2() {
+ foo3();
+}
+
+function foo3() {
+ console.trace();
+}
+
+foo1(); foo1();
+foo1b();
+
+</script>
+ </head>
+ <body>
+ <p>Web Console test for bug 939783 - different console.trace() calls
+ wrongly filtered as duplicates</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-certificate-messages.html b/browser/devtools/webconsole/test/test-certificate-messages.html
new file mode 100644
index 000000000..b0419a6fc
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-certificate-messages.html
@@ -0,0 +1,22 @@
+<!--
+ Bug 1068949 - Log crypto warnings to the security pane in the webconsole
+-->
+
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <meta charset="utf8">
+ <title>Security warning test - no violations</title>
+ <!-- ensure no subresource errors so window re-use doesn't cause failures -->
+ <link rel="icon" href="data:;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC">
+ <script>
+ console.log("If you haven't seen ssl warnings yet, you won't");
+ </script>
+ <!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-closure-optimized-out.html b/browser/devtools/webconsole/test/test-closure-optimized-out.html
new file mode 100644
index 000000000..3ad4e8fc0
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-closure-optimized-out.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'/>
+ <title>Debugger Test for Inspecting Optimized-Out Variables</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <script type="text/javascript">
+ window.addEventListener("load", function onload() {
+ window.removeEventListener("load", onload);
+ function clickHandler(event) {
+ button.removeEventListener("click", clickHandler, false);
+ function outer(arg) {
+ var upvar = arg * 2;
+ // The inner lambda only aliases arg, so the frontend alias analysis decides
+ // that upvar is not aliased and is not in the CallObject.
+ return function () {
+ arg += 2;
+ };
+ }
+
+ var f = outer(42);
+ f();
+ }
+ var button = document.querySelector("button");
+ button.addEventListener("click", clickHandler, false);
+ });
+ </script>
+
+ </head>
+ <body>
+ <button>Click me!</button>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-closures.html b/browser/devtools/webconsole/test/test-closures.html
new file mode 100644
index 000000000..4fadade20
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-closures.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'/>
+ <title>Console Test for Closure Inspection</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <script type="text/javascript">
+ function injectPerson() {
+ var PersonFactory = function _pfactory(name) {
+ var foo = 10;
+ return {
+ getName: function() { return name; },
+ getFoo: function() { foo = Date.now(); return foo; }
+ };
+ };
+ window.george = new PersonFactory("George");
+ debugger;
+ }
+ </script>
+
+ </head>
+ <body>
+ <button onclick="injectPerson()">Test</button>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-console-api-stackframe.html b/browser/devtools/webconsole/test/test-console-api-stackframe.html
new file mode 100644
index 000000000..df7fef9b1
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-api-stackframe.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html dir="ltr" lang="en">
+ <head>
+ <meta charset="utf8">
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ <title>Test for bug 920116 - stacktraces for console API messages</title>
+ <script>
+ function firstCall() {
+ secondCall();
+ }
+
+ function secondCall() {
+ thirdCall();
+ }
+
+ function thirdCall() {
+ console.log("foo-log");
+ console.error("foo-error");
+ console.exception("foo-exception");
+ console.assert("red" == "blue", "foo-assert");
+ }
+
+ window.onload = firstCall;
+ </script>
+ </head>
+ <body>
+ <p>Hello world!</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-console-assert.html b/browser/devtools/webconsole/test/test-console-assert.html
new file mode 100644
index 000000000..b104d72d4
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-assert.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ <meta charset="utf-8">
+ <title>console.assert() test</title>
+ <script type="text/javascript">
+ function test() {
+ console.log("start");
+ console.assert(false, "false assert");
+ console.assert(0, "falsy assert");
+ console.assert(true, "true assert");
+ console.log("end");
+ }
+ </script>
+ </head>
+ <body>
+ <p>test console.assert()</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-console-column.html b/browser/devtools/webconsole/test/test-console-column.html
new file mode 100644
index 000000000..ff9cc81e1
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-column.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <meta charset="utf-8">
+ <title>Console test</title>
+
+ <script type="text/javascript">
+ console.info("INLINE SCRIPT:"); console.log('Further');
+ console.warn("I'm warning you, he will eat up all yr bacon.");
+ console.error("Error Message");
+ console.log('Rainbooooww');
+ console.log('NYAN CATZ');
+ </script>
+ </head>
+</html>
diff --git a/browser/devtools/webconsole/test/test-console-count-external-file.js b/browser/devtools/webconsole/test/test-console-count-external-file.js
new file mode 100644
index 000000000..77959b831
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-count-external-file.js
@@ -0,0 +1,7 @@
+function counterExternalFile() {
+ console.count("console.count() testcounter");
+}
+function externalCountersWithoutLabel() {
+ console.count();
+ console.count();
+}
diff --git a/browser/devtools/webconsole/test/test-console-count.html b/browser/devtools/webconsole/test/test-console-count.html
new file mode 100644
index 000000000..e6db0ebb0
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-count.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ <meta charset="utf-8">
+ <title>console.count() test</title>
+ <script src="test-console-count-external-file.js"></script>
+ <script tyoe="text/javascript">
+ function counterSeperateScriptTag() {
+ console.count("console.count() testcounter");
+ }
+ </script>
+ <script type="text/javascript">
+ function counterNoLabel() {
+ console.count();
+ }
+ function countersWithoutLabel() {
+ console.count();
+ console.count();
+ }
+ function counterWithLabel() {
+ console.count("console.count() testcounter");
+ }
+ function testLocal() {
+ console.log("start");
+ counterNoLabel();
+ counterNoLabel();
+ countersWithoutLabel();
+ counterWithLabel();
+ counterWithLabel();
+ counterSeperateScriptTag();
+ counterSeperateScriptTag();
+ console.log("end");
+ }
+ function testExternal() {
+ console.log("start");
+ counterExternalFile();
+ counterExternalFile();
+ externalCountersWithoutLabel();
+ console.log("end");
+ }
+ </script>
+ </head>
+ <body>
+ <p>test console.count()</p>
+ <button id="local" onclick="testLocal();">
+ test local console.count() calls
+ </button>
+ <button id="external" onclick="testExternal();">
+ test external console.count() calls
+ </button>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-console-extras.html b/browser/devtools/webconsole/test/test-console-extras.html
new file mode 100644
index 000000000..ae0b521c5
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-extras.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+ <meta charset="utf-8">
+ <title>Console extended API test</title>
+ <script type="text/javascript">
+ function test() {
+ console.log("start");
+ console.clear()
+ console.dirxml()
+ console.log("end");
+ }
+ </script>
+ </head>
+ <body>
+ <h1 id="header">Heads Up Display Demo</h1>
+ <button onclick="test();">Test Extended API</button>
+ <div id="myDiv"></div>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-console-output-02.html b/browser/devtools/webconsole/test/test-console-output-02.html
new file mode 100644
index 000000000..c2fe21233
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-output-02.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html dir="ltr" lang="en-US">
+<head>
+ <meta charset="utf-8">
+ <title>Test the web console output - 02</title>
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+</head>
+<body>
+ <p>hello world!</p>
+ <script type="text/javascript">
+function testfn1() { return 42; }
+
+var testobj1 = {
+ testfn2: function() { return 42; },
+};
+
+function testfn3() { return 42; }
+testfn3.displayName = "testfn3DisplayName";
+
+var array1 = [1, 2, 3, "a", "b", "c", "4", "5"];
+
+var array2 = ["a", document, document.body, document.body.dataset,
+ document.body.classList];
+
+var array3 = [1, window, null, "a", "b", undefined, false, "", -Infinity, testfn3, testobj1, "foo", "bar"];
+
+var array4 = new Array(5);
+array4.push("test");
+array4.push(array4);
+
+var typedarray1 = new Int32Array([1, 287, 8651, 40983, 8754]);
+
+var set1 = new Set([1, 2, null, array3, "a", "b", undefined, document.head]);
+set1.add(set1);
+
+var testobj2 = {a: "b", c: "d", e: 1, f: "2"};
+testobj2.foo = testobj1;
+testobj2.bar = testobj2;
+Object.defineProperty(testobj2, "getterTest", {
+ enumerable: true,
+ get: function() {
+ return 42;
+ },
+});
+
+var testobj3 = {a: "b", c: "d", e: 1, f: "2", g: true, h: null, i: undefined,
+ j: "", k: document.styleSheets, l: document.body.childNodes,
+ o: new Array(125), m: document.head};
+
+var testobj4 = {a: "b", c: "d"};
+Object.defineProperty(testobj4, "nonEnumerable", { value: "hello world" });
+
+var map1 = new Map([["a", "b"], [document.body.children, testobj2]]);
+map1.set(map1, set1);
+
+ </script>
+</body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-console-output-03.html b/browser/devtools/webconsole/test/test-console-output-03.html
new file mode 100644
index 000000000..9dcf051a6
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-output-03.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html dir="ltr" lang="en-US">
+<head>
+ <meta charset="utf-8">
+ <title>Test the web console output - 03</title>
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+</head>
+<body>
+ <p>hello world!</p>
+ <script type="text/javascript">
+function testBodyClassName() {
+ document.body.className = "test1 tezt2";
+ return document.body;
+}
+
+function testBodyID() {
+ document.body.id = 'foobarid';
+ return document.body;
+}
+
+function testBodyDataset() {
+ document.body.dataset.preview = 'zuzu"<a>foo';
+ return document.body;
+}
+ </script>
+</body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-console-output-04.html b/browser/devtools/webconsole/test/test-console-output-04.html
new file mode 100644
index 000000000..bb4345277
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-output-04.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html dir="ltr" lang="en-US">
+<head>
+ <meta charset="utf-8">
+ <title>Test the web console output - 04</title>
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+</head>
+<body>
+ <p>hello world!</p>
+ <script type="text/javascript">
+function testTextNode() {
+ return document.querySelector("p").childNodes[0];
+}
+
+function testCommentNode() {
+ return document.head.childNodes[5];
+}
+
+function testDocumentFragment() {
+ var frag = document.createDocumentFragment();
+
+ var div = document.createElement("div");
+ div.id = "foo1";
+ div.className = "bar";
+ frag.appendChild(div);
+
+ var span = document.createElement("span");
+ span.id = "foo2";
+ span.textContent = "hello world";
+ div.appendChild(span);
+
+ var div2 = document.createElement("div");
+ div2.id = "foo3";
+ frag.appendChild(div2);
+
+ return frag;
+}
+
+function testError() {
+ try {
+ window.foobar("a");
+ } catch (ex) {
+ return ex;
+ }
+ return null;
+}
+
+function testDOMException() {
+ try {
+ var foo = document.querySelector("foo;()bar!");
+ } catch (ex) {
+ return ex;
+ }
+ return null;
+}
+
+function testCSSStyleDeclaration() {
+ document.body.style = 'color: green; font-size: 2em';
+ return document.body.style;
+}
+
+function testStyleSheetList() {
+ var style = document.querySelector("style");
+ if (!style) {
+ style = document.createElement("style");
+ style.textContent = "p, div { color: blue; font-weight: bold }\n" +
+ "@media print { p { background-color: yellow } }";
+ document.head.appendChild(style);
+ }
+ return document.styleSheets;
+}
+ </script>
+</body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-console-output-dom-elements.html b/browser/devtools/webconsole/test/test-console-output-dom-elements.html
new file mode 100644
index 000000000..84ec58a7b
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-output-dom-elements.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html dir="ltr" lang="en-US">
+<head>
+ <meta charset="utf-8">
+ <title>Test the web console output - 05</title>
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+</head>
+<body class="body-class" id="body-id">
+ <p some-attribute="some-value">hello world!</p>
+ <iframe src="data:text/html,<p>hello from iframe</p>"></iframe>
+ <div class="some classname here with more classnames here"></div>
+ <script type="text/javascript">
+function testBodyNode() {
+ return document.body;
+}
+
+function testDocumentElement() {
+ return document.documentElement;
+}
+
+function testDocument() {
+ return document;
+}
+
+function testNode() {
+ return document.querySelector("p");
+}
+
+function testNodeList() {
+ return document.querySelectorAll("*");
+}
+
+function testNodeInIframe() {
+ return document.querySelector("iframe").contentWindow.document.querySelector("p");
+}
+
+function testDocumentFragment() {
+ var frag = document.createDocumentFragment();
+
+ var span = document.createElement("span");
+ span.className = 'foo';
+ span.dataset.lolz = 'hehe';
+
+ var div = document.createElement('div')
+ div.id = 'fragdiv';
+
+ frag.appendChild(span);
+ frag.appendChild(div);
+
+ return frag;
+}
+
+function testNodeInDocumentFragment() {
+ var frag = testDocumentFragment();
+ return frag.firstChild;
+}
+
+function testUnattachedNode() {
+ var p = document.createElement("p");
+ p.className = "such-class";
+ p.dataset.data = "such-data";
+ return p;
+}
+ </script>
+</body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-console-output-events.html b/browser/devtools/webconsole/test/test-console-output-events.html
new file mode 100644
index 000000000..908a86fab
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-output-events.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html dir="ltr" lang="en-US">
+<head>
+ <meta charset="utf-8">
+ <title>Test the web console output for DOM events</title>
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+</head>
+<body>
+ <p>hello world!</p>
+
+ <script type="text/javascript">
+function testDOMEvents() {
+ function eventLogger(ev) {
+ console.log("eventLogger", ev);
+ }
+ document.addEventListener("mousemove", eventLogger);
+ document.addEventListener("keypress", eventLogger);
+
+ synthesizeMouseMove();
+ synthesizeKeyPress("a", {shiftKey: true});
+}
+
+function synthesizeMouseMove(element) {
+ var mouseEvent = document.createEvent("MouseEvent");
+ mouseEvent.initMouseEvent("mousemove", true, true, window, 0, 0, 0, 0, 0,
+ false, false, false, false, 0, null);
+
+ document.dispatchEvent(mouseEvent);
+}
+
+function synthesizeKeyPress(key, options) {
+ var keyboardEvent = document.createEvent("KeyboardEvent");
+ keyboardEvent.initKeyEvent("keypress", true, true, window, false, false,
+ options.shiftKey, false, key.charCodeAt(0), 0);
+ document.dispatchEvent(keyboardEvent);
+}
+ </script>
+</body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-console-replaced-api.html b/browser/devtools/webconsole/test/test-console-replaced-api.html
new file mode 100644
index 000000000..2b05d023a
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-replaced-api.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+ <meta charset="utf-8">
+ <title>Console test replaced API</title>
+ </head>
+ <body>
+ <h1 id="header">Web Console Replace API Test</h1>
+ <script type="text/javascript">
+ window.console = {log: function (msg){}, info: function (msg){}, warn: function (msg){}, error: function (msg){}};
+ </script>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-console-table.html b/browser/devtools/webconsole/test/test-console-table.html
new file mode 100644
index 000000000..7a3f2333e
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console-table.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html dir="ltr" lang="en">
+ <head>
+ <meta charset="utf8">
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ <title>Test for Bug 899753 - console.table support</title>
+ <script>
+ var languages1 = [
+ { name: "JavaScript", fileExtension: [".js"] },
+ { name: { a: "TypeScript" }, fileExtension: ".ts" },
+ { name: "CoffeeScript", fileExtension: ".coffee" }
+ ];
+
+ var languages2 = {
+ csharp: { name: "C#", paradigm: "object-oriented" },
+ fsharp: { name: "F#", paradigm: "functional" }
+ };
+
+ function Person(firstName, lastName, age)
+ {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.age = age;
+ }
+
+ var family = {};
+ family.mother = new Person("Susan", "Doyle", 32);
+ family.father = new Person("John", "Doyle", 33);
+ family.daughter = new Person("Lily", "Doyle", 5);
+ family.son = new Person("Mike", "Doyle", 8);
+
+ var myMap = new Map();
+
+ myMap.set("a string", "value associated with 'a string'");
+ myMap.set(5, "value associated with 5");
+
+ var mySet = new Set();
+
+ mySet.add(1);
+ mySet.add(5);
+ mySet.add("some text");
+ mySet.add(null);
+ mySet.add(undefined);
+ </script>
+ </head>
+ <body>
+ <p>Hello world!</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-console.html b/browser/devtools/webconsole/test/test-console.html
new file mode 100644
index 000000000..27df226e4
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-console.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+ <meta charset="utf-8">
+ <title>Console test</title>
+ <script type="text/javascript">
+ function test() {
+ var str = "Dolske Digs Bacon, Now and Forevermore."
+ for (var i=0; i < 5; i++) {
+ console.log(str);
+ }
+ }
+ console.info("INLINE SCRIPT:");
+ test();
+ console.warn("I'm warning you, he will eat up all yr bacon.");
+ console.error("Error Message");
+ </script>
+ </head>
+ <body>
+ <h1 id="header">Heads Up Display Demo</h1>
+ <button onclick="test();">Log stuff about Dolske</button>
+ <div id="myDiv"></div>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-consoleiframes.html b/browser/devtools/webconsole/test/test-consoleiframes.html
new file mode 100644
index 000000000..a8176f93a
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-consoleiframes.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+ <script>
+ console.log("main file");
+ </script>
+</head>
+<body>
+<h1>iframe console test</h1>
+<iframe src="test-iframe1.html"></iframe>
+<iframe src="test-iframe2.html"></iframe>
+<iframe src="test-iframe3.html"></iframe>
+</body>
+</html> \ No newline at end of file
diff --git a/browser/devtools/webconsole/test/test-data.json b/browser/devtools/webconsole/test/test-data.json
new file mode 100644
index 000000000..471d240b5
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-data.json
@@ -0,0 +1 @@
+{ id: "test JSON data", myArray: [ "foo", "bar", "baz", "biff" ] } \ No newline at end of file
diff --git a/browser/devtools/webconsole/test/test-data.json^headers^ b/browser/devtools/webconsole/test/test-data.json^headers^
new file mode 100644
index 000000000..7b5e82d4b
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-data.json^headers^
@@ -0,0 +1 @@
+Content-Type: application/json
diff --git a/browser/devtools/webconsole/test/test-duplicate-error.html b/browser/devtools/webconsole/test/test-duplicate-error.html
new file mode 100644
index 000000000..1b2691672
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-duplicate-error.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <meta charset="utf-8">
+ <title>Console duplicate error test</title>
+ <!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+
+ See https://bugzilla.mozilla.org/show_bug.cgi?id=582201
+ -->
+ </head>
+ <body>
+ <h1>Heads Up Display - duplicate error test</h1>
+
+ <script type="text/javascript"><!--
+ fooDuplicateError1.bar();
+ // --></script>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test-encoding-ISO-8859-1.html b/browser/devtools/webconsole/test/test-encoding-ISO-8859-1.html
new file mode 100644
index 000000000..cf19629f4
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-encoding-ISO-8859-1.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="ISO-8859-1">
+</head>
+<body>üöä</body>
+</html> \ No newline at end of file
diff --git a/browser/devtools/webconsole/test/test-error.html b/browser/devtools/webconsole/test/test-error.html
new file mode 100644
index 000000000..abf62a3f1
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-error.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <meta charset="utf-8">
+ <title>Console error test</title>
+ </head>
+ <body>
+ <h1>Heads Up Display - error test</h1>
+ <p><button>generate error</button></p>
+
+ <script type="text/javascript"><!--
+ var button = document.getElementsByTagName("button")[0];
+
+ button.addEventListener("click", function clicker () {
+ button.removeEventListener("click", clicker, false);
+ fooBazBaz.bar();
+ }, false);
+ // --></script>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test-eval-in-stackframe.html b/browser/devtools/webconsole/test/test-eval-in-stackframe.html
new file mode 100644
index 000000000..ec1bf3f30
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-eval-in-stackframe.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html dir="ltr" lang="en">
+ <head>
+ <meta charset="utf8">
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ <title>Test for bug 783499 - use the debugger API in the web console</title>
+ <script>
+ var foo = "globalFooBug783499";
+ var fooObj = {
+ testProp: "testValue",
+ };
+
+ function firstCall()
+ {
+ var foo = "fooFirstCall";
+ var foo3 = "foo3FirstCall";
+ secondCall();
+ }
+
+ function secondCall()
+ {
+ var foo2 = "foo2SecondCall";
+ var fooObj = {
+ testProp2: "testValue2",
+ };
+ var fooObj2 = {
+ testProp22: "testValue22",
+ };
+ debugger;
+ }
+ </script>
+ </head>
+ <body>
+ <p>Hello world!</p>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-file-location.js b/browser/devtools/webconsole/test/test-file-location.js
new file mode 100644
index 000000000..f97ce5725
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-file-location.js
@@ -0,0 +1,9 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+console.log("message for level log");
+console.info("message for level info");
+console.warn("message for level warn");
+console.error("message for level error");
+console.debug("message for level debug");
diff --git a/browser/devtools/webconsole/test/test-filter.html b/browser/devtools/webconsole/test/test-filter.html
new file mode 100644
index 000000000..219177bb2
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-filter.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+ <meta charset="utf-8">
+ <title>Console test</title>
+ <script type="text/javascript">
+ </script>
+ </head>
+ <body>
+ <h1>Heads Up Display Filter Test Page</h1>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-for-of.html b/browser/devtools/webconsole/test/test-for-of.html
new file mode 100644
index 000000000..876010c9e
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-for-of.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML>
+<html>
+<meta charset="utf-8">
+<body>
+<h1>a</h1>
+<div><p>b</p></div>
+<h2>c</h2>
+<p>d</p>
diff --git a/browser/devtools/webconsole/test/test-iframe-762593-insecure-form-action.html b/browser/devtools/webconsole/test/test-iframe-762593-insecure-form-action.html
new file mode 100644
index 000000000..d14b5cdd7
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-iframe-762593-insecure-form-action.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<html>
+ <head>
+ <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <h1>iframe 2</h1>
+ <p>This frame contains a password field inside a form with insecure action.</p>
+ <form action="http://test">
+ <input type="password" name="pwd">
+ </form>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-iframe-762593-insecure-frame.html b/browser/devtools/webconsole/test/test-iframe-762593-insecure-frame.html
new file mode 100644
index 000000000..505676acb
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-iframe-762593-insecure-frame.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<html>
+ <head>
+ <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <h1>iframe 1</h1>
+ <p>This frame is served with an insecure password field.</p>
+ <iframe src=
+ "http://example.com/browser/browser/devtools/webconsole/test/test-iframe-762593-insecure-form-action.html">
+ </iframe>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-iframe1.html b/browser/devtools/webconsole/test/test-iframe1.html
new file mode 100644
index 000000000..4dd4eddfe
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-iframe1.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+ <script>
+ console.log("iframe 1");
+ </script>
+</head>
+<body>
+<h1>iframe 1</h1>
+</body>
+</html> \ No newline at end of file
diff --git a/browser/devtools/webconsole/test/test-iframe2.html b/browser/devtools/webconsole/test/test-iframe2.html
new file mode 100644
index 000000000..c15884795
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-iframe2.html
@@ -0,0 +1,11 @@
+<html>
+<head>
+ <script>
+ console.log("iframe 2");
+ blah;
+ </script>
+</head>
+<body>
+<h1>iframe 2</h1>
+</body>
+</html> \ No newline at end of file
diff --git a/browser/devtools/webconsole/test/test-iframe3.html b/browser/devtools/webconsole/test/test-iframe3.html
new file mode 100644
index 000000000..f0df8b669
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-iframe3.html
@@ -0,0 +1,11 @@
+<html>
+<head>
+ <script>
+ console.log("iframe 3");
+ </script>
+</head>
+<body>
+<h1>iframe 3</h1>
+<iframe src="test-iframe1.html"></iframe>
+</body>
+</html> \ No newline at end of file
diff --git a/browser/devtools/webconsole/test/test-image.png b/browser/devtools/webconsole/test/test-image.png
new file mode 100644
index 000000000..769c63634
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-image.png
Binary files differ
diff --git a/browser/devtools/webconsole/test/test-mixedcontent-securityerrors.html b/browser/devtools/webconsole/test/test-mixedcontent-securityerrors.html
new file mode 100644
index 000000000..cb8cfdaaf
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-mixedcontent-securityerrors.html
@@ -0,0 +1,21 @@
+<!--
+ Bug 875456 - Log mixed content messages from the Mixed Content Blocker to the
+ Security Pane in the Web Console
+-->
+
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <meta charset="utf8">
+ <title>Mixed Content test - http on https</title>
+ <script src="testscript.js"></script>
+ <!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ </head>
+ <body>
+ <iframe src="http://example.com"></iframe>
+ <img src="http://example.com/tests/image/test/mochitest/blue.png"></img>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-mutation.html b/browser/devtools/webconsole/test/test-mutation.html
new file mode 100644
index 000000000..e80933b06
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-mutation.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <meta charset="utf-8">
+ <title>Console mutation test</title>
+ <script>
+ window.onload = function (){
+ var node = document.createElement("div");
+ document.body.appendChild(node);
+ };
+ </script>
+ </head>
+ <body>
+ <h1>Heads Up Display DOM Mutation Test Page</h1>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-network-request.html b/browser/devtools/webconsole/test/test-network-request.html
new file mode 100644
index 000000000..f8f75d60b
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-network-request.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <meta charset="utf-8">
+ <title>Console HTTP test page</title>
+ <script type="text/javascript"><!--
+ function makeXhr(aMethod, aUrl, aRequestBody, aCallback) {
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.open(aMethod, aUrl, true);
+ xmlhttp.onreadystatechange = function() {
+ if (aCallback && xmlhttp.readyState == 4) {
+ aCallback();
+ }
+ };
+ xmlhttp.send(aRequestBody);
+ }
+
+ function testXhrGet(aCallback) {
+ makeXhr('get', 'test-data.json', null, aCallback);
+ }
+
+ function testXhrWarn(aCallback) {
+ makeXhr('get', 'http://example.com/browser/browser/devtools/netmonitor/test/sjs_cors-test-server.sjs', null, aCallback);
+ }
+
+ function testXhrPost(aCallback) {
+ makeXhr('post', 'test-data.json', "Hello world!", aCallback);
+ }
+ // --></script>
+ </head>
+ <body>
+ <h1>Heads Up Display HTTP Logging Testpage</h1>
+ <h2>This page is used to test the HTTP logging.</h2>
+
+ <form action="https://example.com/browser/browser/devtools/webconsole/test/test-network-request.html" method="post">
+ <input name="name" type="text" value="foo bar"><br>
+ <input name="age" type="text" value="144"><br>
+ </form>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-network.html b/browser/devtools/webconsole/test/test-network.html
new file mode 100644
index 000000000..69d3422e3
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-network.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+ <meta charset="utf-8">
+ <title>Console network test</title>
+ <script src="testscript.js?foo"></script>
+ </head>
+ <body>
+ <h1>Heads Up Display Network Test Page</h1>
+ <img src="test-image.png"></img>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-observe-http-ajax.html b/browser/devtools/webconsole/test/test-observe-http-ajax.html
new file mode 100644
index 000000000..5abcefdad
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-observe-http-ajax.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+ <meta charset="utf-8">
+ <title>Console HTTP test page</title>
+ <script type="text/javascript">
+ function test() {
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.open('get', 'test-data.json', false);
+ xmlhttp.send(null);
+ }
+ </script>
+ </head>
+ <body onload="test();">
+ <h1>Heads Up Display HTTP & AJAX Test Page</h1>
+ <h2>This page fires an ajax request so we can see the http logging of the console</h2>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-own-console.html b/browser/devtools/webconsole/test/test-own-console.html
new file mode 100644
index 000000000..d1d18ebc2
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-own-console.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+<head>
+<meta charset="utf-8">
+<script>
+ var _console = {
+ foo: "bar"
+ }
+
+ window.console = _console;
+
+ function loadIFrame() {
+ var iframe = document.body.querySelector("iframe");
+ iframe.addEventListener("load", function() {
+ iframe.removeEventListener("load", arguments.callee, true);
+ }, true);
+
+ iframe.setAttribute("src", "test-console.html");
+ }
+</script>
+</head>
+<body>
+ <iframe></iframe>
+</body>
diff --git a/browser/devtools/webconsole/test/test-property-provider.html b/browser/devtools/webconsole/test/test-property-provider.html
new file mode 100644
index 000000000..532b00f44
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-property-provider.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+ <meta charset="utf-8">
+ <title>Property provider test</title>
+ <script>
+ var testObj = {
+ testProp: 'testValue'
+ };
+ </script>
+ </head>
+ <body>
+ <h1>Heads Up Property Provider Test Page</h1>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-repeated-messages.html b/browser/devtools/webconsole/test/test-repeated-messages.html
new file mode 100644
index 000000000..97f5482e4
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-repeated-messages.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <meta charset="utf8">
+ <title>Test for bugs 720180, 800510 and 865288</title>
+ <script>
+ function testConsole() {
+ // same line and column number
+ for(var i = 0; i < 2; i++) {
+ console.log("foo repeat");
+ }
+ console.log("foo repeat"); console.error("foo repeat");
+ }
+ function testConsoleObjects() {
+ for (var i = 0; i < 3; i++) {
+ var o = { id: "abba" + i };
+ console.log("abba", o);
+ }
+ }
+ </script>
+ <style>
+ body {
+ background-image: foobarz;
+ }
+ p {
+ background-image: foobarz;
+ }
+ </style>
+ <!--
+ - Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+ </head>
+ <body>
+ <p>Hello world!</p>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test-result-format-as-string.html b/browser/devtools/webconsole/test/test-result-format-as-string.html
new file mode 100644
index 000000000..c3ab78ee7
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-result-format-as-string.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Web Console test: jsterm eval format as a string</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ <p>Make sure js eval results are formatted as strings.</p>
+ <script>
+ document.querySelector("p").toSource = function() {
+ var element = document.createElement("div");
+ element.id = "foobar";
+ element.textContent = "bug772506_content";
+ element.setAttribute("onmousemove",
+ "(function () {" +
+ " gBrowser._bug772506 = 'foobar';" +
+ "})();"
+ );
+ return element;
+ };
+ </script>
+ </body>
+</html>
diff --git a/browser/devtools/webconsole/test/test-webconsole-error-observer.html b/browser/devtools/webconsole/test/test-webconsole-error-observer.html
new file mode 100644
index 000000000..8466bc6f2
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-webconsole-error-observer.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+ <head>
+ <meta charset="utf-8">
+ <title>WebConsoleErrorObserver test - bug 611032</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+ <script type="text/javascript">
+ console.log("log Bazzle");
+ console.info("info Bazzle");
+ console.warn("warn Bazzle");
+ console.error("error Bazzle");
+
+ var foo = {};
+ foo.bazBug611032();
+ </script>
+ <style type="text/css">
+ .foo { color: cssColorBug611032; }
+ </style>
+ </head>
+ <body>
+ <h1>WebConsoleErrorObserver test</h1>
+ </body>
+</html>
+
diff --git a/browser/devtools/webconsole/test/test_bug1045902_console_csp_ignore_reflected_xss_message.html b/browser/devtools/webconsole/test/test_bug1045902_console_csp_ignore_reflected_xss_message.html
new file mode 100644
index 000000000..4872a1df7
--- /dev/null
+++ b/browser/devtools/webconsole/test/test_bug1045902_console_csp_ignore_reflected_xss_message.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Bug 1045902 - CSP: Log console message for 'reflected-xss'</title>
+</head>
+<body>
+Bug 1045902 - CSP: Log console message for 'reflected-xss'
+</body>
+</html>
diff --git a/browser/devtools/webconsole/test/test_bug1045902_console_csp_ignore_reflected_xss_message.html^headers^ b/browser/devtools/webconsole/test/test_bug1045902_console_csp_ignore_reflected_xss_message.html^headers^
new file mode 100644
index 000000000..0b234f0e8
--- /dev/null
+++ b/browser/devtools/webconsole/test/test_bug1045902_console_csp_ignore_reflected_xss_message.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: reflected-xss filter;
diff --git a/browser/devtools/webconsole/test/test_bug1092055_shouldwarn.html b/browser/devtools/webconsole/test/test_bug1092055_shouldwarn.html
new file mode 100644
index 000000000..ebb7773cb
--- /dev/null
+++ b/browser/devtools/webconsole/test/test_bug1092055_shouldwarn.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Bug 1092055 - Log console messages for non-top-level security errors</title>
+ <script src="test_bug1092055_shouldwarn.js"></script>
+ <!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+ -->
+</head>
+<body>
+Bug 1092055 - Log console messages for non-top-level security errors
+</body>
+</html>
diff --git a/browser/devtools/webconsole/test/test_bug1092055_shouldwarn.js b/browser/devtools/webconsole/test/test_bug1092055_shouldwarn.js
new file mode 100644
index 000000000..c7d5cec14
--- /dev/null
+++ b/browser/devtools/webconsole/test/test_bug1092055_shouldwarn.js
@@ -0,0 +1,2 @@
+// It doesn't matter what this script does, but the broken HSTS header sent
+// with it should result in warnings in the webconsole
diff --git a/browser/devtools/webconsole/test/test_bug1092055_shouldwarn.js^headers^ b/browser/devtools/webconsole/test/test_bug1092055_shouldwarn.js^headers^
new file mode 100644
index 000000000..f99377fc6
--- /dev/null
+++ b/browser/devtools/webconsole/test/test_bug1092055_shouldwarn.js^headers^
@@ -0,0 +1 @@
+Strict-Transport-Security: some complete nonsense
diff --git a/browser/devtools/webconsole/test/test_bug_1010953_cspro.html b/browser/devtools/webconsole/test/test_bug_1010953_cspro.html
new file mode 100644
index 000000000..83ac6391f
--- /dev/null
+++ b/browser/devtools/webconsole/test/test_bug_1010953_cspro.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 1010953 - Verify that CSP and CSPRO log different console
+messages.</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1010953">Mozilla Bug 1010953</a>
+
+
+<!-- this script file allowed by the CSP header (but not by the report-only header) -->
+<script src="http://some.example.com/test_bug_1010953_cspro.js"></script>
+
+<!-- this image allowed only be the CSP report-only header. -->
+<img src="http://some.example.com/test.png">
+</body>
+</html> \ No newline at end of file
diff --git a/browser/devtools/webconsole/test/test_bug_1010953_cspro.html^headers^ b/browser/devtools/webconsole/test/test_bug_1010953_cspro.html^headers^
new file mode 100644
index 000000000..03056e2cb
--- /dev/null
+++ b/browser/devtools/webconsole/test/test_bug_1010953_cspro.html^headers^
@@ -0,0 +1,2 @@
+Content-Security-Policy: default-src 'self'; img-src 'self'; script-src some.example.com;
+Content-Security-Policy-Report-Only: default-src 'self'; img-src some.example.com; script-src 'self'; report-uri https://example.com/ignored/; \ No newline at end of file
diff --git a/browser/devtools/webconsole/test/test_bug_770099_violation.html b/browser/devtools/webconsole/test/test_bug_770099_violation.html
new file mode 100644
index 000000000..ccbded87a
--- /dev/null
+++ b/browser/devtools/webconsole/test/test_bug_770099_violation.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 770099 - policy violation</title>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=770099">Mozilla Bug 770099</a>
+<img src="http://some.example.com/test.png">
+</body>
+</html>
diff --git a/browser/devtools/webconsole/test/test_bug_770099_violation.html^headers^ b/browser/devtools/webconsole/test/test_bug_770099_violation.html^headers^
new file mode 100644
index 000000000..4c6fa3c26
--- /dev/null
+++ b/browser/devtools/webconsole/test/test_bug_770099_violation.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self'
diff --git a/browser/devtools/webconsole/test/testscript.js b/browser/devtools/webconsole/test/testscript.js
new file mode 100644
index 000000000..c69919df4
--- /dev/null
+++ b/browser/devtools/webconsole/test/testscript.js
@@ -0,0 +1 @@
+console.log("running network console logging tests");