From 53132fa900ec9d14da1b39fb02373f0efb56ff10 Mon Sep 17 00:00:00 2001
From: Alejandro Celaya <alejandro@alejandrocelaya.com>
Date: Thu, 1 Nov 2018 13:15:09 +0100
Subject: [PATCH] Created CreateShortUrl test

---
 src/short-urls/CreateShortUrl.js       | 68 ++++++++++++++------------
 src/short-urls/helpers/PreviewModal.js | 28 +++++------
 src/short-urls/helpers/QrCodeModal.js  | 26 +++++-----
 test/short-urls/CreateShortUrl.test.js | 66 +++++++++++++++++++++++++
 4 files changed, 128 insertions(+), 60 deletions(-)
 create mode 100644 test/short-urls/CreateShortUrl.test.js

diff --git a/src/short-urls/CreateShortUrl.js b/src/short-urls/CreateShortUrl.js
index 64330ba6..5e0163f7 100644
--- a/src/short-urls/CreateShortUrl.js
+++ b/src/short-urls/CreateShortUrl.js
@@ -5,12 +5,22 @@ import { assoc, dissoc, isNil, pick, pipe, replace, trim } from 'ramda';
 import React from 'react';
 import { connect } from 'react-redux';
 import { Collapse } from 'reactstrap';
+import * as PropTypes from 'prop-types';
 import DateInput from '../utils/DateInput';
 import TagsSelector from '../tags/helpers/TagsSelector';
 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 {
+  static propTypes = {
+    createShortUrl: PropTypes.func,
+    shortUrlCreationResult: createShortUrlResultType,
+    resetCreateShortUrl: PropTypes.func,
+  };
+
   state = {
     longUrl: '',
     tags: [],
@@ -24,27 +34,31 @@ export class CreateShortUrlComponent extends React.Component {
   render() {
     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 = {}) => (
-      <input
-        className="form-control"
-        type={type}
-        placeholder={placeholder}
-        value={this.state[id]}
-        onChange={(e) => this.setState({ [id]: e.target.value })}
-        {...props}
-      />
+      <div className="form-group">
+        <input
+          className="form-control"
+          id={id}
+          type={type}
+          placeholder={placeholder}
+          value={this.state[id]}
+          onChange={(e) => this.setState({ [id]: e.target.value })}
+          {...props}
+        />
+      </div>
     );
-    const createDateInput = (id, placeholder, props = {}) => (
-      <DateInput
-        selected={this.state[id]}
-        placeholderText={placeholder}
-        isClearable
-        onChange={(date) => this.setState({ [id]: date })}
-        {...props}
-      />
+    const renderDateInput = (id, placeholder, props = {}) => (
+      <div className="form-group">
+        <DateInput
+          selected={this.state[id]}
+          placeholderText={placeholder}
+          isClearable
+          onChange={(date) => this.setState({ [id]: date })}
+          {...props}
+        />
+      </div>
     );
-    const formatDate = (date) => isNil(date) ? date : date.format();
     const save = (e) => {
       e.preventDefault();
       createShortUrl(pipe(
@@ -75,20 +89,12 @@ export class CreateShortUrlComponent extends React.Component {
 
             <div className="row">
               <div className="col-sm-6">
-                <div className="form-group">
-                  {renderOptionalInput('customSlug', 'Custom slug')}
-                </div>
-                <div className="form-group">
-                  {renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
-                </div>
+                {renderOptionalInput('customSlug', 'Custom slug')}
+                {renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
               </div>
               <div className="col-sm-6">
-                <div className="form-group">
-                  {createDateInput('validSince', 'Enabled since...', { maxDate: this.state.validUntil })}
-                </div>
-                <div className="form-group">
-                  {createDateInput('validUntil', 'Enabled until...', { minDate: this.state.validSince })}
-                </div>
+                {renderDateInput('validSince', 'Enabled since...', { maxDate: this.state.validUntil })}
+                {renderDateInput('validUntil', 'Enabled until...', { minDate: this.state.validSince })}
               </div>
             </div>
           </Collapse>
diff --git a/src/short-urls/helpers/PreviewModal.js b/src/short-urls/helpers/PreviewModal.js
index 13b1ef61..8496be7a 100644
--- a/src/short-urls/helpers/PreviewModal.js
+++ b/src/short-urls/helpers/PreviewModal.js
@@ -10,21 +10,19 @@ const propTypes = {
   isOpen: PropTypes.bool,
 };
 
-const PreviewModal = ({ url, toggle, isOpen }) => {
-  return (
-    <Modal isOpen={isOpen} toggle={toggle} size="lg">
-      <ModalHeader toggle={toggle}>
-        Preview for <ExternalLink href={url}>{url}</ExternalLink>
-      </ModalHeader>
-      <ModalBody>
-        <div className="text-center">
-          <p className="preview-modal__loader">Loading...</p>
-          <img src={`${url}/preview`} className="preview-modal__img" alt="Preview" />
-        </div>
-      </ModalBody>
-    </Modal>
-  );
-};
+const PreviewModal = ({ url, toggle, isOpen }) => (
+  <Modal isOpen={isOpen} toggle={toggle} size="lg">
+    <ModalHeader toggle={toggle}>
+      Preview for <ExternalLink href={url}>{url}</ExternalLink>
+    </ModalHeader>
+    <ModalBody>
+      <div className="text-center">
+        <p className="preview-modal__loader">Loading...</p>
+        <img src={`${url}/preview`} className="preview-modal__img" alt="Preview" />
+      </div>
+    </ModalBody>
+  </Modal>
+);
 
 PreviewModal.propTypes = propTypes;
 
diff --git a/src/short-urls/helpers/QrCodeModal.js b/src/short-urls/helpers/QrCodeModal.js
index d98696ef..3a8cd43f 100644
--- a/src/short-urls/helpers/QrCodeModal.js
+++ b/src/short-urls/helpers/QrCodeModal.js
@@ -10,20 +10,18 @@ const propTypes = {
   isOpen: PropTypes.bool,
 };
 
-const QrCodeModal = ({ url, toggle, isOpen }) => {
-  return (
-    <Modal isOpen={isOpen} toggle={toggle} centered>
-      <ModalHeader toggle={toggle}>
-        QR code for <ExternalLink href={url}>{url}</ExternalLink>
-      </ModalHeader>
-      <ModalBody>
-        <div className="text-center">
-          <img src={`${url}/qr-code`} className="qr-code-modal__img" alt="QR code" />
-        </div>
-      </ModalBody>
-    </Modal>
-  );
-};
+const QrCodeModal = ({ url, toggle, isOpen }) => (
+  <Modal isOpen={isOpen} toggle={toggle} centered>
+    <ModalHeader toggle={toggle}>
+      QR code for <ExternalLink href={url}>{url}</ExternalLink>
+    </ModalHeader>
+    <ModalBody>
+      <div className="text-center">
+        <img src={`${url}/qr-code`} className="qr-code-modal__img" alt="QR code" />
+      </div>
+    </ModalBody>
+  </Modal>
+);
 
 QrCodeModal.propTypes = propTypes;
 
diff --git a/test/short-urls/CreateShortUrl.test.js b/test/short-urls/CreateShortUrl.test.js
new file mode 100644
index 00000000..041fb1c3
--- /dev/null
+++ b/test/short-urls/CreateShortUrl.test.js
@@ -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();
+    });
+  });
+});