diff options
Diffstat (limited to 'browser/devtools/webconsole/test')
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"<a>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"<a>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 Binary files differnew file mode 100644 index 000000000..947e5f11b --- /dev/null +++ b/browser/devtools/webconsole/test/test-bug-595934-image.jpg 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 Binary files differnew file mode 100644 index 000000000..769c63634 --- /dev/null +++ b/browser/devtools/webconsole/test/test-image.png 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"); |