UNPKG

react-url-query

Version:

A library for managing state through query parameters in the URL in React. Works well with or without Redux and React Router.

486 lines (372 loc) 17.9 kB
'use strict'; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _enzyme = require('enzyme'); var _addUrlProps = require('../addUrlProps'); var _addUrlProps2 = _interopRequireDefault(_addUrlProps); var _UrlQueryParamTypes = require('../../UrlQueryParamTypes'); var _UrlQueryParamTypes2 = _interopRequireDefault(_UrlQueryParamTypes); var _UrlUpdateTypes = require('../../UrlUpdateTypes'); var _UrlUpdateTypes2 = _interopRequireDefault(_UrlUpdateTypes); var _urlQueryConfig = require('../../urlQueryConfig'); var _urlQueryConfig2 = _interopRequireDefault(_urlQueryConfig); var _configureUrlQuery = require('../../configureUrlQuery'); var _configureUrlQuery2 = _interopRequireDefault(_configureUrlQuery); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var defaultUrlQueryConfig = _extends({}, _urlQueryConfig2.default); var MyComponent = function MyComponent() { return _react2.default.createElement('div', null); }; beforeEach(function () { (0, _configureUrlQuery2.default)(_extends({}, defaultUrlQueryConfig)); }); describe('url query params as props', function () { it('passes URL query parameters through', function () { var location = { query: { foo: '94', bar: 'baz' } }; var Wrapped = (0, _addUrlProps2.default)()(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location, otherProp: true, foo: 1000 })); var props = wrapper.first().props(); // this only works when using `shallow` not `mount` expect(props.otherProp).toBe(true); expect(props.location).toBe(location); expect(props.foo).toBe('94'); expect(props.bar).toBe('baz'); }); it('decodes URL query params as props based on config', function () { var location = { query: { fooInUrl: '94', bar: 'baz' } }; var urlPropsQueryConfig = { foo: { type: _UrlQueryParamTypes2.default.number, queryParam: 'fooInUrl' }, bar: { type: _UrlQueryParamTypes2.default.string } }; var Wrapped = (0, _addUrlProps2.default)({ urlPropsQueryConfig: urlPropsQueryConfig })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); expect(props.location).toBe(location); expect(props.foo).toBe(94); expect(props.bar).toBe('baz'); }); it('mapUrlToProps updates url query params as props', function () { var location = { query: { fooInUrl: '94', bar: 'baz' } }; function mapUrlToProps(url) { return { foo: parseInt(url.fooInUrl, 10), bar: url.bar }; } var Wrapped = (0, _addUrlProps2.default)({ mapUrlToProps: mapUrlToProps })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); expect(props.location).toBe(location); expect(props.foo).toBe(94); expect(props.bar).toBe('baz'); }); it('mapUrlToProps given decoded URL params if config also passed', function () { var location = { query: { fooInUrl: '94', bar: 'baz' } }; var urlPropsQueryConfig = { foo: { type: _UrlQueryParamTypes2.default.number, queryParam: 'fooInUrl' }, bar: { type: _UrlQueryParamTypes2.default.string } }; function mapUrlToProps(url) { return { foo: url.foo * 100, bar: url.bar }; } var Wrapped = (0, _addUrlProps2.default)({ mapUrlToProps: mapUrlToProps, urlPropsQueryConfig: urlPropsQueryConfig })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); expect(props.location).toBe(location); expect(props.foo).toBe(9400); expect(props.bar).toBe('baz'); }); it('reads query params from urlQueryConfig.history.location', function () { var location = { query: { foo: '94', bar: 'baz' } }; var Wrapped = (0, _addUrlProps2.default)()(MyComponent); // set the history to have our location in it. Configure the history after // the Wrapped component is defined as that is likely how it will happen // in applications due to the way imports are resolved. (0, _configureUrlQuery2.default)({ history: { location: location } }); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, null)); var props = wrapper.first().props(); expect(props.foo).toBe('94'); expect(props.bar).toBe('baz'); }); // TODO: would be nice to test for reading from window.location // but https://github.com/facebook/jest/issues/890 }); describe('adds router params', function () { it('url props includes props.params if addRouterParams is true', function () { var location = { query: { fooInUrl: '94', bar: 'baz' } }; var Wrapped = (0, _addUrlProps2.default)({ addRouterParams: true })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location, params: { word: 'test' } })); var props = wrapper.first().props(); expect(props.word).toBe('test'); }); it('url props does not include props.params if addRouterParams is false', function () { var location = { query: { fooInUrl: '94', bar: 'baz' } }; var Wrapped = (0, _addUrlProps2.default)({ addRouterParams: false })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location, params: { word: 'test' } })); var props = wrapper.first().props(); expect(props.word).not.toBeDefined(); }); it('reads addRouterParams from urlQueryConfig dynamically', function () { var location = { query: { fooInUrl: '94', bar: 'baz' } }; // set to true before creating component (0, _configureUrlQuery2.default)({ addRouterParams: true }); var Wrapped = (0, _addUrlProps2.default)()(MyComponent); // update global config to be false after creating component, before rendering (0, _configureUrlQuery2.default)({ addRouterParams: false }); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location, params: { word: 'test' } })); var props = wrapper.first().props(); expect(props.word).not.toBeDefined(); }); }); describe('url change callbacks', function () { it('generates change handlers based on config', function () { var location = { query: { fooInUrl: '94', bar: 'baz' } }; var urlPropsQueryConfig = { foo: { type: _UrlQueryParamTypes2.default.number, queryParam: 'fooInUrl' }, bar: { type: _UrlQueryParamTypes2.default.string } }; var Wrapped = (0, _addUrlProps2.default)({ urlPropsQueryConfig: urlPropsQueryConfig, addUrlChangeHandlers: true })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); expect(props.onChangeFoo).toBeDefined(); expect(props.onChangeBar).toBeDefined(); expect(props.onChangeUrlQueryParams).toBeDefined(); }); it('does not generate change handlers when addUrlChangeHandlers is false', function () { var location = { query: { fooInUrl: '94', bar: 'baz' } }; var urlPropsQueryConfig = { foo: { type: _UrlQueryParamTypes2.default.number, queryParam: 'fooInUrl' }, bar: { type: _UrlQueryParamTypes2.default.string } }; var Wrapped = (0, _addUrlProps2.default)({ urlPropsQueryConfig: urlPropsQueryConfig, addUrlChangeHandlers: false })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); expect(props.onChangeFoo).not.toBeDefined(); expect(props.onChangeBar).not.toBeDefined(); expect(props.onChangeUrlQueryParams).not.toBeDefined(); }); it('reads addUrlChangeHandlers from urlQueryConfig', function () { var location = { query: { fooInUrl: '94', bar: 'baz' } }; var urlPropsQueryConfig = { foo: { type: _UrlQueryParamTypes2.default.number, queryParam: 'fooInUrl' }, bar: { type: _UrlQueryParamTypes2.default.string } }; (0, _configureUrlQuery2.default)({ addUrlChangeHandlers: false }); var Wrapped = (0, _addUrlProps2.default)({ urlPropsQueryConfig: urlPropsQueryConfig })(MyComponent); (0, _configureUrlQuery2.default)({ addUrlChangeHandlers: true }); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); expect(props.onChangeFoo).toBeDefined(); expect(props.onChangeBar).toBeDefined(); (0, _configureUrlQuery2.default)({ addUrlChangeHandlers: false }); wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); props = wrapper.first().props(); expect(props.onChangeFoo).not.toBeDefined(); expect(props.onChangeBar).not.toBeDefined(); }); it('generated change handlers have name configured by changeHandlerName', function () { (0, _configureUrlQuery2.default)({ addUrlChangeHandlers: true }); var location = { query: { fooInUrl: '94', bar: 'baz' } }; var urlPropsQueryConfig = { foo: { type: _UrlQueryParamTypes2.default.number, queryParam: 'fooInUrl' }, bar: { type: _UrlQueryParamTypes2.default.string } }; var changeHandlerName = function changeHandlerName(propName) { return 'handle_' + propName; }; var Wrapped = (0, _addUrlProps2.default)({ urlPropsQueryConfig: urlPropsQueryConfig, changeHandlerName: changeHandlerName })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); expect(props.handle_foo).toBeDefined(); expect(props.handle_bar).toBeDefined(); }); it('generated change handlers have name configured by changeHandlerName in urlQueryConfig', function () { var location = { query: { fooInUrl: '94', bar: 'baz' } }; var urlPropsQueryConfig = { foo: { type: _UrlQueryParamTypes2.default.number, queryParam: 'fooInUrl' }, bar: { type: _UrlQueryParamTypes2.default.string } }; var changeHandlerName = function changeHandlerName(propName) { return 'handle_' + propName; }; var Wrapped = (0, _addUrlProps2.default)({ urlPropsQueryConfig: urlPropsQueryConfig })(MyComponent); (0, _configureUrlQuery2.default)({ addUrlChangeHandlers: true, changeHandlerName: changeHandlerName }); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); expect(props.handle_foo).toBeDefined(); expect(props.handle_bar).toBeDefined(); }); it('mapUrlChangeHandlersToProps adds props', function () { var location = { query: { foo: '94', bar: 'baz' } }; function onChangeFoo(foo) { return foo; } function mapUrlChangeHandlersToProps() { return { onChangeFoo: onChangeFoo }; } var Wrapped = (0, _addUrlProps2.default)({ mapUrlChangeHandlersToProps: mapUrlChangeHandlersToProps })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); expect(props.onChangeFoo).toBe(onChangeFoo); expect(props.onChangeBar).not.toBeDefined(); props.onChangeFoo(123); }); it('mapUrlChangeHandlersToProps can access generated handlers', function () { var location = { query: { foo: '94', bar: 'baz' } }; var urlPropsQueryConfig = { foo: { type: _UrlQueryParamTypes2.default.number }, bar: { type: _UrlQueryParamTypes2.default.string } }; var onChangeFoo = function onChangeFoo(foo) { return foo; }; function mapUrlChangeHandlersToProps(props, handlers) { return { onChangeFoo: onChangeFoo, onChangeBar: handlers.onChangeBar }; } var Wrapped = (0, _addUrlProps2.default)({ urlPropsQueryConfig: urlPropsQueryConfig, mapUrlChangeHandlersToProps: mapUrlChangeHandlersToProps, addUrlChangeHandlers: true })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); expect(props.onChangeFoo).toBe(onChangeFoo); expect(props.onChangeBar).toBeDefined(); }); it('generated change handlers are only generated once, not every render', function () { var location = { query: { foo: '94', bar: 'baz' } }; var urlPropsQueryConfig = { foo: { type: _UrlQueryParamTypes2.default.number }, bar: { type: _UrlQueryParamTypes2.default.string } }; var Wrapped = (0, _addUrlProps2.default)({ urlPropsQueryConfig: urlPropsQueryConfig, addUrlChangeHandlers: true })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); var onChangeFoo = props.onChangeFoo; var onChangeBar = props.onChangeBar; // cause a re-render wrapper.setProps({ baz: 123 }); var newProps = wrapper.first().props(); expect(newProps.onChangeFoo).toBe(onChangeFoo); expect(newProps.onChangeBar).toBe(onChangeBar); }); it('generated change handlers encode values properly and interpret updateType', function () { var location = { query: { foo: '94', bar: 'baz' } }; var urlPropsQueryConfig = { foo: { type: _UrlQueryParamTypes2.default.number }, bar: { type: _UrlQueryParamTypes2.default.string, updateType: _UrlUpdateTypes2.default.pushIn } }; // make the history just return the new location so we can test for logging var history = { replace: jest.fn().mockImplementation(function (d) { return d; }), push: jest.fn().mockImplementation(function (d) { return d; }) }; (0, _configureUrlQuery2.default)({ history: history }); var Wrapped = (0, _addUrlProps2.default)({ urlPropsQueryConfig: urlPropsQueryConfig, addUrlChangeHandlers: true })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); var onChangeFoo = props.onChangeFoo; var onChangeBar = props.onChangeBar; var fooChangeResult = onChangeFoo(123); expect(history.replace).toBeCalled(); expect(history.push).not.toBeCalled(); expect(fooChangeResult).toEqual({ query: { foo: '123', bar: 'baz' } }); var barChangeResult = onChangeBar('new-bar'); expect(history.push).toBeCalled(); expect(barChangeResult).toEqual({ query: { foo: '94', bar: 'new-bar' } }); }); it('generated change handlers to read location dynamically from props', function () { var location = { query: { foo: '94', bar: 'baz' } }; var urlPropsQueryConfig = { foo: { type: _UrlQueryParamTypes2.default.number }, bar: { type: _UrlQueryParamTypes2.default.string, updateType: _UrlUpdateTypes2.default.pushIn } }; // make the history just return the new location so we can test for logging var history = { replace: jest.fn().mockImplementation(function (d) { return d; }), push: jest.fn().mockImplementation(function (d) { return d; }) }; (0, _configureUrlQuery2.default)({ history: history }); var Wrapped = (0, _addUrlProps2.default)({ urlPropsQueryConfig: urlPropsQueryConfig, addUrlChangeHandlers: true })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); var onChangeFoo = props.onChangeFoo; var onChangeBar = props.onChangeBar; // update the prop location var location2 = { query: { foo: '1000', bar: 'BAR' } }; wrapper.setProps({ location: location2 }); var fooChangeResult = onChangeFoo(123); expect(fooChangeResult).toEqual({ query: { foo: '123', bar: 'BAR' } }); var barChangeResult = onChangeBar('new-bar'); expect(barChangeResult).toEqual({ query: { foo: '1000', bar: 'new-bar' } }); }); it('generated change handlers do not update if the URL is the same', function () { var location = { query: { foo: '94', bar: 'baz' } }; var urlPropsQueryConfig = { foo: { type: _UrlQueryParamTypes2.default.number }, bar: { type: _UrlQueryParamTypes2.default.string, updateType: _UrlUpdateTypes2.default.pushIn } }; // make the history just return the new location so we can test for logging var history = { replace: jest.fn().mockImplementation(function (d) { return d; }), push: jest.fn().mockImplementation(function (d) { return d; }) }; (0, _configureUrlQuery2.default)({ history: history }); var Wrapped = (0, _addUrlProps2.default)({ urlPropsQueryConfig: urlPropsQueryConfig, addUrlChangeHandlers: true })(MyComponent); var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(Wrapped, { location: location })); var props = wrapper.first().props(); var onChangeFoo = props.onChangeFoo; var onChangeBar = props.onChangeBar; onChangeFoo(94); expect(history.replace).not.toBeCalled(); onChangeBar('baz'); expect(history.push).not.toBeCalled(); }); });