blob: 681ccdf2194b0aa78cc640911668c6b64462aa7a [file] [log] [blame]
Adam Raineb1ac4232022-07-21 12:13:29 -07001// Copyright 2022 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.
4
5import {assert} from 'chai';
6
7import {expectError} from '../../conductor/events.js';
Adam Raine2a9afbc2022-11-30 10:28:58 -08008import {
9 $textContent,
10 getBrowserAndPages,
11 setDevToolsSettings,
12 waitFor,
13 waitForElementWithTextContent,
14} from '../../shared/helper.js';
Adam Raineb1ac4232022-07-21 12:13:29 -070015import {describe, it} from '../../shared/mocha-extensions.js';
16import {
17 clickStartButton,
18 getAuditsBreakdown,
Adam Raine3983f182022-10-11 09:11:06 -070019 getServiceWorkerCount,
Adam Raine242a8622022-10-12 09:56:47 -070020 interceptNextFileSave,
Adam Raineb1ac4232022-07-21 12:13:29 -070021 navigateToLighthouseTab,
Adam Raine3983f182022-10-11 09:11:06 -070022 registerServiceWorker,
Adam Raine242a8622022-10-12 09:56:47 -070023 renderHtmlInIframe,
Adam Rainea708e012022-08-10 09:58:23 -070024 selectCategories,
Adam Rainebf8654c2022-09-13 13:24:07 -070025 selectDevice,
Adam Raineb1ac4232022-07-21 12:13:29 -070026 setLegacyNavigation,
27 setThrottlingMethod,
Adam Raineda3fa692022-09-06 17:47:28 -070028 setToolbarCheckboxWithText,
Danil Somsikovde4ef172022-11-30 18:29:55 +010029 unregisterAllServiceWorkers,
Adam Raineb1ac4232022-07-21 12:13:29 -070030 waitForResult,
31} from '../helpers/lighthouse-helpers.js';
32
33// This test will fail (by default) in headful mode, as the target page never gets painted.
34// To resolve this when debugging, just make sure the target page is visible during the lighthouse run.
35
Adam Rainecd6d4492022-07-27 12:01:36 -070036describe('Navigation', async function() {
Adam Raineb1ac4232022-07-21 12:13:29 -070037 // The tests in this suite are particularly slow
38 this.timeout(60_000);
39
Adam Raine62373ba2022-10-31 16:34:25 -070040 beforeEach(() => {
Adam Rainede6c4e52023-02-09 14:10:42 -080041 // https://github.com/GoogleChrome/lighthouse/issues/14572
42 expectError(/Request CacheStorage\.requestCacheNames failed/);
43
Adam Raine62373ba2022-10-31 16:34:25 -070044 // https://bugs.chromium.org/p/chromium/issues/detail?id=1357791
45 expectError(/Protocol Error: the message with wrong session id/);
46 expectError(/Protocol Error: the message with wrong session id/);
47 expectError(/Protocol Error: the message with wrong session id/);
48 expectError(/Protocol Error: the message with wrong session id/);
49 expectError(/Protocol Error: the message with wrong session id/);
50 });
51
Danil Somsikovde4ef172022-11-30 18:29:55 +010052 afterEach(async () => {
53 await unregisterAllServiceWorkers();
54 });
55
Adam Raineb1ac4232022-07-21 12:13:29 -070056 const modes = ['legacy', 'FR'];
57
58 for (const mode of modes) {
59 describe(`in ${mode} mode`, () => {
Adam Raineb1ac4232022-07-21 12:13:29 -070060 it('successfully returns a Lighthouse report', async () => {
61 await navigateToLighthouseTab('lighthouse/hello.html');
Adam Raine3983f182022-10-11 09:11:06 -070062 await registerServiceWorker();
Adam Raineb1ac4232022-07-21 12:13:29 -070063
64 await setLegacyNavigation(mode === 'legacy');
Adam Raine7179cf52022-09-29 13:09:37 -070065 await selectCategories([
66 'performance',
67 'accessibility',
68 'best-practices',
69 'seo',
70 'pwa',
71 'lighthouse-plugin-publisher-ads',
72 ]);
Adam Rainea708e012022-08-10 09:58:23 -070073
Adam Rainef25ab502022-10-17 12:54:06 -070074 let numNavigations = 0;
75 const {target} = await getBrowserAndPages();
76 target.on('framenavigated', () => ++numNavigations);
77
Adam Raineb1ac4232022-07-21 12:13:29 -070078 await clickStartButton();
79
80 const {lhr, artifacts, reportEl} = await waitForResult();
81
Adam Rainef25ab502022-10-17 12:54:06 -070082 if (mode === 'legacy') {
83 // 1 initial about:blank jump
84 // 1 about:blank jump + 1 navigation for the default pass
85 // 1 about:blank jump + 1 navigation for the offline pass
Adam Rainede6c4e52023-02-09 14:10:42 -080086 // 2 navigations to go to chrome://terms and back testing bfcache
Adam Rainef25ab502022-10-17 12:54:06 -070087 // 1 navigation after auditing to reset state
Adam Rainede6c4e52023-02-09 14:10:42 -080088 assert.strictEqual(numNavigations, 8);
Adam Rainef25ab502022-10-17 12:54:06 -070089 } else {
90 // 1 initial about:blank jump
91 // 1 about:blank jump + 1 navigation for the default pass
Adam Rainede6c4e52023-02-09 14:10:42 -080092 // 2 navigations to go to chrome://terms and back testing bfcache
Adam Rainef25ab502022-10-17 12:54:06 -070093 // 1 navigation after auditing to reset state
Adam Rainede6c4e52023-02-09 14:10:42 -080094 assert.strictEqual(numNavigations, 6);
Adam Rainef25ab502022-10-17 12:54:06 -070095 }
96
Adam Rainede6c4e52023-02-09 14:10:42 -080097 assert.strictEqual(lhr.lighthouseVersion, '10.0.0');
Adam Raineb1ac4232022-07-21 12:13:29 -070098 assert.match(lhr.finalUrl, /^https:\/\/localhost:[0-9]+\/test\/e2e\/resources\/lighthouse\/hello.html/);
Adam Raine4515db62022-09-28 16:37:20 -070099
Adam Raineb1ac4232022-07-21 12:13:29 -0700100 assert.strictEqual(lhr.configSettings.throttlingMethod, 'simulate');
Adam Rainea708e012022-08-10 09:58:23 -0700101 assert.strictEqual(lhr.configSettings.disableStorageReset, false);
102 assert.strictEqual(lhr.configSettings.formFactor, 'mobile');
Adam Raine4515db62022-09-28 16:37:20 -0700103 assert.strictEqual(lhr.configSettings.throttling.rttMs, 150);
104 assert.strictEqual(lhr.configSettings.screenEmulation.disabled, true);
105 assert.include(lhr.configSettings.emulatedUserAgent, 'Mobile');
Adam Rainede6c4e52023-02-09 14:10:42 -0800106 assert.include(lhr.environment.networkUserAgent, 'Mobile');
Adam Raine4515db62022-09-28 16:37:20 -0700107
108 assert.deepStrictEqual(artifacts.ViewportDimensions, {
Adam Raine14274762023-02-02 13:07:07 -0800109 innerHeight: 823,
110 innerWidth: 412,
111 outerHeight: 823,
112 outerWidth: 412,
113 devicePixelRatio: 1.75,
Adam Raine4515db62022-09-28 16:37:20 -0700114 });
Adam Raineb1ac4232022-07-21 12:13:29 -0700115
116 const {auditResults, erroredAudits, failedAudits} = getAuditsBreakdown(lhr);
Adam Rainede6c4e52023-02-09 14:10:42 -0800117 assert.strictEqual(auditResults.length, 173);
118 assert.deepStrictEqual(erroredAudits, []);
Adam Raineb1ac4232022-07-21 12:13:29 -0700119 assert.deepStrictEqual(failedAudits.map(audit => audit.id), [
120 'service-worker',
Adam Raineb1ac4232022-07-21 12:13:29 -0700121 'installable-manifest',
Adam Raineb1ac4232022-07-21 12:13:29 -0700122 'splash-screen',
123 'themed-omnibox',
124 'maskable-icon',
Adam Raineb1ac4232022-07-21 12:13:29 -0700125 'document-title',
126 'html-has-lang',
127 'meta-description',
Adam Rainede6c4e52023-02-09 14:10:42 -0800128 'bf-cache',
Adam Raineb1ac4232022-07-21 12:13:29 -0700129 ]);
130
Adam Raine2a9afbc2022-11-30 10:28:58 -0800131 const viewTraceButton = await $textContent('View Original Trace', reportEl);
132 if (!viewTraceButton) {
133 throw new Error('Could not find view trace button');
134 }
Adam Raine2fcf01b2022-10-04 15:17:38 -0700135
Adam Raine2a9afbc2022-11-30 10:28:58 -0800136 // Test view trace button behavior
Adam Raine2fcf01b2022-10-04 15:17:38 -0700137 await viewTraceButton.click();
Adam Raine2a9afbc2022-11-30 10:28:58 -0800138 let selectedTab = await waitFor('.tabbed-pane-header-tab.selected[aria-label="Performance"]');
139 let selectedTabText = await selectedTab.evaluate(selectedTabEl => {
Adam Raine2fcf01b2022-10-04 15:17:38 -0700140 return selectedTabEl.textContent;
141 });
142 assert.strictEqual(selectedTabText, 'Performance');
Adam Raine3983f182022-10-11 09:11:06 -0700143
Adam Raine242a8622022-10-12 09:56:47 -0700144 await navigateToLighthouseTab();
145
Adam Raine2a9afbc2022-11-30 10:28:58 -0800146 // Test element link behavior
147 const lcpElementAudit = await waitForElementWithTextContent('Largest Contentful Paint element', reportEl);
148 await lcpElementAudit.click();
149 const lcpElementLink = await waitForElementWithTextContent('button');
150 await lcpElementLink.click();
151
152 selectedTab = await waitFor('.tabbed-pane-header-tab.selected[aria-label="Elements"]');
153 selectedTabText = await selectedTab.evaluate(selectedTabEl => {
154 return selectedTabEl.textContent;
155 });
156 assert.strictEqual(selectedTabText, 'Elements');
157
Adam Raine242a8622022-10-12 09:56:47 -0700158 const waitForJson = await interceptNextFileSave();
159
160 // For some reason the CDP click command doesn't work here even if the tools menu is open.
Connor Clark76abfb32022-11-03 15:50:41 -0700161 await reportEl.$eval(
162 'a[data-action="save-json"]:not(.hidden)', saveJsonEl => (saveJsonEl as HTMLElement).click());
Adam Raine242a8622022-10-12 09:56:47 -0700163
164 const jsonContent = await waitForJson();
165 assert.strictEqual(jsonContent, JSON.stringify(lhr, null, 2));
166
167 const waitForHtml = await interceptNextFileSave();
168
169 // For some reason the CDP click command doesn't work here even if the tools menu is open.
Connor Clark76abfb32022-11-03 15:50:41 -0700170 await reportEl.$eval(
171 'a[data-action="save-html"]:not(.hidden)', saveHtmlEl => (saveHtmlEl as HTMLElement).click());
Adam Raine242a8622022-10-12 09:56:47 -0700172
173 const htmlContent = await waitForHtml();
174 const iframeHandle = await renderHtmlInIframe(htmlContent);
175 const iframeAuditDivs = await iframeHandle.$$('.lh-audit');
176 const frontendAuditDivs = await reportEl.$$('.lh-audit');
177 assert.strictEqual(frontendAuditDivs.length, iframeAuditDivs.length);
178
Adam Raine3983f182022-10-11 09:11:06 -0700179 // Ensure service worker was cleared.
180 assert.strictEqual(await getServiceWorkerCount(), 0);
Adam Raineb1ac4232022-07-21 12:13:29 -0700181 });
182
183 it('successfully returns a Lighthouse report with DevTools throttling', async () => {
184 await navigateToLighthouseTab('lighthouse/hello.html');
185
186 await setThrottlingMethod('devtools');
187 await setLegacyNavigation(mode === 'legacy');
Adam Rainea708e012022-08-10 09:58:23 -0700188
Adam Raineb1ac4232022-07-21 12:13:29 -0700189 await clickStartButton();
190
191 const {lhr, reportEl} = await waitForResult();
192
193 assert.strictEqual(lhr.configSettings.throttlingMethod, 'devtools');
194
Adam Rainecd6d4492022-07-27 12:01:36 -0700195 // [crbug.com/1347220] DevTools throttling can force resources to load slow enough for these audits to fail sometimes.
196 const flakyAudits = [
197 'server-response-time',
198 'render-blocking-resources',
199 ];
200
201 const {auditResults, erroredAudits, failedAudits} = getAuditsBreakdown(lhr, flakyAudits);
Adam Rainede6c4e52023-02-09 14:10:42 -0800202 assert.strictEqual(auditResults.length, 150);
203 assert.deepStrictEqual(erroredAudits, []);
Adam Raineb1ac4232022-07-21 12:13:29 -0700204 assert.deepStrictEqual(failedAudits.map(audit => audit.id), [
205 'service-worker',
Adam Raineb1ac4232022-07-21 12:13:29 -0700206 'installable-manifest',
Adam Raineb1ac4232022-07-21 12:13:29 -0700207 'splash-screen',
208 'themed-omnibox',
209 'maskable-icon',
Adam Raineb1ac4232022-07-21 12:13:29 -0700210 'document-title',
211 'html-has-lang',
212 'meta-description',
Adam Rainede6c4e52023-02-09 14:10:42 -0800213 'bf-cache',
Adam Raineb1ac4232022-07-21 12:13:29 -0700214 ]);
215
Adam Raine2a9afbc2022-11-30 10:28:58 -0800216 const viewTraceButton = await $textContent('View Trace', reportEl);
217 assert.ok(viewTraceButton);
Adam Raineb1ac4232022-07-21 12:13:29 -0700218 });
Adam Rainea708e012022-08-10 09:58:23 -0700219
220 it('successfully returns a Lighthouse report when settings changed', async () => {
Adam Rained34ecbc2022-10-10 11:33:44 -0700221 await setDevToolsSettings({language: 'es'});
Adam Rainea708e012022-08-10 09:58:23 -0700222 await navigateToLighthouseTab('lighthouse/hello.html');
Adam Raine3983f182022-10-11 09:11:06 -0700223 await registerServiceWorker();
Adam Rainea708e012022-08-10 09:58:23 -0700224
Adam Rained34ecbc2022-10-10 11:33:44 -0700225 await setToolbarCheckboxWithText(mode === 'legacy', 'Navegación antigua');
226 await setToolbarCheckboxWithText(false, 'Borrar almacenamiento');
Adam Rainea708e012022-08-10 09:58:23 -0700227 await selectCategories(['performance', 'best-practices']);
Adam Rainebf8654c2022-09-13 13:24:07 -0700228 await selectDevice('desktop');
Adam Rainea708e012022-08-10 09:58:23 -0700229
230 await clickStartButton();
231
Adam Raineda3fa692022-09-06 17:47:28 -0700232 const {reportEl, lhr, artifacts} = await waitForResult();
Adam Rainea708e012022-08-10 09:58:23 -0700233
234 const {innerWidth, innerHeight, devicePixelRatio} = artifacts.ViewportDimensions;
235 // TODO: Figure out why outerHeight can be different depending on OS
236 assert.strictEqual(innerHeight, 720);
237 assert.strictEqual(innerWidth, 1280);
238 assert.strictEqual(devicePixelRatio, 1);
239
240 const {erroredAudits} = getAuditsBreakdown(lhr);
Adam Rainede6c4e52023-02-09 14:10:42 -0800241 assert.deepStrictEqual(erroredAudits, []);
Adam Rainea708e012022-08-10 09:58:23 -0700242
243 assert.deepStrictEqual(Object.keys(lhr.categories), ['performance', 'best-practices']);
244 assert.strictEqual(lhr.configSettings.disableStorageReset, true);
245 assert.strictEqual(lhr.configSettings.formFactor, 'desktop');
Adam Raine4515db62022-09-28 16:37:20 -0700246 assert.strictEqual(lhr.configSettings.throttling.rttMs, 40);
247 assert.strictEqual(lhr.configSettings.screenEmulation.disabled, true);
248 assert.notInclude(lhr.configSettings.emulatedUserAgent, 'Mobile');
Adam Rainede6c4e52023-02-09 14:10:42 -0800249 assert.notInclude(lhr.environment.networkUserAgent, 'Mobile');
Adam Raine4515db62022-09-28 16:37:20 -0700250
Adam Rainede6c4e52023-02-09 14:10:42 -0800251 const viewTraceButton = await $textContent('Ver rastro original', reportEl);
Adam Raine2a9afbc2022-11-30 10:28:58 -0800252 assert.ok(viewTraceButton);
Adam Raineda3fa692022-09-06 17:47:28 -0700253
Adam Rained34ecbc2022-10-10 11:33:44 -0700254 const footerIssueText = await reportEl.$eval('.lh-footer__version_issue', footerIssueEl => {
255 return footerIssueEl.textContent;
256 });
257 assert.strictEqual(lhr.i18n.rendererFormattedStrings.footerIssue, 'Notificar un problema');
258 assert.strictEqual(footerIssueText, 'Notificar un problema');
Adam Raine3983f182022-10-11 09:11:06 -0700259
260 // Ensure service worker is not cleared because we disable the storage reset.
261 assert.strictEqual(await getServiceWorkerCount(), 1);
Adam Rainea708e012022-08-10 09:58:23 -0700262 });
Adam Raineb1ac4232022-07-21 12:13:29 -0700263 });
264 }
265});