Move Webstore URL concepts to //extensions and out
[chromium-blink-merge.git] / chrome / test / data / webui / history_browsertest.js
blob267e5a3c0d16326d60ba291ae4dc54d2da03b765
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 GEN('#include "chrome/test/data/webui/history_ui_browsertest.h"');
7 /** @const */ var TOTAL_RESULT_COUNT = 160;
8 /** @const */ var WAIT_TIMEOUT = 200;
10 /**
11 * Test fixture for history WebUI testing.
12 * @constructor
13 * @extends {testing.Test}
15 function HistoryUIBrowserTest() {}
17 /**
18 * Create a fake history result with the given timestamp.
19 * @param {Number} timestamp Timestamp of the entry, in ms since the epoch.
20 * @param {String} url The URL to set on this entry.
21 * @return {Object} An object representing a history entry.
23 function createHistoryEntry(timestamp, url) {
24 var d = new Date(timestamp);
25 // Extract domain from url.
26 var domainMatch = url.replace(/^.+?:\/\//, '').match(/[^/]+/);
27 var domain = domainMatch ? domainMatch[0] : '';
28 return {
29 dateTimeOfDay: d.getHours() + ':' + d.getMinutes(),
30 dateRelativeDay: d.toDateString(),
31 allTimestamps: [timestamp],
32 starred: false,
33 time: timestamp,
34 title: d.toString(), // Use the stringified date as the title.
35 url: url,
36 domain: domain
40 /**
41 * Wait for the history backend to call the global function named
42 * |callbackName|, and then execute |afterFunction|. This allows tests to
43 * wait on asynchronous backend operations before proceeding.
45 function waitForCallback(callbackName, afterFunction) {
46 var originalCallback = window[callbackName];
48 // Install a wrapper that temporarily replaces the original function.
49 window[callbackName] = function() {
50 window[callbackName] = originalCallback;
51 originalCallback.apply(this, arguments);
52 afterFunction();
56 /**
57 * Asynchronously execute the global function named |functionName|. This
58 * should be used for all calls from backend stubs to the frontend.
60 function callFrontendAsync(functionName) {
61 var args = Array.prototype.slice.call(arguments, 1);
62 setTimeout(function() {
63 window[functionName].apply(window, args);
64 }, 1);
67 /**
68 * Checks that all the checkboxes in the [|start|, |end|] interval are checked
69 * and that their IDs are properly set. Does that against the checkboxes in
70 * |checked|, starting from the |startInChecked| position.
71 * @param {Array} checked An array of all the relevant checked checkboxes
72 * on this page.
73 * @param {Number} start The starting checkbox id.
74 * @param {Number} end The ending checkbox id.
76 function checkInterval(checked, start, end) {
77 for (var i = start; i <= end; i++)
78 expectEquals('checkbox-' + i, checked[i - start].id);
81 /**
82 * Returns a period of 7 days, |offset| weeks back from |today|. The behavior
83 * of this function should be identical to
84 * BrowsingHistoryHandler::SetQueryTimeInWeeks.
85 * @param {Number} offset Number of weeks to go back.
86 * @param {Date} today Which date to consider as "today" (since we're not using
87 * the actual current date in this case).
88 * @return {Object} An object containing the begin date and the end date of the
89 * computed period.
91 function setQueryTimeInWeeks(offset, today) {
92 // Going back one day at a time starting from midnight will make sure that
93 // the other values get updated properly.
94 var endTime = new Date(today);
95 endTime.setHours(24, 0, 0, 0);
96 for (var i = 0; i < 7 * offset; i++)
97 endTime.setDate(endTime.getDate() - 1);
98 var beginTime = new Date(endTime);
99 for (var i = 0; i < 7; i++)
100 beginTime.setDate(beginTime.getDate() - 1);
101 return {'endTime': endTime, 'beginTime': beginTime};
105 * Returns the period of a month, |offset| months back from |today|. The
106 * behavior of this function should be identical to
107 * BrowsingHistoryHandler::SetQueryTimeInMonths.
108 * @param {Number} offset Number of months to go back.
109 * @param {Date} today Which date to consider as "today" (since we're not using
110 * the actual current date in this case).
111 * @return {Object} An object containing the begin date and the end date of the
112 * computed period.
114 function setQueryTimeInMonths(offset, today) {
115 var endTime = new Date(today);
116 var beginTime = new Date(today);
117 // Last day of this month.
118 endTime.setMonth(endTime.getMonth() + 1, 0);
119 // First day of the current month.
120 beginTime.setMonth(beginTime.getMonth(), 1);
121 for (var i = 0; i < offset; i++) {
122 beginTime.setMonth(beginTime.getMonth() - 1);
123 endTime.setMonth(endTime.getMonth() - 1);
125 return {'endTime': endTime, 'beginTime': beginTime};
129 * Base fixture for History WebUI testing.
130 * @extends {testing.Test}
131 * @constructor
133 function BaseHistoryWebUITest() {}
135 BaseHistoryWebUITest.prototype = {
136 __proto__: testing.Test.prototype,
139 * Browse to the history page & call our preLoad().
141 browsePreload: 'chrome://history-frame',
143 /** @override */
144 typedefCppFixture: 'HistoryUIBrowserTest',
146 isAsync: true,
150 * Fixture for History WebUI testing which returns some fake history results
151 * to the frontend. Other fixtures that want to stub out calls to the backend
152 * can extend this one.
153 * @extends {BaseHistoryWebUITest}
154 * @constructor
156 function HistoryWebUIFakeBackendTest() {
159 HistoryWebUIFakeBackendTest.prototype = {
160 __proto__: BaseHistoryWebUITest.prototype,
163 * Register handlers to stub out calls to the history backend.
164 * @override
166 preLoad: function() {
167 this.registerMockHandler_(
168 'queryHistory', this.queryHistoryStub_.bind(this));
172 * Register a mock handler for a message to the history backend.
173 * @param handlerName The name of the message to mock.
174 * @param handler The mock message handler function.
176 registerMockHandler_: function(handlerName, handler) {
177 // Mock4JS doesn't pass in the actual arguments to the stub, but it _will_
178 // pass the original args to the matcher object. SaveMockArguments acts as
179 // a proxy for another matcher, but keeps track of all the arguments it was
180 // asked to match.
181 var savedArgs = new SaveMockArguments();
183 this.makeAndRegisterMockHandler([handlerName]);
184 this.mockHandler.stubs()[handlerName](savedArgs.match(ANYTHING)).will(
185 callFunctionWithSavedArgs(savedArgs, handler));
189 * Default stub for the queryHistory message to the history backend.
190 * Simulates an empty history database. Override this to customize this
191 * behavior for particular tests.
192 * @param {Array} arguments The original arguments to queryHistory.
194 queryHistoryStub_: function(args) {
195 callFrontendAsync(
196 'historyResult', { term: args[0], finished: true }, []);
200 function queryHistoryImpl(args, beginTime, history) {
201 var searchText = args[0];
202 var offset = args[1];
203 var range = args[2];
204 var endTime = args[3] || Number.MAX_VALUE;
205 var maxCount = args[4];
207 var results = [];
208 if (searchText) {
209 for (var k = 0; k < history.length; k++) {
210 // Search only by title in this stub.
211 if (history[k].title.indexOf(searchText) != -1)
212 results.push(history[k]);
214 } else {
215 results = history;
218 // Advance past all entries newer than the specified end time.
219 var i = 0;
220 // Finished is set from the history database so this behavior may not be
221 // completely identical.
222 var finished = true;
223 while (i < results.length && results[i].time >= endTime)
224 ++i;
226 if (beginTime) {
227 var j = i;
228 while (j < results.length && results[j].time >= beginTime)
229 ++j;
231 finished = (j == results.length);
232 results = results.slice(i, j);
233 } else {
234 results = results.slice(i);
237 if (maxCount) {
238 finished = (maxCount >= results.length);
239 results = results.slice(0, maxCount);
242 var queryStartTime = '';
243 var queryEndTime = '';
244 if (results.length) {
245 queryStartTime = results[results.length - 1].dateRelativeDay;
246 queryEndTime = results[0].dateRelativeDay;
247 } else if (beginTime) {
248 queryStartTime = Date(beginTime);
249 queryEndTime = Date(endTime);
252 callFrontendAsync(
253 'historyResult',
255 term: searchText,
256 finished: finished,
257 queryStartTime: queryStartTime,
258 queryEndTime: queryEndTime
260 results);
264 * Fixture for History WebUI testing which returns some fake history results
265 * to the frontend.
266 * @extends {HistoryWebUIFakeBackendTest}
267 * @constructor
269 function HistoryWebUITest() {}
271 HistoryWebUITest.prototype = {
272 __proto__: HistoryWebUIFakeBackendTest.prototype,
274 preLoad: function() {
275 HistoryWebUIFakeBackendTest.prototype.preLoad.call(this);
277 this.registerMockHandler_(
278 'removeVisits', this.removeVisitsStub_.bind(this));
280 // Prepare a list of fake history results. The entries will begin at
281 // 1:00 AM on Sept 2, 2008, and will be spaced two minutes apart.
282 var timestamp = new Date(2008, 9, 2, 1, 0).getTime();
283 this.fakeHistory_ = [];
285 for (var i = 0; i < TOTAL_RESULT_COUNT; i++) {
286 this.fakeHistory_.push(
287 createHistoryEntry(timestamp, 'http://google.com/' + timestamp));
288 timestamp -= 2 * 60 * 1000; // Next visit is two minutes earlier.
293 * Stub for the 'queryHistory' message to the history backend.
294 * Simulates a history database using the fake history data that is
295 * initialized in preLoad().
296 * @param {Array} arguments The original arguments to queryHistory.
298 queryHistoryStub_: function(args) {
299 var searchText = args[0];
300 var offset = args[1];
301 var range = args[2];
302 var endTime = args[3] || Number.MAX_VALUE;
303 var maxCount = args[4];
304 if (range == HistoryModel.Range.ALL_TIME) {
305 queryHistoryImpl(args, null, this.fakeHistory_);
306 return;
308 if (range == HistoryModel.Range.WEEK)
309 var interval = setQueryTimeInWeeks(offset, this.today);
310 else
311 var interval = setQueryTimeInMonths(offset, this.today);
313 args[3] = interval.endTime.getTime();
314 queryHistoryImpl(args, interval.beginTime.getTime(), this.fakeHistory_);
318 * Stub for the 'removeVisits' message to the history backend.
319 * This will modify the fake history data in the test instance, so that
320 * further 'queryHistory' messages will not contain the deleted entries.
321 * @param {Array} arguments The original arguments to removeVisits.
323 removeVisitsStub_: function(args) {
324 for (var i = 0; i < args.length; ++i) {
325 var url = args[i].url;
326 var timestamps = args[i].timestamps;
327 assertEquals(timestamps.length, 1);
328 this.removeVisitsToUrl_(url, new Date(timestamps[0]));
330 callFrontendAsync('deleteComplete');
334 * Removes any visits to |url| on the same day as |date| from the fake
335 * history data.
336 * @param {string} url
337 * @param {Date} date
339 removeVisitsToUrl_: function(url, date) {
340 var day = date.toDateString();
341 var newHistory = [];
342 for (var i = 0, visit; visit = this.fakeHistory_[i]; ++i) {
343 if (url != visit.url || visit.dateRelativeDay != day)
344 newHistory.push(visit);
346 this.fakeHistory_ = newHistory;
351 * Examines the time column of every entry on the page, and ensure that they
352 * are all the same width.
354 function ensureTimeWidthsEqual() {
355 var times = document.querySelectorAll('.entry .time');
356 var timeWidth = times[0].clientWidth;
357 for (var i = 1; i < times.length; ++i) {
358 assertEquals(timeWidth, times[i].clientWidth);
362 TEST_F('HistoryWebUIFakeBackendTest', 'emptyHistory', function() {
363 expectTrue($('newest-button').hidden);
364 expectTrue($('newer-button').hidden);
365 expectTrue($('older-button').hidden);
366 testDone();
369 // Times out on Win: http://crbug.com/336845
370 TEST_F('HistoryWebUITest', 'DISABLED_basicTest', function() {
371 var resultCount = document.querySelectorAll('.entry').length;
373 // Check that there are two days of entries.
374 var dayHeaders = document.querySelectorAll('.day');
375 assertEquals(2, dayHeaders.length);
376 expectNotEquals(dayHeaders[0].textContent, dayHeaders[1].textContent);
378 // Check that the entries in each day are time-ordered, and that no
379 // duplicate URLs appear on a given day.
380 var urlsByDay = {};
381 var lastDate = new Date();
382 for (var day = 0; day < dayHeaders.length; ++day) {
383 var dayTitle = dayHeaders[day].textContent;
384 var dayResults = document.querySelectorAll('.day-results')[day];
385 var entries = dayResults.querySelectorAll('.entry');
386 expectGT(entries.length, 0);
388 for (var i = 0, entry; entry = entries[i]; ++i) {
389 var time = entry.querySelector('.time').textContent;
390 expectGT(time.length, 0);
392 var date = new Date(dayTitle + ' ' + time);
393 expectGT(lastDate, date);
394 lastDate = date;
396 // Ensure it's not a duplicate URL for this day.
397 var dayAndUrl = day + entry.querySelector('a').href;
398 expectFalse(urlsByDay.hasOwnProperty(dayAndUrl));
399 urlsByDay[dayAndUrl] = dayAndUrl;
401 // Reconstruct the entry date from the title, and ensure that it's
402 // consistent with the date header and with the time.
403 var entryDate = new Date(entry.querySelector('.title').textContent);
404 expectEquals(entryDate.getYear(), date.getYear());
405 expectEquals(entryDate.getMonth(), date.getMonth());
406 expectEquals(entryDate.getDay(), date.getDay());
407 expectEquals(entryDate.getHours(), date.getHours());
408 expectEquals(entryDate.getMinutes(), date.getMinutes());
412 // Check that there are 3 page navigation links and that only the "Older"
413 // link is visible.
414 expectEquals(3, document.querySelectorAll('.link-button').length);
415 expectTrue($('newest-button').hidden);
416 expectTrue($('newer-button').hidden);
417 expectFalse($('older-button').hidden);
419 ensureTimeWidthsEqual();
421 // Go to the next page.
422 $('older-button').click();
423 waitForCallback('historyResult', function() {
424 resultCount += document.querySelectorAll('.entry').length;
426 // Check that the two pages include all of the entries.
427 expectEquals(TOTAL_RESULT_COUNT, resultCount);
429 // Check that the day header was properly continued -- the header for the
430 // last day on the first page should be a substring of the header on the
431 // second page. E.g. "Wed, Oct 8, 2008" and "Web, Oct 8, 2008 - cont'd".
432 var newDayHeaders = document.querySelectorAll('.day');
433 expectEquals(1, newDayHeaders.length);
434 expectEquals(0,
435 newDayHeaders[0].textContent.indexOf(dayHeaders[1].textContent));
437 // Check that the "Newest" and "Newer" links are now visible, but the
438 // "Older" link is hidden.
439 expectEquals(3, document.querySelectorAll('.link-button').length);
440 expectFalse($('newest-button').hidden);
441 expectFalse($('newer-button').hidden);
442 expectTrue($('older-button').hidden);
444 ensureTimeWidthsEqual();
446 // Go back to the first page, and check that the same day headers are there.
447 $('newest-button').click();
448 var newDayHeaders = document.querySelectorAll('.day');
449 expectEquals(2, newDayHeaders.length);
451 expectNotEquals(newDayHeaders[0].textContent,
452 newDayHeaders[1].textContent);
453 expectEquals(dayHeaders[0].textContent, newDayHeaders[0].textContent);
454 expectEquals(dayHeaders[1].textContent, newDayHeaders[1].textContent);
456 testDone();
461 * Test bulk deletion of history entries.
462 * Disabled because it is currently very flaky on the Windows XP bot.
464 TEST_F('HistoryWebUITest', 'DISABLED_bulkDeletion', function() {
465 var checkboxes = document.querySelectorAll(
466 '#results-display input[type=checkbox]');
468 // Immediately confirm the history deletion.
469 confirmDeletion = function(okCallback, cancelCallback) {
470 okCallback();
473 // The "remove" button should be initially disabled.
474 var removeButton = $('remove-selected');
475 expectTrue(removeButton.disabled);
477 checkboxes[0].click();
478 expectFalse(removeButton.disabled);
480 var firstEntry = document.querySelector('.title a').textContent;
481 removeButton.click();
483 // After deletion, expect the results to be reloaded.
484 waitForCallback('historyResult', function() {
485 expectNotEquals(document.querySelector('.title a').textContent, firstEntry);
486 expectTrue(removeButton.disabled);
488 // Delete the first 3 entries.
489 checkboxes = document.querySelectorAll(
490 '#results-display input[type=checkbox]');
491 checkboxes[0].click();
492 checkboxes[1].click();
493 checkboxes[2].click();
494 expectFalse(removeButton.disabled);
496 var nextEntry = document.querySelectorAll('.title a')[3];
497 removeButton.click();
498 waitForCallback('historyResult', function() {
499 // The next entry after the deleted ones should now be the first.
500 expectEquals(document.querySelector('.title a').textContent,
501 nextEntry.textContent);
502 testDone();
508 * Test selecting multiple entries using shift click.
509 * Disabled due to time out on all platforms: crbug/375910
511 TEST_F('HistoryWebUITest', 'DISABLED_multipleSelect', function() {
512 var checkboxes = document.querySelectorAll(
513 '#results-display input[type=checkbox]');
515 var getAllChecked = function() {
516 return Array.prototype.slice.call(document.querySelectorAll(
517 '#results-display input[type=checkbox]:checked'));
520 // Make sure that nothing is checked.
521 expectEquals(0, getAllChecked().length);
523 var shiftClick = function(el) {
524 el.dispatchEvent(new MouseEvent('click', { shiftKey: true }));
527 // Check the start.
528 shiftClick($('checkbox-4'));
529 // And the end.
530 shiftClick($('checkbox-9'));
532 // See if they are checked.
533 var checked = getAllChecked();
534 expectEquals(6, checked.length);
535 checkInterval(checked, 4, 9);
537 // Extend the selection.
538 shiftClick($('checkbox-14'));
540 checked = getAllChecked();
541 expectEquals(11, checked.length);
542 checkInterval(checked, 4, 14);
544 // Now do a normal click on a higher ID box and a shift click on a lower ID
545 // one (test the other way around).
546 $('checkbox-24').click();
547 shiftClick($('checkbox-19'));
549 checked = getAllChecked();
550 expectEquals(17, checked.length);
551 // First set of checkboxes (11).
552 checkInterval(checked, 4, 14);
553 // Second set (6).
554 checkInterval(checked.slice(11), 19, 24);
556 // Test deselection.
557 $('checkbox-26').click();
558 shiftClick($('checkbox-20'));
560 checked = getAllChecked();
561 // checkbox-20 to checkbox-24 should be deselected now.
562 expectEquals(12, checked.length);
563 // First set of checkboxes (11).
564 checkInterval(checked, 4, 14);
565 // Only checkbox-19 should still be selected.
566 expectEquals('checkbox-19', checked[11].id);
568 testDone();
571 TEST_F('HistoryWebUITest', 'DISABLED_searchHistory', function() {
572 var getResultCount = function() {
573 return document.querySelectorAll('.entry').length;
575 // See that all the elements are there.
576 expectEquals(RESULTS_PER_PAGE, getResultCount());
578 // See that the search works.
579 $('search-field').value = 'Thu Oct 02 2008';
580 $('search-button').click();
582 waitForCallback('historyResult', function() {
583 expectEquals(31, getResultCount());
585 // Clear the search.
586 $('search-field').value = '';
587 $('search-button').click();
588 waitForCallback('historyResult', function() {
589 expectEquals(RESULTS_PER_PAGE, getResultCount());
590 testDone();
595 function setPageState(searchText, page, groupByDomain, range, offset) {
596 window.location = '#' + PageState.getHashString(
597 searchText, page, groupByDomain, range, offset);
600 function RangeHistoryWebUITest() {}
602 RangeHistoryWebUITest.prototype = {
603 __proto__: HistoryWebUITest.prototype,
605 /** @override */
606 preLoad: function() {
607 HistoryWebUITest.prototype.preLoad.call(this);
608 // Repeat the domain visits every 4 days. The nested lists contain the
609 // domain suffixes for the visits in a day.
610 var domainSuffixByDay = [
611 [1, 2, 3, 4],
612 [1, 2, 2, 3],
613 [1, 2, 1, 2],
614 [1, 1, 1, 1]
617 var buildDomainUrl = function(timestamp) {
618 var d = new Date(timestamp);
619 // Repeat the same setup of domains every 4 days.
620 var day = d.getDate() % 4;
621 // Assign an entry for every 6 hours so that we get 4 entries per day
622 // maximum.
623 var visitInDay = Math.floor(d.getHours() / 6);
624 return 'http://google' + domainSuffixByDay[day][visitInDay] + '.com/' +
625 timestamp;
628 // Prepare a list of fake history results. Start the results on
629 // 11:00 PM on May 2, 2012 and add 4 results every day (one result every 6
630 // hours).
631 var timestamp = new Date(2012, 4, 2, 23, 0).getTime();
632 this.today = new Date(2012, 4, 2);
633 this.fakeHistory_ = [];
635 // Put in 2 days for May and 30 days for April so the results span over
636 // the month limit.
637 for (var i = 0; i < 4 * 32; i++) {
638 this.fakeHistory_.push(
639 createHistoryEntry(timestamp, buildDomainUrl(timestamp)));
640 timestamp -= 6 * 60 * 60 * 1000;
643 // Leave March empty.
644 timestamp -= 31 * 24 * 3600 * 1000;
646 // Put results in February.
647 for (var i = 0; i < 29 * 4; i++) {
648 this.fakeHistory_.push(
649 createHistoryEntry(timestamp, buildDomainUrl(timestamp)));
650 timestamp -= 6 * 60 * 60 * 1000;
654 setUp: function() {
655 // Show the filter controls as if the command line switch was active.
656 $('top-container').hidden = true;
657 $('history-page').classList.add('big-topbar-page');
658 $('filter-controls').hidden = false;
659 expectFalse($('filter-controls').hidden);
664 * Disabled due intermitent failures on multiple OSes http://crbug.com/377338
666 TEST_F('RangeHistoryWebUITest', 'DISABLED_allView', function() {
667 // Check that we start off in the all time view.
668 expectTrue($('timeframe-filter-all').checked);
669 // See if the correct number of days is shown.
670 var dayHeaders = document.querySelectorAll('.day');
671 assertEquals(Math.ceil(RESULTS_PER_PAGE / 4), dayHeaders.length);
672 testDone();
676 * Checks whether the domains in a day are ordered decreasingly.
677 * @param {Element} element Ordered list containing the grouped domains for a
678 * day.
680 function checkGroupedVisits(element) {
681 // The history page contains the number of visits next to a domain in
682 // parentheses (e.g. 'google.com (5)'). This function extracts that number
683 // and returns it.
684 var getNumberVisits = function(element) {
685 return parseInt(element.textContent.replace(/\D/g, ''), 10);
688 // Read the number of visits from each domain and make sure that it is lower
689 // than or equal to the number of visits from the previous domain.
690 var domainEntries = element.querySelectorAll('.number-visits');
691 var currentNumberOfVisits = getNumberVisits(domainEntries[0]);
692 for (var j = 1; j < domainEntries.length; j++) {
693 var numberOfVisits = getNumberVisits(domainEntries[j]);
694 assertTrue(currentNumberOfVisits >= numberOfVisits);
695 currentNumberOfVisits = numberOfVisits;
699 TEST_F('RangeHistoryWebUITest', 'weekViewGrouped', function() {
700 // Change to weekly view.
701 setPageState('', 0, HistoryModel.Range.WEEK, 0);
702 waitForCallback('historyResult', function() {
703 // See if the correct number of days is still shown.
704 var dayResults = document.querySelectorAll('.day-results');
705 assertEquals(7, dayResults.length);
707 // Check whether the results are ordered by visits.
708 for (var i = 0; i < dayResults.length; i++)
709 checkGroupedVisits(dayResults[i]);
711 ensureTimeWidthsEqual();
713 testDone();
717 TEST_F('RangeHistoryWebUITest', 'monthViewGrouped', function() {
718 // Change to monthly view.
719 setPageState('', 0, HistoryModel.Range.MONTH, 0);
720 waitForCallback('historyResult', function() {
721 // See if the correct number of days is shown.
722 var monthResults = document.querySelectorAll('.month-results');
723 assertEquals(1, monthResults.length);
725 checkGroupedVisits(monthResults[0]);
726 ensureTimeWidthsEqual();
728 testDone();
732 TEST_F('RangeHistoryWebUITest', 'monthViewEmptyMonth', function() {
733 // Change to monthly view.
734 setPageState('', 0, HistoryModel.Range.MONTH, 2);
736 waitForCallback('historyResult', function() {
737 // See if the correct number of days is shown.
738 var resultsDisplay = $('results-display');
739 assertEquals(0, resultsDisplay.querySelectorAll('.months-results').length);
740 assertEquals(1, resultsDisplay.querySelectorAll('div').length);
742 testDone();
747 * Fixture for History WebUI tests using the real history backend.
748 * @extends {BaseHistoryWebUITest}
749 * @constructor
751 function HistoryWebUIRealBackendTest() {}
753 HistoryWebUIRealBackendTest.prototype = {
754 __proto__: BaseHistoryWebUITest.prototype,
756 /** @override */
757 testGenPreamble: function() {
758 // Add some visits to the history database.
759 GEN(' AddPageToHistory(0, "http://google.com", "Google");');
760 GEN(' AddPageToHistory(1, "http://example.com", "Example");');
761 GEN(' AddPageToHistory(2, "http://google.com", "Google");');
763 // Add a visit on the next day.
764 GEN(' AddPageToHistory(36, "http://google.com", "Google");');
769 * Simple test that verifies that the correct entries are retrieved from the
770 * history database and displayed in the UI.
772 TEST_F('HistoryWebUIRealBackendTest', 'basic', function() {
773 // Check that there are two days of entries, and three entries in total.
774 assertEquals(2, document.querySelectorAll('.day').length);
775 assertEquals(3, document.querySelectorAll('.entry').length);
777 testDone();
780 TEST_F('HistoryWebUIRealBackendTest', 'atLeastOneFocusable', function() {
781 expectEquals(1, document.querySelectorAll('[tabindex="0"]').length);
782 testDone();
785 TEST_F('HistoryWebUIRealBackendTest', 'deleteRemovesEntry', function() {
786 assertTrue(historyModel.deletingHistoryAllowed);
788 var visit = document.querySelector('.entry').visit;
789 visit.titleLink.focus();
790 assertEquals(visit.titleLink, document.activeElement);
792 var deleteKey = document.createEvent('KeyboardEvent');
793 deleteKey.initKeyboardEvent('keydown', true, true, window, 'U+007F');
794 assertEquals('U+007F', deleteKey.keyIdentifier);
796 assertFalse(historyModel.isDeletingVisits());
797 expectFalse(visit.titleLink.dispatchEvent(deleteKey));
798 expectTrue(historyModel.isDeletingVisits());
800 expectNotEquals(visit.dropDown, document.activeElement);
801 testDone();
805 * Test individual deletion of history entries.
807 TEST_F('HistoryWebUIRealBackendTest', 'singleDeletion', function() {
808 // Deletes the history entry represented by |entryElement|, and calls callback
809 // when the deletion is complete.
810 var removeEntry = function(entryElement, callback) {
811 var dropDownButton = entryElement.querySelector('.drop-down');
812 var removeMenuItem = $('remove-visit');
814 assertFalse(dropDownButton.disabled);
815 assertFalse(removeMenuItem.disabled);
817 waitForCallback('onEntryRemoved', callback);
819 cr.dispatchSimpleEvent(dropDownButton, 'mousedown');
820 cr.dispatchSimpleEvent(removeMenuItem, 'activate');
823 var secondTitle = document.querySelectorAll('.entry a')[1].textContent;
824 var thirdTitle = document.querySelectorAll('.entry a')[2].textContent;
826 // historyDeleted() should not be called when deleting individual entries
827 // using the drop down.
828 waitForCallback('historyDeleted', function() {
829 testDone([false, 'historyDeleted() called when deleting single entry']);
832 expectEquals(2, document.querySelectorAll('.day').length);
834 // Delete the first entry. The previous second entry should now be the first.
835 removeEntry(document.querySelector('.entry'), function() {
836 expectEquals(secondTitle, document.querySelector('.entry a').textContent);
838 // After removing the first entry, its day header should also be gone.
839 expectEquals(1, document.querySelectorAll('.day').length);
841 // Delete another entry. The original third entry should now be the first.
842 removeEntry(document.querySelector('.entry'), function() {
843 expectEquals(thirdTitle, document.querySelector('.entry a').textContent);
844 testDone();
849 TEST_F('HistoryWebUIRealBackendTest', 'leftRightChangeFocus', function() {
850 var visit = document.querySelector('.entry').visit;
851 visit.titleLink.focus();
852 assertEquals(visit.titleLink, document.activeElement);
854 var right = document.createEvent('KeyboardEvent');
855 right.initKeyboardEvent('keydown', true, true, window, 'Right');
856 assertEquals('Right', right.keyIdentifier);
857 expectFalse(visit.titleLink.dispatchEvent(right));
859 assertEquals(visit.dropDown, document.activeElement);
861 var left = document.createEvent('KeyboardEvent');
862 left.initKeyboardEvent('keydown', true, true, window, 'Left');
863 assertEquals('Left', left.keyIdentifier);
864 expectFalse(visit.dropDown.dispatchEvent(left));
866 expectEquals(visit.titleLink, document.activeElement);
867 testDone();
871 * Fixture for History WebUI testing when deletions are prohibited.
872 * @extends {HistoryWebUIRealBackendTest}
873 * @constructor
875 function HistoryWebUIDeleteProhibitedTest() {}
877 HistoryWebUIDeleteProhibitedTest.prototype = {
878 __proto__: HistoryWebUIRealBackendTest.prototype,
880 /** @override */
881 testGenPreamble: function() {
882 HistoryWebUIRealBackendTest.prototype.testGenPreamble.call(this);
883 GEN(' SetDeleteAllowed(false);');
887 // Test UI when removing entries is prohibited.
888 TEST_F('HistoryWebUIDeleteProhibitedTest', 'deleteProhibited', function() {
889 // No checkboxes should be created.
890 var checkboxes = document.querySelectorAll(
891 '#results-display input[type=checkbox]');
892 expectEquals(0, checkboxes.length);
894 // The "remove" button should be disabled.
895 var removeButton = $('remove-selected');
896 expectTrue(removeButton.disabled);
898 // The "Remove from history" drop-down item should be disabled.
899 var removeVisit = $('remove-visit');
900 expectTrue(removeVisit.disabled);
902 testDone();
905 TEST_F('HistoryWebUIDeleteProhibitedTest', 'atLeastOneFocusable', function() {
906 expectEquals(1, document.querySelectorAll('[tabindex="0"]').length);
907 testDone();
910 TEST_F('HistoryWebUIDeleteProhibitedTest', 'leftRightChangeFocus', function() {
911 var visit = document.querySelector('.entry').visit;
912 visit.titleLink.focus();
913 assertEquals(visit.titleLink, document.activeElement);
915 var right = document.createEvent('KeyboardEvent');
916 right.initKeyboardEvent('keydown', true, true, window, 'Right');
917 assertEquals('Right', right.keyIdentifier);
918 expectFalse(visit.titleLink.dispatchEvent(right));
920 assertEquals(visit.dropDown, document.activeElement);
922 var left = document.createEvent('KeyboardEvent');
923 left.initKeyboardEvent('keydown', true, true, window, 'Left');
924 assertEquals('Left', left.keyIdentifier);
925 expectFalse(visit.dropDown.dispatchEvent(left));
927 expectEquals(visit.titleLink, document.activeElement);
928 testDone();
931 TEST_F('HistoryWebUIDeleteProhibitedTest', 'deleteIgnored', function() {
932 assertFalse(historyModel.deletingHistoryAllowed);
934 var visit = document.querySelector('.entry').visit;
935 visit.titleLink.focus();
936 assertEquals(visit.titleLink, document.activeElement);
938 var deleteKey = document.createEvent('KeyboardEvent');
939 deleteKey.initKeyboardEvent('keydown', true, true, window, 'U+007F');
940 assertEquals('U+007F', deleteKey.keyIdentifier);
942 assertFalse(historyModel.isDeletingVisits());
943 expectTrue(visit.titleLink.dispatchEvent(deleteKey));
944 expectFalse(historyModel.isDeletingVisits());
946 expectEquals(visit.titleLink, document.activeElement);
947 testDone();
951 * Fixture for History WebUI testing IDN.
952 * @extends {BaseHistoryWebUITest}
953 * @constructor
955 function HistoryWebUIIDNTest() {}
957 HistoryWebUIIDNTest.prototype = {
958 __proto__: BaseHistoryWebUITest.prototype,
960 /** @override */
961 testGenPreamble: function() {
962 // Add some visits to the history database.
963 GEN(' AddPageToHistory(0, "http://xn--d1abbgf6aiiy.xn--p1ai/",' +
964 ' "Some");');
966 // Clear AcceptLanguages to get domain in unicode.
967 GEN(' ClearAcceptLanguages();');
972 * Simple test that verifies that the correct entries are retrieved from the
973 * history database and displayed in the UI.
975 TEST_F('HistoryWebUIIDNTest', 'basic', function() {
976 // Check that there is only one entry and domain is in unicode.
977 assertEquals(1, document.querySelectorAll('.domain').length);
978 assertEquals("\u043f\u0440\u0435\u0437\u0438\u0434\u0435\u043d\u0442." +
979 "\u0440\u0444", document.querySelector('.domain').textContent);
981 testDone();
985 * Fixture for a test that uses the real backend and tests how the history
986 * page deals with odd schemes in URLs.
987 * @extends {HistoryWebUIRealBackendTest}
989 function HistoryWebUIWithSchemesTest() {}
991 HistoryWebUIWithSchemesTest.prototype = {
992 __proto__: HistoryWebUIRealBackendTest.prototype,
994 /** @override */
995 testGenPreamble: function() {
996 // Add a bunch of entries on the same day, including some weird schemes.
997 GEN(' AddPageToHistory(12, "http://google.com", "Google");');
998 GEN(' AddPageToHistory(13, "file:///tmp/foo", "");');
999 GEN(' AddPageToHistory(14, "mailto:chromium@chromium.org", "");');
1000 GEN(' AddPageToHistory(15, "tel:555123456", "");');
1003 setUp: function() {
1004 // Show the filter controls as if the command line switch was active.
1005 $('top-container').hidden = true;
1006 $('history-page').classList.add('big-topbar-page');
1007 $('filter-controls').hidden = false;
1008 expectFalse($('filter-controls').hidden);
1012 TEST_F('HistoryWebUIWithSchemesTest', 'groupingWithSchemes', function() {
1013 // Switch to the week view.
1014 $('timeframe-filter-week').click();
1015 waitForCallback('historyResult', function() {
1016 // Each URL should be organized under a different "domain".
1017 expectEquals(document.querySelectorAll('.entry').length, 4);
1018 expectEquals(document.querySelectorAll('.site-domain-wrapper').length, 4);
1019 testDone();