diff --git a/assets/js/components/ReportError.js b/assets/js/components/ReportError.js index 25fb8071288..2ee6b853dc5 100644 --- a/assets/js/components/ReportError.js +++ b/assets/js/components/ReportError.js @@ -25,66 +25,34 @@ import uniqWith from 'lodash/uniqWith'; /** * WordPress dependencies */ -import { Fragment, useCallback } from '@wordpress/element'; +import { Fragment } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; /** * Internal dependencies */ import Data from 'googlesitekit-data'; -import { Button } from 'googlesitekit-components'; import { CORE_MODULES } from '../googlesitekit/modules/datastore/constants'; import { - isErrorRetryable, isInsufficientPermissionsError, + getReportErrorMessage, } from '../util/errors'; import { getInsufficientPermissionsErrorDescription } from '../util/insufficient-permissions-error-description'; import { purify } from '../util/purify'; import ErrorText from '../components/ErrorText'; import CTA from './notifications/CTA'; -import Link from './Link'; -import { CORE_SITE } from '../googlesitekit/datastore/site/constants'; +import ReportErrorActions from './ReportErrorActions'; import useViewOnly from '../hooks/useViewOnly'; -const { useSelect, useDispatch } = Data; +const { useSelect } = Data; export default function ReportError( { moduleSlug, error } ) { const isViewOnly = useViewOnly(); const module = useSelect( ( select ) => select( CORE_MODULES ).getModule( moduleSlug ) ); - const storeName = useSelect( ( select ) => - select( CORE_MODULES ).getModuleStoreName( moduleSlug ) - ); - const requestAccessURL = useSelect( ( select ) => - typeof select( storeName )?.getServiceEntityAccessURL === 'function' - ? select( storeName ).getServiceEntityAccessURL() - : null - ); const errors = Array.isArray( error ) ? error : [ error ]; - const retryableErrors = errors.filter( - ( err ) => - isErrorRetryable( err, err.selectorData ) && - err.selectorData.name === 'getReport' - ); - - const showRetry = !! retryableErrors.length && ! isViewOnly; - - const errorTroubleshootingLinkURL = useSelect( ( select ) => { - const err = { - ...( showRetry ? retryableErrors[ 0 ] : errors[ 0 ] ), - }; - - if ( isInsufficientPermissionsError( err ) ) { - err.code = `${ moduleSlug }_insufficient_permissions`; - } - - return select( CORE_SITE ).getErrorTroubleshootingLinkURL( err ); - } ); - - const dispatch = useDispatch(); - let title; const getMessage = ( err ) => { @@ -116,7 +84,7 @@ export default function ReportError( { moduleSlug, error } ) { ); } - return err.message; + return getReportErrorMessage( err ); }; const uniqueErrors = uniqWith( @@ -167,45 +135,9 @@ export default function ReportError( { moduleSlug, error } ) { ); - const handleRetry = useCallback( () => { - retryableErrors.forEach( ( err ) => { - const { selectorData } = err; - dispatch( selectorData.storeName ).invalidateResolution( - selectorData.name, - selectorData.args - ); - } ); - }, [ dispatch, retryableErrors ] ); - - const showRequestAccessURL = - requestAccessURL && hasInsufficientPermissionsError && ! isViewOnly; - return ( -
- { showRequestAccessURL && ( - - ) } - { showRetry ? ( - - - - { __( 'Retry didn’t work?', 'google-site-kit' ) }{ ' ' } - - - { __( 'Get help', 'google-site-kit' ) } - - - ) : ( - - { __( 'Get help', 'google-site-kit' ) } - - ) } -
+
); } diff --git a/assets/js/components/ReportError.stories.js b/assets/js/components/ReportError.stories.js index 4278052e28f..e64a235c2a2 100644 --- a/assets/js/components/ReportError.stories.js +++ b/assets/js/components/ReportError.stories.js @@ -252,6 +252,28 @@ MultipleUniqueReportErrorsWithRetryButtonWith.args = { ], }; +export const ReportErrorWithCustomInternalServerErrorMessage = Template.bind( + {} +); +ReportErrorWithCustomInternalServerErrorMessage.storyName = + 'ReportError with custom Internal Server Error message'; +ReportErrorWithCustomInternalServerErrorMessage.args = { + error: { + code: 'internal_server_error', + message: 'Test error message', + }, +}; + +export const ReportErrorWithCustomInvalidJSONMessage = Template.bind( {} ); +ReportErrorWithCustomInvalidJSONMessage.storyName = + 'ReportError with custom Invalid JSON message'; +ReportErrorWithCustomInvalidJSONMessage.args = { + error: { + code: 'invalid_json', + message: 'Test error message', + }, +}; + export const ReportErrorViewOnlyMode = Template.bind( {} ); ReportErrorViewOnlyMode.storyName = 'ReportError with ViewOnly Mode'; ReportErrorViewOnlyMode.args = { diff --git a/assets/js/components/ReportErrorActions.js b/assets/js/components/ReportErrorActions.js new file mode 100644 index 00000000000..c0327f7b554 --- /dev/null +++ b/assets/js/components/ReportErrorActions.js @@ -0,0 +1,148 @@ +/** + * ReportErrorActions component. + * + * Site Kit by Google, Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * External dependencies + */ +import PropTypes from 'prop-types'; + +/** + * WordPress dependencies + */ +import { + createInterpolateElement, + Fragment, + useCallback, +} from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import Data from 'googlesitekit-data'; +import { Button } from 'googlesitekit-components'; +import { CORE_SITE } from '../googlesitekit/datastore/site/constants'; +import { CORE_MODULES } from '../googlesitekit/modules/datastore/constants'; +import { + isErrorRetryable, + isInsufficientPermissionsError, +} from '../util/errors'; +import useViewOnly from '../hooks/useViewOnly'; +import Link from './Link'; + +const { useSelect, useDispatch } = Data; + +export default function ReportErrorActions( { moduleSlug, error } ) { + const isViewOnly = useViewOnly(); + const storeName = useSelect( ( select ) => + select( CORE_MODULES ).getModuleStoreName( moduleSlug ) + ); + const requestAccessURL = useSelect( ( select ) => + typeof select( storeName )?.getServiceEntityAccessURL === 'function' + ? select( storeName ).getServiceEntityAccessURL() + : null + ); + + const errors = Array.isArray( error ) ? error : [ error ]; + + const retryableErrors = errors.filter( + ( err ) => + isErrorRetryable( err, err.selectorData ) && + err.selectorData.name === 'getReport' + ); + + const showRetry = !! retryableErrors.length && ! isViewOnly; + + const errorTroubleshootingLinkURL = useSelect( ( select ) => { + const err = { + ...( showRetry ? retryableErrors[ 0 ] : errors[ 0 ] ), + }; + + if ( isInsufficientPermissionsError( err ) ) { + err.code = `${ moduleSlug }_insufficient_permissions`; + } + + return select( CORE_SITE ).getErrorTroubleshootingLinkURL( err ); + } ); + + const dispatch = useDispatch(); + + const hasInsufficientPermissionsError = errors.some( ( err ) => + isInsufficientPermissionsError( err ) + ); + + const handleRetry = useCallback( () => { + retryableErrors.forEach( ( err ) => { + const { selectorData } = err; + dispatch( selectorData.storeName ).invalidateResolution( + selectorData.name, + selectorData.args + ); + } ); + }, [ dispatch, retryableErrors ] ); + + const showRequestAccessURL = + requestAccessURL && hasInsufficientPermissionsError && ! isViewOnly; + + return ( +
+ { showRequestAccessURL && ( + + ) } + { showRetry ? ( + + + + { createInterpolateElement( + __( + 'Retry didn’t work? ', + 'google-site-kit' + ), + { + HelpLink: ( + + { __( 'Get help', 'google-site-kit' ) } + + ), + } + ) } + + + ) : ( + + { __( 'Get help', 'google-site-kit' ) } + + ) } +
+ ); +} + +ReportErrorActions.propTypes = { + moduleSlug: PropTypes.string.isRequired, + error: PropTypes.oneOfType( [ + PropTypes.arrayOf( PropTypes.object ), + PropTypes.object, + ] ).isRequired, +}; diff --git a/assets/js/modules/pagespeed-insights/components/common/FieldReportMetrics.js b/assets/js/modules/pagespeed-insights/components/common/FieldReportMetrics.js index 6ab60b1d5ea..91bf95e22b1 100644 --- a/assets/js/modules/pagespeed-insights/components/common/FieldReportMetrics.js +++ b/assets/js/modules/pagespeed-insights/components/common/FieldReportMetrics.js @@ -33,6 +33,8 @@ import { __, _x, sprintf } from '@wordpress/i18n'; import ReportMetric from './ReportMetric'; import MetricsLearnMoreLink from './MetricsLearnMoreLink'; import ErrorText from '../../../../components/ErrorText'; +import ReportErrorActions from '../../../../components/ReportErrorActions'; +import { getReportErrorMessage } from '../../../../util/errors'; import { CATEGORY_AVERAGE } from '../../util/constants'; export default function FieldReportMetrics( { data, error } ) { @@ -44,10 +46,17 @@ export default function FieldReportMetrics( { data, error } ) { } = data?.loadingExperience?.metrics || {}; if ( error ) { + const errorMessage = getReportErrorMessage( error ); + return (
-
- +
+ + +
); diff --git a/assets/js/modules/pagespeed-insights/components/common/LabReportMetrics.js b/assets/js/modules/pagespeed-insights/components/common/LabReportMetrics.js index 3d0202b732f..e68e9d5d732 100644 --- a/assets/js/modules/pagespeed-insights/components/common/LabReportMetrics.js +++ b/assets/js/modules/pagespeed-insights/components/common/LabReportMetrics.js @@ -33,6 +33,8 @@ import ReportMetric from './ReportMetric'; import MetricsLearnMoreLink from './MetricsLearnMoreLink'; import { getScoreCategory } from '../../util'; import { CATEGORY_AVERAGE } from '../../util/constants'; +import { getReportErrorMessage } from '../../../../util/errors'; +import ReportErrorActions from '../../../../components/ReportErrorActions'; import ErrorText from '../../../../components/ErrorText'; export default function LabReportMetrics( { data, error } ) { @@ -44,10 +46,17 @@ export default function LabReportMetrics( { data, error } ) { data?.lighthouseResult?.audits?.[ 'total-blocking-time' ]; if ( error ) { + const errorMessage = getReportErrorMessage( error ); + return (
-
- +
+ + +
); diff --git a/assets/js/modules/pagespeed-insights/components/dashboard/DashboardPageSpeedWidget.stories.js b/assets/js/modules/pagespeed-insights/components/dashboard/DashboardPageSpeedWidget.stories.js new file mode 100644 index 00000000000..e5ec47e458e --- /dev/null +++ b/assets/js/modules/pagespeed-insights/components/dashboard/DashboardPageSpeedWidget.stories.js @@ -0,0 +1,222 @@ +/** + * PageSpeed Insights Module Component Stories. + * + * Site Kit by Google, Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Internal dependencies + */ +import { + freezeFetch, + provideModules, + provideSiteInfo, +} from '../../../../../../tests/js/utils'; +import { withWidgetComponentProps } from '../../../../googlesitekit/widgets/util'; +import { + MODULES_PAGESPEED_INSIGHTS, + STRATEGY_MOBILE, + STRATEGY_DESKTOP, +} from '../../datastore/constants'; +import WithRegistrySetup from '../../../../../../tests/js/WithRegistrySetup'; +import DashboardPageSpeedWidget from './DashboardPageSpeedWidget'; +import * as fixtures from '../../datastore/__fixtures__'; + +const url = fixtures.pagespeedMobile.loadingExperience.id; + +const WidgetWithComponentProps = withWidgetComponentProps( 'widget-slug' )( + DashboardPageSpeedWidget +); + +const Template = ( { setupRegistry, ...args } ) => ( + + + +); + +export const Ready = Template.bind( {} ); +Ready.storyName = 'Ready'; +Ready.args = { + setupRegistry: ( registry ) => { + const { dispatch } = registry; + dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( + fixtures.pagespeedMobile, + { + url, + strategy: STRATEGY_MOBILE, + } + ); + dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( 'getReport', [ + url, + STRATEGY_MOBILE, + ] ); + + dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( + fixtures.pagespeedDesktop, + { + url, + strategy: STRATEGY_DESKTOP, + } + ); + dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( 'getReport', [ + url, + STRATEGY_DESKTOP, + ] ); + }, +}; + +export const Loading = Template.bind( {} ); +Loading.storyName = 'Loading'; +Loading.args = { + setupRegistry: ( { dispatch } ) => { + freezeFetch( + /^\/google-site-kit\/v1\/modules\/pagespeed-insights\/data\/pagespeed/ + ); + + // Component will be loading as long as both reports are not present. + // Omit receiving mobile here to trigger the request only once. + dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( + fixtures.pagespeedDesktop, + { + url, + strategy: STRATEGY_DESKTOP, + } + ); + }, +}; + +export const NoRecommendations = Template.bind( {} ); +NoRecommendations.storyName = 'No Recommendations'; +NoRecommendations.args = { + setupRegistry: ( { dispatch } ) => { + dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( + fixtures.pagespeedMobileNoStackPacks, + { + url, + strategy: STRATEGY_MOBILE, + } + ); + dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( 'getReport', [ + url, + STRATEGY_MOBILE, + ] ); + + dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( + fixtures.pagespeedDesktopNoStackPacks, + { + url, + strategy: STRATEGY_DESKTOP, + } + ); + dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( 'getReport', [ + url, + STRATEGY_DESKTOP, + ] ); + }, +}; + +export const FieldDataUnavailable = Template.bind( {} ); +FieldDataUnavailable.storyName = 'Field Data Unavailable'; +FieldDataUnavailable.args = { + setupRegistry: ( { dispatch } ) => { + dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( + fixtures.pagespeedMobileNoFieldData, + { + url, + strategy: STRATEGY_MOBILE, + } + ); + dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( 'getReport', [ + url, + STRATEGY_MOBILE, + ] ); + + dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( + fixtures.pagespeedDesktopNoFieldData, + { + url, + strategy: STRATEGY_DESKTOP, + } + ); + dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( 'getReport', [ + url, + STRATEGY_DESKTOP, + ] ); + }, +}; + +export const Error = Template.bind( {} ); +Error.storyName = 'Errors for Mobile and Desktop'; +Error.args = { + setupRegistry: ( { dispatch } ) => { + const mobileError = { + code: 'fetching_mobile_data_failed', + message: + 'Fetching PageSpeed Insights report with strategy mobile failed.', + }; + const desktopError = { + code: 'fetching_desktop_data_failed', + message: + 'Fetching PageSpeed Insights report with strategy desktop failed.', + }; + dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveError( + mobileError, + 'getReport', + [ url, STRATEGY_MOBILE ] + ); + dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( 'getReport', [ + url, + STRATEGY_MOBILE, + ] ); + dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveError( + desktopError, + 'getReport', + [ url, STRATEGY_DESKTOP ] + ); + dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( 'getReport', [ + url, + STRATEGY_DESKTOP, + ] ); + }, +}; + +export default { + title: 'Modules/PageSpeed Insights/Widgets/DashboardPageSpeedWidget', + decorators: [ + ( Story, { args } ) => { + const setupRegistry = ( registry ) => { + provideSiteInfo( registry, { + referenceSiteURL: url, + } ); + provideModules( registry, [ + { + slug: 'pagespeed-insights', + active: true, + connected: true, + }, + ] ); + + // Call story-specific setup. + args.setupRegistry( registry ); + }; + + return ( + + + + ); + }, + ], +}; diff --git a/assets/js/util/errors.js b/assets/js/util/errors.js index afb05f4860a..9ea35b54e0a 100644 --- a/assets/js/util/errors.js +++ b/assets/js/util/errors.js @@ -21,10 +21,17 @@ */ import isPlainObject from 'lodash/isPlainObject'; +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + // Error codes and reasons. export const ERROR_CODE_MISSING_REQUIRED_SCOPE = 'missing_required_scopes'; // When scopes are missing. export const ERROR_REASON_INSUFFICIENT_PERMISSIONS = 'insufficientPermissions'; export const ERROR_REASON_FORBIDDEN = 'forbidden'; +export const ERROR_INTERNAL_SERVER_ERROR = 'internal_server_error'; +export const ERROR_INVALID_JSON = 'invalid_json'; /** * Checks if the provided object is an instance of WP_Error class. @@ -103,3 +110,27 @@ export function isErrorRetryable( error, selectorData ) { ! isAuthError( error ) ); } + +/** + * Sets the error message for specific error codes. + * + * @since n.e.x.t + * + * @param {Object} error The error object to check. + * @return {Object} The updated error object. + */ +export function getReportErrorMessage( error ) { + if ( error?.code === ERROR_INTERNAL_SERVER_ERROR ) { + return __( + 'There was a critical error on this website while fetching data.', + 'google-site-kit' + ); + } else if ( error?.code === ERROR_INVALID_JSON ) { + return __( + 'The server provided an invalid response.', + 'google-site-kit' + ); + } + + return error?.message; +} diff --git a/assets/js/util/errors.test.js b/assets/js/util/errors.test.js index e4e1f98732a..fdbadae645c 100644 --- a/assets/js/util/errors.test.js +++ b/assets/js/util/errors.test.js @@ -26,8 +26,11 @@ import { ERROR_CODE_MISSING_REQUIRED_SCOPE, ERROR_REASON_INSUFFICIENT_PERMISSIONS, ERROR_REASON_FORBIDDEN, + ERROR_INTERNAL_SERVER_ERROR, + ERROR_INVALID_JSON, isAuthError, isErrorRetryable, + getReportErrorMessage, } from './errors'; describe( 'Error Utilities', () => { @@ -230,4 +233,31 @@ describe( 'Error Utilities', () => { ).toBe( true ); } ); } ); + + describe( 'getReportErrorMessage', () => { + describe.each( [ + [ + 'return the same error message when error code is not internal_server_error or invalid_json', + { code: 'some-error', message: 'Not found' }, + 'Not found', + ], + [ + 'return the appropriate error message when error code is internal_server_error', + { + code: ERROR_INTERNAL_SERVER_ERROR, + message: 'Internal server error', + }, + 'There was a critical error on this website while fetching data.', + ], + [ + 'return the appropriate error message when error code is invalid_json', + { code: ERROR_INVALID_JSON, message: 'Invalid JSON' }, + 'The server provided an invalid response.', + ], + ] )( '%s', ( label, error, message ) => { + it( `should ${ label }`, () => { + expect( getReportErrorMessage( error ) ).toEqual( message ); + } ); + } ); + } ); } ); diff --git a/assets/sass/components/dashboard/_googlesitekit-DashboardPageSpeed.scss b/assets/sass/components/dashboard/_googlesitekit-DashboardPageSpeed.scss index bab936c9cbf..c1a8e66d4a6 100644 --- a/assets/sass/components/dashboard/_googlesitekit-DashboardPageSpeed.scss +++ b/assets/sass/components/dashboard/_googlesitekit-DashboardPageSpeed.scss @@ -198,6 +198,16 @@ } } + .googlesitekit-pagespeed-report__row--error { + align-items: flex-start; + flex-direction: column; + padding: 12px $grid-gap-phone 8px $grid-gap-phone; + + @media (min-width: $bp-tablet) { + padding: 18px $grid-gap-desktop 12px $grid-gap-desktop; + } + } + .googlesitekit-pagespeed--recommendations { box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1); display: flex; diff --git a/assets/sass/components/global/_googlesitekit-error-text.scss b/assets/sass/components/global/_googlesitekit-error-text.scss index 0becb4486c4..3d327a90099 100644 --- a/assets/sass/components/global/_googlesitekit-error-text.scss +++ b/assets/sass/components/global/_googlesitekit-error-text.scss @@ -26,7 +26,7 @@ margin-left: 1rem; } -.googlesitekit-error-cta-wrapper { +.googlesitekit-report-error-actions { align-items: center; display: flex; gap: 1rem; diff --git a/stories/module-pagespeed-insights-components.stories.js b/stories/module-pagespeed-insights-components.stories.js deleted file mode 100644 index e45f6d22ff2..00000000000 --- a/stories/module-pagespeed-insights-components.stories.js +++ /dev/null @@ -1,262 +0,0 @@ -/** - * PageSpeed Insights Module Component Stories. - * - * Site Kit by Google, Copyright 2021 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * External dependencies - */ -import { storiesOf } from '@storybook/react'; - -/** - * Internal dependencies - */ -import DashboardPageSpeedWidget from '../assets/js/modules/pagespeed-insights/components/dashboard/DashboardPageSpeedWidget'; -import * as fixtures from '../assets/js/modules/pagespeed-insights/datastore/__fixtures__'; -import { - MODULES_PAGESPEED_INSIGHTS, - STRATEGY_MOBILE, - STRATEGY_DESKTOP, -} from '../assets/js/modules/pagespeed-insights/datastore/constants'; -import { - WithTestRegistry, - freezeFetch, - provideSiteInfo, - provideModules, -} from '../tests/js/utils'; -import { getWidgetComponentProps } from '../assets/js/googlesitekit/widgets/util'; - -const widgetComponentProps = getWidgetComponentProps( 'dashboardPageSpeed' ); - -storiesOf( 'PageSpeed Insights Module/Components', module ) - .add( 'Dashboard widget', () => { - const url = fixtures.pagespeedMobile.loadingExperience.id; - const setupRegistry = ( registry ) => { - const { dispatch } = registry; - dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( - fixtures.pagespeedMobile, - { - url, - strategy: STRATEGY_MOBILE, - } - ); - dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( - 'getReport', - [ url, STRATEGY_MOBILE ] - ); - - dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( - fixtures.pagespeedDesktop, - { - url, - strategy: STRATEGY_DESKTOP, - } - ); - dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( - 'getReport', - [ url, STRATEGY_DESKTOP ] - ); - - provideSiteInfo( registry, { - referenceSiteURL: url, - } ); - provideModules( registry, [ - { - slug: 'pagespeed-insights', - active: true, - connected: true, - }, - ] ); - }; - - return ( - - - - ); - } ) - .add( 'Dashboard widget (loading)', () => { - freezeFetch( - /^\/google-site-kit\/v1\/modules\/pagespeed-insights\/data\/pagespeed/ - ); - const url = fixtures.pagespeedMobile.loadingExperience.id; - const setupRegistry = ( registry ) => { - const { dispatch } = registry; - // Component will be loading as long as both reports are not present. - // Omit receiving mobile here to trigger the request only once. - dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( - fixtures.pagespeedDesktop, - { - url, - strategy: STRATEGY_DESKTOP, - } - ); - provideSiteInfo( registry, { - referenceSiteURL: url, - } ); - provideModules( registry, [ - { - slug: 'pagespeed-insights', - active: true, - connected: true, - }, - ] ); - }; - return ( - - - - ); - } ) - .add( 'Dashboard widget (No Recommendations)', () => { - const url = fixtures.pagespeedMobile.loadingExperience.id; - const setupRegistry = ( registry ) => { - const { dispatch } = registry; - dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( - fixtures.pagespeedMobileNoStackPacks, - { - url, - strategy: STRATEGY_MOBILE, - } - ); - dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( - 'getReport', - [ url, STRATEGY_MOBILE ] - ); - - dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( - fixtures.pagespeedDesktopNoStackPacks, - { - url, - strategy: STRATEGY_DESKTOP, - } - ); - dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( - 'getReport', - [ url, STRATEGY_DESKTOP ] - ); - - provideSiteInfo( registry, { - referenceSiteURL: url, - } ); - provideModules( registry, [ - { - slug: 'pagespeed-insights', - active: true, - connected: true, - }, - ] ); - }; - return ( - - - - ); - } ) - .add( 'Dashboard widget (Field Data Unavailable)', () => { - const url = fixtures.pagespeedMobile.loadingExperience.id; - const setupRegistry = ( registry ) => { - const { dispatch } = registry; - dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( - fixtures.pagespeedMobileNoFieldData, - { - url, - strategy: STRATEGY_MOBILE, - } - ); - dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( - 'getReport', - [ url, STRATEGY_MOBILE ] - ); - - dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveGetReport( - fixtures.pagespeedDesktopNoFieldData, - { - url, - strategy: STRATEGY_DESKTOP, - } - ); - dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( - 'getReport', - [ url, STRATEGY_DESKTOP ] - ); - - provideSiteInfo( registry, { - referenceSiteURL: url, - } ); - provideModules( registry, [ - { - slug: 'pagespeed-insights', - active: true, - connected: true, - }, - ] ); - }; - return ( - - - - ); - } ) - .add( 'Dashboard widget (Errors for Mobile and Desktop)', () => { - const url = fixtures.pagespeedMobile.loadingExperience.id; - const setupRegistry = ( registry ) => { - const { dispatch } = registry; - const mobileError = { - code: 'fetching_mobile_data_failed', - message: - 'Fetching PageSpeed Insights report with strategy mobile failed.', - }; - const desktopError = { - code: 'fetching_desktop_data_failed', - message: - 'Fetching PageSpeed Insights report with strategy desktop failed.', - }; - dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveError( - mobileError, - 'getReport', - [ url, STRATEGY_MOBILE ] - ); - dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( - 'getReport', - [ url, STRATEGY_MOBILE ] - ); - dispatch( MODULES_PAGESPEED_INSIGHTS ).receiveError( - desktopError, - 'getReport', - [ url, STRATEGY_DESKTOP ] - ); - dispatch( MODULES_PAGESPEED_INSIGHTS ).finishResolution( - 'getReport', - [ url, STRATEGY_DESKTOP ] - ); - provideSiteInfo( registry, { - referenceSiteURL: url, - } ); - provideModules( registry, [ - { - slug: 'pagespeed-insights', - active: true, - connected: true, - }, - ] ); - }; - return ( - - - - ); - } );