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 = {