diff --git a/test/e2e/resources/search/search.css b/test/e2e/resources/search/search.css
new file mode 100644
index 0000000000..1946bce2e4
--- /dev/null
+++ b/test/e2e/resources/search/search.css
@@ -0,0 +1,10 @@
+div.searchTestUniqueString {
+ background-color: red;
+}
+
+div.searchTestUniqueString:hover {
+ /* another searchTestUniqueString occurence */
+ background-color: red;
+}
+
+/* searchTestUnique space String */
diff --git a/test/e2e/resources/search/search.html b/test/e2e/resources/search/search.html
new file mode 100644
index 0000000000..d8cd25c89c
--- /dev/null
+++ b/test/e2e/resources/search/search.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+searchTestUniqueString
+other text
+
+some other text
+div text
+
+
+
+
diff --git a/test/e2e/resources/search/search.js b/test/e2e/resources/search/search.js
new file mode 100644
index 0000000000..3d6968e3e0
--- /dev/null
+++ b/test/e2e/resources/search/search.js
@@ -0,0 +1,26 @@
+function searchTestUniqueString() {
+ var variable = 0;
+ // searchTestUniqueString two occurences on the same line searchTestUniqueString
+ // searchTestUniqueString on the next line.
+ var variable2 = 0;
+}
+
+function doSomething() {
+ searchTestUniqueString();
+ // SEARCHTestUniqueString();
+}
+
+// searchTestUnique space String
+// AAAAAAAAAAA 11xA here
+
+// replaceMe1
+// replaceMe2 replaceMe2
+
+// REPLACEME1
+// REPLACEME2 REPLACEME2
+
+
+// replaceMe3
+// replaceMe4 replaceMe4
+// REPLACEME3
+// REPLACEME4 REPLACEME4
diff --git a/test/e2e/search/search-helpers.ts b/test/e2e/search/search-helpers.ts
new file mode 100644
index 0000000000..0b784f2765
--- /dev/null
+++ b/test/e2e/search/search-helpers.ts
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import * as puppeteer from 'puppeteer';
+
+import {platform} from '../../shared/helper.js';
+
+export async function triggerFindDialog(frontend: puppeteer.Page) {
+ switch (platform) {
+ case 'mac':
+ await frontend.keyboard.down('Meta');
+ await frontend.keyboard.down('Alt');
+ break;
+
+ default:
+ await frontend.keyboard.down('Ctrl');
+ await frontend.keyboard.down('Shift');
+ }
+
+ await frontend.keyboard.press('f');
+
+ switch (platform) {
+ case 'mac':
+ await frontend.keyboard.up('Meta');
+ await frontend.keyboard.up('Alt');
+ break;
+
+ default:
+ await frontend.keyboard.up('Ctrl');
+ await frontend.keyboard.up('Shift');
+ }
+}
diff --git a/test/e2e/search/search-scope.ts b/test/e2e/search/search-scope.ts
new file mode 100644
index 0000000000..ca0c2da316
--- /dev/null
+++ b/test/e2e/search/search-scope.ts
@@ -0,0 +1,88 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {assert} from 'chai';
+import {describe, it} from 'mocha';
+import {$, $$, getBrowserAndPages, resetPages, resourcesPath, waitFor} from '../../shared/helper.js';
+import {triggerFindDialog} from './search-helpers.js';
+
+describe('The Search Panel', async () => {
+ beforeEach(async () => {
+ await resetPages();
+ });
+
+ it('provides results across scopes', async () => {
+ const {target, frontend} = getBrowserAndPages();
+ const SEARCH_QUERY = '[aria-label="Search Query"]';
+ const SEARCH_RESULTS = '.search-results';
+ const SEARCH_FILE_RESULT = '.search-result';
+ const SEARCH_CHILDREN_RESULT = '.search-match-link';
+
+ // Load the search page, which has results in the HTML, JS, and CSS.
+ await target.goto(`${resourcesPath}/search/search.html`);
+
+ // Launch the search panel.
+ await triggerFindDialog(frontend);
+ await waitFor(SEARCH_QUERY);
+ const query = await $(SEARCH_QUERY);
+ const inputElement = query.asElement();
+ if (!inputElement) {
+ assert.fail('Unable to find search input field');
+ return;
+ }
+
+ // Go ahead and search.
+ await inputElement.focus();
+ await inputElement.type('searchTestUniqueString');
+ await frontend.keyboard.press('Enter');
+
+ // Wait for results.
+ await waitFor(SEARCH_RESULTS);
+ const resultsContainer = await $(SEARCH_RESULTS);
+ await waitFor(SEARCH_FILE_RESULT, resultsContainer);
+
+ // Process the results into something manageable.
+ const fileResults = await $$(SEARCH_FILE_RESULT, resultsContainer);
+ const files = await fileResults.evaluate(result => result.map((value: Element) => {
+ const SEARCH_RESULT_FILE_NAME = '.search-result-file-name';
+ const SEARCH_RESULT_MATCHES_COUNT = '.search-result-matches-count';
+
+ // Wrap the entries with the file details.
+ return {
+ fileName: value.querySelector(SEARCH_RESULT_FILE_NAME)!.firstChild!.textContent,
+ matchesCount: value.querySelector(SEARCH_RESULT_MATCHES_COUNT)!.textContent,
+ };
+ }));
+
+ assert.deepEqual(files, [
+ {fileName: 'search.css', matchesCount: '3'}, {fileName: 'search.js', matchesCount: '5'},
+ {fileName: 'search.html', matchesCount: '4'},
+ ]);
+
+ // Now step through the actual entries of the search result.
+ const entryResults = await $$(SEARCH_CHILDREN_RESULT, resultsContainer);
+ const entries = await entryResults.evaluate(result => result.map((value: Element) => {
+ const SEARCH_MATCH_LINE_NUMBER = '.search-match-line-number';
+ const SEARCH_MATCH_CONTENT = '.search-match-content';
+
+ return {
+ line: value.querySelector(SEARCH_MATCH_LINE_NUMBER)!.textContent,
+ content: value.querySelector(SEARCH_MATCH_CONTENT)!.textContent,
+ };
+ }));
+
+ assert.deepEqual(entries, [
+ {line: '1', content: 'div.searchTestUniqueString {'}, {line: '5', content: 'div.searchTestUniqueString:hover {'},
+ {line: '6', content: '/* another searchTestUniqueString occurence */'},
+ {line: '1', content: 'function searchTestUniqueString() {'},
+ {line: '3', content: '// searchTestUniqueString two occurences on the same line searchTestUniqueString'},
+ {line: '4', content: '// searchTestUniqueString on the next line.'},
+ {line: '9', content: 'searchTestUniqueString();'}, {line: '10', content: '// SEARCHTestUniqueString();'},
+ {line: '5', content: '…eval("function searchTestUniqueString() {}");'},
+ {line: '7', content: 'searchTestUniqueString
'},
+ {line: '9', content: ''},
+ {line: '11', content: 'div text
'},
+ ]);
+ });
+});
diff --git a/test/shared/helper.ts b/test/shared/helper.ts
index f0ec5693d0..feb3bc6978 100644
--- a/test/shared/helper.ts
+++ b/test/shared/helper.ts
@@ -6,6 +6,22 @@ import * as fs from 'fs';
import {join} from 'path';
import {performance} from 'perf_hooks';
import * as puppeteer from 'puppeteer';
+import * as os from 'os';
+
+export let platform: string;
+switch (os.platform()) {
+ case 'darwin':
+ platform = 'mac';
+ break;
+
+ case 'win32':
+ platform = 'win32';
+ break;
+
+ default:
+ platform = 'linux';
+ break;
+}
interface BrowserAndPages {
browser: puppeteer.Browser;
diff --git a/test/shared/screenshot.ts b/test/shared/screenshot.ts
index 945f2197e4..6db61de869 100644
--- a/test/shared/screenshot.ts
+++ b/test/shared/screenshot.ts
@@ -8,28 +8,12 @@
import {assert} from 'chai';
import * as childProcess from 'child_process';
import * as fs from 'fs';
-import * as os from 'os';
import * as path from 'path';
import {join} from 'path';
import * as puppeteer from 'puppeteer';
import * as rimraf from 'rimraf';
-import {getBrowserAndPages, mkdirp} from './helper.js';
-
-let platform: string;
-switch (os.platform()) {
- case 'darwin':
- platform = 'mac';
- break;
-
- case 'win32':
- platform = 'win32';
- break;
-
- default:
- platform = 'linux';
- break;
-}
+import {getBrowserAndPages, mkdirp, platform} from './helper.js';
const goldensScreenshotFolderParts = ['..', 'screenshots', 'goldens', platform];
const goldensScreenshotFolder = join(__dirname, ...goldensScreenshotFolderParts);