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;
11 * Test fixture for history WebUI testing.
13 * @extends {testing.Test}
15 function HistoryUIBrowserTest() {}
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] : '';
29 dateTimeOfDay
: d
.getHours() + ':' + d
.getMinutes(),
30 dateRelativeDay
: d
.toDateString(),
31 allTimestamps
: [timestamp
],
34 title
: d
.toString(), // Use the stringified date as the title.
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
);
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
);
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
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
);
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
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
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}
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',
144 typedefCppFixture
: 'HistoryUIBrowserTest',
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}
156 function HistoryWebUIFakeBackendTest() {
159 HistoryWebUIFakeBackendTest
.prototype = {
160 __proto__
: BaseHistoryWebUITest
.prototype,
163 * Register handlers to stub out calls to the history backend.
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
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
) {
196 'historyResult', { term
: args
[0], finished
: true }, []);
200 function queryHistoryImpl(args
, beginTime
, history
) {
201 var searchText
= args
[0];
202 var offset
= args
[1];
204 var endTime
= args
[3] || Number
.MAX_VALUE
;
205 var maxCount
= args
[4];
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
]);
218 // Advance past all entries newer than the specified end time.
220 // Finished is set from the history database so this behavior may not be
221 // completely identical.
223 while (i
< results
.length
&& results
[i
].time
>= endTime
)
228 while (j
< results
.length
&& results
[j
].time
>= beginTime
)
231 finished
= (j
== results
.length
);
232 results
= results
.slice(i
, j
);
234 results
= results
.slice(i
);
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
);
257 queryStartTime
: queryStartTime
,
258 queryEndTime
: queryEndTime
264 * Fixture for History WebUI testing which returns some fake history results
266 * @extends {HistoryWebUIFakeBackendTest}
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];
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_
);
308 if (range
== HistoryModel
.Range
.WEEK
)
309 var interval
= setQueryTimeInWeeks(offset
, this.today
);
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
336 * @param {string} url
339 removeVisitsToUrl_: function(url
, date
) {
340 var day
= date
.toDateString();
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
);
369 TEST_F('HistoryWebUITest', 'basicTest', function() {
370 var resultCount
= document
.querySelectorAll('.entry').length
;
372 // Check that there are two days of entries.
373 var dayHeaders
= document
.querySelectorAll('.day');
374 assertEquals(2, dayHeaders
.length
);
375 expectNotEquals(dayHeaders
[0].textContent
, dayHeaders
[1].textContent
);
377 // Check that the entries in each day are time-ordered, and that no
378 // duplicate URLs appear on a given day.
380 var lastDate
= new Date();
381 for (var day
= 0; day
< dayHeaders
.length
; ++day
) {
382 var dayTitle
= dayHeaders
[day
].textContent
;
383 var dayResults
= document
.querySelectorAll('.day-results')[day
];
384 var entries
= dayResults
.querySelectorAll('.entry');
385 expectGT(entries
.length
, 0);
387 for (var i
= 0, entry
; entry
= entries
[i
]; ++i
) {
388 var time
= entry
.querySelector('.time').textContent
;
389 expectGT(time
.length
, 0);
391 var date
= new Date(dayTitle
+ ' ' + time
);
392 expectGT(lastDate
, date
);
395 // Ensure it's not a duplicate URL for this day.
396 var dayAndUrl
= day
+ entry
.querySelector('a').href
;
397 expectFalse(urlsByDay
.hasOwnProperty(dayAndUrl
));
398 urlsByDay
[dayAndUrl
] = dayAndUrl
;
400 // Reconstruct the entry date from the title, and ensure that it's
401 // consistent with the date header and with the time.
402 var entryDate
= new Date(entry
.querySelector('.title').textContent
);
403 expectEquals(entryDate
.getYear(), date
.getYear());
404 expectEquals(entryDate
.getMonth(), date
.getMonth());
405 expectEquals(entryDate
.getDay(), date
.getDay());
406 expectEquals(entryDate
.getHours(), date
.getHours());
407 expectEquals(entryDate
.getMinutes(), date
.getMinutes());
411 // Check that there are 3 page navigation links and that only the "Older"
413 expectEquals(3, document
.querySelectorAll('.link-button').length
);
414 expectTrue($('newest-button').hidden
);
415 expectTrue($('newer-button').hidden
);
416 expectFalse($('older-button').hidden
);
418 ensureTimeWidthsEqual();
420 // Go to the next page.
421 $('older-button').click();
422 waitForCallback('historyResult', function() {
423 resultCount
+= document
.querySelectorAll('.entry').length
;
425 // Check that the two pages include all of the entries.
426 expectEquals(TOTAL_RESULT_COUNT
, resultCount
);
428 // Check that the day header was properly continued -- the header for the
429 // last day on the first page should be a substring of the header on the
430 // second page. E.g. "Wed, Oct 8, 2008" and "Web, Oct 8, 2008 - cont'd".
431 var newDayHeaders
= document
.querySelectorAll('.day');
432 expectEquals(1, newDayHeaders
.length
);
434 newDayHeaders
[0].textContent
.indexOf(dayHeaders
[1].textContent
));
436 // Check that the "Newest" and "Newer" links are now visible, but the
437 // "Older" link is hidden.
438 expectEquals(3, document
.querySelectorAll('.link-button').length
);
439 expectFalse($('newest-button').hidden
);
440 expectFalse($('newer-button').hidden
);
441 expectTrue($('older-button').hidden
);
443 ensureTimeWidthsEqual();
445 // Go back to the first page, and check that the same day headers are there.
446 $('newest-button').click();
447 var newDayHeaders
= document
.querySelectorAll('.day');
448 expectEquals(2, newDayHeaders
.length
);
450 expectNotEquals(newDayHeaders
[0].textContent
,
451 newDayHeaders
[1].textContent
);
452 expectEquals(dayHeaders
[0].textContent
, newDayHeaders
[0].textContent
);
453 expectEquals(dayHeaders
[1].textContent
, newDayHeaders
[1].textContent
);
460 * Test bulk deletion of history entries.
461 * Disabled because it is currently very flaky on the Windows XP bot.
463 TEST_F('HistoryWebUITest', 'DISABLED_bulkDeletion', function() {
464 var checkboxes
= document
.querySelectorAll(
465 '#results-display input[type=checkbox]');
467 // Immediately confirm the history deletion.
468 confirmDeletion = function(okCallback
, cancelCallback
) {
472 // The "remove" button should be initially disabled.
473 var removeButton
= $('remove-selected');
474 expectTrue(removeButton
.disabled
);
476 checkboxes
[0].click();
477 expectFalse(removeButton
.disabled
);
479 var firstEntry
= document
.querySelector('.title a').textContent
;
480 removeButton
.click();
482 // After deletion, expect the results to be reloaded.
483 waitForCallback('historyResult', function() {
484 expectNotEquals(document
.querySelector('.title a').textContent
, firstEntry
);
485 expectTrue(removeButton
.disabled
);
487 // Delete the first 3 entries.
488 checkboxes
= document
.querySelectorAll(
489 '#results-display input[type=checkbox]');
490 checkboxes
[0].click();
491 checkboxes
[1].click();
492 checkboxes
[2].click();
493 expectFalse(removeButton
.disabled
);
495 var nextEntry
= document
.querySelectorAll('.title a')[3];
496 removeButton
.click();
497 waitForCallback('historyResult', function() {
498 // The next entry after the deleted ones should now be the first.
499 expectEquals(document
.querySelector('.title a').textContent
,
500 nextEntry
.textContent
);
507 * Test selecting multiple entries using shift click.
509 TEST_F('HistoryWebUITest', 'multipleSelect', function() {
510 var checkboxes
= document
.querySelectorAll(
511 '#results-display input[type=checkbox]');
513 var getAllChecked = function() {
514 return Array
.prototype.slice
.call(document
.querySelectorAll(
515 '#results-display input[type=checkbox]:checked'));
518 // Make sure that nothing is checked.
519 expectEquals(0, getAllChecked().length
);
521 var shiftClick = function(el
) {
522 el
.dispatchEvent(new MouseEvent('click', { shiftKey
: true }));
526 shiftClick($('checkbox-4'));
528 shiftClick($('checkbox-9'));
530 // See if they are checked.
531 var checked
= getAllChecked();
532 expectEquals(6, checked
.length
);
533 checkInterval(checked
, 4, 9);
535 // Extend the selection.
536 shiftClick($('checkbox-14'));
538 checked
= getAllChecked();
539 expectEquals(11, checked
.length
);
540 checkInterval(checked
, 4, 14);
542 // Now do a normal click on a higher ID box and a shift click on a lower ID
543 // one (test the other way around).
544 $('checkbox-24').click();
545 shiftClick($('checkbox-19'));
547 checked
= getAllChecked();
548 expectEquals(17, checked
.length
);
549 // First set of checkboxes (11).
550 checkInterval(checked
, 4, 14);
552 checkInterval(checked
.slice(11), 19, 24);
555 $('checkbox-26').click();
556 shiftClick($('checkbox-20'));
558 checked
= getAllChecked();
559 // checkbox-20 to checkbox-24 should be deselected now.
560 expectEquals(12, checked
.length
);
561 // First set of checkboxes (11).
562 checkInterval(checked
, 4, 14);
563 // Only checkbox-19 should still be selected.
564 expectEquals('checkbox-19', checked
[11].id
);
569 TEST_F('HistoryWebUITest', 'DISABLED_searchHistory', function() {
570 var getResultCount = function() {
571 return document
.querySelectorAll('.entry').length
;
573 // See that all the elements are there.
574 expectEquals(RESULTS_PER_PAGE
, getResultCount());
576 // See that the search works.
577 $('search-field').value
= 'Thu Oct 02 2008';
578 $('search-button').click();
580 waitForCallback('historyResult', function() {
581 expectEquals(31, getResultCount());
584 $('search-field').value
= '';
585 $('search-button').click();
586 waitForCallback('historyResult', function() {
587 expectEquals(RESULTS_PER_PAGE
, getResultCount());
593 function setPageState(searchText
, page
, groupByDomain
, range
, offset
) {
594 window
.location
= '#' + PageState
.getHashString(
595 searchText
, page
, groupByDomain
, range
, offset
);
598 function RangeHistoryWebUITest() {}
600 RangeHistoryWebUITest
.prototype = {
601 __proto__
: HistoryWebUITest
.prototype,
604 preLoad: function() {
605 HistoryWebUITest
.prototype.preLoad
.call(this);
606 // Repeat the domain visits every 4 days. The nested lists contain the
607 // domain suffixes for the visits in a day.
608 var domainSuffixByDay
= [
615 var buildDomainUrl = function(timestamp
) {
616 var d
= new Date(timestamp
);
617 // Repeat the same setup of domains every 4 days.
618 var day
= d
.getDate() % 4;
619 // Assign an entry for every 6 hours so that we get 4 entries per day
621 var visitInDay
= Math
.floor(d
.getHours() / 6);
622 return 'http://google' + domainSuffixByDay
[day
][visitInDay
] + '.com/' +
626 // Prepare a list of fake history results. Start the results on
627 // 11:00 PM on May 2, 2012 and add 4 results every day (one result every 6
629 var timestamp
= new Date(2012, 4, 2, 23, 0).getTime();
630 this.today
= new Date(2012, 4, 2);
631 this.fakeHistory_
= [];
633 // Put in 2 days for May and 30 days for April so the results span over
635 for (var i
= 0; i
< 4 * 32; i
++) {
636 this.fakeHistory_
.push(
637 createHistoryEntry(timestamp
, buildDomainUrl(timestamp
)));
638 timestamp
-= 6 * 60 * 60 * 1000;
641 // Leave March empty.
642 timestamp
-= 31 * 24 * 3600 * 1000;
644 // Put results in February.
645 for (var i
= 0; i
< 29 * 4; i
++) {
646 this.fakeHistory_
.push(
647 createHistoryEntry(timestamp
, buildDomainUrl(timestamp
)));
648 timestamp
-= 6 * 60 * 60 * 1000;
653 // Show the filter controls as if the command line switch was active.
654 $('top-container').hidden
= true;
655 $('history-page').classList
.add('big-topbar-page');
656 $('filter-controls').hidden
= false;
657 expectFalse($('filter-controls').hidden
);
661 TEST_F('RangeHistoryWebUITest', 'allView', function() {
662 // Check that we start off in the all time view.
663 expectTrue($('timeframe-filter-all').checked
);
664 // See if the correct number of days is shown.
665 var dayHeaders
= document
.querySelectorAll('.day');
666 assertEquals(Math
.ceil(RESULTS_PER_PAGE
/ 4), dayHeaders
.length
);
671 * Checks whether the domains in a day are ordered decreasingly.
672 * @param {Element} element Ordered list containing the grouped domains for a
675 function checkGroupedVisits(element
) {
676 // The history page contains the number of visits next to a domain in
677 // parentheses (e.g. 'google.com (5)'). This function extracts that number
679 var getNumberVisits = function(element
) {
680 return parseInt(element
.textContent
.replace(/\D/g, ''), 10);
683 // Read the number of visits from each domain and make sure that it is lower
684 // than or equal to the number of visits from the previous domain.
685 var domainEntries
= element
.querySelectorAll('.number-visits');
686 var currentNumberOfVisits
= getNumberVisits(domainEntries
[0]);
687 for (var j
= 1; j
< domainEntries
.length
; j
++) {
688 var numberOfVisits
= getNumberVisits(domainEntries
[j
]);
689 assertTrue(currentNumberOfVisits
>= numberOfVisits
);
690 currentNumberOfVisits
= numberOfVisits
;
694 TEST_F('RangeHistoryWebUITest', 'weekViewGrouped', function() {
695 // Change to weekly view.
696 setPageState('', 0, HistoryModel
.Range
.WEEK
, 0);
697 waitForCallback('historyResult', function() {
698 // See if the correct number of days is still shown.
699 var dayResults
= document
.querySelectorAll('.day-results');
700 assertEquals(7, dayResults
.length
);
702 // Check whether the results are ordered by visits.
703 for (var i
= 0; i
< dayResults
.length
; i
++)
704 checkGroupedVisits(dayResults
[i
]);
706 ensureTimeWidthsEqual();
712 TEST_F('RangeHistoryWebUITest', 'monthViewGrouped', function() {
713 // Change to monthly view.
714 setPageState('', 0, HistoryModel
.Range
.MONTH
, 0);
715 waitForCallback('historyResult', function() {
716 // See if the correct number of days is shown.
717 var monthResults
= document
.querySelectorAll('.month-results');
718 assertEquals(1, monthResults
.length
);
720 checkGroupedVisits(monthResults
[0]);
721 ensureTimeWidthsEqual();
727 TEST_F('RangeHistoryWebUITest', 'monthViewEmptyMonth', function() {
728 // Change to monthly view.
729 setPageState('', 0, HistoryModel
.Range
.MONTH
, 2);
731 waitForCallback('historyResult', function() {
732 // See if the correct number of days is shown.
733 var resultsDisplay
= $('results-display');
734 assertEquals(0, resultsDisplay
.querySelectorAll('.months-results').length
);
735 assertEquals(1, resultsDisplay
.querySelectorAll('div').length
);
742 * Fixture for History WebUI tests using the real history backend.
743 * @extends {BaseHistoryWebUITest}
746 function HistoryWebUIRealBackendTest() {}
748 HistoryWebUIRealBackendTest
.prototype = {
749 __proto__
: BaseHistoryWebUITest
.prototype,
752 testGenPreamble: function() {
753 // Add some visits to the history database.
754 GEN(' AddPageToHistory(0, "http://google.com", "Google");');
755 GEN(' AddPageToHistory(1, "http://example.com", "Example");');
756 GEN(' AddPageToHistory(2, "http://google.com", "Google");');
758 // Add a visit on the next day.
759 GEN(' AddPageToHistory(36, "http://google.com", "Google");');
764 * Simple test that verifies that the correct entries are retrieved from the
765 * history database and displayed in the UI.
767 TEST_F('HistoryWebUIRealBackendTest', 'basic', function() {
768 // Check that there are two days of entries, and three entries in total.
769 assertEquals(2, document
.querySelectorAll('.day').length
);
770 assertEquals(3, document
.querySelectorAll('.entry').length
);
776 * Test individual deletion of history entries.
778 TEST_F('HistoryWebUIRealBackendTest', 'singleDeletion', function() {
779 // Deletes the history entry represented by |entryElement|, and calls callback
780 // when the deletion is complete.
781 var removeEntry = function(entryElement
, callback
) {
782 var dropDownButton
= entryElement
.querySelector('.drop-down');
783 var removeMenuItem
= $('remove-visit');
785 assertFalse(dropDownButton
.disabled
);
786 assertFalse(removeMenuItem
.disabled
);
788 waitForCallback('onEntryRemoved', callback
);
790 cr
.dispatchSimpleEvent(dropDownButton
, 'mousedown');
791 cr
.dispatchSimpleEvent(removeMenuItem
, 'activate');
794 var secondTitle
= document
.querySelectorAll('.entry a')[1].textContent
;
795 var thirdTitle
= document
.querySelectorAll('.entry a')[2].textContent
;
797 // historyDeleted() should not be called when deleting individual entries
798 // using the drop down.
799 waitForCallback('historyDeleted', function() {
800 testDone([false, 'historyDeleted() called when deleting single entry']);
803 expectEquals(2, document
.querySelectorAll('.day').length
);
805 // Delete the first entry. The previous second entry should now be the first.
806 removeEntry(document
.querySelector('.entry'), function() {
807 expectEquals(secondTitle
, document
.querySelector('.entry a').textContent
);
809 // After removing the first entry, its day header should also be gone.
810 expectEquals(1, document
.querySelectorAll('.day').length
);
812 // Delete another entry. The original third entry should now be the first.
813 removeEntry(document
.querySelector('.entry'), function() {
814 expectEquals(thirdTitle
, document
.querySelector('.entry a').textContent
);
821 * Fixture for History WebUI testing when deletions are prohibited.
822 * @extends {HistoryWebUIRealBackendTest}
825 function HistoryWebUIDeleteProhibitedTest() {}
827 HistoryWebUIDeleteProhibitedTest
.prototype = {
828 __proto__
: HistoryWebUIRealBackendTest
.prototype,
831 testGenPreamble: function() {
832 HistoryWebUIRealBackendTest
.prototype.testGenPreamble
.call(this);
833 GEN(' SetDeleteAllowed(false);');
837 // Test UI when removing entries is prohibited.
838 TEST_F('HistoryWebUIDeleteProhibitedTest', 'deleteProhibited', function() {
839 // No checkboxes should be created.
840 var checkboxes
= document
.querySelectorAll(
841 '#results-display input[type=checkbox]');
842 expectEquals(0, checkboxes
.length
);
844 // The "remove" button should be disabled.
845 var removeButton
= $('remove-selected');
846 expectTrue(removeButton
.disabled
);
848 // The "Remove from history" drop-down item should be disabled.
849 var removeVisit
= $('remove-visit');
850 expectTrue(removeVisit
.disabled
);
852 // Attempting to remove items anyway should fail.
853 historyModel
.removeVisitsFromHistory(historyModel
.visits_
, function () {
854 // The callback is only called on success.
855 testDone([false, 'Delete succeeded even though it was prohibited.']);
857 waitForCallback('deleteFailed', testDone
);
861 * Fixture for History WebUI testing IDN.
862 * @extends {BaseHistoryWebUITest}
865 function HistoryWebUIIDNTest() {}
867 HistoryWebUIIDNTest
.prototype = {
868 __proto__
: BaseHistoryWebUITest
.prototype,
871 testGenPreamble: function() {
872 // Add some visits to the history database.
873 GEN(' AddPageToHistory(0, "http://xn--d1abbgf6aiiy.xn--p1ai/",' +
876 // Clear AcceptLanguages to get domain in unicode.
877 GEN(' ClearAcceptLanguages();');
882 * Simple test that verifies that the correct entries are retrieved from the
883 * history database and displayed in the UI.
885 TEST_F('HistoryWebUIIDNTest', 'basic', function() {
886 // Check that there is only one entry and domain is in unicode.
887 assertEquals(1, document
.querySelectorAll('.domain').length
);
888 assertEquals("\u043f\u0440\u0435\u0437\u0438\u0434\u0435\u043d\u0442." +
889 "\u0440\u0444", document
.querySelector('.domain').textContent
);
895 * Fixture for a test that uses the real backend and tests how the history
896 * page deals with odd schemes in URLs.
898 function HistoryWebUIWithSchemesTest() {}
900 HistoryWebUIWithSchemesTest
.prototype = {
901 __proto__
: HistoryWebUIRealBackendTest
.prototype,
904 testGenPreamble: function() {
905 // Add a bunch of entries on the same day, including some weird schemes.
906 GEN(' AddPageToHistory(12, "http://google.com", "Google");');
907 GEN(' AddPageToHistory(13, "file:///tmp/foo", "");');
908 GEN(' AddPageToHistory(14, "mailto:chromium@chromium.org", "");');
909 GEN(' AddPageToHistory(15, "tel:555123456", "");');
913 // Show the filter controls as if the command line switch was active.
914 $('top-container').hidden
= true;
915 $('history-page').classList
.add('big-topbar-page');
916 $('filter-controls').hidden
= false;
917 expectFalse($('filter-controls').hidden
);
921 TEST_F('HistoryWebUIWithSchemesTest', 'groupingWithSchemes', function() {
922 // Switch to the week view.
923 $('timeframe-filter-week').click();
924 waitForCallback('historyResult', function() {
925 // Each URL should be organized under a different "domain".
926 expectEquals(document
.querySelectorAll('.entry').length
, 4);
927 expectEquals(document
.querySelectorAll('.site-domain-wrapper').length
, 4);