breadcrumbs:
Note: This page is out of date. If you are using modern practices, you are using a BrowserProxy for your JS/C++ interactions. The BrowserProxy document covers some testing practices for that case.
[TOC]
### Problem
See Also domui-testing.
WebUI contains Javascript, which runs in the renderer and a C++ handler, which runs in the UI thread of the browser process. While this is a necessary part of the design, testing across these boundaries of both language and process/thread is cumbersome at best.
### Objective
Make it possible to test the Javascript portion of WebUI in Javascript:
### Solution
The solution comes in the following parts:
chrome/test/data/webui/test_api.js
, chrome/third_party/mock4js/mock4js.js
.chrome/browser/ui/webui/web_ui_browsertest*
.### How to write a test
The best reference examples are chrome/test/data/webui/print_preview.js and chrome/browser/ui/webui/options/options_browsertest.js
#### [maybe] create a new test file
chrome/test/data/webui/
mytest
.js
chrome/test/data/webui/
mytest
.js
to the sources for browser_tests in chrome/chrome_tests.gypi
#### Write a test fixture, defining the page to browse to:
none /** * TestFixture for OptionsPage WebUI testing. * @extends {testing.Test} * @constructor **/ function OptionsWebUITest() {} OptionsWebUITest.prototype = { __proto__: testing.Test.prototype, /** * Browse to the options page & call our preLoad(). **/ browsePreload: 'chrome://settings-frame', // ... };
none OptionsWebUITest.prototype = { ... /** * Register a mock handler to ensure expectations are met and options pages * behave correctly. **/ preLoad: function() { this.makeAndRegisterMockHandler( ['defaultZoomFactorAction', 'fetchPrefs', 'observePrefs', 'setBooleanPref', 'setIntegerPref', 'setDoublePref', 'setStringPref', 'setObjectPref', 'clearPref', 'coreOptionsUserMetricsAction', ]); // Register stubs for methods expected to be called before/during tests. // Specific expectations can be made in the tests themselves. this.mockHandler.stubs().fetchPrefs(ANYTHING); this.mockHandler.stubs().observePrefs(ANYTHING); this.mockHandler.stubs().coreOptionsUserMetricsAction(ANYTHING); }, ... };
none mockHandler.stubs().getDefaultPrinter(). will(callFunction(function() { setDefaultPrinter('FooDevice'); }));
none TEST_F('OptionsWebUITest', 'testSetBooleanPrefTriggers', function() { var showHomeButton = $('toolbarShowHomeButton'); var trueListValue = [ 'browser.show_home_button', true, 'Options_Homepage_HomeButton', ]; // Note: this expectation is checked in testing::Test::TearDown. this.mockHandler.expects(once()).setBooleanPref(trueListValue); // Cause the handler to be called. showHomeButton.click(); showHomeButton.blur(); });
#### See Handling a failing test for more details on style and how/when to disable a test.
none // Not meant to run on ChromeOS at this time. // Not finishing in windows. http://crbug.com/81723 GEN('#if defined(OS_CHROMEOS) || defined(OS_MACOSX) || defined(OS_WIN) \\'); GEN(' || defined(TOUCH_UI)'); GEN('#define MAYBE_testRefreshStaysOnCurrentPage \\'); GEN(' DISABLED_testRefreshStaysOnCurrentPage'); GEN('#else'); GEN('#define MAYBE_testRefreshStaysOnCurrentPage ' + 'testRefreshStaysOnCurrentPage'); GEN('#endif'); TEST_F('OptionsWebUITest', 'MAYBE_testRefreshStaysOnCurrentPage', function() { var item = $('advancedPageNav'); item.onclick(); window.location.reload(); var pageInstance = AdvancedOptions.getInstance(); var topPage = OptionsPage.getTopmostVisiblePage(); var expectedTitle = pageInstance.title; var actualTitle = document.title; expectEquals("chrome://settings/advanced", document.location.href); expectEquals(expectedTitle, actualTitle); expectEquals(pageInstance, topPage); });
### Maintaining
chrome/test/ui/webui/javascript2webui.js
and tests in chrome/test/data/webui/
.chrome/test/data/webui/
& mark FLAKY_
, DISABLED_
or use the MAYBE_
trick shown above to conditionally decide.### Considerations/FAQs
### Caveats
MAYBE_
to ifdef will have a different run name from GTEST than from test_api.js
- this is because MAYBE_xyz
will be defined as either xyz
or DISABLED_xyz
in C++, but not changed in javascript.### Best practices
message
parameter should only include information not available:none // NO TEST_F('FooTest', 'TestFoo', function() { expectEquals(foo, bar, 'foo != bar'); expectEquals(foo, bar, foo + '!=' + bar); var i = ...; expectEquals(5, array[i], 'array[i] != 5'); }); // YES TEST_F('FooTest', 'TestFoo', function() { expectEquals(foo, bar); expectEquals(foo, bar); var i = ...; expectEquals(5, array[i], 'i=' + i); });