Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f7d1f8a
Update packages with React 17 and tests passing.
tofumatt Mar 15, 2026
1cf9a8d
Update Stylelint version.
tofumatt Mar 17, 2026
a343a91
Merge branch 'develop' into typescript-fewer-package-changes.
tofumatt Mar 18, 2026
4be3e51
Fix Stylelint issues and package resolutions.
tofumatt Mar 21, 2026
e7b1dd8
Merge branch 'develop' into typescript-fewer-package-changes.
tofumatt Mar 21, 2026
c92c709
Fix tests.
tofumatt Mar 22, 2026
1509b8e
Merge branch 'develop' into typescript-fewer-package-changes.
tofumatt Mar 24, 2026
ae6dae6
Update snapshots to include retry buttons.
tofumatt Mar 24, 2026
2421344
Update settings module snapshot with example URL.
tofumatt Mar 24, 2026
00a421e
Mock Analytics settings endpoint for tests that rely on it.
tofumatt Mar 25, 2026
9c2d6fd
Wait for registry to complete work in test.
tofumatt Mar 25, 2026
34c6558
Re-render tooltip test.
tofumatt Mar 25, 2026
8c886a5
Ensure console errors are consistently fired/caught in tests.
tofumatt Apr 1, 2026
caf5590
Fix tests and related fixes.
aaemnnosttv Apr 1, 2026
0d17205
Revert added storeName in modules list fixture.
aaemnnosttv Apr 1, 2026
2b67f55
Add missing calls to provideModuleRegistrations.
aaemnnosttv Apr 1, 2026
8aaa7e6
Fix typecheck errors.
aaemnnosttv Apr 1, 2026
1c01fd2
Fix remaining tests.
aaemnnosttv Apr 1, 2026
96b27b2
Fix lint warnings.
aaemnnosttv Apr 1, 2026
b089add
Fix typo in body parameter name.
aaemnnosttv Apr 1, 2026
31ec565
Remove extra quote in assertion.
aaemnnosttv Apr 1, 2026
b26a87a
Merge branch 'develop' into typescript-fewer-package-changes.
aaemnnosttv Apr 1, 2026
06d92af
Update deprecated action.
aaemnnosttv Apr 1, 2026
7a46c67
Upgrade react-test-renderer to match new react version.
aaemnnosttv Apr 1, 2026
27059b8
Merge branch 'develop' into typescript-fewer-package-changes.
tofumatt Apr 2, 2026
0cc7951
Prevent hash changes from breaking VRTs.
tofumatt Apr 2, 2026
9af15ce
Trigger enhanced measurement settings fetch in Analytics component.
tofumatt Apr 3, 2026
2291758
Fix `isLoading` check in Analytics.
tofumatt Apr 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/visual-regression.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
- name: npm install
run: npm ci -w assets -w tests/backstop -w storybook -w tests/js --include-workspace-root
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: google-site-kit-bot
Expand Down
67 changes: 34 additions & 33 deletions .stylelintrc
Original file line number Diff line number Diff line change
@@ -1,34 +1,35 @@
{
"extends": [
"@wordpress/stylelint-config",
"stylelint-config-standard-scss"
],
"plugins": [
"stylelint-declaration-strict-value",
"stylelint-order",
"stylelint-scss"
],
"rules": {
"indentation": "tab",
"declaration-empty-line-before": null,
"scss/no-global-function-names": null,
"scss/dollar-variable-empty-line-before": null,
"scss/at-extend-no-missing-placeholder": null,
"scss/dollar-variable-pattern": null,
"color-function-notation": null,
"alpha-value-notation": null,
"rule-empty-line-before": null,
"at-rule-empty-line-before": null,
"string-quotes": "double",
"at-rule-no-unknown": null,
"declaration-property-unit-allowed-list": null,
"function-url-quotes": "always",
"selector-class-pattern": null,
"order/properties-alphabetical-order": true,
"value-keyword-case": [ "lower", {
"ignoreKeywords": ["/([A-Z])/"]
}
],
"selector-nested-pattern": "^(?!&__|&--|&-|&_).*"
}
}
"extends": [
"@wordpress/stylelint-config",
"stylelint-config-standard-scss"
],
"plugins": [
"stylelint-declaration-strict-value",
"stylelint-order",
"stylelint-scss"
],
"rules": {
"shorthand-property-no-redundant-values": null,
"declaration-empty-line-before": null,
"scss/no-global-function-names": null,
"scss/dollar-variable-empty-line-before": null,
"scss/at-extend-no-missing-placeholder": null,
"scss/dollar-variable-pattern": null,
"color-function-notation": null,
"alpha-value-notation": null,
"rule-empty-line-before": null,
"at-rule-empty-line-before": null,
"at-rule-no-unknown": null,
"declaration-property-unit-allowed-list": null,
"function-url-quotes": "always",
"selector-class-pattern": null,
"order/properties-alphabetical-order": true,
"value-keyword-case": [
"lower",
{
"ignoreKeywords": [ "/([A-Z])/" ]
}
],
"selector-nested-pattern": "^(?!&__|&--|&-|&_).*"
}
}
20 changes: 16 additions & 4 deletions assets/js/components/ErrorHandler/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,26 @@ class ErrorHandler extends Component {
}

render() {
const { children } = this.props;
const { children, hideFilenamesInStack } = this.props;
const { error, info } = this.state;

// If there is no caught error, render the children components normally.
if ( ! error ) {
return children;
}

let componentStack = info?.componentStack;

// Hide filenames in stack trace to prevent issues with Visual Regression
// tests and hashes changing in the stack trace.
if ( hideFilenamesInStack && componentStack ) {
componentStack = componentStack
.replace( /\(.*\)/g, '(filtered)' )
.replace( /at (.+) ?https?:\/\/.*/g, 'at $1 (filtered)' )
.replace( /at https?:\/\/.*/g, '' )
.replace( /\n \n /g, '\n ' );
}

return (
<BannerNotification
notificationID="googlesitekit-error"
Expand All @@ -81,15 +93,15 @@ class ErrorHandler extends Component {
<Fragment>
<GenericErrorHandlerActions
message={ error.message }
componentStack={ info.componentStack }
componentStack={ componentStack }
/>
<pre className="googlesitekit-overflow-auto">
{ error.message }
{ info.componentStack }
{ componentStack }
</pre>
</Fragment>
}
></BannerNotification>
/>
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion assets/js/components/ErrorHandler/index.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import ErrorHandler from './';

function Template() {
return (
<ErrorHandler>
<ErrorHandler hideFilenamesInStack>
<ThrowErrorComponent throwErrorOnMount />
</ErrorHandler>
);
Expand Down
1 change: 0 additions & 1 deletion assets/js/components/ModalDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ function ModalDialog( {
<Button
className="mdc-dialog__cancel-button"
onClick={ handleCancel }
disabled={ inProgress }
tertiary
>
{ __( 'Cancel', 'google-site-kit' ) }
Expand Down
17 changes: 14 additions & 3 deletions assets/js/components/TourTooltips.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
render,
createTestRegistry,
fireEvent,
act,
} from '../../../tests/js/test-utils';
import TourTooltips, { GA_ACTIONS } from './TourTooltips';
import { CORE_UI } from '@/js/googlesitekit/datastore/ui/constants';
Expand Down Expand Up @@ -227,11 +228,21 @@ describe( 'TourTooltips', () => {
);
} );

it( 'should end tour when close icon is clicked', () => {
const { getByRole, queryByRole } =
it( 'should end tour when close icon is clicked', async () => {
const { getByRole, queryByRole, rerender } =
renderTourTooltipsWithMockUI( registry );

fireEvent.click( getByRole( 'button', { name: /close/i } ) );
await act( () => {
fireEvent.click( getByRole( 'button', { name: /close/i } ) );
} );

rerender();

// This error is caused by the `react-select` component trying to update
// state after the component has unmounted, so we can't fix it ourselves.
expect( console ).toHaveErrored(
"Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s"
);

expect( queryByRole( 'alertdialog' ) ).not.toBeInTheDocument();
expect( dismissTourSpy ).toHaveBeenCalled();
Expand Down
43 changes: 27 additions & 16 deletions assets/js/components/WelcomeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,25 +80,34 @@ export default function WelcomeModal() {

const [ isOpen, setIsOpen ] = useState( true );

const analyticsConnected = useSelect( ( select: Select ) =>
select( CORE_MODULES ).isModuleConnected( MODULE_SLUG_ANALYTICS_4 )
const analyticsConnected = useSelect(
( select: Select ) =>
select( CORE_MODULES ).isModuleConnected( MODULE_SLUG_ANALYTICS_4 ),
[]
);

const analyticsGatheringData = useSelect( ( select: Select ) => {
if ( ! analyticsConnected ) {
return false;
}
return select( MODULES_ANALYTICS_4 ).isGatheringData();
} );
const analyticsGatheringData = useSelect(
( select: Select ) => {
if ( ! analyticsConnected ) {
return false;
}
return select( MODULES_ANALYTICS_4 ).isGatheringData();
},
[ analyticsConnected ]
);

const searchConsoleGatheringData = useSelect( ( select: Select ) =>
select( MODULES_SEARCH_CONSOLE ).isGatheringData()
const searchConsoleGatheringData = useSelect(
( select: Select ) =>
select( MODULES_SEARCH_CONSOLE ).isGatheringData(),
[]
);

const isGatheringDataVariantDismissed = useSelect( ( select: Select ) =>
select( CORE_USER ).isItemDismissed(
WELCOME_GATHERING_DATA_DISMISSED_ITEM_SLUG
)
const isGatheringDataVariantDismissed = useSelect(
( select: Select ) =>
select( CORE_USER ).isItemDismissed(
WELCOME_GATHERING_DATA_DISMISSED_ITEM_SLUG
),
[]
);

const showGatheringDataModal = analyticsConnected
Expand Down Expand Up @@ -224,8 +233,10 @@ export default function WelcomeModal() {
);
}, [ viewContext, modalVariant ] );

const isDataGatheringCompleteModalActive = useSelect( ( select: Select ) =>
select( CORE_USER ).isDataGatheringCompleteModalActive()
const isDataGatheringCompleteModalActive = useSelect(
( select: Select ) =>
select( CORE_USER ).isDataGatheringCompleteModalActive(),
[]
);

if (
Expand Down
13 changes: 10 additions & 3 deletions assets/js/components/dashboard-sharing/UserRoleSelect.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ import {
render,
fireEvent,
createTestRegistry,
act,
} from '../../../../tests/js/test-utils';
import { waitForTimeouts } from '../../../../tests/js/utils';
import UserRoleSelect from './UserRoleSelect';
import { MODULE_SLUG_SEARCH_CONSOLE } from '@/js/modules/search-console/constants';

Expand Down Expand Up @@ -224,9 +226,14 @@ describe( 'CurrentSurvey', () => {

await waitForRegistry();

fireEvent.click(
container.querySelector( '.googlesitekit-user-role-select__button' )
);
await act( async () => {
fireEvent.click(
container.querySelector(
'.googlesitekit-user-role-select__button'
)
);
await waitForTimeouts( 100 );
} );

expect(
container.querySelector(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import {
provideModules,
} from '../../../../../tests/js/test-utils';
import { CORE_SITE } from '@/js/googlesitekit/datastore/site/constants';
import { MODULES_ANALYTICS_4 } from '@/js/modules/analytics-4/datastore/constants';
import { defaultSettings as analytics4DefaultSettings } from '@/js/modules/analytics-4/datastore/__fixtures__';
import * as tracking from '@/js/util/tracking';
import { VIEW_CONTEXT_MAIN_DASHBOARD_VIEW_ONLY } from '@/js/googlesitekit/constants';

Expand Down Expand Up @@ -76,6 +78,9 @@ describe( 'EmailReportingErrorNotices', () => {

it( 'should render the permissions error notice when email reporting is enabled, user is not view-only, and there is a permissions_error category ID and a module slug', () => {
provideModules( registry );
registry
.dispatch( MODULES_ANALYTICS_4 )
.receiveGetSettings( analytics4DefaultSettings );
registry.dispatch( CORE_SITE ).receiveGetEmailReportingSettings( {
enabled: true,
} );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ const ActivateAnalyticsNotification: FC<

const showTooltip = useShowTooltip( tooltipSettings );

const isDismissalFinal = useSelect( ( select: Select ) =>
select( CORE_NOTIFICATIONS ).isNotificationDismissalFinal( id )
const isDismissalFinal = useSelect(
( select: Select ) =>
select( CORE_NOTIFICATIONS ).isNotificationDismissalFinal( id ),
[]
);

const dismissLabel = useRetriableNotificationDismissButtonLabel( {
Expand All @@ -82,13 +84,15 @@ const ActivateAnalyticsNotification: FC<
}

return select( CORE_LOCATION ).isNavigatingTo( adminReauthURL );
} );

const isActivatingAnalytics = useSelect( ( select: Select ) =>
select( CORE_MODULES ).isFetchingSetModuleActivation(
MODULE_SLUG_ANALYTICS_4,
true
)
}, [] );

const isActivatingAnalytics = useSelect(
( select: Select ) =>
select( CORE_MODULES ).isFetchingSetModuleActivation(
MODULE_SLUG_ANALYTICS_4,
true
),
[]
);

const activateAnalytics = useActivateModuleCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,15 @@ const ConnectMoreServicesNotification: FC<
const showTooltip = useShowTooltip( tooltipSettings );
const { navigateTo } = useDispatch( CORE_LOCATION );

const connectMoreServicesURL = useSelect( ( select: Select ) =>
select( CORE_SITE ).getConnectMoreServicesURL()
const connectMoreServicesURL = useSelect(
( select: Select ) => select( CORE_SITE ).getConnectMoreServicesURL(),
[]
);

const isNavigatingToConnectMoreServices = useSelect( ( select: Select ) =>
select( CORE_LOCATION ).isNavigatingTo( connectMoreServicesURL )
const isNavigatingToConnectMoreServices = useSelect(
( select: Select ) =>
select( CORE_LOCATION ).isNavigatingTo( connectMoreServicesURL ),
[ connectMoreServicesURL ]
);

const viewContext = useViewContext();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import fetchMock from 'fetch-mock';
*/
import GoogleTagGatewaySetupBanner from './GoogleTagGatewaySetupBanner';
import {
act,
createTestRegistry,
fireEvent,
provideModules,
Expand Down Expand Up @@ -311,11 +312,13 @@ describe( 'GoogleTagGatewaySetupBanner', () => {
NOTIFICATION_GROUPS.DEFAULT,
] );

fireEvent.click(
getByRole( 'button', {
name: 'Enable Google tag gateway for advertisers',
} )
);
await act( () => {
fireEvent.click(
getByRole( 'button', {
name: 'Enable Google tag gateway for advertisers',
} )
);
} );

await waitForRegistry();

Expand All @@ -329,6 +332,8 @@ describe( 'GoogleTagGatewaySetupBanner', () => {
expect( fetchMock ).toHaveFetched( dismissItemEndpoint );
} );

await waitForRegistry();

expect(
registry
.select( CORE_NOTIFICATIONS )
Expand Down
Loading
Loading