diff --git a/__tests__/fixtures/config/export.example.json b/__tests__/fixtures/config/export.example.json new file mode 100644 index 0000000000000000000000000000000000000000..4e7c31dcb9eada7c456c37f77d021c497ca730c6 --- /dev/null +++ b/__tests__/fixtures/config/export.example.json @@ -0,0 +1,148 @@ +{ + "config": { + "canvasNavigation": { + "height": 50, + "width": 50 + }, + "theme": { + "palette": { + "type": "light", + "primary": { + "main": "#f5f5f5", + "light": "#ffffff", + "dark": "#eeeeee", + "contrastText": "rgba(0, 0, 0, 0.87)" + }, + "secondary": { + "main": "#1967d2", + "light": "#64b5f6", + "dark": "#0d47a1", + "contrastText": "#fff" + }, + "error": { + "main": "#b00020", + "light": "rgb(191, 51, 76)", + "dark": "rgb(123, 0, 22)", + "contrastText": "#fff" + } + }, + "typography": { + "useNextVariants": true + }, + "overrides": { + "MuiInput": { + "input": { + "backgroundColor": "LightGray" + } + } + } + }, + "language": "en", + "availableLanguages": { + "de": "Deutsch", + "en": "English" + }, + "translations": {}, + "window": { + "defaultView": "single" + }, + "windows": [ + { + "loadedManifest": "https://iiif.harvardartmuseums.org/manifests/object/299843", + "canvasIndex": 2 + }, + { + "loadedManifest": "https://iiif.bodleian.ox.ac.uk/iiif/manifest/e32a277e-91e2-4a6d-8ba6-cc4bad230410.json", + "thumbnailNavigationPosition": "off" + } + ], + "thumbnailNavigation": { + "defaultPosition": "bottom", + "height": 150, + "width": 100 + }, + "workspace": { + "type": "mosaic" + }, + "workspaceControlPanel": { + "enabled": true + }, + "id": "mirador", + "manifests": { + "https://media.nga.gov/public/manifests/nga_highlights.json": { + "provider": "National Gallery of Art" + }, + "https://data.ucd.ie/api/img/manifests/ucdlib:33064": { + "provider": "Irish Architectural Archive" + }, + "https://wellcomelibrary.org/iiif/b18035723/manifest": { + "provider": "Wellcome Library" + }, + "https://demos.biblissima.fr/iiif/metadata/florus-dispersus/manifest.json": { + "provider": "Biblissima" + }, + "https://www.e-codices.unifr.ch/metadata/iiif/gau-Fragment/manifest.json": { + "provider": "e-codices - Virtual Manuscript Library of Switzerland" + }, + "https://wellcomelibrary.org/iiif/collection/b18031511": { + "provider": "Wellcome Library" + }, + "https://gallica.bnf.fr/iiif/ark:/12148/btv1b10022508f/manifest.json": { + "provider": "Bibliothèque nationale de France" + }, + "https://manifests.britishart.yale.edu/Osbornfa1": { + "provider": "Beinecke Rare Book and Manuscript Library, Yale University" + }, + "https://iiif.biblissima.fr/chateauroux/B360446201_MS0005/manifest.json": { + "provider": "Biblissima" + }, + "https://iiif.durham.ac.uk/manifests/trifle/32150/t1/m4/q7/t1m4q77fr328/manifest": { + "provider": "Durham University Library" + } + } + }, + "viewers": { + "window-32450374-dd2c-455e-83f6-ce0e70d21c5c": { + "x": 2696, + "y": 4079, + "zoom": 0.0001107429053115508 + }, + "window-65138dce-d192-484d-8445-b579f5ee14d6": { + "x": 1129.5, + "y": 1275, + "zoom": 0.0002890035037322365 + } + }, + "windows": { + "window-65138dce-d192-484d-8445-b579f5ee14d6": { + "id": "window-65138dce-d192-484d-8445-b579f5ee14d6", + "canvasIndex": 2, + "collectionIndex": 0, + "manifestId": "https://iiif.harvardartmuseums.org/manifests/object/299843", + "rangeId": null, + "thumbnailNavigationPosition": "bottom", + "width": 400, + "height": 400, + "x": 2700, + "y": 2700, + "companionWindowIds": [], + "rotation": null, + "view": "single" + }, + "window-32450374-dd2c-455e-83f6-ce0e70d21c5c": { + "id": "window-32450374-dd2c-455e-83f6-ce0e70d21c5c", + "canvasIndex": 0, + "collectionIndex": 0, + "manifestId": "https://iiif.bodleian.ox.ac.uk/iiif/manifest/e32a277e-91e2-4a6d-8ba6-cc4bad230410.json", + "rangeId": null, + "thumbnailNavigationPosition": "off", + "width": 400, + "height": 400, + "x": 2700, + "y": 2700, + "companionWindowIds": [], + "rotation": null, + "view": "single" + } + } +} \ No newline at end of file diff --git a/__tests__/src/actions/erros.test.js b/__tests__/src/actions/erros.test.js new file mode 100644 index 0000000000000000000000000000000000000000..8fcc5faa80e27a764d61edbceef694cf3ccfb556 --- /dev/null +++ b/__tests__/src/actions/erros.test.js @@ -0,0 +1,27 @@ +import * as actions from '../../../src/state/actions'; +import ActionTypes from '../../../src/state/actions/action-types'; + +describe('errors actions', () => { + describe('addError', () => { + it('adds an error', () => { + const errorMessage = 'errorMessage'; + const createdAction = actions.addError(errorMessage); + + expect(createdAction).toHaveProperty('message', errorMessage); + expect(createdAction).toHaveProperty('id'); + expect(createdAction.id).toBeDefined(); + }); + }); + + describe('removeError', () => { + it('removes an existing error', () => { + const errorId = 'testId123'; + const expectedAction = { + type: ActionTypes.REMOVE_ERROR, + id: errorId, + }; + + expect(actions.removeError(errorId)).toEqual(expectedAction); + }); + }); +}); diff --git a/__tests__/src/components/ErrorDialog.test.js b/__tests__/src/components/ErrorDialog.test.js new file mode 100644 index 0000000000000000000000000000000000000000..109187269e2245289d63b30b19d512771e01e86d --- /dev/null +++ b/__tests__/src/components/ErrorDialog.test.js @@ -0,0 +1,43 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { ErrorDialog } from '../../../src/components/ErrorDialog'; + +/** + * Helper function to create a shallow wrapper around ErrorDialog + */ +function createWrapper(props) { + return shallow( + <ErrorDialog + t={key => key} + {...props} + />, + ); +} + +describe('ErrorDialog', () => { + let wrapper; + + it('renders properly', () => { + const errors = { testid123: { id: 'testid123', message: '' } }; + + wrapper = createWrapper({ errors }); + expect(wrapper.find('WithStyles(Dialog)').length).toBe(1); + }); + + it('shows up error message correctly', () => { + const errorMessage = 'error testMessage 123'; + const errors = { testid123: { id: 'testid123', message: errorMessage } }; + + wrapper = createWrapper({ errors }); + expect(wrapper.find('WithStyles(Typography)[variant="body2"]').render().text()).toBe(errorMessage); + }); + + it('triggers the handleClick prop when clicking the ok button', () => { + const errors = { testid123: { id: 'testid123', message: '' } }; + const mockHandleClick = jest.fn(); + + wrapper = createWrapper({ errors, removeError: mockHandleClick }); + wrapper.find('WithStyles(Button)').simulate('click'); + expect(mockHandleClick).toHaveBeenCalledTimes(1); + }); +}); diff --git a/__tests__/src/reducers/config.test.js b/__tests__/src/reducers/config.test.js index 9c53c62eea778dfa844f1c393d0c4fd8533ed18a..36d4cc2bcf76a91b6d9da3b891274bfb9078b4b0 100644 --- a/__tests__/src/reducers/config.test.js +++ b/__tests__/src/reducers/config.test.js @@ -1,5 +1,6 @@ import { configReducer } from '../../../src/state/reducers/config'; import ActionTypes from '../../../src/state/actions/action-types'; +import configFixture from '../../fixtures/config/export.example.json'; describe('config reducer', () => { describe('SET_CONFIG', () => { @@ -42,4 +43,12 @@ describe('config reducer', () => { }); }); }); + describe('IMPORT_CONFIG', () => { + it('should handle IMPORT_CONFIG', () => { + expect(configReducer([], { + type: ActionTypes.IMPORT_CONFIG, + config: configFixture, + })).toEqual(configFixture); + }); + }); }); diff --git a/__tests__/src/reducers/errors.test.js b/__tests__/src/reducers/errors.test.js new file mode 100644 index 0000000000000000000000000000000000000000..1bef0d93ccbaca7976f5bff131eb1c2a1ce221a7 --- /dev/null +++ b/__tests__/src/reducers/errors.test.js @@ -0,0 +1,42 @@ + +import { errorsReducer } from '../../../src/state/reducers/errors'; +import ActionTypes from '../../../src/state/actions/action-types'; + +describe('ADD_ERROR', () => { + const errorMessage = 'testErrorMessage'; + const errorId = 'errorId123'; + + it('should handle ADD_ERROR', () => { + const error = { + id: errorId, + message: errorMessage, + }; + const ret = errorsReducer(undefined, { + type: ActionTypes.ADD_ERROR, + ...error, + + }); + expect(ret.items).toEqual([error.id]); + expect(ret).toHaveProperty(error.id); + expect(ret[error.id]).toEqual(error); + }); + + it('should handle REMOVE_ERROR', () => { + const stateBefore = { + items: [errorId], + errorId: { + id: errorId, + message: errorMessage, + }, + }; + + /* + Only the id is removed from the 'items' array. The error itself remains part of the state, + so we are able to provide an error history or some kind of logs later on + */ + expect(errorsReducer(stateBefore, { + type: ActionTypes.REMOVE_ERROR, + id: errorId, + })).toHaveProperty('items', []); + }); +}); diff --git a/src/components/ErrorDialog.js b/src/components/ErrorDialog.js index 9b819ef9d60e8bd2cc480a0f0abcbac916ebd151..40032c0bb6a8cfd98d599868085c02cbdbafdff5 100644 --- a/src/components/ErrorDialog.js +++ b/src/components/ErrorDialog.js @@ -27,7 +27,6 @@ export class ErrorDialog extends Component { /* extract 'items' value and get first key-value-pair (an error) */ const error = first(values(omit(errors, 'items'))); const hasError = !isUndefined(error); - return ( <div> { hasError && ( diff --git a/src/containers/ErrorDialog.js b/src/containers/ErrorDialog.js index 2d1fc27cfae474e4f16e7c7d50bfd1501b8c99e9..c491690dd6cf034888c1e5c87df7f7524b2e33d9 100644 --- a/src/containers/ErrorDialog.js +++ b/src/containers/ErrorDialog.js @@ -20,7 +20,6 @@ const mapStateToProps = state => ({ * @private */ const mapDispatchToProps = { - addError: actions.addError, removeError: actions.removeError, };