Skip to content

Commit

Permalink
feat: add preserveQuery option to Wizard (#126)
Browse files Browse the repository at this point in the history
  • Loading branch information
teofanis authored Nov 22, 2023
1 parent ba94b90 commit 142d4b3
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ A higher order component that adds [`context.wizard`](#contextwizard) as a `wiza
* `step` (object): Describes the current step with structure: `{ id: string }`.
* `steps` (array): Array of `step` objects in the order they were declared within `<Steps>`.
* `history` (object): The backing [`history`](https://github.com/ReactTraining/history#properties) object.
* `preserveQuery` (boolean): Whether or not to preserve the query string when navigating between steps.
* `next()` (function): Moves to the next step in order.
* `previous()` (function): Moves to the previous step in order.
* `go(n)` (function): Moves `n` steps in history.
Expand Down
126 changes: 126 additions & 0 deletions __tests__/components/Wizard.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,130 @@ describe('Wizard', () => {
mounted.unmount();
});
});

describe('with existing history and preserving search params', () => {
let wizard;
let mounted;

const mockReplace = jest.fn();
const mockPush = jest.fn();

beforeEach(() => {
jest.clearAllMocks();
});

describe('initially at /gryffindor with ?foo=bar', () => {
const history = {
replace: mockReplace,
listen: () => () => null,
location: {
pathname: '/gryffindor',
search: '?foo=bar',
},
};

beforeEach(() => {
mounted = mount(
<Wizard history={history} preserveQuery={true}>
<WithWizard>
{prop => {
wizard = prop;
return null;
}}
</WithWizard>
<Steps>
<Step id="gryffindor">
<div />
</Step>
<Step id="slytherin">
<div />
</Step>
<Step id="hufflepuff">
<div />
</Step>
</Steps>
</Wizard>
);
});

it('should preserve query when calling next', () => {
wizard.history.push = mockPush;
wizard.next();
expect(mockPush).toBeCalledWith({ pathname: '/slytherin', search: '?foo=bar' });
});

it('should preserve query when calling replace', () => {
wizard.replace('hufflepuff');
expect(mockReplace).toBeCalledWith({ pathname: '/hufflepuff', search: '?foo=bar' });
});

it('should produce the correct URL string when preserving search params', () => {
wizard.replace('hufflepuff');
const callArgs = mockReplace.mock.calls[0][0];
const actualURL = `${callArgs.pathname}${callArgs.search}`;
expect(actualURL).toBe('/hufflepuff?foo=bar');
});

it('should not add search params if none existed initially when calling push', () => {
history.location.search = '';
wizard.push('hufflepuff');
expect(mockPush).toBeCalledWith({ pathname: '/hufflepuff', search: '' });
});
});

describe('initially at /slytherin with ?quidditch=true', () => {
const history = {
replace: mockReplace,
listen: () => () => null,
location: {
pathname: '/slytherin',
search: '?quidditch=true',
},
};

beforeEach(() => {
mounted = mount(
<Wizard history={history} preserveQuery={true}>
<WithWizard>
{prop => {
wizard = prop;
return null;
}}
</WithWizard>
<Steps>
<Step id="gryffindor">
<div />
</Step>
<Step id="slytherin">
<div />
</Step>
<Step id="hufflepuff">
<div />
</Step>
</Steps>
</Wizard>
);
});

it('should preserve query when calling next', () => {
wizard.history.push = jest.fn();
wizard.next();
expect(wizard.history.push).toBeCalledWith({
pathname: '/hufflepuff',
search: '?quidditch=true',
});
});

it('should produce the correct URL string when preserving search params', () => {
wizard.replace('gryffindor');
const callArgs = mockReplace.mock.calls[0][0];
const actualURL = `${callArgs.pathname}${callArgs.search}`;
expect(actualURL).toBe('/gryffindor?quidditch=true');
});
});

afterEach(() => {
mounted.unmount();
});
});
});
16 changes: 14 additions & 2 deletions src/components/Wizard.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,19 @@ class Wizard extends Component {
});
};

set = step => this.history.push(`${this.basename}${step}`);
constructPath = step => {
if (this.props.preserveQuery) {
return {
...this.history.location,
pathname: `${this.basename}${step}`,
};
}
return `${this.basename}${step}`;
};

push = (step = this.nextStep) => this.set(step);
replace = (step = this.nextStep) => this.history.replace(`${this.basename}${step}`);
set = step => this.history.push(this.constructPath(step));
replace = (step = this.nextStep) => this.history.replace(this.constructPath(step));
pushPrevious = (step = this.previousStep) => this.set(step);

next = () => {
Expand All @@ -122,6 +132,7 @@ class Wizard extends Component {

Wizard.propTypes = {
basename: PropTypes.string,
preserveQuery: PropTypes.bool,
history: PropTypes.shape({
// disabling due to lost context
// eslint-disable-next-line react/forbid-prop-types
Expand All @@ -141,6 +152,7 @@ Wizard.propTypes = {

Wizard.defaultProps = {
basename: '',
preserveQuery: false,
history: null,
onNext: null,
render: null,
Expand Down

0 comments on commit 142d4b3

Please sign in to comment.