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
JavaScript
'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();
});
});