diff --git a/package-lock.json b/package-lock.json
index ab7c73c..78262f4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -947,9 +947,9 @@
}
},
"@testing-library/dom": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-5.2.1.tgz",
- "integrity": "sha512-K30UE+UKwyI/iTaQsSJXVYBPnPsTLlcNT1QEhHKKqlsehu7SzWTSkCE3xW0qvMPIkPb3/rVisDx7Viez/qmAKA==",
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-5.4.0.tgz",
+ "integrity": "sha512-0OQsquNYfbxgqqoGf9RZ9lglXEYgKlhSe+W9UFQGDAvT554Y9PG6hGe0RHYggAXe/GoNPccSsl65nn+qq0cFKw==",
"dev": true,
"requires": {
"@babel/runtime": "^7.4.5",
@@ -2704,9 +2704,9 @@
}
},
"bser": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz",
- "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz",
+ "integrity": "sha512-8zsjWrQkkBoLK6uxASk1nJ2SKv97ltiGDo6A3wA0/yRPz+CwmEyDo0hUrhIuukG2JHpAl3bvFIixw2/3Hi0DOg==",
"requires": {
"node-int64": "^0.4.0"
}
@@ -3842,9 +3842,9 @@
},
"dependencies": {
"semver": {
- "version": "6.1.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz",
- "integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ=="
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.2.tgz",
+ "integrity": "sha512-z4PqiCpomGtWj8633oeAdXm1Kn1W++3T8epkZYnwiVgIYIJ0QHszhInYSJTYxebByQH7KVCEAn8R9duzZW2PhQ=="
}
}
},
@@ -4706,6 +4706,38 @@
"entities": "^1.1.1"
}
},
+ "dom-testing-library": {
+ "version": "3.19.4",
+ "resolved": "https://registry.npmjs.org/dom-testing-library/-/dom-testing-library-3.19.4.tgz",
+ "integrity": "sha512-GJOx8CLpnkvM3takILOsld/itUUc9+7Qh6caN1Spj6+9jIgNPY36fsvoH7sEgYokC0lBRdttO7G7fIFYCXlmcA==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.4.3",
+ "@sheerun/mutationobserver-shim": "^0.3.2",
+ "pretty-format": "^24.7.0",
+ "wait-for-expect": "^1.1.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "pretty-format": {
+ "version": "24.8.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.8.0.tgz",
+ "integrity": "sha512-P952T7dkrDEplsR+TuY7q3VXDae5Sr7zmQb12JU/NDQa/3CH7/QW0yvqLcGN6jL+zQFKaoJcPc+yJxMTGmosqw==",
+ "dev": true,
+ "requires": {
+ "@jest/types": "^24.8.0",
+ "ansi-regex": "^4.0.0",
+ "ansi-styles": "^3.2.0",
+ "react-is": "^16.8.4"
+ }
+ }
+ }
+ },
"domain-browser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
@@ -4795,9 +4827,9 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"electron-to-chromium": {
- "version": "1.3.167",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.167.tgz",
- "integrity": "sha512-84IjpeRudjP43Q0+K7tlS7ESoHOl0W6CIdzs5reS9p+sAjCQEDiaAyiXN2v1qLUdL+Of6ZSaH4Cq6bl+sfzy8A=="
+ "version": "1.3.172",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.172.tgz",
+ "integrity": "sha512-bHgFvYeHBiQNNuY/WvoX37zLosPgMbR8nKU1r4mylHptLvuMMny/KG/L28DTIlcoOCJjMAhEimy3DHDgDayPbg=="
},
"elliptic": {
"version": "6.4.1",
@@ -9859,9 +9891,9 @@
},
"dependencies": {
"resolve": {
- "version": "1.11.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz",
- "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==",
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz",
+ "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==",
"requires": {
"path-parse": "^1.0.6"
}
@@ -14381,6 +14413,16 @@
"workbox-webpack-plugin": "3.6.3"
}
},
+ "react-testing-library": {
+ "version": "5.9.0",
+ "resolved": "https://registry.npmjs.org/react-testing-library/-/react-testing-library-5.9.0.tgz",
+ "integrity": "sha512-T303PJZvrLKeeiPpjmMD1wxVpzEg9yI0qteH/cUvpFqNHOzPe3yN+Pu+jo9JlxuTMvVGPAmCAcgZ3sEtEDpJUQ==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.3.1",
+ "dom-testing-library": "^3.13.1"
+ }
+ },
"reactcss": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
diff --git a/package.json b/package.json
index 321d382..6899f4f 100644
--- a/package.json
+++ b/package.json
@@ -40,7 +40,8 @@
"husky": "^1.3.1",
"jest-dom": "^3.0.0",
"prettier": "1.15.3",
- "pretty-quick": "^1.11.1",
+ "pretty-quick": "^1.8.0",
+ "prop-types": "^15.7.2",
"redux-mock-store": "^1.5.3"
}
}
diff --git a/src/components/App.js b/src/components/App.js
index 6bab841..6e2fbf7 100644
--- a/src/components/App.js
+++ b/src/components/App.js
@@ -1,4 +1,5 @@
import React, { Component } from 'react';
+import PropTypes from 'prop-types';
import Header from '../components/Header';
import SidebarContainer from '../containers/SidebarContainer';
import PreviewContainer from '../containers/PreviewContainer';
@@ -48,4 +49,12 @@ class App extends Component {
}
}
+App.defaultProps = {
+ onEscape: () => {}
+};
+
+App.propTypes = {
+ onEscape: PropTypes.func.isRequired
+};
+
export default App;
diff --git a/src/components/Burst.js b/src/components/Burst.js
index b43238e..bb43f8a 100644
--- a/src/components/Burst.js
+++ b/src/components/Burst.js
@@ -1,6 +1,9 @@
import React, { Component } from 'react';
+import PropTypes from 'prop-types';
import classNames from 'classnames';
import { getCalcState, setCalcState } from '../lib/calc-helpers';
+import { imageSettingPropTypes } from '../lib/propTypes';
+import { imageSettingDefaults } from '../lib/defaultProps';
import { getBurstErrors } from '../lib/input-helpers';
import './Burst.css';
import InfoIcon from './InfoIcon';
@@ -168,4 +171,16 @@ class Burst extends Component {
}
}
+Burst.defaultProps = {
+ ...imageSettingDefaults,
+ expanded: false,
+ requestBurst: () => {}
+};
+
+Burst.propTypes = {
+ ...imageSettingPropTypes,
+ expanded: PropTypes.bool.isRequired,
+ requestBurst: PropTypes.func.isRequired
+};
+
export default Burst;
diff --git a/src/components/ErrorToast.js b/src/components/ErrorToast.js
index 1de439a..9509c5e 100644
--- a/src/components/ErrorToast.js
+++ b/src/components/ErrorToast.js
@@ -1,4 +1,5 @@
import React from 'react';
+import PropTypes from 'prop-types';
import './ErrorToast.css';
const ErrorToast = ({ message }) => {
@@ -14,4 +15,8 @@ ErrorToast.defaultProps = {
message: ''
};
+ErrorToast.propTypes = {
+ message: PropTypes.string.isRequired
+};
+
export default ErrorToast;
diff --git a/src/components/Frame.js b/src/components/Frame.js
index d1be70e..9569f66 100644
--- a/src/components/Frame.js
+++ b/src/components/Frame.js
@@ -1,4 +1,5 @@
import React from 'react';
+import PropTypes from 'prop-types';
import classNames from 'classnames';
import './Frame.css';
@@ -24,4 +25,16 @@ const Frame = ({ imageSrc, playing, togglePlaying }) => (
);
+Frame.defaultProps = {
+ imageSrc: '',
+ playing: false,
+ togglePlaying: () => {}
+};
+
+Frame.propTypes = {
+ imageSrc: PropTypes.string.isRequired,
+ playing: PropTypes.bool.isRequired,
+ togglePlaying: PropTypes.func.isRequired
+};
+
export default Frame;
diff --git a/src/components/Preview.js b/src/components/Preview.js
index 1d88ccf..9a942ad 100644
--- a/src/components/Preview.js
+++ b/src/components/Preview.js
@@ -1,4 +1,5 @@
import React, { Component } from 'react';
+import PropTypes from 'prop-types';
import classNames from 'classnames';
import Frame from './Frame';
import InfoIcon from './InfoIcon';
@@ -164,10 +165,39 @@ class Preview extends Component {
}
Preview.defaultProps = {
+ expanded: false,
previewIdx: 0,
+ playing: false,
frames: {},
frameIDs: [],
- gifData: ''
+ gifData: '',
+ gifProgress: 0,
+ width: 300,
+ height: 300,
+ oversample: false,
+ interval: 100,
+ updatePreviewIdx: () => {},
+ generateGIF: () => {},
+ startAnimation: () => {},
+ stopAnimation: () => {}
+};
+
+Preview.propTypes = {
+ expanded: PropTypes.bool.isRequired,
+ previewIdx: PropTypes.number.isRequired,
+ playing: PropTypes.bool.isRequired,
+ frames: PropTypes.object.isRequired,
+ frameIDs: PropTypes.array.isRequired,
+ gifData: PropTypes.string.isRequired,
+ gifProgress: PropTypes.number.isRequired,
+ width: PropTypes.number.isRequired,
+ height: PropTypes.number.isRequired,
+ oversample: PropTypes.bool.isRequired,
+ interval: PropTypes.number.isRequired,
+ updatePreviewIdx: PropTypes.func.isRequired,
+ generateGIF: PropTypes.func.isRequired,
+ startAnimation: PropTypes.func.isRequired,
+ stopAnimation: PropTypes.func.isRequired
};
export default Preview;
diff --git a/src/components/Preview.test.js b/src/components/Preview.test.js
index d0bdd1b..caa6970 100644
--- a/src/components/Preview.test.js
+++ b/src/components/Preview.test.js
@@ -11,7 +11,7 @@ describe('', () => {
it('renders appropriate content', () => {
const { getByTestId } = global.renderWithRedux(
-
+
);
expect(getByTestId('Preview-scrubber').firstChild.type).toBe('range');
expect(getByTestId('Preview-scrubber-counter').textContent).toBe('1 / 1');
diff --git a/src/components/Settings.js b/src/components/Settings.js
index 6e22274..c0b3b0a 100644
--- a/src/components/Settings.js
+++ b/src/components/Settings.js
@@ -1,4 +1,7 @@
import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { imageSettingPropTypes } from '../lib/propTypes';
+import { imageSettingDefaults } from '../lib/defaultProps';
import classNames from 'classnames';
import { isPositiveInteger, isProperBound } from '../lib/input-helpers';
import './Settings.css';
@@ -168,4 +171,18 @@ class Settings extends Component {
}
}
+Settings.defaultProps = {
+ expanded: false,
+ ...imageSettingDefaults,
+ interval: 100,
+ updateSetting: () => {}
+};
+
+Settings.propTypes = {
+ expanded: PropTypes.bool.isRequired,
+ ...imageSettingPropTypes,
+ interval: PropTypes.number.isRequired,
+ updateSetting: PropTypes.func.isRequired
+};
+
export default Settings;
diff --git a/src/components/Sidebar.js b/src/components/Sidebar.js
index 708582f..450a92b 100644
--- a/src/components/Sidebar.js
+++ b/src/components/Sidebar.js
@@ -1,4 +1,7 @@
import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { imageSettingPropTypes } from '../lib/propTypes';
+import { imageSettingDefaults } from '../lib/defaultProps';
import SidebarButton from './SidebarButton';
import SidebarButtonWithBadge from './SidebarButtonWithBadge';
import panes from '../constants/pane-types';
@@ -113,8 +116,24 @@ class Sidebar extends Component {
}
}
+Sidebar.propTypes = {
+ ...imageSettingPropTypes,
+ numFrames: PropTypes.number.isRequired,
+ expandedPane: PropTypes.string.isRequired,
+ gifData: PropTypes.string.isRequired,
+ requestFrame: PropTypes.func.isRequired,
+ togglePane: PropTypes.func.isRequired,
+ reset: PropTypes.func.isRequired
+};
+
Sidebar.defaultProps = {
- gifData: ''
+ numFrames: 0,
+ expandedPane: 'NONE',
+ gifData: '',
+ ...imageSettingDefaults,
+ requestFrame: () => {},
+ togglePane: () => {},
+ reset: () => {}
};
export default Sidebar;
diff --git a/src/components/SidebarButton.js b/src/components/SidebarButton.js
index 0bd01d6..ad594dd 100644
--- a/src/components/SidebarButton.js
+++ b/src/components/SidebarButton.js
@@ -1,4 +1,7 @@
import React from 'react';
+import PropTypes from 'prop-types';
+import { sidebarButtonDefaults } from '../lib/defaultProps';
+import { sidebarButtonPropTypes } from '../lib/propTypes';
import classNames from 'classnames';
import camera from './icons/camera.svg';
import preview from './icons/preview.svg';
@@ -47,7 +50,13 @@ const SidebarButton = ({ children, icon, onClick, expanded }) => (
);
SidebarButton.defaultProps = {
- icon: 'icon'
+ ...sidebarButtonDefaults,
+ expanded: false
+};
+
+SidebarButton.propTypes = {
+ ...sidebarButtonPropTypes,
+ expanded: PropTypes.bool
};
export default SidebarButton;
diff --git a/src/components/SidebarButton.test.js b/src/components/SidebarButton.test.js
index 977b8b7..64cd101 100644
--- a/src/components/SidebarButton.test.js
+++ b/src/components/SidebarButton.test.js
@@ -10,9 +10,7 @@ describe('', () => {
});
it('renders appropriate content', () => {
- const { getByTestId } = global.renderWithRedux(
-
- );
+ const { getByTestId } = global.renderWithRedux();
expect(getByTestId('SidebarButton-icon-button').firstChild.alt).toBe(
'icon icon'
);
diff --git a/src/components/SidebarButtonWithBadge.js b/src/components/SidebarButtonWithBadge.js
index ed8a85c..8cfa0ea 100644
--- a/src/components/SidebarButtonWithBadge.js
+++ b/src/components/SidebarButtonWithBadge.js
@@ -1,4 +1,7 @@
import React from 'react';
+import PropTypes from 'prop-types';
+import { sidebarButtonDefaults } from '../lib/defaultProps';
+import { sidebarButtonPropTypes } from '../lib/propTypes';
import classNames from 'classnames';
import SidebarButton from './SidebarButton';
@@ -18,4 +21,20 @@ const SidebarButtonWithBadge = ({ showBadge, value, color, ...props }) => (
);
+SidebarButtonWithBadge.defaultProps = {
+ ...sidebarButtonDefaults,
+ expanded: false,
+ color: '',
+ showBadge: false,
+ value: 0
+};
+
+SidebarButtonWithBadge.propTypes = {
+ ...sidebarButtonPropTypes,
+ expanded: PropTypes.bool,
+ color: PropTypes.string.isRequired,
+ showBadge: PropTypes.bool.isRequired,
+ value: PropTypes.number.isRequired
+};
+
export default SidebarButtonWithBadge;
diff --git a/src/components/SidebarButtonWithBadge.test.js b/src/components/SidebarButtonWithBadge.test.js
index a833c2f..e3b49ff 100644
--- a/src/components/SidebarButtonWithBadge.test.js
+++ b/src/components/SidebarButtonWithBadge.test.js
@@ -10,9 +10,7 @@ describe('', () => {
});
it('renders appropriate content', () => {
- const { getByTestId } = global.renderWithRedux(
-
- );
+ const { getByTestId } = global.renderWithRedux();
// check that badge is present
expect(getByTestId('SidebarButton-icon-button').lastChild).toBeTruthy();
});
diff --git a/src/lib/defaultProps.js b/src/lib/defaultProps.js
new file mode 100644
index 0000000..ef0ed51
--- /dev/null
+++ b/src/lib/defaultProps.js
@@ -0,0 +1,10 @@
+export const imageSettingDefaults = {
+ width: 300,
+ height: 300,
+ oversample: false
+};
+
+export const sidebarButtonDefaults = {
+ icon: 'icon',
+ onClick: () => {}
+};
diff --git a/src/lib/propTypes.js b/src/lib/propTypes.js
new file mode 100644
index 0000000..1055907
--- /dev/null
+++ b/src/lib/propTypes.js
@@ -0,0 +1,12 @@
+import PropTypes from 'prop-types';
+
+export const imageSettingPropTypes = {
+ width: PropTypes.number.isRequired,
+ height: PropTypes.number.isRequired,
+ oversample: PropTypes.bool.isRequired
+};
+
+export const sidebarButtonPropTypes = {
+ icon: PropTypes.string.isRequired,
+ onClick: PropTypes.func.isRequired
+};
diff --git a/src/setupTests.js b/src/setupTests.js
index 1816586..dc76778 100644
--- a/src/setupTests.js
+++ b/src/setupTests.js
@@ -6,7 +6,8 @@ import { render } from '@testing-library/react';
import rootReducer from './reducers';
global.console = {
- log: jest.fn()
+ log: jest.fn(),
+ error: jest.fn()
};
global.Desmos = {