fix: Preserve unknown URL params (#21785)

This commit is contained in:
Michael S. Molina 2022-10-12 19:52:36 -03:00 committed by GitHub
parent 75e6a04269
commit 11d7d6e078
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 31 additions and 15 deletions

View File

@ -75,7 +75,8 @@ const reduxState = {
}, },
}; };
const key = 'aWrs7w29sd'; const KEY = 'aWrs7w29sd';
const SEARCH = `?form_data_key=${KEY}&dataset_id=1`;
jest.mock('react-resize-detector', () => ({ jest.mock('react-resize-detector', () => ({
__esModule: true, __esModule: true,
@ -87,21 +88,20 @@ jest.mock('lodash/debounce', () => ({
default: (fuc: Function) => fuc, default: (fuc: Function) => fuc,
})); }));
fetchMock.post('glob:*/api/v1/explore/form_data*', { key }); fetchMock.post('glob:*/api/v1/explore/form_data*', { key: KEY });
fetchMock.put('glob:*/api/v1/explore/form_data*', { key }); fetchMock.put('glob:*/api/v1/explore/form_data*', { key: KEY });
fetchMock.get('glob:*/api/v1/explore/form_data*', {}); fetchMock.get('glob:*/api/v1/explore/form_data*', {});
fetchMock.get('glob:*/favstar/slice*', { count: 0 }); fetchMock.get('glob:*/favstar/slice*', { count: 0 });
const defaultPath = '/explore/'; const defaultPath = '/explore/';
const renderWithRouter = ({ const renderWithRouter = ({
withKey, search = '',
overridePathname, overridePathname,
}: { }: {
withKey?: boolean; search?: string;
overridePathname?: string; overridePathname?: string;
} = {}) => { } = {}) => {
const path = overridePathname ?? defaultPath; const path = overridePathname ?? defaultPath;
const search = withKey ? `?form_data_key=${key}&dataset_id=1` : '';
Object.defineProperty(window, 'location', { Object.defineProperty(window, 'location', {
get() { get() {
return { pathname: path, search }; return { pathname: path, search };
@ -143,12 +143,12 @@ test('generates a new form_data param when none is available', async () => {
test('generates a different form_data param when one is provided and is mounting', async () => { test('generates a different form_data param when one is provided and is mounting', async () => {
const replaceState = jest.spyOn(window.history, 'replaceState'); const replaceState = jest.spyOn(window.history, 'replaceState');
await waitFor(() => renderWithRouter({ withKey: true })); await waitFor(() => renderWithRouter({ search: SEARCH }));
expect(replaceState).not.toHaveBeenLastCalledWith( expect(replaceState).not.toHaveBeenLastCalledWith(
0, 0,
expect.anything(), expect.anything(),
undefined, undefined,
expect.stringMatching(key), expect.stringMatching(KEY),
); );
expect(replaceState).toHaveBeenCalledWith( expect(replaceState).toHaveBeenCalledWith(
expect.anything(), expect.anything(),
@ -164,7 +164,7 @@ test('reuses the same form_data param when updating', async () => {
}); });
const replaceState = jest.spyOn(window.history, 'replaceState'); const replaceState = jest.spyOn(window.history, 'replaceState');
const pushState = jest.spyOn(window.history, 'pushState'); const pushState = jest.spyOn(window.history, 'pushState');
await waitFor(() => renderWithRouter({ withKey: true })); await waitFor(() => renderWithRouter({ search: SEARCH }));
expect(replaceState.mock.calls.length).toBe(1); expect(replaceState.mock.calls.length).toBe(1);
userEvent.click(screen.getByText('Update chart')); userEvent.click(screen.getByText('Update chart'));
await waitFor(() => expect(pushState.mock.calls.length).toBe(1)); await waitFor(() => expect(pushState.mock.calls.length).toBe(1));
@ -188,3 +188,17 @@ test('doesnt call replaceState when pathname is not /explore', async () => {
expect(replaceState).not.toHaveBeenCalled(); expect(replaceState).not.toHaveBeenCalled();
replaceState.mockRestore(); replaceState.mockRestore();
}); });
test('preserves unknown parameters', async () => {
const replaceState = jest.spyOn(window.history, 'replaceState');
const unknownParam = 'test=123';
await waitFor(() =>
renderWithRouter({ search: `${SEARCH}&${unknownParam}` }),
);
expect(replaceState).toHaveBeenCalledWith(
expect.anything(),
undefined,
expect.stringMatching(unknownParam),
);
replaceState.mockRestore();
});

View File

@ -167,7 +167,9 @@ const updateHistory = debounce(
) => { ) => {
const payload = { ...formData }; const payload = { ...formData };
const chartId = formData.slice_id; const chartId = formData.slice_id;
const additionalParam = {}; const params = new URLSearchParams(window.location.search);
const additionalParam = Object.fromEntries(params);
if (chartId) { if (chartId) {
additionalParam[URL_PARAMS.sliceId.name] = chartId; additionalParam[URL_PARAMS.sliceId.name] = chartId;
} else { } else {

View File

@ -31,7 +31,7 @@ test('get form_data_key and slice_id from search params - url when moving from d
`${EXPLORE_BASE_URL}?form_data_key=yrLXmyE9fmhQ11lM1KgaD1PoPSBpuLZIJfqdyIdw9GoBwhPFRZHeIgeFiNZljbpd&slice_id=56`, `${EXPLORE_BASE_URL}?form_data_key=yrLXmyE9fmhQ11lM1KgaD1PoPSBpuLZIJfqdyIdw9GoBwhPFRZHeIgeFiNZljbpd&slice_id=56`,
); );
expect(getParsedExploreURLParams().toString()).toEqual( expect(getParsedExploreURLParams().toString()).toEqual(
'slice_id=56&form_data_key=yrLXmyE9fmhQ11lM1KgaD1PoPSBpuLZIJfqdyIdw9GoBwhPFRZHeIgeFiNZljbpd', 'form_data_key=yrLXmyE9fmhQ11lM1KgaD1PoPSBpuLZIJfqdyIdw9GoBwhPFRZHeIgeFiNZljbpd&slice_id=56',
); );
}); });

View File

@ -77,7 +77,7 @@ const EXPLORE_URL_PATH_PARAMS = {
// we need to "flatten" the search params to use them with /v1/explore endpoint // we need to "flatten" the search params to use them with /v1/explore endpoint
const getParsedExploreURLSearchParams = (search: string) => { const getParsedExploreURLSearchParams = (search: string) => {
const urlSearchParams = new URLSearchParams(search); const urlSearchParams = new URLSearchParams(search);
return Object.keys(EXPLORE_URL_SEARCH_PARAMS).reduce((acc, currentParam) => { return Array.from(urlSearchParams.keys()).reduce((acc, currentParam) => {
const paramValue = urlSearchParams.get(currentParam); const paramValue = urlSearchParams.get(currentParam);
if (paramValue === null) { if (paramValue === null) {
return acc; return acc;
@ -93,9 +93,10 @@ const getParsedExploreURLSearchParams = (search: string) => {
if (typeof parsedParamValue === 'object') { if (typeof parsedParamValue === 'object') {
return { ...acc, ...parsedParamValue }; return { ...acc, ...parsedParamValue };
} }
const key = EXPLORE_URL_SEARCH_PARAMS[currentParam]?.name || currentParam;
return { return {
...acc, ...acc,
[EXPLORE_URL_SEARCH_PARAMS[currentParam].name]: parsedParamValue, [key]: parsedParamValue,
}; };
}, {}); }, {});
}; };

View File

@ -334,8 +334,7 @@ class Slice( # pylint: disable=too-many-public-methods
@property @property
def url(self) -> str: def url(self) -> str:
form_data = f"%7B%22slice_id%22%3A%20{self.id}%7D" return f"/explore/?slice_id={self.id}"
return f"/explore/?slice_id={self.id}&form_data={form_data}"
def get_query_context_factory(self) -> QueryContextFactory: def get_query_context_factory(self) -> QueryContextFactory:
if self.query_context_factory is None: if self.query_context_factory is None: