mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2026-03-11 18:13:47 +00:00
Created CreateShortUrl test
This commit is contained in:
@@ -5,12 +5,22 @@ import { assoc, dissoc, isNil, pick, pipe, replace, trim } from 'ramda';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Collapse } from 'reactstrap';
|
import { Collapse } from 'reactstrap';
|
||||||
|
import * as PropTypes from 'prop-types';
|
||||||
import DateInput from '../utils/DateInput';
|
import DateInput from '../utils/DateInput';
|
||||||
import TagsSelector from '../tags/helpers/TagsSelector';
|
import TagsSelector from '../tags/helpers/TagsSelector';
|
||||||
import CreateShortUrlResult from './helpers/CreateShortUrlResult';
|
import CreateShortUrlResult from './helpers/CreateShortUrlResult';
|
||||||
import { createShortUrl, resetCreateShortUrl } from './reducers/shortUrlCreation';
|
import { createShortUrl, createShortUrlResultType, resetCreateShortUrl } from './reducers/shortUrlCreation';
|
||||||
|
|
||||||
|
const normalizeTag = pipe(trim, replace(/ /g, '-'));
|
||||||
|
const formatDate = (date) => isNil(date) ? date : date.format();
|
||||||
|
|
||||||
export class CreateShortUrlComponent extends React.Component {
|
export class CreateShortUrlComponent extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
createShortUrl: PropTypes.func,
|
||||||
|
shortUrlCreationResult: createShortUrlResultType,
|
||||||
|
resetCreateShortUrl: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
longUrl: '',
|
longUrl: '',
|
||||||
tags: [],
|
tags: [],
|
||||||
@@ -24,27 +34,31 @@ export class CreateShortUrlComponent extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
const { createShortUrl, shortUrlCreationResult, resetCreateShortUrl } = this.props;
|
const { createShortUrl, shortUrlCreationResult, resetCreateShortUrl } = this.props;
|
||||||
|
|
||||||
const changeTags = (tags) => this.setState({ tags: tags.map(pipe(trim, replace(/ /g, '-'))) });
|
const changeTags = (tags) => this.setState({ tags: tags.map(normalizeTag) });
|
||||||
const renderOptionalInput = (id, placeholder, type = 'text', props = {}) => (
|
const renderOptionalInput = (id, placeholder, type = 'text', props = {}) => (
|
||||||
<input
|
<div className="form-group">
|
||||||
className="form-control"
|
<input
|
||||||
type={type}
|
className="form-control"
|
||||||
placeholder={placeholder}
|
id={id}
|
||||||
value={this.state[id]}
|
type={type}
|
||||||
onChange={(e) => this.setState({ [id]: e.target.value })}
|
placeholder={placeholder}
|
||||||
{...props}
|
value={this.state[id]}
|
||||||
/>
|
onChange={(e) => this.setState({ [id]: e.target.value })}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
const createDateInput = (id, placeholder, props = {}) => (
|
const renderDateInput = (id, placeholder, props = {}) => (
|
||||||
<DateInput
|
<div className="form-group">
|
||||||
selected={this.state[id]}
|
<DateInput
|
||||||
placeholderText={placeholder}
|
selected={this.state[id]}
|
||||||
isClearable
|
placeholderText={placeholder}
|
||||||
onChange={(date) => this.setState({ [id]: date })}
|
isClearable
|
||||||
{...props}
|
onChange={(date) => this.setState({ [id]: date })}
|
||||||
/>
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
const formatDate = (date) => isNil(date) ? date : date.format();
|
|
||||||
const save = (e) => {
|
const save = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
createShortUrl(pipe(
|
createShortUrl(pipe(
|
||||||
@@ -75,20 +89,12 @@ export class CreateShortUrlComponent extends React.Component {
|
|||||||
|
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-sm-6">
|
<div className="col-sm-6">
|
||||||
<div className="form-group">
|
{renderOptionalInput('customSlug', 'Custom slug')}
|
||||||
{renderOptionalInput('customSlug', 'Custom slug')}
|
{renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
|
||||||
</div>
|
|
||||||
<div className="form-group">
|
|
||||||
{renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="col-sm-6">
|
<div className="col-sm-6">
|
||||||
<div className="form-group">
|
{renderDateInput('validSince', 'Enabled since...', { maxDate: this.state.validUntil })}
|
||||||
{createDateInput('validSince', 'Enabled since...', { maxDate: this.state.validUntil })}
|
{renderDateInput('validUntil', 'Enabled until...', { minDate: this.state.validSince })}
|
||||||
</div>
|
|
||||||
<div className="form-group">
|
|
||||||
{createDateInput('validUntil', 'Enabled until...', { minDate: this.state.validSince })}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|||||||
@@ -10,21 +10,19 @@ const propTypes = {
|
|||||||
isOpen: PropTypes.bool,
|
isOpen: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
const PreviewModal = ({ url, toggle, isOpen }) => {
|
const PreviewModal = ({ url, toggle, isOpen }) => (
|
||||||
return (
|
<Modal isOpen={isOpen} toggle={toggle} size="lg">
|
||||||
<Modal isOpen={isOpen} toggle={toggle} size="lg">
|
<ModalHeader toggle={toggle}>
|
||||||
<ModalHeader toggle={toggle}>
|
Preview for <ExternalLink href={url}>{url}</ExternalLink>
|
||||||
Preview for <ExternalLink href={url}>{url}</ExternalLink>
|
</ModalHeader>
|
||||||
</ModalHeader>
|
<ModalBody>
|
||||||
<ModalBody>
|
<div className="text-center">
|
||||||
<div className="text-center">
|
<p className="preview-modal__loader">Loading...</p>
|
||||||
<p className="preview-modal__loader">Loading...</p>
|
<img src={`${url}/preview`} className="preview-modal__img" alt="Preview" />
|
||||||
<img src={`${url}/preview`} className="preview-modal__img" alt="Preview" />
|
</div>
|
||||||
</div>
|
</ModalBody>
|
||||||
</ModalBody>
|
</Modal>
|
||||||
</Modal>
|
);
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
PreviewModal.propTypes = propTypes;
|
PreviewModal.propTypes = propTypes;
|
||||||
|
|
||||||
|
|||||||
@@ -10,20 +10,18 @@ const propTypes = {
|
|||||||
isOpen: PropTypes.bool,
|
isOpen: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
const QrCodeModal = ({ url, toggle, isOpen }) => {
|
const QrCodeModal = ({ url, toggle, isOpen }) => (
|
||||||
return (
|
<Modal isOpen={isOpen} toggle={toggle} centered>
|
||||||
<Modal isOpen={isOpen} toggle={toggle} centered>
|
<ModalHeader toggle={toggle}>
|
||||||
<ModalHeader toggle={toggle}>
|
QR code for <ExternalLink href={url}>{url}</ExternalLink>
|
||||||
QR code for <ExternalLink href={url}>{url}</ExternalLink>
|
</ModalHeader>
|
||||||
</ModalHeader>
|
<ModalBody>
|
||||||
<ModalBody>
|
<div className="text-center">
|
||||||
<div className="text-center">
|
<img src={`${url}/qr-code`} className="qr-code-modal__img" alt="QR code" />
|
||||||
<img src={`${url}/qr-code`} className="qr-code-modal__img" alt="QR code" />
|
</div>
|
||||||
</div>
|
</ModalBody>
|
||||||
</ModalBody>
|
</Modal>
|
||||||
</Modal>
|
);
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
QrCodeModal.propTypes = propTypes;
|
QrCodeModal.propTypes = propTypes;
|
||||||
|
|
||||||
|
|||||||
66
test/short-urls/CreateShortUrl.test.js
Normal file
66
test/short-urls/CreateShortUrl.test.js
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import moment from 'moment';
|
||||||
|
import * as sinon from 'sinon';
|
||||||
|
import { identity } from 'ramda';
|
||||||
|
import { CreateShortUrlComponent as CreateShortUrl } from '../../src/short-urls/CreateShortUrl';
|
||||||
|
import TagsSelector from '../../src/tags/helpers/TagsSelector';
|
||||||
|
import DateInput from '../../src/utils/DateInput';
|
||||||
|
|
||||||
|
describe('<CreateShortUrl />', () => {
|
||||||
|
let wrapper;
|
||||||
|
const shortUrlCreationResult = {
|
||||||
|
loading: false,
|
||||||
|
};
|
||||||
|
const createShortUrl = sinon.spy();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = shallow(
|
||||||
|
<CreateShortUrl shortUrlCreationResult={shortUrlCreationResult} createShortUrl={createShortUrl} />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
wrapper.unmount();
|
||||||
|
createShortUrl.resetHistory();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('saves short URL with data set in form controls', (done) => {
|
||||||
|
const validSince = moment('2017-01-01');
|
||||||
|
const validUntil = moment('2017-01-06');
|
||||||
|
|
||||||
|
const urlInput = wrapper.find('.form-control-lg');
|
||||||
|
const tagsInput = wrapper.find(TagsSelector);
|
||||||
|
const customSlugInput = wrapper.find('#customSlug');
|
||||||
|
const maxVisitsInput = wrapper.find('#maxVisits');
|
||||||
|
const dateInputs = wrapper.find(DateInput);
|
||||||
|
const validSinceInput = dateInputs.at(0);
|
||||||
|
const validUntilInput = dateInputs.at(1);
|
||||||
|
|
||||||
|
urlInput.simulate('change', { target: { value: 'https://long-domain.com/foo/bar' } });
|
||||||
|
tagsInput.simulate('change', [ 'tag_foo', 'tag_bar' ]);
|
||||||
|
customSlugInput.simulate('change', { target: { value: 'my-slug' } });
|
||||||
|
maxVisitsInput.simulate('change', { target: { value: '20' } });
|
||||||
|
validSinceInput.simulate('change', validSince);
|
||||||
|
validUntilInput.simulate('change', validUntil);
|
||||||
|
|
||||||
|
setImmediate(() => {
|
||||||
|
const form = wrapper.find('form');
|
||||||
|
|
||||||
|
form.simulate('submit', { preventDefault: identity });
|
||||||
|
expect(createShortUrl.callCount).toEqual(1);
|
||||||
|
expect(createShortUrl.getCall(0).args).toEqual(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
longUrl: 'https://long-domain.com/foo/bar',
|
||||||
|
tags: [ 'tag_foo', 'tag_bar' ],
|
||||||
|
customSlug: 'my-slug',
|
||||||
|
validSince: validSince.format(),
|
||||||
|
validUntil: validUntil.format(),
|
||||||
|
maxVisits: '20',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user