Skip to content

Commit

Permalink
feat(connectVoiceSearch): clear the state on dispose (#3823)
Browse files Browse the repository at this point in the history
* test(connectVoiceSearch): scope dispose tests togheter

* test(connectVoiceSearch): do not throw without unmount function

* feat(connectVoiceSearch): remove query on dispose

* test(connectVoiceSearch): rename jsHelper -> algoliasearchHelper

* test(connectVoiceSearch): inline test setup
  • Loading branch information
samouss authored and Haroenv committed Oct 23, 2019
1 parent 940522c commit 705b3e6
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 60 deletions.
173 changes: 114 additions & 59 deletions src/connectors/voice-search/__tests__/connectVoiceSearch-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import jsHelper, { SearchParameters } from 'algoliasearch-helper';
import algoliasearchHelper, { SearchParameters } from 'algoliasearch-helper';
import connectVoiceSearch from '../connectVoiceSearch';

jest.mock('../../../lib/voiceSearchHelper', () => {
Expand All @@ -16,30 +16,18 @@ jest.mock('../../../lib/voiceSearchHelper', () => {
};
});

function getDefaultSetup() {
const renderFn = jest.fn();
const unmountFn = jest.fn();
const makeWidget = connectVoiceSearch(renderFn, unmountFn);
const widget = makeWidget({});
const helper = jsHelper({});

return {
renderFn,
unmountFn,
widget,
helper,
};
}

function getInitializedWidget() {
const { renderFn, unmountFn, widget, helper } = getDefaultSetup();
const helper = algoliasearchHelper({}, '');

const renderFn = () => {};
const makeWidget = connectVoiceSearch(renderFn);
const widget = makeWidget({});

helper.search = () => {};
widget.init({ helper });

return {
renderFn,
unmountFn,
widget,
helper,
refine: query => widget._refine(query),
Expand All @@ -59,72 +47,139 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/voice-searc
});
});

describe('lifecycle', () => {
it('calls renderFn during init and render', () => {
const { renderFn, widget, helper } = getDefaultSetup();
widget.init({ helper });
expect(renderFn).toHaveBeenCalledTimes(1);
expect(renderFn).toHaveBeenLastCalledWith(
expect.objectContaining({}),
true
);
widget.render({
helper,
});
expect(renderFn).toHaveBeenCalledTimes(2);
expect(renderFn).toHaveBeenLastCalledWith(
expect.objectContaining({}),
false
);
});
it('calls renderFn during init and render', () => {
const helper = algoliasearchHelper({}, '');

it('calls unmount on `dispose`', () => {
const { unmountFn, widget, helper } = getDefaultSetup();
widget.init({ helper });
widget.dispose({ helper, state: helper.state });
expect(unmountFn).toHaveBeenCalledTimes(1);
});
const renderFn = jest.fn();
const makeWidget = connectVoiceSearch(renderFn);
const widget = makeWidget({});

it('removes event listeners on `dispose`', () => {
const { widget, helper } = getDefaultSetup();
widget.init({ helper });
widget.dispose({ helper, state: helper.state });
expect(widget._voiceSearchHelper.dispose).toHaveBeenCalledTimes(1);
});
widget.init({ helper });

it('does not throw without the unmount function', () => {
const renderFn = () => {};
const makeWidget = connectVoiceSearch(renderFn);
const widget = makeWidget({});
const helper = jsHelper({});
widget.init({ helper });
expect(() =>
widget.dispose({ helper, state: helper.state })
).not.toThrow();
expect(renderFn).toHaveBeenCalledTimes(1);
expect(renderFn).toHaveBeenLastCalledWith(
expect.objectContaining({}),
true
);

widget.render({
helper,
});

expect(renderFn).toHaveBeenCalledTimes(2);
expect(renderFn).toHaveBeenLastCalledWith(
expect.objectContaining({}),
false
);
});

it('triggers render when state changes', () => {
const { renderFn, widget, helper } = getDefaultSetup();
const helper = algoliasearchHelper({}, '');

const renderFn = jest.fn();
const makeWidget = connectVoiceSearch(renderFn);
const widget = makeWidget({});

widget.init({ helper });

expect(renderFn).toHaveBeenCalledTimes(1);

widget._voiceSearchHelper.changeState();

expect(renderFn).toHaveBeenCalledTimes(2);

widget._voiceSearchHelper.changeState();

expect(renderFn).toHaveBeenCalledTimes(3);
});

it('setQuery and search when query changes', () => {
const { widget, helper } = getDefaultSetup();
const helper = algoliasearchHelper({}, '');

const renderFn = jest.fn();
const makeWidget = connectVoiceSearch(renderFn);
const widget = makeWidget({});

jest.spyOn(helper, 'setQuery');

helper.search = jest.fn();

widget.init({ helper });

widget._voiceSearchHelper.changeQuery('foo');

expect(helper.setQuery).toHaveBeenCalledTimes(1);
expect(helper.setQuery).toHaveBeenCalledWith('foo');
expect(helper.search).toHaveBeenCalledTimes(1);
});

describe('dispose', () => {
it('calls the unmount function', () => {
const helper = algoliasearchHelper({}, '');

const renderFn = () => {};
const unmountFn = jest.fn();
const makeWidget = connectVoiceSearch(renderFn, unmountFn);
const widget = makeWidget({});

widget.init({ helper });

expect(unmountFn).toHaveBeenCalledTimes(0);

widget.dispose({ helper, state: helper.state });

expect(unmountFn).toHaveBeenCalledTimes(1);
});

it('does not throw without the unmount function', () => {
const helper = algoliasearchHelper({}, '');

const renderFn = () => {};
const makeWidget = connectVoiceSearch(renderFn);
const widget = makeWidget({});

widget.init({ helper });

expect(() =>
widget.dispose({ helper, state: helper.state })
).not.toThrow();
});

it('removes event listeners on the voice helper', () => {
const helper = algoliasearchHelper({}, '');

const renderFn = () => {};
const makeWidget = connectVoiceSearch(renderFn);
const widget = makeWidget({});

widget.init({ helper });

expect(widget._voiceSearchHelper.dispose).toHaveBeenCalledTimes(0);

widget.dispose({ helper, state: helper.state });

expect(widget._voiceSearchHelper.dispose).toHaveBeenCalledTimes(1);
});

it('removes the `query` from the `SearchParameters`', () => {
const helper = algoliasearchHelper({}, '', {
query: 'Apple',
});

const renderFn = () => {};
const makeWidget = connectVoiceSearch(renderFn);
const widget = makeWidget({});

widget.init({ helper });

expect(helper.state.query).toBe('Apple');

const nextState = widget.dispose({ helper, state: helper.state });

expect(nextState.query).toBeUndefined();
});
});

describe('getWidgetState', () => {
it('returns the same state if query is an empty string', () => {
const { widget, helper, refine } = getInitializedWidget();
Expand Down
8 changes: 7 additions & 1 deletion src/connectors/voice-search/connectVoiceSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,23 @@ const connectVoiceSearch: VoiceSearchConnector = (
voiceSearchHelper: (this as any)._voiceSearchHelper,
});
},

render({ instantSearchInstance }) {
render({
isFirstRendering: false,
instantSearchInstance,
voiceSearchHelper: (this as any)._voiceSearchHelper,
});
},

dispose({ state }) {
(this as any)._voiceSearchHelper.dispose();

unmountFn();
return state.setQuery('');

return state.setQueryParameter('query', undefined);
},

getWidgetState(uiState, { searchParameters }) {
const query = searchParameters.query || '';

Expand All @@ -123,6 +128,7 @@ const connectVoiceSearch: VoiceSearchConnector = (
query,
};
},

getWidgetSearchParameters(searchParameters, { uiState }) {
return searchParameters.setQueryParameter('query', uiState.query);
},
Expand Down

0 comments on commit 705b3e6

Please sign in to comment.