Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: filter modal refactoring, ts migration #67

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,22 @@ type TToggleSwitch = {
handleToggle: () => void;
id: string;
is_enabled: boolean;
name?: string;
};

const ToggleSwitch = ({ className, classNameButton, classNameLabel, handleToggle, id, is_enabled }: TToggleSwitch) => {
const ToggleSwitch = ({
className,
classNameButton,
classNameLabel,
handleToggle,
id,
is_enabled,
name = 'toggle_switch',
}: TToggleSwitch) => {
return (
<React.Fragment>
<input
aria-label={name}
className={classNames('dc-toggle-switch', className)}
id={id}
type='checkbox'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,26 @@ const ModalManagerContextProvider = (props: React.PropsWithChildren<{ mock?: TMo
* @param {key} string - the key to specify when persisting the local state, by default you should specify the local state name
* @param {default_state} - the value you want the state to be initially
*/
const useSavedState = (key, default_state) => {
const useSavedState = (key: string, default_state: string[]) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-blocking: i changed a bit here as well and fixed the typing issue for it but i dont think it'll cause any huge conflicts when we merge quick add modal as well 🙏

const [saved_state, setSavedState] = React.useState(default_state);
const saved_state_ref = React.useRef(saved_state);

React.useEffect(() => {
const persisted_state = persisted_states.current[active_modal.key];
const persisted_state = persisted_states.current[modal.active_modal.key];

if (persisted_state) {
if (persisted_state[key]) {
setSavedState(persisted_state[key]);
}
} else {
persisted_states.current[active_modal.key] = {
persisted_states.current[modal.active_modal.key] = {
[key]: default_state,
};
}

return () => {
if (persisted_states.current[active_modal.key]) {
persisted_states.current[active_modal.key][key] = saved_state_ref.current;
if (persisted_states.current[modal.active_modal.key]) {
persisted_states.current[modal.active_modal.key][key] = saved_state_ref.current;
}
};
}, []);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ describe('<CancelAddPaymentMethodModal />', () => {
expect(mock_modal_manager_context.hideModal).toHaveBeenCalledWith({
should_save_form_history: false,
should_hide_all_modals: true,
should_restore_local_state: false,
});
});

Expand All @@ -78,6 +79,7 @@ describe('<CancelAddPaymentMethodModal />', () => {
expect(mock_modal_manager_context.hideModal).toHaveBeenCalledWith({
should_save_form_history: false,
should_hide_all_modals: false,
should_restore_local_state: false,
});
});

Expand All @@ -88,6 +90,7 @@ describe('<CancelAddPaymentMethodModal />', () => {

expect(mock_modal_manager_context.hideModal).toHaveBeenCalledWith({
should_save_form_history: true,
should_restore_local_state: true,
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { useStores } from 'Stores';
import FilterModalBody from '../filter-modal-body';

const mock_store_values: DeepPartial<ReturnType<typeof useStores>> = {
buy_sell_store: {
setShowFilterPaymentMethods: jest.fn(),
setShouldUseClientLimits: jest.fn(),
show_filter_payment_methods: false,
should_use_client_limits: false,
},
my_profile_store: {
payment_methods_list_items: [
{
text: 'Skrill',
value: 'skrill',
},
],
},
};

const mock_props = {
onChange: jest.fn(),
selected_methods: ['skrill'],
selected_methods_text: ['Skrill'],
setHasMadeChanges: jest.fn(),
};

jest.mock('Stores', () => ({
...jest.requireActual('Stores'),
useStores: jest.fn(() => mock_store_values),
}));

jest.mock('../filter-modal-result', () => jest.fn(() => <div>FilterModalResult</div>));
jest.mock('../filter-modal-search', () => jest.fn(() => <div>FilterModalSearch</div>));

describe('<FilterModalBody />', () => {
it('should render the modal content', () => {
render(<FilterModalBody {...mock_props} />);
expect(screen.getByText('Payment methods')).toBeInTheDocument();
expect(screen.getByText('Matching ads')).toBeInTheDocument();
});
it('should handle onclick for payment methods section', () => {
render(<FilterModalBody {...mock_props} />);
userEvent.click(screen.getByText('Payment methods'));
expect(mock_store_values.buy_sell_store.setShowFilterPaymentMethods).toHaveBeenCalledWith(true);
});
it('should handle toggle button click', () => {
render(<FilterModalBody {...mock_props} />);
userEvent.click(screen.getByRole('checkbox', { name: 'matching_ads_toggler' }));
expect(mock_store_values.buy_sell_store.setShouldUseClientLimits).toHaveBeenCalledWith(true);
expect(mock_props.setHasMadeChanges).toHaveBeenCalledWith(true);
});
it('should show the result section and search section when payment method section was already clicked', () => {
mock_store_values.buy_sell_store.show_filter_payment_methods = true;
render(<FilterModalBody {...mock_props} />);
expect(screen.getByText('FilterModalResult')).toBeInTheDocument();
expect(screen.getByText('FilterModalSearch')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { useStores } from 'Stores';
import FilterModalFooter from '../filter-modal-footer';

const mock_store_values: DeepPartial<ReturnType<typeof useStores>> = {
buy_sell_store: {
show_filter_payment_methods: false,
},
};

const mock_props = {
class_name: '',
has_made_changes: false,
has_selected_payment_methods: false,
onClickApply: jest.fn(),
onClickClearPaymentMethods: jest.fn(),
onClickConfirmPaymentMethods: jest.fn(),
onClickReset: jest.fn(),
selected_methods: ['skrill'],
};

jest.mock('Stores', () => ({
...jest.requireActual('Stores'),
useStores: jest.fn(() => mock_store_values),
}));

describe('<FilterModalFooter />', () => {
it('should render the component', () => {
render(<FilterModalFooter {...mock_props} />);
expect(screen.getByRole('button', { name: 'Reset' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Apply' })).toBeInTheDocument();
});
it('should handle reset button click', () => {
render(<FilterModalFooter {...mock_props} />);
userEvent.click(screen.getByRole('button', { name: 'Reset' }));
expect(mock_props.onClickReset).toHaveBeenCalledTimes(1);
});
it('should handle apply button click', () => {
const new_props = { ...mock_props, has_made_changes: true };

render(<FilterModalFooter {...new_props} />);
userEvent.click(screen.getByRole('button', { name: 'Apply' }));
expect(mock_props.onClickApply).toHaveBeenCalledTimes(1);
});
it('should handle clear button click', () => {
mock_store_values.buy_sell_store.show_filter_payment_methods = true;

render(<FilterModalFooter {...mock_props} />);
userEvent.click(screen.getByRole('button', { name: 'Clear' }));
expect(mock_props.onClickClearPaymentMethods).toHaveBeenCalledTimes(1);
});
it('should handle confirm button click', () => {
mock_store_values.buy_sell_store.show_filter_payment_methods = true;
const new_props = { ...mock_props, has_selected_payment_methods: true };

render(<FilterModalFooter {...new_props} />);
userEvent.click(screen.getByRole('button', { name: 'Confirm' }));
expect(mock_props.onClickConfirmPaymentMethods).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import FilterModalHeader from '../filter-modal-header';

const mock_store = {
buy_sell_store: {
show_filter_payment_methods: false,
},
};

const mock_props = {
pageHeaderReturnFn: jest.fn(),
};

jest.mock('Stores', () => ({
...jest.requireActual('Stores'),
useStores: jest.fn(() => mock_store),
}));

describe('<FilterModalHeader />', () => {
it('should render the component', () => {
render(<FilterModalHeader {...mock_props} />);
expect(screen.getByText('Filter')).toBeInTheDocument();
});
it('should render the component with payment methods', () => {
mock_store.buy_sell_store.show_filter_payment_methods = true;
render(<FilterModalHeader {...mock_props} />);
expect(screen.getByText('Payment methods')).toBeInTheDocument();
});
it('should handle clicking return', () => {
render(<FilterModalHeader {...mock_props} />);
const return_button = screen.getByTestId('dt_page_return_icon');
userEvent.click(return_button);
expect(mock_props.pageHeaderReturnFn).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import FilterModalNoResults from '../filter-modal-no-results';

const mock_props = {
text: 'test word',
};

describe('<FilterModalNoResults />', () => {
it('should render the component with the passed props', () => {
render(<FilterModalNoResults {...mock_props} />);
expect(screen.getByText('No results for "test word".')).toBeInTheDocument();
expect(screen.getByText('Check your spelling or use a different term.')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import { useStores } from 'Stores';
import FilterModalResult from '../filter-modal-result';
import userEvent from '@testing-library/user-event';

const mock_store_values: DeepPartial<ReturnType<typeof useStores>> = {
buy_sell_store: {
is_filter_modal_loading: false,
},
my_profile_store: {
payment_methods_list_items: [
{
text: 'Skrill',
value: 'skrill',
},
{
value: 'bank',
text: 'Bank',
},
{
value: 'upi',
text: 'UPI',
},
],
search_results: [],
search_term: '',
},
};

jest.mock('Stores', () => ({
...jest.requireActual('Stores'),
useStores: jest.fn(() => mock_store_values),
}));

jest.mock('@deriv/components', () => ({
...jest.requireActual('@deriv/components'),
Loading: () => <div>Loading</div>,
}));

const mock_props = {
onChange: jest.fn(),
selected_methods: ['skrill'],
};

describe('<FilterModalResult />', () => {
it('should render the component with the passed props', () => {
render(<FilterModalResult {...mock_props} />);
expect(screen.getByText('Skrill')).toBeInTheDocument();
expect(screen.getByText('Bank')).toBeInTheDocument();
});
it('should handle checkbox selection', () => {
render(<FilterModalResult {...mock_props} />);
const checkbox = screen.getByRole('checkbox', { name: 'Skrill' });
userEvent.click(checkbox);
expect(mock_props.onChange).toHaveBeenCalledWith({ text: 'Skrill', value: 'skrill' });
});
it('should show no results if search term is present and no results are found', () => {
mock_store_values.my_profile_store.search_term = 'test';
render(<FilterModalResult {...mock_props} />);
expect(screen.getByText('No results for "test".')).toBeInTheDocument();
});
it('should show the search results if search term is present and results are found', () => {
mock_store_values.my_profile_store.search_term = 'skrill';
mock_store_values.my_profile_store.search_results = [{ text: 'Skrill', value: 'skrill' }];
render(<FilterModalResult {...mock_props} />);
expect(screen.getByText('Skrill')).toBeInTheDocument();
});
it('should handle selection of search results', () => {
mock_store_values.my_profile_store.search_term = 'skrill';
mock_store_values.my_profile_store.search_results = [{ text: 'Skrill', value: 'skrill' }];
render(<FilterModalResult {...mock_props} />);
expect(screen.getByText('Skrill')).toBeInTheDocument();
const checkbox = screen.getByRole('checkbox', { name: 'Skrill' });
userEvent.click(checkbox);
expect(mock_props.onChange).toHaveBeenCalledWith({ text: 'Skrill', value: 'skrill' });
});
it('should show the Loading indicator when in loading state', () => {
mock_store_values.buy_sell_store.is_filter_modal_loading = true;
render(<FilterModalResult {...mock_props} />);
expect(screen.getByText('Loading')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import FilterModalSearch from '../filter-modal-search';

const mock_store = {
buy_sell_store: {
setIsFilterModalLoading: jest.fn(),
},
my_profile_store: {
getPaymentMethodsList: jest.fn(),
setSearchResults: jest.fn(),
setSearchTerm: jest.fn(),
},
};
jest.mock('Stores', () => ({
...jest.requireActual('Stores'),
useStores: jest.fn(() => mock_store),
}));

describe('<FilterModalSearch />', () => {
it('should render the component', () => {
render(<FilterModalSearch />);
expect(screen.getByPlaceholderText('Search payment method')).toBeInTheDocument();
});
it('should handle search functionality', async () => {
jest.useFakeTimers();
jest.spyOn(global, 'setTimeout');
render(<FilterModalSearch />);
const field = screen.getByRole('textbox');
userEvent.type(field, 'test');
act(() => {
jest.advanceTimersByTime(1000);
});
await waitFor(() => {
expect(setTimeout).toHaveBeenCalled();
});
jest.clearAllTimers();
});
it('should handle clearing search text', () => {
render(<FilterModalSearch />);
const field = screen.getByRole('textbox');
userEvent.type(field, 'test');
const cross_icon = screen.getByTestId('dt_filter_modal_search_icon');
userEvent.click(cross_icon);
expect(field).toHaveValue('');
expect(mock_store.my_profile_store.setSearchTerm).toHaveBeenCalledWith('');
});
});
Loading
Loading