diff --git a/__tests__/src/components/WindowIcon.test.js b/__tests__/src/components/WindowIcon.test.js index d5a209d73edf42cffb9d4729b23ced59b1230883..93a26f5f58a47466e0f039739874992d914e24df 100644 --- a/__tests__/src/components/WindowIcon.test.js +++ b/__tests__/src/components/WindowIcon.test.js @@ -2,40 +2,27 @@ import React from 'react'; import { shallow } from 'enzyme'; import WindowIcon from '../../../src/components/WindowIcon'; -describe('WindowIcon', () => { - let wrapper; - let manifestation; - - describe('without a manifestation', () => { - beforeEach(() => { - wrapper = shallow(<WindowIcon />).dive(); - }); - - it('renders without an error', () => { - expect(wrapper.find('img').length).toBe(0); - }); - }); +/** createWrapper */ +function createWrapper(props) { + return shallow( + <WindowIcon + manifestLogo="" + classses={{}} + {...props} + />, + ).dive(); // to unwrap HOC created by withStyles(); +} - - describe('with a manifestation without a logo', () => { - beforeEach(() => { - manifestation = { getLogo: () => null }; - wrapper = shallow(<WindowIcon manifestation={manifestation} />).dive(); - }); - - it('renders without an error', () => { - expect(wrapper.find('img').length).toBe(0); - }); +describe('WindowIcon', () => { + it('should render nothing if no manifest logo given', () => { + const wrapper = createWrapper(); + expect(wrapper.find('img').length).toBe(0); }); - describe('with a manifestation with a logo', () => { - beforeEach(() => { - manifestation = { getLogo: () => 'http://example.com/thumbnail.jpg' }; - wrapper = shallow(<WindowIcon manifestation={manifestation} classes={{ logo: 'logo-class' }} />).dive(); - }); - - it('renders without an error', () => { - expect(wrapper.find('img.logo-class[src="http://example.com/thumbnail.jpg"]').length).toBe(1); - }); + it('should render logo if manifest logo is given', () => { + const manifestLogo = 'http://foo.bar'; + const wrapper = createWrapper({ manifestLogo }); + expect(wrapper.find('img').first().prop('src')) + .toEqual(manifestLogo); }); }); diff --git a/__tests__/src/components/WindowTopBar.test.js b/__tests__/src/components/WindowTopBar.test.js index 250249f37af3c547cf540201c7d912e525662eda..e3002a0ce8fc6306eb71d3195d05ebf9402acf20 100644 --- a/__tests__/src/components/WindowTopBar.test.js +++ b/__tests__/src/components/WindowTopBar.test.js @@ -1,6 +1,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import WindowTopBar from '../../../src/components/WindowTopBar'; +import WindowIcon from '../../../src/containers/WindowIcon'; const manifestFixture = { manifestation: { @@ -37,7 +38,7 @@ describe('WindowTopBar', () => { }); it('renders a window icon', () => { - expect(topBar.find('WithStyles(WindowIcon)').length).toBe(1); + expect(topBar.find(WindowIcon).length).toBe(1); }); it('calls the toggleWindowSideBar prop when the menu IconButton is clicked', () => { diff --git a/__tests__/src/selectors/index.test.js b/__tests__/src/selectors/index.test.js new file mode 100644 index 0000000000000000000000000000000000000000..6340113a7657a0a4dc5490453f3dc5a96b00821b --- /dev/null +++ b/__tests__/src/selectors/index.test.js @@ -0,0 +1,55 @@ +import manifesto from 'manifesto.js'; +import manifestFixture from '../../fixtures/version-2/001.json'; +import { + getWindowManifest, + getManifestLogo, +} from '../../../src/state/selectors'; + + +describe('getWindowManifest()', () => { + const state = { + windows: { + a: { id: 'a', manifestId: 'x' }, + b: { id: 'b', manifestId: 'y' }, + c: { id: 'c' }, + }, + manifests: { + x: { id: 'x' }, + }, + }; + + it('should return the manifest of a certain window', () => { + const received = getWindowManifest(state, 'a'); + const expected = { id: 'x' }; + expect(received).toEqual(expected); + }); + + it('should return undefined if window doesnt exist', () => { + const received = getWindowManifest(state, 'unknown'); + expect(received).toBeUndefined(); + }); + + it('should return undefined if window has no manifest id', () => { + const received = getWindowManifest(state, 'c'); + expect(received).toBeUndefined(); + }); + + it('should return undefined if manifest does not exist', () => { + const received = getWindowManifest(state, 'b'); + expect(received).toBeUndefined(); + }); +}); + +describe('getManifestLogo()', () => { + it('should return manifest logo id', () => { + const manifest = { manifestation: manifesto.create(manifestFixture) }; + const received = getManifestLogo(manifest); + expect(received).toEqual(manifestFixture.logo['@id']); + }); + + it('should return null if manifest has no logo', () => { + const manifest = { manifestation: manifesto.create({}) }; + const received = getManifestLogo(manifest); + expect(received).toBeNull(); + }); +}); diff --git a/src/components/WindowIcon.js b/src/components/WindowIcon.js index 28a4edf9579a1ba771553f8e4d024f06acd9eb95..63894236feb9c737ba040e706ceb0c301e58d656 100644 --- a/src/components/WindowIcon.js +++ b/src/components/WindowIcon.js @@ -10,30 +10,32 @@ class WindowIcon extends Component { * @return */ render() { - const { - manifestation, classes, - } = this.props; + const { manifestLogo, classes } = this.props; - if (manifestation && manifestation.getLogo()) { - return (<img src={manifestation.getLogo()} alt="" role="presentation" className={classes.logo} />); - } + const img = manifestLogo && ( + <img + src={manifestLogo} + alt="" + role="presentation" + className={classes.logo} + /> + ); return ( - <></> + <> + {img} + </> ); } } WindowIcon.propTypes = { - manifestation: PropTypes.shape({ - getLogo: PropTypes.func, - }), - classes: PropTypes.shape({ logo: PropTypes.string }), + manifestLogo: PropTypes.string, + classes: PropTypes.shape({ logo: PropTypes.string }).isRequired, }; WindowIcon.defaultProps = { - manifestation: null, - classes: {}, + manifestLogo: null, }; const styles = { diff --git a/src/components/WindowTopBar.js b/src/components/WindowTopBar.js index 23c9b07ddc3e5c06de8cdeb24966d58d8463a0c3..1f300358d07f00613edfbe2c84c2d5f38f329746 100644 --- a/src/components/WindowTopBar.js +++ b/src/components/WindowTopBar.js @@ -7,7 +7,7 @@ import IconButton from '@material-ui/core/IconButton'; import MenuIcon from '@material-ui/icons/Menu'; import Toolbar from '@material-ui/core/Toolbar'; import classNames from 'classnames'; -import WindowIcon from './WindowIcon'; +import WindowIcon from '../containers/WindowIcon'; import WindowTopMenuButton from './WindowTopMenuButton'; import WindowTopBarButtons from '../containers/WindowTopBarButtons'; import ns from '../config/css-ns'; @@ -35,7 +35,7 @@ class WindowTopBar extends Component { */ render() { const { - removeWindow, windowId, classes, toggleWindowSideBar, manifest, + removeWindow, windowId, classes, toggleWindowSideBar, } = this.props; return ( <Toolbar disableGutters className={classNames(classes.reallyDense, ns('window-top-bar'))} variant="dense"> @@ -46,7 +46,7 @@ class WindowTopBar extends Component { > <MenuIcon /> </IconButton> - <WindowIcon manifestation={manifest.manifestation} /> + <WindowIcon windowId={windowId} /> <Typography variant="h3" noWrap color="inherit" className={classes.typographyBody}> {this.titleContent()} </Typography> diff --git a/src/containers/WindowIcon.js b/src/containers/WindowIcon.js new file mode 100644 index 0000000000000000000000000000000000000000..49e61e703c4b8c3c820b674fc009748a4e0c60ce --- /dev/null +++ b/src/containers/WindowIcon.js @@ -0,0 +1,10 @@ +import { connect } from 'react-redux'; +import { getWindowManifest, getManifestLogo } from '../state/selectors'; +import WindowIcon from '../components/WindowIcon'; + +/** */ +const mapStateToProps = (state, { windowId }) => ({ + manifestLogo: getManifestLogo(getWindowManifest(state, windowId)), +}); + +export default connect(mapStateToProps)(WindowIcon); diff --git a/src/state/selectors/index.js b/src/state/selectors/index.js new file mode 100644 index 0000000000000000000000000000000000000000..67cb226d861aee449ca914531e1aa0d1b8e782e0 --- /dev/null +++ b/src/state/selectors/index.js @@ -0,0 +1,22 @@ + +/** +* Return the manifest that belongs to a certain window. +* @param {object} state +* @param {String} windowId +* @return {object} +*/ +export function getWindowManifest(state, windowId) { + return state.windows[windowId] + && state.windows[windowId].manifestId + && state.manifests[state.windows[windowId].manifestId]; +} + +/** +* Return the logo of a manifest or null +* @param {object} manifest +* @return {String|null} +*/ +export function getManifestLogo(manifest) { + return manifest.manifestation + && manifest.manifestation.getLogo(); +}