Skip to content

Commit a919426

Browse files
diana-villalvazo-wgudiana-villalvazo-wgu
andauthored
chore: Replace query-string with URLSearchParams (#613)
Co-authored-by: diana-villalvazo-wgu <[email protected]>
1 parent 11a7512 commit a919426

File tree

8 files changed

+54
-53
lines changed

8 files changed

+54
-53
lines changed

package-lock.json

Lines changed: 0 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
"lodash": "^4.17.21",
5353
"moment": "^2.29.4",
5454
"prop-types": "15.8.1",
55-
"query-string": "7.1.3",
5655
"react": "^18.3.1",
5756
"react-dom": "^18.3.1",
5857
"react-helmet": "^6.1.0",

src/containers/CoursesPanel/hooks.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import React from 'react';
22

3-
import queryString from 'query-string';
4-
53
import { ListPageSize, SortKeys } from 'data/constants/app';
64
import { reduxHooks } from 'hooks';
75
import { StrictDict } from 'utils';
@@ -27,12 +25,13 @@ export const useCourseListData = () => {
2725

2826
const [sortBy, setSortBy] = module.state.sortBy(SortKeys.enrolled);
2927

30-
const querySearch = queryString.parse(window.location.search, { parseNumbers: true });
28+
const querySearch = new URLSearchParams(window.location.search);
29+
const disablePagination = querySearch.get('disable_pagination');
3130

3231
const { numPages, visibleList } = reduxHooks.useCurrentCourseList({
3332
sortBy,
3433
filters,
35-
pageSize: querySearch?.disable_pagination === 1 ? 0 : ListPageSize,
34+
pageSize: Number(disablePagination) === 1 ? 0 : ListPageSize,
3635
});
3736

3837
const handleRemoveFilter = (filter) => () => removeFilter(filter);

src/containers/CoursesPanel/hooks.test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import queryString from 'query-string';
2-
31
import { MockUseState } from 'testUtils';
42
import { reduxHooks } from 'hooks';
53
import { ListPageSize, SortKeys } from 'data/constants/app';
@@ -15,8 +13,10 @@ jest.mock('hooks', () => ({
1513
},
1614
}));
1715

18-
jest.mock('query-string', () => ({
19-
parse: jest.fn(() => ({})),
16+
const mockGet = jest.fn(() => ({}));
17+
18+
global.URLSearchParams = jest.fn().mockImplementation(() => ({
19+
get: mockGet,
2020
}));
2121

2222
const state = new MockUseState(hooks);
@@ -67,7 +67,7 @@ describe('CourseList hooks', () => {
6767
it('loads current course list with page size 0 if/when there is query param disable_pagination=1', () => {
6868
state.mock();
6969
state.mockVal(state.keys.sortBy, testSortBy);
70-
queryString.parse.mockReturnValueOnce({ disable_pagination: 1 });
70+
mockGet.mockReturnValueOnce('1');
7171
out = hooks.useCourseListData();
7272
expect(reduxHooks.useCurrentCourseList).toHaveBeenCalledWith({
7373
sortBy: testSortBy,

src/data/services/lms/utils.js

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,34 @@
1-
import queryString from 'query-string';
21
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
32

3+
/**
4+
* stringify(query, existingQuery)
5+
* simple wrapper to convert an object to a query string
6+
* @param {object} query - object to convert
7+
* @param {string} existingQuery - existing query string
8+
* @returns {string} - query string
9+
*/
10+
11+
export const stringify = (query, existingQuery = '') => {
12+
const searchParams = new URLSearchParams(existingQuery);
13+
14+
Object.entries(query).forEach(([key, value]) => {
15+
if (value === undefined || value === null || value === '') {
16+
searchParams.delete(key);
17+
} else if (Array.isArray(value)) {
18+
searchParams.delete(key);
19+
value.forEach((val) => {
20+
if (val !== undefined && val !== null && val !== '') {
21+
searchParams.append(key, val);
22+
}
23+
});
24+
} else {
25+
searchParams.set(key, value);
26+
}
27+
});
28+
29+
return searchParams.toString();
30+
};
31+
432
/**
533
* get(url)
634
* simple wrapper providing an authenticated Http client get action
@@ -10,21 +38,23 @@ export const get = (...args) => getAuthenticatedHttpClient().get(...args);
1038
/**
1139
* post(url, data)
1240
* simple wrapper providing an authenticated Http client post action
13-
* queryString.stringify is used to convert the object to query string with = and &
41+
* stringify is used to convert the object to query string with = and &
1442
* @param {string} url - target url
1543
* @param {object|string} body - post payload
1644
*/
17-
export const post = (url, body) => getAuthenticatedHttpClient().post(url, queryString.stringify(body));
45+
export const post = (url, body) => getAuthenticatedHttpClient().post(url, stringify(body));
1846

1947
export const client = getAuthenticatedHttpClient;
2048

2149
/**
2250
* stringifyUrl(url, query)
23-
* simple wrapper around queryString.stringifyUrl that sets skip behavior
51+
* simple wrapper to convert a url and query object to a full url
2452
* @param {string} url - base url string
2553
* @param {object} query - query parameters
54+
* @returns {string} - full url
2655
*/
27-
export const stringifyUrl = (url, query) => queryString.stringifyUrl(
28-
{ url, query },
29-
{ skipNull: true, skipEmptyString: true },
30-
);
56+
export const stringifyUrl = (url, query) => {
57+
const [baseUrl, existingQuery = ''] = url.split('?');
58+
const queryString = stringify(query, existingQuery);
59+
return queryString ? `${baseUrl}?${queryString}` : baseUrl;
60+
};

src/data/services/lms/utils.test.js

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
1-
import queryString from 'query-string';
21
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
32
import * as utils from './utils';
43

5-
jest.mock('query-string', () => ({
6-
stringifyUrl: jest.fn((url, options) => ({ url, options })),
7-
stringify: jest.fn((data) => data),
8-
}));
94
jest.mock('@edx/frontend-platform/auth', () => ({
105
getAuthenticatedHttpClient: jest.fn(),
116
}));
@@ -20,28 +15,25 @@ describe('lms service utils', () => {
2015
});
2116
});
2217
describe('post', () => {
23-
it('forwards arguments to authenticatedHttpClient().post', () => {
18+
it('forwards arguments to authenticatedHttpClient().post, removes undefined attributes and appends array values', () => {
2419
const post = jest.fn((...args) => ({ post: args }));
2520
getAuthenticatedHttpClient.mockReturnValue({ post });
2621
const url = 'some url';
2722
const body = {
2823
some: 'body',
29-
for: 'the',
24+
for: undefined,
3025
test: 'yay',
26+
array: ['one', 'two', undefined],
3127
};
3228
const expectedUrl = utils.post(url, body);
33-
expect(queryString.stringify).toHaveBeenCalledWith(body);
34-
expect(expectedUrl).toEqual(post(url, body));
29+
expect(expectedUrl).toEqual(post(url, 'some=body&test=yay&array=one&array=two'));
3530
});
3631
});
3732
describe('stringifyUrl', () => {
38-
it('forwards url and query to stringifyUrl with options to skip null and ""', () => {
33+
it('forwards url and query to stringifyUrl skipping null and ""', () => {
3934
const url = 'here.com';
4035
const query = { some: 'set', of: 'queryParams' };
41-
const options = { skipNull: true, skipEmptyString: true };
42-
expect(utils.stringifyUrl(url, query)).toEqual(
43-
queryString.stringifyUrl({ url, query }, options),
44-
);
36+
expect(utils.stringifyUrl(url, query)).toEqual('here.com?some=set&of=queryParams');
4537
});
4638
});
4739
});

webpack.dev.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ config.resolve.modules = [
99
'node_modules',
1010
];
1111

12-
config.module.rules[0].exclude = /node_modules\/(?!(query-string|split-on-first|strict-uri-encode|@edx))/;
12+
config.module.rules[0].exclude = /node_modules\/(?!(split-on-first|strict-uri-encode|@edx))/;
1313

1414
config.plugins.push(
1515
new CopyPlugin({

webpack.prod.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ config.resolve.modules = [
99
'node_modules',
1010
];
1111

12-
config.module.rules[0].exclude = /node_modules\/(?!(query-string|split-on-first|strict-uri-encode|@edx))/;
12+
config.module.rules[0].exclude = /node_modules\/(?!(split-on-first|strict-uri-encode|@edx))/;
1313

1414
config.plugins.push(
1515
new CopyPlugin({

0 commit comments

Comments
 (0)