import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,6 @@
"use strict";
module.exports = {
// Extend from the shared list of defined globals for mochitests.
"extends": "../../../.eslintrc.mochitests.js"
};

View file

@ -0,0 +1,396 @@
[DEFAULT]
tags = devtools
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-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-clear.html
test-console-count.html
test-console-count-external-file.js
test-console-extras.html
test-console-replaced-api.html
test-console-server-logging.sjs
test-console-server-logging-array.sjs
test-console.html
test-console-workers.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-output-regexp.html
test-console-column.html
test-consoleiframes.html
test-console-trace-async.html
test-certificate-messages.html
test-cu-reporterror.js
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_hpkp-invalid-headers.sjs
test_hsts-invalid-headers.sjs
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-trackingprotection-securityerrors.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-bug_1050691_click_function_to_source.html
test-bug_1050691_click_function_to_source.js
test-console-api-stackframe.html
test-exception-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
test_bug_1247459_violation.html
!/devtools/client/framework/test/shared-head.js
!/devtools/client/netmonitor/test/sjs_cors-test-server.sjs
!/image/test/mochitest/blue.png
[browser_bug1045902_console_csp_ignore_reflected_xss_message.js]
skip-if = (e10s && debug) || (e10s && os == 'win') # Bug 1221499 enabled these on windows
[browser_bug664688_sandbox_update_after_navigation.js]
[browser_bug_638949_copy_link_location.js]
subsuite = clipboard
[browser_bug_862916_console_dir_and_filter_off.js]
skip-if = (e10s && (os == 'win' || os == 'mac')) # Bug 1243976
[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]
[browser_cached_messages.js]
[browser_console.js]
[browser_console_addonsdk_loader_exception.js]
[browser_console_clear_method.js]
[browser_console_clear_on_reload.js]
[browser_console_click_focus.js]
[browser_console_consolejsm_output.js]
[browser_console_copy_command.js]
subsuite = clipboard
[browser_console_dead_objects.js]
skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
[browser_console_copy_entire_message_context_menu.js]
subsuite = clipboard
[browser_console_error_source_click.js]
[browser_console_filters.js]
[browser_console_iframe_messages.js]
[browser_console_keyboard_accessibility.js]
[browser_console_log_inspectable_object.js]
[browser_console_native_getters.js]
[browser_console_navigation_marker.js]
[browser_console_netlogging.js]
[browser_console_nsiconsolemessage.js]
[browser_console_optimized_out_vars.js]
[browser_console_private_browsing.js]
skip-if = e10s # Bug 1042253 - webconsole e10s tests
[browser_console_server_logging.js]
[browser_console_variables_view.js]
[browser_console_variables_view_filter.js]
[browser_console_variables_view_dom_nodes.js]
[browser_console_variables_view_dont_sort_non_sortable_classes_properties.js]
[browser_console_variables_view_special_names.js]
[browser_console_variables_view_while_debugging.js]
[browser_console_variables_view_while_debugging_and_inspecting.js]
[browser_eval_in_debugger_stackframe.js]
[browser_eval_in_debugger_stackframe2.js]
[browser_jsterm_inspect.js]
skip-if = e10s && debug && (os == 'win' || os == 'mac') # Bug 1243966
[browser_longstring_hang.js]
[browser_output_breaks_after_console_dir_uninspectable.js]
[browser_output_longstring_expand.js]
[browser_repeated_messages_accuracy.js]
[browser_result_format_as_string.js]
[browser_warn_user_about_replaced_api.js]
[browser_webconsole_allow_mixedcontent_securityerrors.js]
tags = mcb
[browser_webconsole_script_errordoc_urls.js]
skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
[browser_webconsole_assert.js]
[browser_webconsole_block_mixedcontent_securityerrors.js]
tags = mcb
[browser_webconsole_bug_579412_input_focus.js]
[browser_webconsole_bug_580001_closing_after_completion.js]
[browser_webconsole_bug_580030_errors_after_page_reload.js]
[browser_webconsole_bug_580454_timestamp_l10n.js]
[browser_webconsole_bug_582201_duplicate_errors.js]
[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]
[browser_webconsole_bug_585991_autocomplete_popup.js]
[browser_webconsole_bug_586388_select_all.js]
[browser_webconsole_bug_587617_output_copy.js]
subsuite = clipboard
[browser_webconsole_bug_588342_document_focus.js]
[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]
[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
[browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js]
[browser_webconsole_bug_597136_external_script_errors.js]
[browser_webconsole_bug_597136_network_requests_from_chrome.js]
[browser_webconsole_bug_597460_filter_scroll.js]
[browser_webconsole_bug_597756_reopen_closed_tab.js]
[browser_webconsole_bug_599725_response_headers.js]
[browser_webconsole_bug_600183_charset.js]
[browser_webconsole_bug_601177_log_levels.js]
[browser_webconsole_bug_601352_scroll.js]
[browser_webconsole_bug_601667_filter_buttons.js]
[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]
subsuite = clipboard
[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]
[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 = true # Bug 1244707
[browser_webconsole_bug_642108_pruneTest.js]
[browser_webconsole_autocomplete_and_selfxss.js]
subsuite = clipboard
[browser_webconsole_bug_644419_log_limits.js]
[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 = true # Requires direct access to content nodes
[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]
tags = mcb
[browser_webconsole_bug_752559_ineffective_iframe_sandbox_warning.js]
[browser_webconsole_bug_762593_insecure_passwords_about_blank_web_console_warning.js]
[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]
[browser_webconsole_bug_770099_violation.js]
skip-if = e10s && (os == 'win' || os == 'mac') # Bug 1243978
[browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js]
[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]
[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]
skip-if = e10s && (os == 'win' || os == 'mac') # Bug 1243967
[browser_webconsole_bug_1247459_violation.js]
skip-if = e10s && (os == 'win') # Bug 1264955
[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 && (os == 'win' || os == 'mac') # Bug 1243987
[browser_webconsole_cached_autocomplete.js]
[browser_webconsole_chrome.js]
[browser_webconsole_clear_method.js]
[browser_webconsole_clickable_urls.js]
[browser_webconsole_closure_inspection.js]
[browser_webconsole_completion.js]
[browser_webconsole_console_extras.js]
[browser_webconsole_console_logging_api.js]
[browser_webconsole_console_logging_workers_api.js]
[browser_webconsole_console_trace_async.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_hpkp_invalid-headers.js]
[browser_webconsole_hsts_invalid-headers.js]
skip-if = e10s # Bug 1042253 - webconsole e10s tests
[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_multiline_input.js]
[browser_webconsole_netlogging.js]
skip-if = true # Bug 1298364
[browser_webconsole_netlogging_basic.js]
[browser_webconsole_netlogging_panel.js]
[browser_webconsole_netlogging_reset_filter.js]
[browser_webconsole_notifications.js]
[browser_webconsole_open-links-without-callback.js]
[browser_webconsole_promise.js]
[browser_webconsole_output_copy_newlines.js]
subsuite = clipboard
[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]
[browser_webconsole_trackingprotection_errors.js]
tags = trackingprotection
[browser_webconsole_view_source.js]
[browser_webconsole_reflow.js]
[browser_webconsole_log_file_filter.js]
[browser_webconsole_expandable_timestamps.js]
[browser_webconsole_autocomplete_accessibility.js]
[browser_webconsole_autocomplete_in_debugger_stackframe.js]
[browser_webconsole_autocomplete_popup_close_on_tab_switch.js]
[browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js]
[browser_console_hide_jsterm_when_devtools_chrome_enabled_false.js]
[browser_console_history_persist.js]
[browser_webconsole_output_01.js]
[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]
skip-if = e10s # Bug 1241019
[browser_webconsole_output_dom_elements_04.js]
skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
[browser_webconsole_output_dom_elements_05.js]
[browser_webconsole_output_events.js]
[browser_webconsole_output_regexp.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_exception_stackframe.js]
[browser_webconsole_column_numbers.js]
[browser_console_open_or_focus.js]
[browser_webconsole_bug_922212_console_dirxml.js]
[browser_webconsole_shows_reqs_in_netmonitor.js]
[browser_netmonitor_shows_reqs_in_webconsole.js]
[browser_webconsole_bug_1050691_click_function_to_source.js]
[browser_webconsole_context_menu_open_in_var_view.js]
[browser_webconsole_context_menu_store_as_global.js]
[browser_webconsole_strict_mode_errors.js]

View file

@ -0,0 +1,52 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 a file with an unsupported CSP directive ('reflected-xss filter')
// displays the appropriate message to the console.
"use strict";
const EXPECTED_RESULT = "Not supporting directive \u2018reflected-xss\u2019. " +
"Directive and values will be ignored.";
const TEST_FILE = "http://example.com/browser/devtools/client/webconsole/" +
"test/test_bug1045902_console_csp_ignore_reflected_xss_" +
"message.html";
var hud = undefined;
var TEST_URI = "data:text/html;charset=utf8,Web Console CSP ignoring " +
"reflected XSS (bug 1045902)";
add_task(function* () {
let { browser } = yield loadTab(TEST_URI);
hud = yield openConsole();
yield loadDocument(browser);
yield testViolationMessage();
hud = null;
});
function loadDocument(browser) {
hud.jsterm.clearOutput();
browser.loadURI(TEST_FILE);
return BrowserTestUtils.browserLoaded(browser);
}
function testViolationMessage() {
let aOutputNode = hud.outputNode;
return waitForSuccess({
name: "Confirming that CSP logs messages to the console when " +
"\u2018reflected-xss\u2019 directive is used!",
validator: function () {
console.log(aOutputNode.textContent);
let success = false;
success = aOutputNode.textContent.indexOf(EXPECTED_RESULT) > -1;
return success;
}
});
}

View file

@ -0,0 +1,92 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 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";
add_task(function* () {
const TEST_URI1 = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-console.html";
const TEST_URI2 = "http://example.org/browser/devtools/client/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
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, 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");
// Navigation clears messages. Wait for that clear to happen before
// continuing the test or it might destroy messages we wait later on (Bug
// 1270234).
let cleared = hud.jsterm.once("messages-cleared");
gBrowser.goBack();
info("Waiting for messages to be cleared due to navigation");
yield cleared;
info("Messages cleared after navigation; checking location");
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");
});

View file

@ -0,0 +1,107 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 for the "Copy link location" context menu item shown when you right
// click network requests in the output.
"use strict";
add_task(function* () {
const TEST_URI = "http://example.com/browser/devtools/client/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.
yield waitForContextMenu(menu, message, () => {
let isHidden = menu.querySelector(CONTEXT_MENU_ID).hidden;
ok(isHidden, CONTEXT_MENU_ID + " is hidden");
});
hud.jsterm.clearOutput();
// Reloading will produce network logging
content.location.reload();
// 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.
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);
}
});

View file

@ -0,0 +1,31 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// 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";
add_task(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 });
});

View file

@ -0,0 +1,63 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 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/devtools/client/webconsole/" +
"test/test-repeated-messages.html";
add_task(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 });
}
});

View file

@ -0,0 +1,75 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// 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/devtools/client/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 result;
let vview;
let msg;
yield openSidebar("fooObj",
'testProp: "testValue"',
{ name: "testProp", value: "testValue" });
let prop = result.matchedProp;
ok(prop, "matched the |testProp| property in the variables view");
vview.window.focus();
let sidebarClosed = jsterm.once("sidebar-closed");
EventUtils.synthesizeKey("VK_ESCAPE", {});
yield sidebarClosed;
jsterm.clearOutput();
yield openSidebar("window.location",
"Location \u2192 http://example.com/browser/",
{ name: "host", value: "example.com" });
vview.window.focus();
msg.scrollIntoView();
sidebarClosed = jsterm.once("sidebar-closed");
EventUtils.synthesizeKey("VK_ESCAPE", {});
yield sidebarClosed;
function* openSidebar(objName, expectedText, expectedObj) {
msg = yield jsterm.execute(objName);
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.includes(expectedText), "message text check");
msg.scrollIntoView();
yield EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow);
let vviewVar = yield jsterm.once("variablesview-fetched");
vview = vviewVar._variablesView;
ok(vview, "variables view object exists");
[result] = yield findVariableViewProperties(vviewVar, [
expectedObj,
], { webconsole: hud });
}
}
}

View file

@ -0,0 +1,77 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that users can inspect objects logged from cross-domain iframes -
// bug 869003.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-bug-869003-top-window.html";
add_task(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();
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, 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.includes('{ 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 });
});

View file

@ -0,0 +1,78 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// 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";
add_task(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;
});

View file

@ -0,0 +1,59 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 to see if the cached messages are displayed when the console UI is
// opened.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-webconsole-error-observer.html";
// On e10s, the exception is triggered in child process
// and is ignored by test harness
if (!Services.appinfo.browserTabsRemoteAutostart) {
expectUncaughtException();
}
function test() {
waitForExplicitFinish();
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);
});
});
});
}

View file

@ -0,0 +1,160 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 the basic features of the Browser Console, bug 587757.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-console.html?" + Date.now();
const TEST_FILE = "chrome://mochitests/content/browser/devtools/client/" +
"webconsole/test/test-cu-reporterror.js";
const TEST_XHR_ERROR_URI = `http://example.com/404.html?${Date.now()}`;
const TEST_IMAGE = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-image.png";
"use strict";
add_task(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");
// Check Cu.reportError stack.
// Use another js script to not depend on the test file line numbers.
Services.scriptloader.loadSubScript(TEST_FILE, hud.iframeWindow);
// 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();
// Check that Fetch requests are categorized as "XHR".
fetch(TEST_IMAGE).then(() => { console.log("fetch loaded"); });
return waitForMessages({
webconsole: hud,
messages: [
{
name: "chrome window console.log() is displayed",
text: "bug587757a",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
},
{
name: "Cu.reportError is displayed",
text: "bug1141222",
category: CATEGORY_JS,
severity: SEVERITY_ERROR,
stacktrace: [{
file: TEST_FILE,
line: 2,
}, {
file: TEST_FILE,
line: 4,
},
// Ignore the rest of the stack,
// just assert Cu.reportError call site
// and consoleOpened call
]
},
{
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,
},
{
name: "network message",
text: "test-image.png",
category: CATEGORY_NETWORK,
severity: SEVERITY_INFO,
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;
}

View file

@ -0,0 +1,92 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// 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;
// non-iterable
toolbox._toolPanels = {};
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 .message-location > .frame-link");
ok(locationNode, "message location element found");
let url = locationNode.getAttribute("data-url");
info("location node url: " + url);
ok(url.indexOf("resource://") === 0, "error comes from a subscript");
let viewSource = browserconsole.viewSource;
let URL = null;
let clickPromise = promise.defer();
browserconsole.viewSourceInDebugger = (sourceURL) => {
info("browserconsole.viewSourceInDebugger() was invoked: " + sourceURL);
URL = sourceURL;
clickPromise.resolve(null);
};
msg.scrollIntoView();
EventUtils.synthesizeMouse(locationNode, 2, 2, {},
browserconsole.iframeWindow);
info("wait for click on locationNode");
yield clickPromise.promise;
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.viewSourceInDebugger = viewSource;
}
}

View file

@ -0,0 +1,41 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that console.clear() does not clear the output of the browser console.
"use strict";
const TEST_URI = "data:text/html;charset=utf8,<p>Bug 1296870";
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield HUDService.toggleBrowserConsole();
info("Log a new message from the content page");
ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
content.wrappedJSObject.console.log("msg");
});
yield waitForMessage("msg", hud);
info("Send a console.clear() from the content page");
ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
content.wrappedJSObject.console.clear();
});
yield waitForMessage("Console was cleared", hud);
info("Check that the messages logged after the first clear are still displayed");
isnot(hud.outputNode.textContent.indexOf("msg"), -1, "msg is in the output");
});
function waitForMessage(message, webconsole) {
return waitForMessages({
webconsole,
messages: [{
text: message,
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
}],
});
}

View file

@ -0,0 +1,86 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that clear output on page reload works - bug 705921.
// Check that clear output and page reload remove the sidebar - bug 971967.
"use strict";
add_task(function* () {
const PREF = "devtools.webconsole.persistlog";
const TEST_URI = "http://example.com/browser/devtools/client/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");
yield openSidebar("fooObj", { name: "testProp", value: "testValue" });
let sidebarClosed = hud.jsterm.once("sidebar-closed");
hud.jsterm.clearOutput();
yield sidebarClosed;
hud.jsterm.execute("console.log('foobarz1')");
yield waitForMessages({
webconsole: hud,
messages: [{
text: "foobarz1",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
}],
});
yield openSidebar("fooObj", { name: "testProp", value: "testValue" });
BrowserReload();
sidebarClosed = hud.jsterm.once("sidebar-closed");
loadBrowser(gBrowser.selectedBrowser);
yield sidebarClosed;
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");
function* openSidebar(objName, expectedObj) {
let msg = yield hud.jsterm.execute(objName);
ok(msg, "output message found");
let anchor = msg.querySelector("a");
let body = msg.querySelector(".message-body");
ok(anchor, "object anchor");
ok(body, "message body");
yield EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow);
let vviewVar = yield hud.jsterm.once("variablesview-fetched");
let vview = vviewVar._variablesView;
ok(vview, "variables view object exists");
yield findVariableViewProperties(vviewVar, [
expectedObj,
], { webconsole: hud });
}
});

View file

@ -0,0 +1,59 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 the input field is focused when the console is opened.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-console.html";
add_task(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");
yield waitForBlurredInput(inputNode);
EventUtils.sendMouseEvent({type: "click"}, hud.outputNode);
ok(inputNode.getAttribute("focused"), "input node is focused, second time");
yield waitForBlurredInput(inputNode);
info("Setting a text selection and making sure a click does not re-focus");
let selection = hud.iframeWindow.getSelection();
selection.selectAllChildren(outputItem);
EventUtils.sendMouseEvent({type: "click"}, hud.outputNode);
ok(!inputNode.getAttribute("focused"),
"input node is not focused after drag");
});
function waitForBlurredInput(inputNode) {
return new Promise(resolve => {
let lostFocus = () => {
inputNode.removeEventListener("blur", lostFocus);
ok(!inputNode.getAttribute("focused"), "input node is not focused");
resolve();
};
inputNode.addEventListener("blur", lostFocus);
document.getElementById("urlbar").click();
});
}

View file

@ -0,0 +1,285 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 Console.jsm outputs messages to the Browser Console, bug 851231.
"use strict";
function onNewMessage(aEvent, aNewMessages) {
for (let msg of aNewMessages) {
// Messages that shouldn't be output contain the substring FAIL_TEST
if (msg.node.textContent.includes("FAIL_TEST")) {
ok(false, "Message shouldn't have been output: " + msg.node.textContent);
}
}
}
add_task(function* () {
let consoleStorage = Cc["@mozilla.org/consoleAPI-storage;1"];
let storage = consoleStorage.getService(Ci.nsIConsoleAPIStorage);
storage.clearEvents();
let {console} = Cu.import("resource://gre/modules/Console.jsm", {});
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 });
yield HUDService.toggleBrowserConsole();
});
add_task(function* testPrefix() {
let consoleStorage = Cc["@mozilla.org/consoleAPI-storage;1"];
let storage = consoleStorage.getService(Ci.nsIConsoleAPIStorage);
storage.clearEvents();
let {ConsoleAPI} = Cu.import("resource://gre/modules/Console.jsm", {});
let consoleOptions = {
maxLogLevel: "error",
prefix: "Log Prefix",
};
let console2 = new ConsoleAPI(consoleOptions);
console2.error("Testing a prefix");
console2.log("FAIL_TEST: Below the maxLogLevel");
let hud = yield HUDService.toggleBrowserConsole();
hud.ui.on("new-messages", onNewMessage);
yield waitForMessages({
webconsole: hud,
messages: [{
name: "cached console.error message",
prefix: "Log Prefix:",
severity: SEVERITY_ERROR,
text: "Testing a prefix",
}],
});
hud.jsterm.clearOutput(true);
hud.ui.off("new-messages", onNewMessage);
yield HUDService.toggleBrowserConsole();
});
add_task(function* testMaxLogLevelPrefMissing() {
let consoleStorage = Cc["@mozilla.org/consoleAPI-storage;1"];
let storage = consoleStorage.getService(Ci.nsIConsoleAPIStorage);
storage.clearEvents();
let {ConsoleAPI} = Cu.import("resource://gre/modules/Console.jsm", {});
let consoleOptions = {
maxLogLevel: "error",
maxLogLevelPref: "testing.maxLogLevel",
};
let console = new ConsoleAPI(consoleOptions);
is(Services.prefs.getPrefType(consoleOptions.maxLogLevelPref),
Services.prefs.PREF_INVALID,
"Check log level pref is missing");
// Since the maxLogLevelPref doesn't exist, we should fallback to the passed
// maxLogLevel of "error".
console.warn("FAIL_TEST: Below the maxLogLevel");
console.error("Error should be shown");
let hud = yield HUDService.toggleBrowserConsole();
hud.ui.on("new-messages", onNewMessage);
yield waitForMessages({
webconsole: hud,
messages: [{
name: "defaulting to error level",
severity: SEVERITY_ERROR,
text: "Error should be shown",
}],
});
hud.jsterm.clearOutput(true);
hud.ui.off("new-messages", onNewMessage);
yield HUDService.toggleBrowserConsole();
});
add_task(function* testMaxLogLevelPref() {
let consoleStorage = Cc["@mozilla.org/consoleAPI-storage;1"];
let storage = consoleStorage.getService(Ci.nsIConsoleAPIStorage);
storage.clearEvents();
let {ConsoleAPI} = Cu.import("resource://gre/modules/Console.jsm", {});
let consoleOptions = {
maxLogLevel: "error",
maxLogLevelPref: "testing.maxLogLevel",
};
info("Setting the pref to warn");
Services.prefs.setCharPref(consoleOptions.maxLogLevelPref, "Warn");
let console = new ConsoleAPI(consoleOptions);
is(console.maxLogLevel, "warn", "Check pref was read at initialization");
console.info("FAIL_TEST: info is below the maxLogLevel");
console.error("Error should be shown");
console.warn("Warn should be shown due to the initial pref value");
info("Setting the pref to info");
Services.prefs.setCharPref(consoleOptions.maxLogLevelPref, "INFO");
is(console.maxLogLevel, "info", "Check pref was lowercased");
console.info("info should be shown due to the pref change being observed");
info("Clearing the pref");
Services.prefs.clearUserPref(consoleOptions.maxLogLevelPref);
console.warn("FAIL_TEST: Shouldn't be shown due to defaulting to error");
console.error("Should be shown due to defaulting to error");
let hud = yield HUDService.toggleBrowserConsole();
hud.ui.on("new-messages", onNewMessage);
yield waitForMessages({
webconsole: hud,
messages: [{
name: "error > warn",
severity: SEVERITY_ERROR,
text: "Error should be shown",
},
{
name: "warn is the inital pref value",
severity: SEVERITY_WARNING,
text: "Warn should be shown due to the initial pref value",
},
{
name: "pref changed to info",
severity: SEVERITY_INFO,
text: "info should be shown due to the pref change being observed",
},
{
name: "default to intial maxLogLevel if pref is removed",
severity: SEVERITY_ERROR,
text: "Should be shown due to defaulting to error",
}],
});
hud.jsterm.clearOutput(true);
hud.ui.off("new-messages", onNewMessage);
yield HUDService.toggleBrowserConsole();
});

View file

@ -0,0 +1,76 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 the `copy` console helper works as intended.
"use strict";
var gWebConsole, gJSTerm;
var 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();
var 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* testCopy() {
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();
});

View file

@ -0,0 +1,97 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
/* globals goDoCommand */
"use strict";
// Test copying of the entire console message when right-clicked
// with no other text selected. See Bug 1100562.
add_task(function* () {
let hud;
let outputNode;
let contextMenu;
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/test/test-console.html";
const { tab, browser } = 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();
yield ContentTask.spawn(browser, {}, function* () {
let button = content.document.getElementById("testTrace");
button.click();
});
let results = yield waitForMessages({
webconsole: hud,
messages: [
{
text: "bug 1100562",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
lines: 1,
},
{
name: "console.trace output",
consoleTrace: true,
lines: 3,
},
]
});
outputNode.focus();
for (let result of results) {
let message = [...result.matched][0];
yield waitForContextMenu(contextMenu, message, () => {
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");
});
let clipboardText;
yield waitForClipboardPromise(
() => goDoCommand("cmd_copy"),
(str) => {
clipboardText = str;
return message.textContent == clipboardText;
}
);
ok(clipboardText, "Clipboard text was found and saved");
let lines = clipboardText.split("\n");
ok(lines.length > 0, "There is at least one newline in the message");
is(lines.pop(), "", "There is a newline at the end");
is(lines.length, result.lines, `There are ${result.lines} lines in the message`);
// Test the first line for "timestamp message repeat file:line"
let firstLine = lines.shift();
ok(/^[\d:.]+ .+ \d+ .+:\d+$/.test(firstLine),
"The message's first line has the right format");
// Test the remaining lines (stack trace) for "TABfunctionName sourceURL:line:col"
for (let line of lines) {
ok(/^\t.+ .+:\d+:\d+$/.test(line), "The stack trace line has the right format");
}
}
yield closeConsole(tab);
yield finishTest();
});

View file

@ -0,0 +1,88 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// 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);
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");
}
}

View file

@ -0,0 +1,79 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that JS errors and CSS warnings open view source when their source link
// is clicked in the Browser Console. See bug 877778.
"use strict";
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>";
add_task(function* () {
yield new Promise(resolve => {
SpecialPowers.pushPrefEnv({"set": [
["devtools.browserconsole.filter.cssparser", true]
]}, resolve);
});
yield loadTab(TEST_URI);
let hud = yield HUDService.toggleBrowserConsole();
ok(hud, "browser console opened");
// On e10s, the exception is triggered in child process
// and is ignored by test harness
if (!Services.appinfo.browserTabsRemoteAutostart) {
expectUncaughtException();
}
info("generate exception and wait for the message");
ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let button = content.document.querySelector("button");
button.click();
});
let results = yield waitForMessages({
webconsole: hud,
messages: [
{
text: "ReferenceError: foobar is not defined",
category: CATEGORY_JS,
severity: SEVERITY_ERROR,
},
{
text: "Unknown property \u2018test-color\u2019",
category: CATEGORY_CSS,
severity: SEVERITY_WARNING,
},
],
});
let viewSourceCalled = false;
let viewSource = hud.viewSource;
hud.viewSource = () => {
viewSourceCalled = true;
};
for (let result of results) {
viewSourceCalled = false;
let msg = [...result.matched][0];
ok(msg, "message element found for: " + result.text);
ok(!msg.classList.contains("filtered-by-type"), "message element is not filtered");
let selector = ".message .message-location .frame-link-source";
let locationNode = msg.querySelector(selector);
ok(locationNode, "message location element found");
locationNode.click();
ok(viewSourceCalled, "view source opened");
}
hud.viewSource = viewSource;
yield finishTest();
});

View file

@ -0,0 +1,60 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// 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.";
add_task(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);
});

View file

@ -0,0 +1,114 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
/*
* 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.
*/
"use strict";
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();
// Filter out other messages to ensure ours stays visible.
hud.ui.filterBox.value = "browser_console_hide_jsterm_test";
hud.jsterm.clearOutput();
hud.jsterm.execute("new Object({ browser_console_hide_jsterm_test: true })");
let [message] = yield waitForMessages({
webconsole: hud,
messages: [{
text: "Object { browser_console_hide_jsterm_test: true }",
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);
}

View file

@ -0,0 +1,119 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 console command input is persisted across toolbox loads.
// See Bug 943306.
"use strict";
requestLongerTimeout(2);
const TEST_URI = "data:text/html;charset=utf-8,Web Console test for " +
"persisting history - bug 943306";
const INPUT_HISTORY_COUNT = 10;
add_task(function* () {
info("Setting custom input history pref to " + INPUT_HISTORY_COUNT);
Services.prefs.setIntPref("devtools.webconsole.inputHistoryCount",
INPUT_HISTORY_COUNT);
// First tab: run a bunch of commands and then make sure that you can
// navigate through their history.
yield loadTab(TEST_URI);
let hud1 = yield openConsole();
is(JSON.stringify(hud1.jsterm.history), "[]",
"No history on first tab initially");
yield populateInputHistory(hud1);
is(JSON.stringify(hud1.jsterm.history),
'["0","1","2","3","4","5","6","7","8","9"]',
"First tab has populated history");
// Second tab: Just make sure that you can navigate through the history
// generated by the first tab.
yield loadTab(TEST_URI);
let hud2 = yield openConsole();
is(JSON.stringify(hud2.jsterm.history),
'["0","1","2","3","4","5","6","7","8","9"]',
"Second tab has populated history");
yield testNaviatingHistoryInUI(hud2);
is(JSON.stringify(hud2.jsterm.history),
'["0","1","2","3","4","5","6","7","8","9",""]',
"An empty entry has been added in the second tab due to history perusal");
// Third tab: Should have the same history as first tab, but if we run a
// command, then the history of the first and second shouldn't be affected
yield loadTab(TEST_URI);
let hud3 = yield openConsole();
is(JSON.stringify(hud3.jsterm.history),
'["0","1","2","3","4","5","6","7","8","9"]',
"Third tab has populated history");
// Set input value separately from execute so UP arrow accurately navigates
// history.
hud3.jsterm.setInputValue('"hello from third tab"');
hud3.jsterm.execute();
is(JSON.stringify(hud1.jsterm.history),
'["0","1","2","3","4","5","6","7","8","9"]',
"First tab history hasn't changed due to command in third tab");
is(JSON.stringify(hud2.jsterm.history),
'["0","1","2","3","4","5","6","7","8","9",""]',
"Second tab history hasn't changed due to command in third tab");
is(JSON.stringify(hud3.jsterm.history),
'["1","2","3","4","5","6","7","8","9","\\"hello from third tab\\""]',
"Third tab has updated history (and purged the first result) after " +
"running a command");
// Fourth tab: Should have the latest command from the third tab, followed
// by the rest of the history from the first tab.
yield loadTab(TEST_URI);
let hud4 = yield openConsole();
is(JSON.stringify(hud4.jsterm.history),
'["1","2","3","4","5","6","7","8","9","\\"hello from third tab\\""]',
"Fourth tab has most recent history");
yield hud4.jsterm.clearHistory();
is(JSON.stringify(hud4.jsterm.history), "[]",
"Clearing history for a tab works");
yield loadTab(TEST_URI);
let hud5 = yield openConsole();
is(JSON.stringify(hud5.jsterm.history), "[]",
"Clearing history carries over to a new tab");
info("Clearing custom input history pref");
Services.prefs.clearUserPref("devtools.webconsole.inputHistoryCount");
});
/**
* Populate the history by running the following commands:
* [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
*/
function* populateInputHistory(hud) {
let jsterm = hud.jsterm;
for (let i = 0; i < INPUT_HISTORY_COUNT; i++) {
// Set input value separately from execute so UP arrow accurately navigates
// history.
jsterm.setInputValue(i);
jsterm.execute();
}
}
/**
* Check pressing up results in history traversal like:
* [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
*/
function* testNaviatingHistoryInUI(hud) {
let jsterm = hud.jsterm;
jsterm.focus();
// Count backwards from original input and make sure that pressing up
// restores this.
for (let i = INPUT_HISTORY_COUNT - 1; i >= 0; i--) {
EventUtils.synthesizeKey("VK_UP", {});
is(jsterm.getInputValue(), i, "Pressing up restores last input");
}
}

View file

@ -0,0 +1,114 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that cached messages from nested iframes are displayed in the
// Web/Browser Console.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/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
},
];
add_task(function* () {
// On e10s, the exception is triggered in child process
// and is ignored by test harness
if (!Services.appinfo.browserTabsRemoteAutostart) {
expectUncaughtException();
}
yield loadTab(TEST_URI);
let hud = yield openConsole();
ok(hud, "web console opened");
yield testWebConsole(hud);
yield closeConsole();
info("web console closed");
hud = yield HUDService.toggleBrowserConsole();
yield testBrowserConsole(hud);
yield closeConsole();
});
function* testWebConsole(hud) {
yield waitForMessages({
webconsole: hud,
messages: expectedMessages,
});
info("first messages matched");
yield waitForMessages({
webconsole: hud,
messages: expectedMessagesAny,
matchCondition: "any",
});
}
function* testBrowserConsole(hud) {
ok(hud, "browser console opened");
// TODO: The browser console doesn't show page's console.log statements
// in e10s windows. See Bug 1241289.
if (Services.appinfo.browserTabsRemoteAutostart) {
todo(false, "Bug 1241289");
return;
}
yield waitForMessages({
webconsole: hud,
messages: expectedMessages,
});
info("first messages matched");
yield waitForMessages({
webconsole: hud,
messages: expectedMessagesAny,
matchCondition: "any",
});
}

View file

@ -0,0 +1,89 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that basic keyboard shortcuts work in the web console.
"use strict";
add_task(function* () {
const TEST_URI = "http://example.com/browser/devtools/client/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.ui.outputWrapper.scrollTop;
let bottom = currentPosition;
EventUtils.synthesizeKey("VK_PAGE_UP", {});
isnot(hud.ui.outputWrapper.scrollTop, currentPosition,
"scroll position changed after page up");
currentPosition = hud.ui.outputWrapper.scrollTop;
EventUtils.synthesizeKey("VK_PAGE_DOWN", {});
ok(hud.ui.outputWrapper.scrollTop > currentPosition,
"scroll position now at bottom");
EventUtils.synthesizeKey("VK_HOME", {});
is(hud.ui.outputWrapper.scrollTop, 0, "scroll position now at top");
EventUtils.synthesizeKey("VK_END", {});
let scrollTop = hud.ui.outputWrapper.scrollTop;
ok(scrollTop > 0 && Math.abs(scrollTop - bottom) <= 5,
"scroll position now at bottom");
info("try ctrl-l to clear output");
executeSoon(() => {
let clearShortcut;
if (Services.appinfo.OS === "Darwin") {
clearShortcut = WCUL10n.getStr("webconsole.clear.keyOSX");
} else {
clearShortcut = WCUL10n.getStr("webconsole.clear.key");
}
synthesizeKeyShortcut(clearShortcut);
});
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");
synthesizeKeyShortcut(WCUL10n.getStr("webconsole.find.key"));
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");
}
});

View file

@ -0,0 +1,52 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 objects given to console.log() are inspectable.
"use strict";
add_task(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);
yield 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.includes('{ 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 });
});

View file

@ -0,0 +1,101 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// 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!";
requestLongerTimeout(2);
add_task(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: "Array [",
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 });
});

View file

@ -0,0 +1,81 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that the navigation marker shows on page reload - bug 793996.
"use strict";
const PREF = "devtools.webconsole.persistlog";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-console.html";
var hud;
add_task(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();
ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
content.console.log("foobarz1");
});
return waitForMessages({
webconsole: hud,
messages: [{
text: "foobarz1",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
}],
});
}
function onReload() {
ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
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,
}],
});
}

View file

@ -0,0 +1,38 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 network log messages bring up the network panel.
"use strict";
const TEST_NETWORK_REQUEST_URI =
"http://example.com/browser/devtools/client/webconsole/test/" +
"test-network-request.html";
add_task(function* () {
let finishedRequest = waitForFinishedRequest(({ request }) => {
return request.url === TEST_NETWORK_REQUEST_URI;
});
const hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI,
"browserConsole");
let request = yield finishedRequest;
ok(request, "Page load was logged");
let client = hud.ui.webConsoleClient;
let args = [request.actor];
const postData = yield getPacket(client, "getRequestPostData", args);
const responseContent = yield getPacket(client, "getResponseContent", args);
is(request.request.url, TEST_NETWORK_REQUEST_URI,
"Logged network entry is page load");
is(request.request.method, "GET", "Method is correct");
ok(!postData.postData.text, "No request body was stored");
ok(postData.postDataDiscarded, "Request body was discarded");
ok(!responseContent.content.text, "No response body was stored");
ok(responseContent.contentDiscarded || request.fromCache,
"Response body was discarded or response came from the cache");
});

View file

@ -0,0 +1,85 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that nsIConsoleMessages are displayed in the Browser Console.
// See bug 859756.
"use strict";
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");
ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
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);
}

View file

@ -0,0 +1,46 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 the "browser console" menu item opens or focuses (if already open)
// the console window instead of toggling it open/close.
"use strict";
var {Tools} = require("devtools/client/definitions");
add_task(function* () {
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, 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, Tools.webConsole.url,
"The Browser Console is open and has focus");
yield HUDService.toggleBrowserConsole();
hud = HUDService.getBrowserConsole();
ok(!hud, "Browser Console has been closed");
});

View file

@ -0,0 +1,91 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that inspecting an optimized out variable works when execution is
// paused.
"use strict";
// Force the old debugger UI since it's directly used (see Bug 1301705)
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", false);
registerCleanupFunction(function* () {
Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend");
});
function test() {
Task.spawn(function* () {
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-closure-optimized-out.html";
let {tab} = yield loadTab(TEST_URI);
let hud = yield openConsole(tab);
let { toolbox, panel, panelWin } = yield openDebugger();
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);
// Cause the debuggee to pause
ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let button = content.document.querySelector("button");
button.click();
});
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 devtools/client/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);
}
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(eventName, ...args) {
info("Thread event '" + eventName + "' fired: " + (++count) + " time(s).");
if (count == aEventRepeat) {
ok(true, "Enough '" + eventName + "' thread events have been fired.");
thread.removeListener(eventName, onEvent);
deferred.resolve.apply(deferred, args);
}
});
return deferred.promise;
}

View file

@ -0,0 +1,192 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Bug 874061: test for how the browser and web consoles display messages coming
// from private windows. See bug for description of expected behavior.
"use strict";
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.
ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
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's 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(injectedHud) {
hud = injectedHud;
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(injectedHud) {
hud = injectedHud;
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");
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(injectedHud) {
hud = injectedHud;
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 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");
HUDService.toggleBrowserConsole().then(() => {
info("reopen the browser console");
executeSoon(() =>
HUDService.toggleBrowserConsole().then(onBrowserConsoleReopen));
});
});
privateWindow.BrowserTryToCloseWindow();
}
function onBrowserConsoleReopen(injectedHud) {
hud = injectedHud;
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);
});
}
}

View file

@ -0,0 +1,74 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
// Check that server log appears in the console panel - bug 1168872
add_task(function* () {
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/test/test-console-server-logging.sjs";
yield loadTab(TEST_URI);
let hud = yield openConsole();
// Set logging filter and wait till it's set on the backend
hud.setFilterState("serverlog", true);
yield updateServerLoggingListener(hud);
BrowserReloadSkipCache();
// Note that the test is also checking out the (printf like)
// formatters and encoding of UTF8 characters (see the one at the end).
let text = "values: string Object { a: 10 } 123 1.12 \u2713";
yield waitForMessages({
webconsole: hud,
messages: [{
text: text,
category: CATEGORY_SERVER,
severity: SEVERITY_LOG,
}],
});
// Clean up filter
hud.setFilterState("serverlog", false);
yield updateServerLoggingListener(hud);
});
add_task(function* () {
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/test/test-console-server-logging-array.sjs";
yield loadTab(TEST_URI);
let hud = yield openConsole();
// Set logging filter and wait till it's set on the backend
hud.setFilterState("serverlog", true);
yield updateServerLoggingListener(hud);
BrowserReloadSkipCache();
// Note that the test is also checking out the (printf like)
// formatters and encoding of UTF8 characters (see the one at the end).
let text = "Object { best: \"Firefox\", reckless: \"Chrome\", " +
"new_ie: \"Safari\", new_new_ie: \"Edge\" }";
yield waitForMessages({
webconsole: hud,
messages: [{
text: text,
category: CATEGORY_SERVER,
severity: SEVERITY_LOG,
}],
});
// Clean up filter
hud.setFilterState("serverlog", false);
yield updateServerLoggingListener(hud);
});
function updateServerLoggingListener(hud) {
let deferred = promise.defer();
hud.ui._updateServerLoggingListener(response => {
deferred.resolve(response);
});
return deferred.promise;
}

View file

@ -0,0 +1,204 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that variables view works as expected in the web console.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-eval-in-stackframe.html";
var hud, gVariablesView;
registerCleanupFunction(function () {
hud = gVariablesView = null;
});
add_task(function* () {
yield loadTab(TEST_URI);
hud = yield openConsole();
let msg = yield hud.jsterm.execute("(function foo(){})");
ok(msg, "output message found");
ok(msg.textContent.includes("function foo()"),
"message text check");
executeSoon(() => {
EventUtils.synthesizeMouse(msg.querySelector("a"), 2, 2, {}, hud.iframeWindow);
});
let varView = yield hud.jsterm.once("variablesview-fetched");
ok(varView, "object inspector opened on click");
yield findVariableViewProperties(varView, [{
name: "name",
value: "foo",
}], { webconsole: hud });
});
add_task(function* () {
let msg = yield hud.jsterm.execute("fooObj");
ok(msg, "output message found");
ok(msg.textContent.includes('{ testProp: "testValue" }'),
"message text check");
let anchor = msg.querySelector("a");
ok(anchor, "object link found");
let fetched = hud.jsterm.once("variablesview-fetched");
// executeSoon
EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.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);
});
function onFooObjFetch(aVar) {
gVariablesView = aVar._variablesView;
ok(gVariablesView, "variables view object");
return findVariableViewProperties(aVar, [
{ name: "testProp", value: "testValue" },
], { webconsole: hud });
}
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: hud
});
}
function onFooObjFetchAfterUpdate(aVar) {
info("onFooObjFetchAfterUpdate");
let expectedValue = content.document.title + content.location +
"[object HTMLParagraphElement]";
return findVariableViewProperties(aVar, [
{ name: "testProp", value: expectedValue },
], { webconsole: hud });
}
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: hud
});
}
function* onFooObjFetchAfterPropRename(aVar) {
info("onFooObjFetchAfterPropRename");
let expectedValue = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let para = content.wrappedJSObject.document.querySelector("p");
return content.document.title + content.location + para;
});
// Check that the new value is in the variables view.
return findVariableViewProperties(aVar, [
{ name: "testUpdatedProp", value: expectedValue },
], { webconsole: hud });
}
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: hud
});
}
function* onPropUpdateError(aVar) {
info("onPropUpdateError");
let expectedValue = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let para = content.wrappedJSObject.document.querySelector("p");
return content.document.title + content.location + para;
});
// Make sure the property did not change.
return findVariableViewProperties(aVar, [
{ name: "testUpdatedProp", value: expectedValue },
], { webconsole: hud });
}
function onRenamedTestPropFoundAgain(aResults) {
let prop = aResults[0].matchedProp;
ok(prop, "matched the renamed |testProp| property again");
return waitForMessages({
webconsole: hud,
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)
});
}

View file

@ -0,0 +1,59 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 ensures DOM nodes are rendered correctly in VariablesView.
"use strict";
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", (_, val) => deferred.resolve(val));
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});
}
}

View file

@ -0,0 +1,135 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 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')");
// Object
yield testSorted("Object({'hello':1,1:5,10:2,4:2,'abc':1})");
// 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");
}
/**
* A helper that ensures the properties are 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* testSorted(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 = ["1", "4", "10",..., "abc", "hello"] <- correct
// If the properties are not sorted:
// keys = ["1", "10", "4",...] <- incorrect
let keyIterator = variableScope._store.keys();
is(keyIterator.next().value, "1", "First key should be 1");
is(keyIterator.next().value, "4", "Second key should be 4");
// If the properties are sorted, the next one will be 10.
is(keyIterator.next().value, "10", "Third key is 10");
// If sorted next properties should be "abc" then "hello"
is(keyIterator.next().value, "abc", "Fourth key is abc");
is(keyIterator.next().value, "hello", "Fifth key is hello");
}
Task.spawn(runner).then(finishTest);
}

View file

@ -0,0 +1,80 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that variables view filter feature works fine in the console.
function props(view, prefix = "") {
// First match only the visible one, not hidden by a search
let visible = [...view].filter(([id, prop]) => prop._isMatch);
// Then flatten the list into a list of strings
// being the jsonpath of each attribute being visible in the view
return visible.reduce((list, [id, prop]) => {
list.push(prefix + id);
return list.concat(props(prop, prefix + id + "."));
}, []);
}
function assertAttrs(view, expected, message) {
is(props(view).join(","), expected, message);
}
add_task(function* () {
yield loadTab("data:text/html;charset=utf-8,webconsole-filter");
let hud = yield openConsole();
let jsterm = hud.jsterm;
let fetched = jsterm.once("variablesview-fetched");
yield jsterm.execute("inspect({ foo: { bar : \"baz\" } })");
let view = yield fetched;
let variablesView = view._variablesView;
let searchbox = variablesView._searchboxNode;
assertAttrs(view, "foo,__proto__",
"To start with, we just see the top level foo attr");
fetched = jsterm.once("variablesview-fetched");
searchbox.value = "bar";
searchbox.doCommand();
view = yield fetched;
assertAttrs(view, "",
"If we don't manually expand nested attr, we don't see them");
fetched = jsterm.once("variablesview-fetched");
searchbox.value = "";
searchbox.doCommand();
view = yield fetched;
assertAttrs(view, "foo",
"If we reset the search, we get back to original state");
yield [...view][0][1].expand();
fetched = jsterm.once("variablesview-fetched");
searchbox.value = "bar";
searchbox.doCommand();
view = yield fetched;
assertAttrs(view, "foo,foo.bar", "Now if we expand, we see the nested attr");
fetched = jsterm.once("variablesview-fetched");
searchbox.value = "baz";
searchbox.doCommand();
view = yield fetched;
assertAttrs(view, "foo,foo.bar", "We can also search for attr values");
fetched = jsterm.once("variablesview-fetched");
searchbox.value = "";
searchbox.doCommand();
view = yield fetched;
assertAttrs(view, "foo",
"If we reset again, we get back to original state again");
});

View file

@ -0,0 +1,97 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that variables view is linked to the inspector for highlighting and
// selecting DOM nodes
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-bug-952277-highlight-nodes-in-vview.html";
var 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", onNodeListViewFetched);
executeSoon(() =>
EventUtils.synthesizeMouse(anchor, 2, 2, {}, gWebConsole.iframeWindow)
);
}
function onNodeListViewFetched(event, variable) {
gVariablesView = variable._variablesView;
ok(gVariablesView, "variables view object");
// Transform the vview into an array we can filter properties from
let props = [...variable].map(([id, prop]) => [id, prop]);
// 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];
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();
}

View file

@ -0,0 +1,38 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that variables view handles special names like "<return>"
// properly for ordinary displays.
"use strict";
const TEST_URI = "data:text/html;charset=utf8,<p>test for bug 1084430";
add_task(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("inspect({ '<return>': 47, '<exception>': 91 })");
let varView = yield hud.jsterm.once("variablesview-fetched");
ok(varView, "variables view object");
let props = yield findVariableViewProperties(varView, [
{ name: "<return>", value: 47 },
{ name: "<exception>", value: 91 },
], { webconsole: hud });
for (let prop of props) {
ok(!prop.matchedProp._internalItem, prop.name + " is not marked internal");
let target = prop.matchedProp._target;
ok(!target.hasAttribute("pseudo-item"),
prop.name + " is not a pseudo-item");
}
});

View file

@ -0,0 +1,109 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 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.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-eval-in-stackframe.html";
// Force the old debugger UI since it's directly used (see Bug 1301705)
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", false);
registerCleanupFunction(function* () {
Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend");
});
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
let dbgPanel = yield openDebugger();
yield waitForFrameAdded();
yield openConsole();
yield testVariablesView(hud);
});
function* waitForFrameAdded() {
let target = TargetFactory.forTab(gBrowser.selectedTab);
let toolbox = gDevTools.getToolbox(target);
let thread = toolbox.threadClient;
info("Waiting for framesadded");
yield new Promise(resolve => {
thread.addOneTimeListener("framesadded", resolve);
ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
content.wrappedJSObject.firstCall();
});
});
}
function* testVariablesView(hud) {
let jsterm = hud.jsterm;
let msg = yield jsterm.execute("fooObj");
ok(msg, "output message found");
ok(msg.textContent.includes('{ testProp2: "testValue2" }'),
"message text check");
let anchor = msg.querySelector("a");
ok(anchor, "object link found");
info("Waiting for variable view to appear");
let variable = yield new Promise(resolve => {
jsterm.once("variablesview-fetched", (e, variable) => {
resolve(variable);
});
executeSoon(() => EventUtils.synthesizeMouse(anchor, 2, 2, {},
hud.iframeWindow));
});
info("Waiting for findVariableViewProperties");
let results = yield findVariableViewProperties(variable, [
{ name: "testProp2", value: "testValue2" },
{ name: "testProp", value: "testValue", dontMatch: true },
], { webconsole: hud });
let prop = results[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.
variable = yield updateVariablesViewProperty({
property: prop,
field: "value",
string: "document.title + foo2 + $('p')",
webconsole: hud
});
info("onFooObjFetchAfterUpdate");
let expectedValue = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let para = content.wrappedJSObject.document.querySelector("p");
return content.document.title + "foo2SecondCall" + para;
});
results = yield findVariableViewProperties(variable, [
{ name: "testProp2", value: expectedValue },
], { webconsole: hud });
prop = results[0].matchedProp;
ok(prop, "matched the updated |testProp2| property value");
// Check that testProp2 was updated.
yield new Promise(resolve => {
executeSoon(() => {
jsterm.execute("fooObj.testProp2").then(resolve);
});
});
expectedValue = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let para = content.wrappedJSObject.document.querySelector("p");
return content.document.title + "foo2SecondCall" + para;
});
isnot(hud.outputNode.textContent.indexOf(expectedValue), -1,
"fooObj.testProp2 is correct");
}

View file

@ -0,0 +1,112 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 makes sure web console eval works while the js debugger paused the
// page, and while the inspector is active. See bug 886137.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-eval-in-stackframe.html";
// Force the old debugger UI since it's directly used (see Bug 1301705)
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", false);
registerCleanupFunction(function* () {
Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend");
});
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
let dbgPanel = yield openDebugger();
yield openInspector();
yield waitForFrameAdded();
yield openConsole();
yield testVariablesView(hud);
});
function* waitForFrameAdded() {
let target = TargetFactory.forTab(gBrowser.selectedTab);
let toolbox = gDevTools.getToolbox(target);
let thread = toolbox.threadClient;
info("Waiting for framesadded");
yield new Promise(resolve => {
thread.addOneTimeListener("framesadded", resolve);
ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
content.wrappedJSObject.firstCall();
});
});
}
function* testVariablesView(hud) {
info("testVariablesView");
let jsterm = hud.jsterm;
let msg = yield jsterm.execute("fooObj");
ok(msg, "output message found");
ok(msg.textContent.includes('{ testProp2: "testValue2" }'),
"message text check");
let anchor = msg.querySelector("a");
ok(anchor, "object link found");
info("Waiting for variable view to appear");
let variable = yield new Promise(resolve => {
jsterm.once("variablesview-fetched", (e, variable) => {
resolve(variable);
});
executeSoon(() => EventUtils.synthesizeMouse(anchor, 2, 2, {},
hud.iframeWindow));
});
info("Waiting for findVariableViewProperties");
let results = yield findVariableViewProperties(variable, [
{ name: "testProp2", value: "testValue2" },
{ name: "testProp", value: "testValue", dontMatch: true },
], { webconsole: hud });
let prop = results[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.
variable = yield updateVariablesViewProperty({
property: prop,
field: "value",
string: "document.title + foo2 + $('p')",
webconsole: hud
});
info("onFooObjFetchAfterUpdate");
let expectedValue = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let para = content.wrappedJSObject.document.querySelector("p");
return content.document.title + "foo2SecondCall" + para;
});
results = yield findVariableViewProperties(variable, [
{ name: "testProp2", value: expectedValue },
], { webconsole: hud });
prop = results[0].matchedProp;
ok(prop, "matched the updated |testProp2| property value");
// Check that testProp2 was updated.
yield new Promise(resolve => {
executeSoon(() => {
jsterm.execute("fooObj.testProp2").then(resolve);
});
});
expectedValue = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let para = content.wrappedJSObject.document.querySelector("p");
return content.document.title + "foo2SecondCall" + para;
});
isnot(hud.outputNode.textContent.indexOf(expectedValue), -1,
"fooObj.testProp2 is correct");
}

View file

@ -0,0 +1,157 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 makes sure web console eval happens in the user-selected stackframe
// from the js debugger.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-eval-in-stackframe.html";
var gWebConsole, gJSTerm, gDebuggerWin, gThread, gDebuggerController;
var gStackframes;
// Force the old debugger UI since it's directly used (see Bug 1301705)
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", false);
registerCleanupFunction(function* () {
Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend");
});
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()");
ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
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()|");
function runOpenConsole() {
openConsole().then(() => {
gJSTerm.execute("foo + foo2 + foo3").then(onExecuteFoo23InFirstCall);
});
}
executeSoon(() => {
gJSTerm.clearOutput();
info("openDebugger and selectFrame(1)");
openDebugger().then(() => {
gStackframes.selectFrame(1);
info("openConsole");
executeSoon(() => runOpenConsole());
});
});
}
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));
}
var onExecuteFooAndFoo3ChangesInFirstCall = Task.async(function*() {
let expected = "abbabug783499";
isnot(gWebConsole.outputNode.textContent.indexOf(expected), -1,
"|foo + foo3| updated in |firstCall()|");
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
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);
});

View file

@ -0,0 +1,71 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 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/devtools/client/webconsole/" +
"test/test-eval-in-stackframe.html";
// Force the old debugger UI since it's directly used (see Bug 1301705)
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", false);
registerCleanupFunction(function* () {
Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend");
});
add_task(function* () {
yield loadTab(TEST_URI);
info("open the web console");
let hud = yield openConsole();
let {jsterm} = hud;
info("open the debugger");
let {panelWin} = yield openDebugger();
let {DebuggerController} = panelWin;
let {activeThread} = 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);
}

View file

@ -0,0 +1,47 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Check that the inspect() jsterm helper function works.
"use strict";
const TEST_URI = "data:text/html;charset=utf8,<p>hello bug 869981";
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
let jsterm = hud.jsterm;
/* Check that the window object is inspected */
jsterm.execute("testProp = 'testValue'");
let updated = jsterm.once("variablesview-updated");
jsterm.execute("inspect(window)");
let view = yield updated;
ok(view, "variables view object");
// The single variable view contains a scope with the variable name
// and unnamed subitem that contains the properties
let variable = view.getScopeAtIndex(0).get(undefined);
ok(variable, "variable object");
yield findVariableViewProperties(variable, [
{ name: "testProp", value: "testValue" },
{ name: "document", value: /HTMLDocument \u2192 data:/ },
], { webconsole: hud });
/* Check that a primitive value can be inspected, too */
let updated2 = jsterm.once("variablesview-updated");
jsterm.execute("inspect(1)");
let view2 = yield updated2;
ok(view2, "variables view object");
// Check the label of the scope - it should contain the value
let scope = view.getScopeAtIndex(0);
ok(scope, "variable object");
is(scope.name, "1", "The value of the primitive var is correct");
});

View file

@ -0,0 +1,57 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 very long strings do not hang the browser.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-bug-859170-longstring-hang.html";
add_task(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,
},
],
});
});

View file

@ -0,0 +1,74 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "data:text/html;charset=utf8,Test that the netmonitor " +
"displays requests that have been recorded in the " +
"web console, even if the netmonitor hadn't opened yet.";
const TEST_FILE = "test-network-request.html";
const TEST_PATH = "http://example.com/browser/devtools/client/webconsole/" +
"test/" + TEST_FILE;
const NET_PREF = "devtools.webconsole.filter.networkinfo";
Services.prefs.setBoolPref(NET_PREF, true);
registerCleanupFunction(() => {
Services.prefs.clearUserPref(NET_PREF);
});
add_task(function* () {
let { tab, browser } = yield loadTab(TEST_URI);
// Test that the request appears in the console.
let hud = yield openConsole();
info("Web console is open");
yield loadDocument(browser);
info("Document loaded.");
yield waitForMessages({
webconsole: hud,
messages: [
{
name: "network message",
text: TEST_FILE,
category: CATEGORY_NETWORK,
severity: SEVERITY_LOG
}
]
});
// Test that the request appears in the network panel.
let target = TargetFactory.forTab(tab);
let toolbox = yield gDevTools.showToolbox(target, "netmonitor");
info("Network panel is open.");
testNetmonitor(toolbox);
});
function loadDocument(browser) {
let deferred = promise.defer();
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
deferred.resolve();
}, true);
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, TEST_PATH);
return deferred.promise;
}
function testNetmonitor(toolbox) {
let monitor = toolbox.getCurrentPanel();
let { RequestsMenu } = monitor.panelWin.NetMonitorView;
RequestsMenu.lazyUpdate = false;
is(RequestsMenu.itemCount, 1, "Network request appears in the network panel");
let item = RequestsMenu.getItemAtIndex(0);
is(item.attachment.method, "GET", "The attached method is correct.");
is(item.attachment.url, TEST_PATH, "The attached url is correct.");
}

View file

@ -0,0 +1,47 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Make sure that the Web Console output does not break after we try to call
// console.dir() for objects that are not inspectable.
"use strict";
const TEST_URI = "data:text/html;charset=utf8,test for bug 773466";
add_task(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,
}],
});
});

View file

@ -0,0 +1,85 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 long strings can be expanded in the console output.
"use strict";
const TEST_URI = "data:text/html;charset=utf8,test for bug 787981 - check " +
"that long strings can be expanded in the output.";
add_task(function* () {
let { DebuggerServer } = require("devtools/server/main");
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;
}

View file

@ -0,0 +1,178 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 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/devtools/client/webconsole/" +
"test/test-repeated-messages.html";
const PREF = "devtools.webconsole.persistlog";
add_task(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);
yield testConsoleFalsyValues(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");
ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
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,
},
],
});
}
function testConsoleFalsyValues(hud) {
hud.jsterm.clearOutput(true);
hud.jsterm.execute("testConsoleFalsyValues()");
info("wait for repeats of falsy values with the console API");
return waitForMessages({
webconsole: hud,
messages: [
{
name: "console.log 'NaN' repeated once",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
repeats: 1,
},
{
name: "console.log 'undefined' repeated once",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
repeats: 1,
},
{
name: "console.log 'null' repeated once",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
repeats: 1,
},
{
name: "console.log 'NaN' repeated twice",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
repeats: 2,
},
{
name: "console.log 'undefined' repeated twice",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
repeats: 2,
},
{
name: "console.log 'null' repeated twice",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
repeats: 2,
},
],
});
}

View file

@ -0,0 +1,40 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// Make sure that JS eval result are properly formatted as strings.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-result-format-as-string.html";
add_task(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;
}

View file

@ -0,0 +1,86 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_REPLACED_API_URI = "http://example.com/browser/devtools/client/" +
"webconsole/test/test-console-replaced-api.html";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/testscript.js";
const PREF = "devtools.webconsole.persistlog";
add_task(function* () {
Services.prefs.setBoolPref(PREF, true);
let { browser } = yield loadTab(TEST_URI);
let hud = yield openConsole();
yield testWarningNotPresent(hud);
let loaded = loadBrowser(browser);
BrowserTestUtils.loadURI(browser, 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(function () {
let browser = gBrowser.selectedBrowser;
ContentTask.spawn(browser, null, "() => 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);
let browser = gBrowser.selectedBrowser;
ContentTask.spawn(browser, null, "() => content.location.reload()");
});
});
return deferred.promise;
}

View file

@ -0,0 +1,69 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// 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
"use strict";
const TEST_URI = "https://example.com/browser/devtools/client/webconsole/" +
"test/test-mixedcontent-securityerrors.html";
const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Web/Security/" +
"Mixed_content" + DOCS_GA_PARAMS;
add_task(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 " +
"\u201chttp://example.com/\u201d on a secure page",
category: CATEGORY_SECURITY,
severity: SEVERITY_WARNING,
objects: true,
},
{
name: "Logged mixed passive content - image",
text: "Loading mixed (insecure) display content " +
"\u201chttp://example.com/tests/image/test/mochitest/blue.png\u201d " +
"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);
}

View file

@ -0,0 +1,56 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 console.assert() works as expected (i.e. outputs only on falsy
// asserts). See bug 760193.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-console-assert.html";
add_task(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");
});
}

View file

@ -0,0 +1,47 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 that properties starting with underscores or dollars can be
// autocompleted (bug 967468).
add_task(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 " + popup.itemCount + " suggestions for '" + term + "'");
}
let { jsterm } = yield openConsole();
let popup = jsterm.autocompletePopup;
yield jsterm.execute("var 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");
// Should work with bug 1207868.
yield jsterm.execute("let foobar = {a: ''}; const blargh = {a: 1};");
yield autocomplete("foobar");
yield autocomplete("blargh");
yield autocomplete("foobar.a");
yield autocomplete("blargh.a");
});

View file

@ -0,0 +1,60 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 the autocomplete input is being blurred and focused when selecting a value.
// This will help screen-readers notify users of the value that was set in the input.
"use strict";
const TEST_URI = "data:text/html;charset=utf8,<p>test code completion";
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
let jsterm = hud.jsterm;
let input = jsterm.inputNode;
info("Type 'd' to open the autocomplete popup");
yield autocomplete(jsterm, "d");
// Add listeners for focus and blur events.
let wasBlurred = false;
input.addEventListener("blur", () => {
wasBlurred = true;
}, {
once: true
});
let wasFocused = false;
input.addEventListener("blur", () => {
ok(wasBlurred, "jsterm input received a blur event before received back the focus");
wasFocused = true;
}, {
once: true
});
info("Close the autocomplete popup by simulating a TAB key event");
let onPopupClosed = jsterm.autocompletePopup.once("popup-closed");
EventUtils.synthesizeKey("VK_TAB", {});
info("Wait for the autocomplete popup to be closed");
yield onPopupClosed;
ok(wasFocused, "jsterm input received a focus event");
});
function* autocomplete(jsterm, value) {
let popup = jsterm.autocompletePopup;
yield new Promise(resolve => {
jsterm.setInputValue(value);
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
ok(popup.isOpen && popup.itemCount > 0,
"Autocomplete popup is open and contains suggestions");
}

View file

@ -0,0 +1,130 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "data:text/html;charset=utf-8,<p>test for bug 642615";
XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
"@mozilla.org/widget/clipboardhelper;1",
"nsIClipboardHelper");
var WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
add_task(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);
},
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.getInputValue();
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.getInputValue(), "Paste blocked by self-xss prevention");
// Allow pasting
jsterm.setInputValue("allow pasting");
let evt = document.createEvent("KeyboardEvent");
evt.initKeyEvent("keyup", true, true, window,
0, 0, 0, 0,
0, " ".charCodeAt(0));
jsterm.inputNode.dispatchEvent(evt);
jsterm.setInputValue("");
goDoCommand("cmd_paste");
isnot("", jsterm.getInputValue(), "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;
}

View file

@ -0,0 +1,64 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 autocomplete doesn't break when trying to reach into objects from
// a different domain, bug 989025.
"use strict";
function test() {
let hud;
const TEST_URI = "http://example.com/browser/devtools/client/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);
}

View file

@ -0,0 +1,245 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 makes sure web console autocomplete happens in the user-selected
// stackframe from the js debugger.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-autocomplete-in-stackframe.html";
// Force the old debugger UI since it's directly used (see Bug 1301705)
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", false);
registerCleanupFunction(function* () {
Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend");
});
var gStackframes;
registerCleanupFunction(function () {
gStackframes = null;
});
requestLongerTimeout(2);
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
yield testCompletion(hud);
});
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);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
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);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
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);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
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);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
newItems = popup.getItems();
ok(!newItems.every(function (item) {
return item.label != "prop21";
}), "autocomplete results do contain prop21");
info("Opening Debugger");
let dbg = yield openDebugger();
info("Waiting for pause");
yield pauseDebugger(dbg);
info("Opening Console again");
yield openConsole();
// From this point on the
// Test if 'f' gives 'foo3' and 'foo1' but not 'foo2'
input.value = "f";
input.setSelectionRange(1, 1);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
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");
yield openDebugger();
gStackframes.selectFrame(1);
info("openConsole");
yield openConsole();
// Test if 'f' gives 'foo2' and 'foo1' but not 'foo3'
input.value = "f";
input.setSelectionRange(1, 1);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
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);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
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);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
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);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
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);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
newItems = popup.getItems();
is(newItems.length, 0, "no items for foo2Obj[0]");
}
function pauseDebugger(aResult) {
let debuggerWin = aResult.panelWin;
let debuggerController = debuggerWin.DebuggerController;
let thread = debuggerController.activeThread;
gStackframes = debuggerController.StackFrames;
return new Promise(resolve => {
thread.addOneTimeListener("framesadded", resolve);
info("firstCall()");
ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
content.wrappedJSObject.firstCall();
});
});
}

View file

@ -0,0 +1,27 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 the autocomplete popup closes on switching tabs. See bug 900448.
"use strict";
const TEST_URI = "data:text/html;charset=utf-8,<p>bug 900448 - autocomplete " +
"popup closes on tab switch";
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
let popup = hud.jsterm.autocompletePopup;
let popupShown = once(popup, "popup-opened");
hud.jsterm.setInputValue("sc");
EventUtils.synthesizeKey("r", {});
yield popupShown;
yield loadTab("data:text/html;charset=utf-8,<p>testing autocomplete closes");
ok(!popup.isOpen, "Popup closes on tab switch");
});

View file

@ -0,0 +1,110 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
// 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
"use strict";
const TEST_URI = "https://example.com/browser/devtools/client/webconsole/" +
"test/test-mixedcontent-securityerrors.html";
const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Web/Security/" +
"Mixed_content" + DOCS_GA_PARAMS;
add_task(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 \u201chttp://example.com/\u201d",
category: CATEGORY_SECURITY,
severity: SEVERITY_ERROR,
objects: true,
},
{
name: "Logged blocking mixed passive content - image",
text: "Blocked loading mixed active content \u201chttp://example.com/\u201d",
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],
["security.mixed_content.use_hsts", false],
["security.mixed_content.send_hsts_priming", false],
]
};
SpecialPowers.pushPrefEnv(options, deferred.resolve);
return deferred.promise;
}
function mixedContentOverrideTest2(hud, browser) {
let deferred = promise.defer();
let {gIdentityHandler} = browser.ownerGlobal;
ok(gIdentityHandler._identityBox.classList.contains("mixedActiveBlocked"),
"Mixed Active Content state appeared on identity box");
gIdentityHandler.disableMixedContentProtection();
waitForMessages({
webconsole: hud,
messages: [
{
name: "Logged blocking mixed active content",
text: "Loading mixed (insecure) active content " +
"\u201chttp://example.com/\u201d 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" +
" \u201chttp://example.com/tests/image/test/mochitest/blue.png\u201d" +
" on a secure page",
category: CATEGORY_SECURITY,
severity: SEVERITY_WARNING,
objects: true,
},
],
}).then(msgs => deferred.resolve(msgs), e => console.error(e));
return deferred.promise;
}
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);
}

View file

@ -0,0 +1,45 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
function test() {
Task.spawn(runner).then(finishTest);
function* runner() {
const {tab} = yield loadTab("data:text/html;charset=utf8,<title>Test for " +
"Bug 1006027");
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) < 2000,
"console.log message timestamp spread < 2000ms confirmed");
}
}

View file

@ -0,0 +1,55 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
/* 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/devtools/client/" +
"webconsole/test/test_bug_1010953_cspro.html";
const CSP_VIOLATION_MSG = "Content Security Policy: The page\u2019s settings " +
"blocked the loading of a resource at " +
"http://some.example.com/test.png " +
"(\u201cimg-src http://example.com\u201d).";
const CSP_REPORT_MSG = "Content Security Policy: The page\u2019s settings " +
"observed the loading of a resource at " +
"http://some.example.com/test_bug_1010953_cspro.js " +
"(\u201cscript-src http://example.com\u201d). A CSP report is " +
"being sent.";
add_task(function* () {
let { browser } = yield loadTab(TEST_URI);
let hud = yield openConsole();
hud.jsterm.clearOutput();
let loaded = loadBrowser(browser);
BrowserTestUtils.loadURI(browser, TEST_VIOLATION);
yield loaded;
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;
}
});
});

View file

@ -0,0 +1,60 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 clicking on a function displays its source in the debugger.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-bug_1050691_click_function_to_source.html";
// Force the old debugger UI since it's directly used (see Bug 1301705)
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", false);
registerCleanupFunction(function* () {
Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend");
});
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
// Open the Debugger panel.
let debuggerPanel = yield openDebugger();
// And right after come back to the Console panel.
yield openConsole();
yield testWithDebuggerOpen(hud, debuggerPanel);
});
function* testWithDebuggerOpen(hud, debuggerPanel) {
let clickable = yield printFunction(hud);
let panelWin = debuggerPanel.panelWin;
let onEditorLocationSet = panelWin.once(panelWin.EVENTS.EDITOR_LOCATION_SET);
synthesizeClick(clickable, hud);
yield onEditorLocationSet;
ok(isDebuggerCaretPos(debuggerPanel, 7),
"Clicking on a function should go to its source in the debugger view");
}
function synthesizeClick(clickable, hud) {
EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow);
}
var printFunction = Task.async(function* (hud) {
hud.jsterm.clearOutput();
ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
content.wrappedJSObject.foo();
});
let [result] = yield waitForMessages({
webconsole: hud,
messages: [{
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
}],
});
let msg = [...result.matched][0];
let clickable = msg.querySelector("a");
ok(clickable, "clickable item for object should exist");
return clickable;
});

View file

@ -0,0 +1,40 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 the Web Console CSP messages for two META policies
// are correctly displayed.
"use strict";
const TEST_URI = "data:text/html;charset=utf8,Web Console CSP violation test";
const TEST_VIOLATION = "https://example.com/browser/devtools/client/" +
"webconsole/test/test_bug_1247459_violation.html";
const CSP_VIOLATION_MSG = "Content Security Policy: The page\u2019s settings " +
"blocked the loading of a resource at " +
"http://some.example.com/test.png (\u201cimg-src " +
"https://example.com\u201d).";
add_task(function* () {
let { browser } = yield loadTab(TEST_URI);
let hud = yield openConsole();
hud.jsterm.clearOutput();
let loaded = loadBrowser(browser);
BrowserTestUtils.loadURI(browser, TEST_VIOLATION);
yield loaded;
yield waitForMessages({
webconsole: hud,
messages: [
{
name: "CSP policy URI warning displayed successfully",
text: CSP_VIOLATION_MSG,
repeats: 2
}
]
});
});

View file

@ -0,0 +1,41 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 the console object still exists after a page reload.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-console.html";
var 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();
}

View file

@ -0,0 +1,20 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 the input field is focused when the console is opened.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-console.html";
add_task(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");
});

View file

@ -0,0 +1,47 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 to ensure that errors don't appear when the console is closed while a
// completion is being performed.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-console.html";
add_task(function* () {
let { browser } = yield loadTab(TEST_URI);
let hud = yield openConsole();
yield testClosingAfterCompletion(hud, browser);
});
function testClosingAfterCompletion(hud, browser) {
let deferred = promise.defer();
let errorWhileClosing = false;
function errorListener() {
errorWhileClosing = true;
}
browser.addEventListener("error", errorListener, false);
// Focus the jsterm and perform the keycombo to close the WebConsole.
hud.jsterm.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;
}

View file

@ -0,0 +1,50 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 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
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/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");
// On e10s, the exception is triggered in child process
// and is ignored by test harness
if (!Services.appinfo.browserTabsRemoteAutostart) {
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);
}

View file

@ -0,0 +1,26 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 appropriately-localized timestamps are printed.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-console.html";
add_task(function* () {
yield loadTab(TEST_URI);
const TEST_TIMESTAMP = 12345678;
let date = new Date(TEST_TIMESTAMP);
let localizedString = WCUL10n.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");
});

View file

@ -0,0 +1,49 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 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/devtools/client/webconsole/" +
"test/test-duplicate-error.html";
add_task(function* () {
yield loadTab(INIT_URI);
let hud = yield openConsole();
// On e10s, the exception is triggered in child process
// and is ignored by test harness
if (!Services.appinfo.browserTabsRemoteAutostart) {
expectUncaughtException();
}
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, 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");
}
});

View file

@ -0,0 +1,35 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/browser/test-console.html";
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
testCompletion(hud);
});
function testCompletion(hud) {
let jsterm = hud.jsterm;
let 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");
}

View file

@ -0,0 +1,89 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 the Web Console limits the number of lines displayed according to
// the user's preferences.
"use strict";
const TEST_URI = "data:text/html;charset=utf8,test for bug 585237";
var outputNode;
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
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++) {
yield ContentTask.spawn(gBrowser.selectedBrowser, i, function (i) {
// must change message to prevent repeats
content.console.log("foo #" + i);
});
}
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");
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function () {
content.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++) {
yield ContentTask.spawn(gBrowser.selectedBrowser, i, function (i) {
// must change message to prevent repeats
content.console.log("boo #" + i);
});
}
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;
}

View file

@ -0,0 +1,70 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "http://example.com/browser/devtools/client/" +
"webconsole/test/test-bug-585956-console-trace.html";
add_task(function* () {
let {tab} = yield loadTab("data:text/html;charset=utf8,<p>hello");
let hud = yield openConsole(tab);
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, 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: 3,
filename: TEST_URI,
functionName: "window.foobar585956c",
language: 2,
lineNumber: 9
},
{
columnNumber: 10,
filename: TEST_URI,
functionName: "foobar585956b",
language: 2,
lineNumber: 14
},
{
columnNumber: 10,
filename: TEST_URI,
functionName: "foobar585956a",
language: 2,
lineNumber: 18
},
{
columnNumber: 1,
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");
});

View file

@ -0,0 +1,367 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "data:text/html;charset=utf-8,<p>bug 585991 - autocomplete " +
"popup keyboard usage test";
// We should turn off auto-multiline editing during these tests
const PREF_AUTO_MULTILINE = "devtools.webconsole.autoMultiline";
var HUD, popup, jsterm, inputNode, completeNode;
add_task(function* () {
Services.prefs.setBoolPref(PREF_AUTO_MULTILINE, false);
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;
Services.prefs.setBoolPref(PREF_AUTO_MULTILINE, true);
});
var consoleOpened = Task.async(function* (hud) {
let deferred = promise.defer();
HUD = hud;
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.once("popup-opened", () => {
ok(popup.isOpen, "popup is open");
// 4 values, and the following properties:
// __defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__
// __proto__ hasOwnProperty isPrototypeOf propertyIsEnumerable
// toLocaleString toString toSource unwatch valueOf watch constructor.
is(popup.itemCount, 19, "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__",
"__proto__",
"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, 18,
"Index of the first item from bottom is selected.");
EventUtils.synthesizeKey("VK_DOWN", {});
let prefix = jsterm.getInputValue().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, 18, "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.once("popup-closed", () => {
deferred.resolve();
});
EventUtils.synthesizeKey("VK_TAB", {});
});
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(jsterm.getInputValue(), "window.foobarBug585991.watch",
"completion was successful after VK_TAB");
ok(!completeNode.value, "completeNode is empty");
popup.once("popup-opened", function onShown() {
ok(popup.isOpen, "popup is open");
is(popup.itemCount, 19, "popup.itemCount is correct");
is(popup.selectedIndex, 18, "First index from bottom is selected");
EventUtils.synthesizeKey("VK_DOWN", {});
let prefix = jsterm.getInputValue().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.once("popup-closed", function onHidden() {
ok(!popup.isOpen, "popup is not open after VK_ESCAPE");
is(jsterm.getInputValue(), "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.once("popup-opened", function onShown() {
ok(popup.isOpen, "popup is open");
is(popup.itemCount, 19, "popup.itemCount is correct");
is(popup.selectedIndex, 18, "First index from bottom is selected");
EventUtils.synthesizeKey("VK_DOWN", {});
let prefix = jsterm.getInputValue().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.once("popup-closed", function onHidden() {
ok(!popup.isOpen, "popup is not open after VK_RETURN");
is(jsterm.getInputValue(), "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");
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
content.wrappedJSObject.foobarBug585991 = ["Sherlock Holmes"];
});
jsterm = HUD.jsterm;
popup = jsterm.autocompletePopup;
popup.once("popup-opened", function onShown() {
let sameItems = popup.getItems().map(function (e) {
return e.label;
});
ok(!sameItems.some(function (prop) {
prop === "0";
}), "Completing on an array doesn't show numbers.");
popup.once("popup-closed", function popupHidden() {
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.once("popup-opened", function 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.once("popup-closed", function 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(jsterm.getInputValue(), "", "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.once("popup-opened", function 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.once("popup-closed", function 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(jsterm.getInputValue(), "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();
}

View file

@ -0,0 +1,123 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "data:text/html;charset=utf-8,<p>bug 585991 - autocomplete " +
"popup test";
add_task(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 = HUD.jsterm.inputNode;
ok(!popup.isOpen, "popup is not open");
ok(!input.hasAttribute("aria-activedescendant"), "no aria-activedescendant");
popup.once("popup-opened", () => {
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 (item, index) {
return item === items[index];
}), 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");
checkActiveDescendant(popup, input);
popup.selectedIndex = 1;
is(popup.selectedIndex, 1, "index 1 is selected");
is(popup.selectedItem, items[1], "item1 is selected");
checkActiveDescendant(popup, input);
popup.selectedItem = items[2];
is(popup.selectedIndex, 2, "index 2 is selected");
is(popup.selectedItem, items[2], "item2 is selected");
checkActiveDescendant(popup, input);
is(popup.selectPreviousItem(), items[1], "selectPreviousItem() works");
is(popup.selectedIndex, 1, "index 1 is selected");
is(popup.selectedItem, items[1], "item1 is selected");
checkActiveDescendant(popup, input);
is(popup.selectNextItem(), items[2], "selectNextItem() works");
is(popup.selectedIndex, 2, "index 2 is selected");
is(popup.selectedItem, items[2], "item2 is selected");
checkActiveDescendant(popup, input);
ok(popup.selectNextItem(), "selectNextItem() works");
is(popup.selectedIndex, 0, "index 0 is selected");
is(popup.selectedItem, items[0], "item0 is selected");
checkActiveDescendant(popup, input);
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");
checkActiveDescendant(popup, input);
popup.removeItem(items[2]);
is(popup.selectedIndex, 2, "index2 is selected");
is(popup.selectedItem, items[3], "item3 is still selected");
checkActiveDescendant(popup, input);
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.once("popup-closed", () => {
deferred.resolve();
});
popup.hidePopup();
});
popup.openPopup(input);
return deferred.promise;
}
function checkActiveDescendant(popup, input) {
let activeElement = input.ownerDocument.activeElement;
let descendantId = activeElement.getAttribute("aria-activedescendant");
let popupItem = popup._tooltip.panel.querySelector("#" + descendantId);
let cloneItem = input.ownerDocument.querySelector("#" + descendantId);
ok(popupItem, "Active descendant is found in the popup list");
ok(cloneItem, "Active descendant is found in the list clone");
is(popupItem.innerHTML, cloneItem.innerHTML,
"Cloned item has the same HTML as the original element");
}

View file

@ -0,0 +1,84 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "http://example.com/";
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
yield testSelectionWhenMovingBetweenBoxes(hud);
performTestsAfterOutput(hud);
});
var testSelectionWhenMovingBetweenBoxes = Task.async(function* (hud) {
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(hud) {
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 = hud.ui.outputWrapper.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();
}

View file

@ -0,0 +1,106 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/ */
/* globals goUpdateCommand goDoCommand */
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-console.html";
var HUD, outputNode;
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
yield consoleOpened(hud);
yield testContextMenuCopy();
HUD = outputNode = null;
});
function consoleOpened(hud) {
HUD = hud;
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");
ContentTask.spawn(gBrowser.selectedBrowser, null,
"() => 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 and whitespace since getSelection() includes
// a new line 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) => {
// Strip out spaces for comparison ease
return selection.trim() == str.trim().replace(/ /g, "");
}, () => {
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 = HUD.ui.outputWrapper.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 and whitespace since getSelection() includes
// a new line 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) => {
// Strip out spaces for comparison ease
return selection.trim() == str.trim().replace(/ /g, "");
}, () => {
goDoCommand("cmd_copy");
}, deferred.resolve, deferred.resolve);
HUD = outputNode = null;
return deferred.promise;
}

View file

@ -0,0 +1,36 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 588342";
add_task(function* () {
let { browser } = yield loadTab(TEST_URI);
let hud = yield openConsole();
yield checkConsoleFocus(hud);
let isFocused = yield ContentTask.spawn(browser, { }, function* () {
var fm = Components.classes["@mozilla.org/focus-manager;1"].
getService(Components.interfaces.nsIFocusManager);
return fm.focusedWindow == content;
});
ok(isFocused, "content document has focus");
});
function* checkConsoleFocus(hud) {
let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
yield new Promise(resolve => {
waitForFocus(resolve);
});
is(hud.jsterm.inputNode.getAttribute("focused"), "true",
"jsterm input is focused on web console open");
is(fm.focusedWindow, hud.iframeWindow, "hud window is focused");
yield closeConsole(null);
}

View file

@ -0,0 +1,53 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 adding text to one of the output labels doesn't cause errors.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-console.html";
add_task(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;
}

View file

@ -0,0 +1,44 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-console.html";
add_task(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;
}

View file

@ -0,0 +1,39 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
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
*/
add_task(function* () {
let {tab} = yield loadTab(TEST_URI);
let hud = yield openConsole(tab);
// CSS warnings are disabled by default.
hud.setFilterState("cssparser", true);
hud.jsterm.clearOutput();
BrowserReload();
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);
});

View file

@ -0,0 +1,29 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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, 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";
add_task(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");
});

View file

@ -0,0 +1,68 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-bug-593003-iframe-wrong-hud.html";
const TEST_IFRAME_URI = "http://example.com/browser/devtools/client/" +
"webconsole/test/test-bug-593003-iframe-wrong-" +
"hud-iframe.html";
const TEST_DUMMY_URI = "http://example.com/browser/devtools/client/" +
"webconsole/test/test-console.html";
add_task(function* () {
let tab1 = (yield loadTab(TEST_URI)).tab;
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
content.console.log("FOO");
});
yield openConsole();
let tab2 = (yield loadTab(TEST_DUMMY_URI)).tab;
yield openConsole(gBrowser.selectedTab);
info("Reloading tab 1");
yield reloadTab(tab1);
info("Checking for messages");
yield checkMessages(tab1, tab2);
info("Cleaning up");
yield closeConsole(tab1);
yield closeConsole(tab2);
});
function* reloadTab(tab) {
let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
tab.linkedBrowser.reload();
yield loaded;
}
function* checkMessages(tab1, tab2) {
let hud1 = yield openConsole(tab1);
let outputNode1 = hud1.outputNode;
info("Waiting for messages");
yield waitForMessages({
webconsole: hud1,
messages: [{
text: TEST_IFRAME_URI,
category: CATEGORY_NETWORK,
severity: SEVERITY_LOG,
}]
});
let hud2 = yield openConsole(tab2);
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);
}

View file

@ -0,0 +1,155 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
var jsterm, inputNode, values;
var TEST_URI = "data:text/html;charset=utf-8,Web Console test for " +
"bug 594497 and bug 619598";
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
setup(hud);
performTests();
jsterm = inputNode = values = null;
});
function setup(HUD) {
jsterm = HUD.jsterm;
inputNode = jsterm.inputNode;
jsterm.focus();
ok(!jsterm.getInputValue(), "jsterm.getInputValue() 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++) {
jsterm.setInputValue(values[i]);
jsterm.execute();
}
}
function performTests() {
EventUtils.synthesizeKey("VK_UP", {});
is(jsterm.getInputValue(), values[4],
"VK_UP: jsterm.getInputValue() #4 is correct");
ok(inputNode.selectionStart == values[4].length &&
inputNode.selectionStart == inputNode.selectionEnd,
"caret location is correct");
EventUtils.synthesizeKey("VK_UP", {});
is(jsterm.getInputValue(), values[3],
"VK_UP: jsterm.getInputValue() #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(jsterm.getInputValue(), values[3],
"VK_UP two times: jsterm.getInputValue() #3 is correct");
ok(inputNode.selectionStart == jsterm.getInputValue().indexOf("\n") &&
inputNode.selectionStart == inputNode.selectionEnd,
"caret location is correct");
EventUtils.synthesizeKey("VK_UP", {});
is(jsterm.getInputValue(), values[3],
"VK_UP again: jsterm.getInputValue() #3 is correct");
ok(inputNode.selectionStart == 0 &&
inputNode.selectionStart == inputNode.selectionEnd,
"caret location is correct");
EventUtils.synthesizeKey("VK_UP", {});
is(jsterm.getInputValue(), values[2],
"VK_UP: jsterm.getInputValue() #2 is correct");
EventUtils.synthesizeKey("VK_UP", {});
is(jsterm.getInputValue(), values[1],
"VK_UP: jsterm.getInputValue() #1 is correct");
EventUtils.synthesizeKey("VK_UP", {});
is(jsterm.getInputValue(), values[0],
"VK_UP: jsterm.getInputValue() #0 is correct");
ok(inputNode.selectionStart == values[0].length &&
inputNode.selectionStart == inputNode.selectionEnd,
"caret location is correct");
EventUtils.synthesizeKey("VK_DOWN", {});
is(jsterm.getInputValue(), values[1],
"VK_DOWN: jsterm.getInputValue() #1 is correct");
ok(inputNode.selectionStart == values[1].length &&
inputNode.selectionStart == inputNode.selectionEnd,
"caret location is correct");
EventUtils.synthesizeKey("VK_DOWN", {});
is(jsterm.getInputValue(), values[2],
"VK_DOWN: jsterm.getInputValue() #2 is correct");
EventUtils.synthesizeKey("VK_DOWN", {});
is(jsterm.getInputValue(), values[3],
"VK_DOWN: jsterm.getInputValue() #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(jsterm.getInputValue(), values[3],
"VK_DOWN two times: jsterm.getInputValue() #3 is correct");
ok(inputNode.selectionStart > jsterm.getInputValue().lastIndexOf("\n") &&
inputNode.selectionStart == inputNode.selectionEnd,
"caret location is correct");
EventUtils.synthesizeKey("VK_DOWN", {});
is(jsterm.getInputValue(), values[3],
"VK_DOWN again: jsterm.getInputValue() #3 is correct");
ok(inputNode.selectionStart == values[3].length &&
inputNode.selectionStart == inputNode.selectionEnd,
"caret location is correct");
EventUtils.synthesizeKey("VK_DOWN", {});
is(jsterm.getInputValue(), values[4],
"VK_DOWN: jsterm.getInputValue() #4 is correct");
EventUtils.synthesizeKey("VK_DOWN", {});
ok(!jsterm.getInputValue(),
"VK_DOWN: jsterm.getInputValue() is empty");
}

View file

@ -0,0 +1,64 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const PREF = "devtools.webconsole.persistlog";
const TEST_FILE = "test-network.html";
const TEST_URI = "data:text/html;charset=utf8,<p>test file URI";
var hud;
add_task(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);
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, 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,
}],
});
}

View file

@ -0,0 +1,100 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 the Web Console doesn't leak when multiple tabs and windows are
// opened and then closed.
"use strict";
const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 595350";
var win1 = window, win2;
var openTabs = [];
var 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() {
function open(i) {
let tab = openTabs[i];
openConsole(tab).then(function (hud) {
ok(hud, "HUD is open for tab " + i);
let window = hud.target.tab.linkedBrowser.contentWindow;
window.console.log("message for tab " + i);
if (i >= openTabs.length - 1) {
// Use executeSoon() to allow the promise to resolve.
executeSoon(closeConsoles);
}
else {
executeSoon(() => open(i + 1));
}
});
}
// open the Web Console for each of the four tabs and log a message.
open(0);
}
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;
}

View file

@ -0,0 +1,211 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
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/devtools/client/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",
},
{
// #4
file: "test-bug-595934-malformedxml.xhtml",
category: "malformed-xml",
matchString: "no root 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",
},
];
var pos = -1;
var foundCategory = false;
var foundText = false;
var pageLoaded = false;
var pageError = false;
var output = null;
var jsterm = null;
var hud = null;
var testEnded = false;
var TestObserver = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
observe: function testObserve(subject) {
if (testEnded || !(subject instanceof Ci.nsIScriptError)) {
return;
}
let expectedCategory = TESTS[pos].category;
info("test #" + pos + " console observer got " + subject.category +
", is expecting " + expectedCategory);
if (subject.category == expectedCategory) {
foundCategory = true;
startNextTest();
} else {
info("unexpected message was: " + subject.sourceName + ":" +
subject.lineNumber + "; " + subject.errorMessage);
}
}
};
function consoleOpened(hudConsole) {
hud = hudConsole;
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) {
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(evt) {
if (content.location.href != testLocation) {
return;
}
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
pageLoaded = true;
test.onload && test.onload(evt);
if (test.expectError) {
content.addEventListener("error", function _onError() {
content.removeEventListener("error", _onError);
pageError = true;
startNextTest();
});
// On e10s, the exception is triggered in child process
// and is ignored by test harness
if (!Services.appinfo.browserTabsRemoteAutostart) {
expectUncaughtException();
}
} else {
pageError = true;
}
startNextTest();
}, true);
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, 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);
});
}

View file

@ -0,0 +1,97 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-console.html";
var tab1, tab2, win1, win2;
var 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();
});
}
openConsoles();
}
function test() {
loadTab(TEST_URI).then(() => {
tab1 = gBrowser.selectedTab;
win1 = window;
tab1Loaded();
});
}

View file

@ -0,0 +1,33 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "http://example.com/browser/devtools/client/" +
"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);
// On e10s, the exception is triggered in child process
// and is ignored by test harness
if (!Services.appinfo.browserTabsRemoteAutostart) {
expectUncaughtException();
}
BrowserTestUtils.synthesizeMouseAtCenter("button", {}, gBrowser.selectedBrowser);
yield waitForMessages({
webconsole: hud,
messages: [{
text: "bogus is not defined",
category: CATEGORY_JS,
severity: SEVERITY_ERROR,
}],
});
}).then(finishTest);
}

View file

@ -0,0 +1,52 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 network requests from chrome don't cause the Web Console to
// throw exceptions.
"use strict";
const TEST_URI = "http://example.com/";
var good = true;
var listener = {
QueryInterface: XPCOMUtils.generateQI([ Ci.nsIObserver ]),
observe: function (subject) {
if (subject instanceof Ci.nsIScriptError &&
subject.category === "XPConnect JavaScript" &&
subject.sourceName.includes("webconsole")) {
good = false;
}
}
};
var xhr;
function test() {
Services.console.registerListener(listener);
// trigger a lazy-load of the HUD Service
HUDService;
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();
}

View file

@ -0,0 +1,80 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-network.html";
const PREF = "devtools.webconsole.persistlog";
add_task(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.ui.outputWrapper;
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);
}

View file

@ -0,0 +1,70 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-bug-597756-reopen-closed-tab.html";
var HUD;
add_task(function* () {
// On e10s, the exception is triggered in child process
// and is ignored by test harness
if (!Services.appinfo.browserTabsRemoteAutostart) {
expectUncaughtException();
}
let { browser } = yield loadTab(TEST_URI);
HUD = yield openConsole();
if (!Services.appinfo.browserTabsRemoteAutostart) {
expectUncaughtException();
}
yield reload(browser);
yield testMessages();
yield closeConsole();
// Close and reopen
gBrowser.removeCurrentTab();
if (!Services.appinfo.browserTabsRemoteAutostart) {
expectUncaughtException();
}
let tab = yield loadTab(TEST_URI);
HUD = yield openConsole();
if (!Services.appinfo.browserTabsRemoteAutostart) {
expectUncaughtException();
}
yield reload(tab.browser);
yield testMessages();
HUD = null;
});
function reload(browser) {
let loaded = loadBrowser(browser);
browser.reload();
return loaded;
}
function testMessages() {
return waitForMessages({
webconsole: HUD,
messages: [{
name: "error message displayed",
text: "fooBug597756_error",
category: CATEGORY_JS,
severity: SEVERITY_ERROR,
}],
});
}

View file

@ -0,0 +1,67 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const INIT_URI = "data:text/plain;charset=utf8,hello world";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-bug-599725-response-headers.sjs";
function performTest(request, hud) {
let deferred = promise.defer();
let headers = null;
function readHeader(name) {
for (let header of headers) {
if (header.name == name) {
return header.value;
}
}
return null;
}
hud.ui.proxy.webConsoleClient.getResponseHeaders(request.actor,
function (response) {
headers = response.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");
executeSoon(deferred.resolve);
});
return deferred.promise;
}
let waitForRequest = Task.async(function*(hud) {
let request = yield waitForFinishedRequest(req=> {
return req.response.status === "304";
});
yield performTest(request, hud);
});
add_task(function* () {
let { browser } = yield loadTab(INIT_URI);
let hud = yield openConsole();
let gotLastRequest = waitForRequest(hud);
let loaded = loadBrowser(browser);
BrowserTestUtils.loadURI(browser, TEST_URI);
yield loaded;
let reloaded = loadBrowser(browser);
ContentTask.spawn(browser, null, "() => content.location.reload()");
yield reloaded;
yield gotLastRequest;
});

View file

@ -0,0 +1,59 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const INIT_URI = "data:text/html;charset=utf-8,Web Console - bug 600183 test";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-bug-600183-charset.html";
function performTest(lastFinishedRequest, console) {
let deferred = promise.defer();
ok(lastFinishedRequest, "charset test page was loaded and logged");
HUDService.lastFinishedRequest.callback = null;
executeSoon(() => {
console.webConsoleClient.getResponseContent(lastFinishedRequest.actor,
(response) => {
ok(!response.contentDiscarded, "response body was not discarded");
let body = response.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;
}
add_task(function* () {
let { browser } = yield loadTab(INIT_URI);
yield openConsole();
let gotLastRequest = waitForRequest();
let loaded = loadBrowser(browser);
BrowserTestUtils.loadURI(browser, TEST_URI);
yield loaded;
yield gotLastRequest;
});

View file

@ -0,0 +1,76 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "data:text/html;charset=utf-8,Web Console test for " +
"bug 601177: log levels";
const TEST_URI2 = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-bug-601177-log-levels.html";
add_task(function* () {
Services.prefs.setBoolPref("javascript.options.strict", true);
yield loadTab(TEST_URI);
let hud = yield openConsole();
// On e10s, the exception is triggered in child process
// and is ignored by test harness
if (!Services.appinfo.browserTabsRemoteAutostart) {
expectUncaughtException();
}
yield testLogLevels(hud);
Services.prefs.clearUserPref("javascript.options.strict");
});
function testLogLevels(hud) {
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, 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,
},
],
});
}

View file

@ -0,0 +1,84 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 the console output scrolls to JS eval results when there are many
// messages displayed. See bug 601352.
"use strict";
add_task(function* () {
let {tab} = yield loadTab("data:text/html;charset=utf-8,Web Console test " +
"for bug 601352");
let hud = yield openConsole(tab);
hud.jsterm.clearOutput();
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
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.ui.outputWrapper;
let rectNode = node.getBoundingClientRect();
let rectOutput = scrollNode.getBoundingClientRect();
yield ContentTask.spawn(gBrowser.selectedBrowser, {
rectNode,
rectOutput,
scrollHeight: scrollNode.scrollHeight,
scrollTop: scrollNode.scrollTop,
clientHeight: scrollNode.clientHeight,
}, function* (args) {
console.debug("rectNode", args.rectNode, "rectOutput", args.rectOutput);
console.log("scrollNode scrollHeight", args.scrollHeight,
"scrollTop", args.scrollTop, "clientHeight",
args.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");
});

View file

@ -0,0 +1,267 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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 the filter button UI logic works correctly.
"use strict";
const TEST_URI = "http://example.com/";
const FILTER_PREF_DOMAIN = "devtools.webconsole.filter.";
var hud, hudId, hudBox;
var prefs = {};
add_task(function* () {
yield loadTab(TEST_URI);
hud = yield openConsole();
hudId = hud.hudId;
hudBox = hud.ui.rootElement;
savePrefs();
testFilterButtons();
restorePrefs();
hud = hudId = hudBox = null;
});
function savePrefs() {
let branch = Services.prefs.getBranch(FILTER_PREF_DOMAIN);
let children = branch.getChildList("");
for (let child of children) {
prefs[child] = branch.getBoolPref(child);
}
}
function restorePrefs() {
let branch = Services.prefs.getBranch(FILTER_PREF_DOMAIN);
for (let p in prefs) {
branch.setBoolPref(p, prefs[p]);
}
}
function testFilterButtons() {
testMenuFilterButton("net");
testMenuFilterButton("css");
testMenuFilterButton("js");
testMenuFilterButton("logging");
testMenuFilterButton("security");
testMenuFilterButton("server");
testIsolateFilterButton("net");
testIsolateFilterButton("css");
testIsolateFilterButton("js");
testIsolateFilterButton("logging");
testIsolateFilterButton("security");
testIsolateFilterButton("server");
}
function testMenuFilterButton(category) {
let selector = ".webconsole-filter-button[category=\"" + category + "\"]";
let button = hudBox.querySelector(selector);
ok(button, "we have the \"" + category + "\" button");
let firstMenuItem = button.querySelector("menuitem");
ok(firstMenuItem, "we have the first menu item for the \"" + category +
"\" 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 " +
category + " 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 " + category + " 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 " +
category + " 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 " + category + " 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 " + category);
clickButton(subbutton);
ok(!isChecked(button), "the button for category " + category + " is " +
"no longer checked after clicking its main part");
menuItem = firstMenuItem;
while (menuItem) {
prefKey = menuItem.getAttribute("prefKey");
if (prefKey) {
ok(!isChecked(menuItem), "menu item " + prefKey + " for category " +
category + " 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 " + category + " is " +
"checked after clicking its main part");
menuItem = firstMenuItem;
while (menuItem) {
if (menuItem.hasAttribute("prefKey")) {
prefKey = menuItem.getAttribute("prefKey");
// The CSS/Log menu item should not be checked. See bug 971798.
if (category == "css" && prefKey == "csslog") {
ok(!isChecked(menuItem), "menu item " + prefKey + " for category " +
category + " 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 " +
category + " 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 " + category + " is " +
"unchecked after unchecking all its filters");
// Turn all the filters on again by clicking the button.
clickButton(subbutton);
}
function testIsolateFilterButton(category) {
let selector = ".webconsole-filter-button[category=\"" + category + "\"]";
let targetButton = hudBox.querySelector(selector);
ok(targetButton, "we have the \"" + category + "\" button");
// Get the main part of the filter button.
let subbutton = getMainButton(targetButton);
ok(subbutton, "we have the subbutton for category " + category);
// Turn on all the filters by alt clicking the main part of the button.
altClickButton(subbutton);
ok(isChecked(targetButton), "the button for category " + category +
" 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 (category == "css" && prefKey == "csslog") {
ok(!isChecked(item), "menu item " + prefKey + " for category " +
category + " should not be checked after isolating for " + category);
ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages should be " +
"turned off after isolating for " + category);
} else if (prefKey) {
ok(isChecked(item), "menu item " + prefKey + " for category " +
category + " is checked after isolating for " + category);
ok(hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
"turned on after isolating for " + category);
}
});
// 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 categoryBtn = filterButton.getAttribute("category");
ok(!isChecked(filterButton), "the button for category " +
categoryBtn + " is unchecked after isolating for " + category);
menuItems = filterButton.querySelectorAll("menuitem");
Array.forEach(menuItems, (item) => {
let prefKey = item.getAttribute("prefKey");
if (prefKey) {
ok(!isChecked(item), "menu item " + prefKey + " for category " +
category + " is unchecked after isolating for " + category);
ok(!hud.ui.filterPrefs[prefKey], prefKey + " messages are " +
"turned off after isolating for " + category);
}
});
// 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(targetButton) {
let anonymousNodes = hud.ui.document.getAnonymousNodes(targetButton);
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(node) {
EventUtils.sendMouseEvent({ type: "click" }, node);
}
function altClickButton(node) {
EventUtils.sendMouseEvent({ type: "click", altKey: true }, node);
}
function chooseMenuItem(node) {
let event = document.createEvent("XULCommandEvent");
event.initCommandEvent("command", true, true, window, 0, false, false, false,
false, null);
node.dispatchEvent(event);
}
function isChecked(node) {
return node.getAttribute("checked") === "true";
}

View file

@ -0,0 +1,37 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
const TEST_URI = "http://example.com/browser/devtools/client/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";
add_task(function* () {
yield loadTab(TEST_URI2);
let hud = yield openConsole();
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, 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,
},
]
});
});

Some files were not shown because too many files have changed in this diff Show more