Normalise the search param for comparison to avoid endless redirections (https://github.com/woocommerce/woocommerce-blocks/pull/8784)

* Replace single quote with the encoded version %27 for URL comparison

This is required as as removeQueryArgs() function uses decodeURIcomponent method which doesn't encode single quotes (') while it was still encoded in the original URL (%27). So when the single quote was in a query param, for example as a search term, it caused endless redirection loop.

* Replace single quote with the encoded version %27 for URL comparison in Filter by Rating

* refactor the solution so it encodes the href rather than decode the newly created URL

* Refactor the normalisation

* Add tests to normalisation function
This commit is contained in:
kmanijak 2023-03-23 08:42:23 +01:00 committed by GitHub
parent f29954abbc
commit a06f4fbd91
4 changed files with 48 additions and 7 deletions

View File

@ -26,7 +26,7 @@ import FilterSubmitButton from '@woocommerce/base-components/filter-submit-butto
import FilterResetButton from '@woocommerce/base-components/filter-reset-button';
import FormTokenField from '@woocommerce/base-components/form-token-field';
import { addQueryArgs, removeQueryArgs } from '@wordpress/url';
import { changeUrl } from '@woocommerce/utils';
import { changeUrl, normalizeQueryParams } from '@woocommerce/utils';
import classnames from 'classnames';
import { difference } from 'lodash';
import type { ReactElement } from 'react';
@ -144,7 +144,7 @@ const RatingFilterBlock = ( {
QUERY_PARAM_KEY
);
if ( url !== window.location.href ) {
if ( url !== normalizeQueryParams( window.location.href ) ) {
changeUrl( url );
}
@ -155,7 +155,7 @@ const RatingFilterBlock = ( {
[ QUERY_PARAM_KEY ]: checkedRatings.join( ',' ),
} );
if ( newUrl === window.location.href ) {
if ( newUrl === normalizeQueryParams( window.location.href ) ) {
return;
}

View File

@ -32,7 +32,11 @@ import isShallowEqual from '@wordpress/is-shallow-equal';
import { decodeEntities } from '@wordpress/html-entities';
import { isBoolean, objectHasProp } from '@woocommerce/types';
import { addQueryArgs, removeQueryArgs } from '@wordpress/url';
import { changeUrl, PREFIX_QUERY_ARG_FILTER_TYPE } from '@woocommerce/utils';
import {
changeUrl,
PREFIX_QUERY_ARG_FILTER_TYPE,
normalizeQueryParams,
} from '@woocommerce/utils';
import { difference } from 'lodash';
import classnames from 'classnames';
@ -224,7 +228,7 @@ const StockStatusFilterBlock = ( {
QUERY_PARAM_KEY
);
if ( url !== window.location.href ) {
if ( url !== normalizeQueryParams( window.location.href ) ) {
changeUrl( url );
}
@ -235,7 +239,7 @@ const StockStatusFilterBlock = ( {
[ QUERY_PARAM_KEY ]: checkedOptions.join( ',' ),
} );
if ( newUrl === window.location.href ) {
if ( newUrl === normalizeQueryParams( window.location.href ) ) {
return;
}

View File

@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { getQueryArg } from '@wordpress/url';
import { getQueryArg, getQueryArgs, addQueryArgs } from '@wordpress/url';
import { getSettingWithCoercion } from '@woocommerce/settings';
import { isBoolean } from '@woocommerce/types';
@ -39,3 +39,13 @@ export function changeUrl( newUrl: string ) {
window.history.replaceState( {}, '', newUrl );
}
}
/**
* Run the query params through buildQueryString to normalise the params.
*
* @param {string} url URL to encode the search param from.
*/
export const normalizeQueryParams = ( url: string ) => {
const queryArgs = getQueryArgs( url );
return addQueryArgs( url, queryArgs );
};

View File

@ -0,0 +1,27 @@
/**
* Internal dependencies
*/
import { normalizeQueryParams } from '../filters';
describe( 'normalizeQueryParams', () => {
test( 'does not change url if there is no query params', () => {
const input = 'https://example.com';
const expected = 'https://example.com';
expect( normalizeQueryParams( input ) ).toBe( expected );
} );
test( 'does not change search term if there is no special character', () => {
const input = 'https://example.com?foo=bar&s=asdf1234&baz=qux';
const expected = 'https://example.com?foo=bar&s=asdf1234&baz=qux';
expect( normalizeQueryParams( input ) ).toBe( expected );
} );
test( 'decodes single quote characters', () => {
const input = 'https://example.com?foo=bar%27&s=asd%27f1234&baz=qux%27';
const expected = "https://example.com?foo=bar'&s=asd'f1234&baz=qux'";
expect( normalizeQueryParams( input ) ).toBe( expected );
} );
} );