Skip to content

Commit 1a4a897

Browse files
[FEQ] P2P-V2 refactor useQueryString (deriv-com#14106)
* chore: removed responsive root * chore: reverted old changes * refactor: usequerystring to use query params * chore: reverted comments * chore: fixed test cases
1 parent c6198e1 commit 1a4a897

File tree

13 files changed

+215
-396
lines changed

13 files changed

+215
-396
lines changed

package-lock.json

+29
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/p2p-v2/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
"start": "rimraf dist && npm run test && npm run serve"
1313
},
1414
"dependencies": {
15-
"@deriv/api-v2": "^1.0.0",
1615
"@deriv-com/ui": "1.11.2",
1716
"@deriv-com/utils": "latest",
17+
"@deriv/api-v2": "^1.0.0",
1818
"@deriv/integration": "^1.0.0",
1919
"@deriv/quill-icons": "^1.19.0",
2020
"@deriv/react-joyride": "^2.6.2",
@@ -34,6 +34,8 @@
3434
"react-router-dom": "^5.2.0",
3535
"react-share": "^5.1.0",
3636
"react-simple-star-rating": "4.0.4",
37+
"serialize-query-params": "^2.0.2",
38+
"use-query-params": "^2.2.1",
3739
"usehooks-ts": "^2.7.0"
3840
},
3941
"devDependencies": {

packages/p2p-v2/src/App.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@ import { APIProvider, AuthProvider } from '@deriv/api-v2';
33
import AppContent from './routes/AppContent';
44
import { Router } from './routes';
55
import './index.scss';
6+
import { QueryParamProvider } from 'use-query-params';
7+
import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5';
68

79
const App: React.FC = () => {
810
return (
911
<APIProvider standalone>
1012
<AuthProvider>
11-
<Router />
12-
<AppContent />
13+
<QueryParamProvider adapter={ReactRouter5Adapter}>
14+
<Router />
15+
<AppContent />
16+
</QueryParamProvider>
1317
</AuthProvider>
1418
</APIProvider>
1519
);
Original file line numberDiff line numberDiff line change
@@ -1,234 +1,51 @@
1-
import * as React from 'react';
2-
import { render, screen } from '@testing-library/react';
3-
import userEvent from '@testing-library/user-event';
4-
import { Router, Route, Switch } from 'react-router-dom';
5-
import useQueryString from '../useQueryString';
1+
import React from 'react';
62
import { createMemoryHistory } from 'history';
3+
import { useQueryParams } from 'use-query-params';
4+
import { renderHook } from '@testing-library/react-hooks';
5+
import useQueryString from '../useQueryString';
76

8-
const MockBuySell = () => <h1>Buy sell page</h1>;
9-
const MockMyProfile = () => {
10-
const { deleteQueryString, queryString, replaceQueryString, setQueryString } = useQueryString();
11-
12-
return (
13-
<div>
14-
<button
15-
onClick={() =>
16-
setQueryString({
17-
tab: 'Payment methods',
18-
})
19-
}
20-
>
21-
Switch payment methods
22-
</button>
23-
<button
24-
onClick={() =>
25-
setQueryString({
26-
tab: 'Stats',
27-
})
28-
}
29-
>
30-
Switch stats
31-
</button>
32-
<button
33-
onClick={() =>
34-
setQueryString({
35-
form: 'Payment method form',
36-
tab: 'Payment methods',
37-
})
38-
}
39-
>
40-
Switch payment method form
41-
</button>
42-
<button
43-
onClick={() =>
44-
replaceQueryString({
45-
form: 'Payment method form',
46-
tab: 'Counterparties',
47-
})
48-
}
49-
>
50-
Switch counterparties
51-
</button>
52-
<button onClick={() => deleteQueryString('tab')}>Go back</button>
53-
{!queryString.get('tab') && <h1>My profile</h1>}
54-
{queryString.get('tab') === 'Stats' && <h1>Stats tab</h1>}
55-
{queryString.get('tab') === 'Counterparties' && <h1>Counterparties tab</h1>}
56-
{queryString.get('tab') === 'Payment methods' && <h1>Payment methods tab</h1>}
57-
{queryString.get('form') === 'Payment method form' && <h1>Payment method form</h1>}
58-
</div>
59-
);
60-
};
61-
62-
const MockHome = () => <h1>Home</h1>;
63-
64-
const MockAppContent = () => {
65-
return (
66-
<Switch>
67-
<Route component={MockHome} exact path='/' />
68-
<Route component={MockBuySell} path='/mock-buy-sell' />
69-
<Route component={MockMyProfile} path='/mock-my-profile' />
70-
</Switch>
71-
);
72-
};
73-
74-
const mockReplace = jest.fn();
75-
76-
jest.mock('react-router-dom', () => ({
77-
...jest.requireActual('react-router-dom'),
78-
useHistory: () => ({
79-
push: jest.fn(),
80-
replace: mockReplace,
81-
}),
7+
jest.mock('use-query-params', () => ({
8+
...jest.requireActual('use-query-params'),
9+
useQueryParams: jest.fn().mockReturnValue([
10+
{},
11+
jest.fn(), // setQuery
12+
]),
8213
}));
83-
84-
let windowLocationSpy: jest.SpyInstance<Location, []>;
85-
14+
const mockUseQueryParams = useQueryParams as jest.MockedFunction<typeof useQueryParams>;
8615
describe('useQueryString', () => {
87-
beforeEach(() => {
88-
windowLocationSpy = jest.spyOn(window, 'location', 'get');
89-
});
90-
afterEach(() => {
91-
jest.restoreAllMocks();
16+
it('returns correct query string', () => {
17+
const history = createMemoryHistory({ initialEntries: ['?x=3'] });
18+
history.push('/');
19+
const { result } = renderHook(() => useQueryString());
20+
expect(result.current.queryString).toEqual({});
9221
});
93-
it('should test case for setting new query strings', () => {
94-
const history = createMemoryHistory();
95-
history.push('/mock-my-profile');
96-
render(
97-
<Router history={history}>
98-
<MockAppContent />
99-
</Router>
100-
);
101-
expect(screen.getByText('My profile')).toBeInTheDocument();
102-
expect(screen.queryByText('Payment methods tab')).not.toBeInTheDocument();
103-
expect(screen.queryByText('Stats tab')).not.toBeInTheDocument();
10422

105-
const btn = screen.getByRole('button', {
106-
name: 'Switch payment methods',
107-
});
108-
const originalLocation = window.location;
109-
const queryChangeEventSpy = jest.spyOn(window, 'dispatchEvent');
110-
windowLocationSpy.mockImplementation(() => ({
111-
...originalLocation,
112-
href: 'http://localhost/my-profile?tab=Payment+methods',
113-
pathname: 'my-profile',
114-
search: '?tab=Payment+methods',
115-
}));
116-
userEvent.click(btn);
117-
expect(mockReplace).toHaveBeenLastCalledWith({
118-
pathname: 'my-profile',
119-
search: 'tab=Payment+methods',
120-
});
121-
expect(mockReplace).toHaveBeenCalled();
122-
expect(queryChangeEventSpy).toHaveBeenCalledWith(expect.any(Event));
123-
expect(queryChangeEventSpy.mock.calls[0][0].type).toBe('queryChange');
124-
expect(screen.getByText('Payment methods tab')).toBeInTheDocument();
125-
126-
const statsBtn = screen.getByRole('button', {
127-
name: 'Switch stats',
128-
});
129-
windowLocationSpy.mockImplementation(() => ({
130-
...originalLocation,
131-
href: 'http://localhost/my-profile?tab=Stats',
132-
pathname: 'my-profile',
133-
search: '?tab=Stats',
134-
}));
135-
userEvent.click(statsBtn);
136-
expect(mockReplace).toHaveBeenLastCalledWith({
137-
pathname: 'my-profile',
138-
search: 'tab=Stats',
139-
});
140-
expect(queryChangeEventSpy).toHaveBeenCalledWith(expect.any(Event));
141-
expect(queryChangeEventSpy.mock.calls[0][0].type).toBe('queryChange');
142-
expect(screen.getByText('Stats tab')).toBeInTheDocument();
143-
144-
const paymentMethodFormBtn = screen.getByRole('button', {
145-
name: 'Switch payment method form',
146-
});
147-
windowLocationSpy.mockImplementation(() => ({
148-
...originalLocation,
149-
href: 'http://localhost/my-profile?tab=Stats&form=Payment+method+form',
150-
pathname: 'my-profile',
151-
search: 'tab=Payment+methods&form=Payment+method+form',
152-
}));
153-
userEvent.click(paymentMethodFormBtn);
154-
expect(queryChangeEventSpy).toHaveBeenCalledWith(expect.any(Event));
155-
expect(queryChangeEventSpy.mock.calls[0][0].type).toBe('queryChange');
156-
expect(screen.getByText('Payment methods tab')).toBeInTheDocument();
157-
expect(screen.getByText('Payment method form')).toBeInTheDocument();
158-
});
23+
it('should add and replace query strings', () => {
24+
mockUseQueryParams.mockReturnValueOnce([
25+
{
26+
modal: 'NicknameModal',
27+
tab: 'Stats',
28+
},
29+
jest.fn(),
30+
]);
31+
const { result } = renderHook(() => useQueryString());
32+
const { queryString, setQueryString } = result.current;
15933

160-
it('should test case for deleting query strings', () => {
161-
const history = createMemoryHistory();
162-
history.push('/mock-my-profile');
163-
render(
164-
<Router history={history}>
165-
<MockAppContent />
166-
</Router>
167-
);
168-
expect(screen.getByText('My profile')).toBeInTheDocument();
169-
expect(screen.queryByText('Payment methods tab')).not.toBeInTheDocument();
170-
expect(screen.queryByText('Payment method form')).not.toBeInTheDocument();
34+
setQueryString({ tab: 'Stats' });
35+
expect(queryString.tab).toEqual('Stats');
17136

172-
const btn = screen.getByRole('button', {
173-
name: 'Switch payment methods',
174-
});
175-
const originalLocation = window.location;
176-
const queryChangeEventSpy = jest.spyOn(window, 'dispatchEvent');
177-
windowLocationSpy.mockImplementation(() => ({
178-
...originalLocation,
179-
href: 'http://localhost/my-profile?tab=Payment+methods',
180-
pathname: 'my-profile',
181-
search: '?tab=Payment+methods',
182-
}));
183-
userEvent.click(btn);
37+
setQueryString({ modal: 'NicknameModal' });
18438

185-
const goBackBtn = screen.getByRole('button', {
186-
name: 'Go back',
187-
});
188-
windowLocationSpy.mockImplementation(() => ({
189-
...originalLocation,
190-
href: 'http://localhost/my-profile?form=Payment+method+form',
191-
pathname: 'my-profile',
192-
search: 'form=Payment+method+form',
193-
}));
194-
userEvent.click(goBackBtn);
195-
expect(mockReplace).toHaveBeenLastCalledWith({
196-
pathname: 'my-profile',
197-
search: 'form=Payment+method+form',
198-
});
199-
expect(queryChangeEventSpy).toHaveBeenCalledWith(expect.any(Event));
200-
expect(queryChangeEventSpy.mock.calls[0][0].type).toBe('queryChange');
201-
expect(screen.getByText('My profile')).toBeInTheDocument();
202-
expect(screen.getByText('Payment method form')).toBeInTheDocument();
39+
expect(queryString.tab).toEqual('Stats');
40+
expect(queryString.modal).toEqual('NicknameModal');
20341
});
204-
it('should test case for replacing query strings', () => {
205-
const history = createMemoryHistory();
206-
history.push('/mock-my-profile');
207-
render(
208-
<Router history={history}>
209-
<MockAppContent />
210-
</Router>
211-
);
212-
expect(screen.getByText('My profile')).toBeInTheDocument();
213-
expect(screen.queryByText('Counterparties tab')).not.toBeInTheDocument();
214-
expect(screen.queryByText('Payment method form')).not.toBeInTheDocument();
21542

216-
const btn = screen.getByRole('button', {
217-
name: 'Switch counterparties',
218-
});
219-
const originalLocation = window.location;
220-
const queryChangeEventSpy = jest.spyOn(window, 'dispatchEvent');
221-
windowLocationSpy.mockImplementation(() => ({
222-
...originalLocation,
223-
href: 'http://localhost/my-profile?tab=Counterparties&form=Payment+method+form',
224-
pathname: 'my-profile',
225-
search: 'tab=Counterparties&form=Payment+method+form',
226-
}));
227-
userEvent.click(btn);
43+
it('calls deleteQueryString with correct key', () => {
44+
mockUseQueryParams.mockReturnValueOnce([{}, jest.fn()]);
45+
const { result } = renderHook(() => useQueryString());
46+
const { deleteQueryString } = result.current;
22847

229-
expect(queryChangeEventSpy).toHaveBeenCalledWith(expect.any(Event));
230-
expect(queryChangeEventSpy.mock.calls[0][0].type).toBe('queryChange');
231-
expect(screen.getByText('Counterparties tab')).toBeInTheDocument();
232-
expect(screen.getByText('Payment method form')).toBeInTheDocument();
48+
deleteQueryString('tab');
49+
expect(result.current.queryString.tab).toBe(undefined);
23350
});
23451
});

0 commit comments

Comments
 (0)