Skip to content
Snippets Groups Projects
Commit 38273345 authored by Jack Reed's avatar Jack Reed
Browse files

implement basic annotation state referenced by canvasId

parent 91f01e10
Branches
No related tags found
No related merge requests found
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import * as actions from '../../../src/state/actions';
import ActionTypes from '../../../src/state/actions/action-types';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
describe('annotation actions', () => {
describe('requestAnnotation', () => {
it('requests an annotation from given a url', () => {
const canvasId = 'foo';
const annotationId = 'abc123';
const expectedAction = {
type: ActionTypes.REQUEST_ANNOTATION,
canvasId,
annotationId,
};
expect(actions.requestAnnotation(canvasId, annotationId)).toEqual(expectedAction);
});
});
describe('receiveAnnotation', () => {
it('recieves an annotation', () => {
const canvasId = 'foo';
const annotationId = 'abc123';
const json = {
annotationId,
content: 'annotation request',
};
const expectedAction = {
type: ActionTypes.RECEIVE_ANNOTATION,
canvasId,
annotationId,
annotationJson: json,
};
expect(actions.receiveAnnotation(canvasId, annotationId, json)).toEqual(expectedAction);
});
});
describe('fetchAnnotation', () => {
let store = null;
beforeEach(() => {
store = mockStore({});
});
describe('success response', () => {
beforeEach(() => {
fetch.mockResponseOnce(JSON.stringify({ data: '12345' })); // eslint-disable-line no-undef
});
it('dispatches the REQUEST_ANNOTATION action', () => {
store.dispatch(actions.fetchAnnotation(
'https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-47174896',
'https://iiif.harvardartmuseums.org/manifests/object/299843/list/47174896',
));
expect(store.getActions()).toEqual([
{
canvasId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-47174896',
annotationId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/list/47174896',
type: 'REQUEST_ANNOTATION',
},
]);
});
it('dispatches the REQUEST_ANNOTATION and then RECEIVE_ANNOTATION', () => {
store.dispatch(actions.fetchAnnotation(
'https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-47174896',
'https://iiif.harvardartmuseums.org/manifests/object/299843/list/47174896',
))
.then(() => {
const expectedActions = store.getActions();
expect(expectedActions).toEqual([
{
canvasId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-47174896',
annotationId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/list/47174896',
type: 'REQUEST_ANNOTATION',
},
{
canvasId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-47174896',
annotationId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/list/47174896',
annotationJson: { data: '12345' },
type: 'RECEIVE_ANNOTATION',
},
]);
});
});
});
describe('error response', () => {
it('dispatches the REQUEST_ANNOTATION and then RECEIVE_ANNOTATION', () => {
store.dispatch(actions.fetchAnnotation(
'https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-47174896',
'https://iiif.harvardartmuseums.org/manifests/object/299843/list/47174896',
))
.then(() => {
const expectedActions = store.getActions();
expect(expectedActions).toEqual([
{
canvasId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-47174896',
annotationId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/list/47174896',
type: 'REQUEST_ANNOTATION',
},
{
canvasId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-47174896',
annotationId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/list/47174896',
error: new Error('invalid json response body at undefined reason: Unexpected end of JSON input'),
type: 'RECEIVE_ANNOTATION_FAILURE',
},
]);
});
});
});
});
});
import { annotationsReducer } from '../../../src/state/reducers/annotations';
import ActionTypes from '../../../src/state/actions/action-types';
describe('annotation reducer', () => {
it('should handle REQUEST_ANNOTATION', () => {
expect(annotationsReducer({}, {
type: ActionTypes.REQUEST_ANNOTATION,
canvasId: 'foo',
annotationId: 'abc123',
})).toEqual({
foo: {
abc123: {
id: 'abc123',
isFetching: true,
},
},
});
});
it('should handle RECEIVE_ANNOTATION', () => {
expect(annotationsReducer(
{
foo: {
abc123: {
id: 'abc123',
isFetching: true,
},
},
},
{
type: ActionTypes.RECEIVE_ANNOTATION,
canvasId: 'foo',
annotationId: 'abc123',
annotationJson: {
id: 'abc123',
'@type': 'sc:AnnotationList',
content: 'anno stuff',
},
},
)).toMatchObject({
foo: {
abc123: {
id: 'abc123',
isFetching: false,
json: {},
},
},
});
});
it('should handle RECEIVE_ANNOTATION_FAILURE', () => {
expect(annotationsReducer(
{
foo: {
abc123: {
id: 'abc123',
isFetching: true,
},
},
},
{
type: ActionTypes.RECEIVE_ANNOTATION_FAILURE,
canvasId: 'foo',
annotationId: 'abc123',
error: "This institution didn't enable CORS.",
},
)).toEqual({
foo: {
abc123: {
id: 'abc123',
isFetching: false,
error: "This institution didn't enable CORS.",
},
},
});
});
});
......@@ -4,6 +4,10 @@ const ActionTypes = {
REMOVE_COMPANION_WINDOW: 'REMOVE_COMPANION_WINDOW',
UPDATE_WINDOW: 'UPDATE_WINDOW',
REQUEST_ANNOTATION: 'REQUEST_ANNOTATION',
RECEIVE_ANNOTATION: 'RECEIVE_ANNOTATION',
RECEIVE_ANNOTATION_FAILURE: 'RECEIVE_ANNOTATION_FAILURE',
FOCUS_WINDOW: 'FOCUS_WINDOW',
SET_WORKSPACE_FULLSCREEN: 'SET_WORKSPACE_FULLSCREEN',
SET_WORKSPACE_VIEWPORT_POSITION: 'SET_WORKSPACE_VIEWPORT_POSITION',
......
import fetch from 'node-fetch';
import ActionTypes from './action-types';
/**
* requestAnnotation - action creator
*
* @param {String} canvasId
* @param {String} annotationId
* @memberof ActionCreators
*/
export function requestAnnotation(canvasId, annotationId) {
return {
type: ActionTypes.REQUEST_ANNOTATION,
canvasId,
annotationId,
};
}
/**
* receiveAnnotation - action creator
*
* @param {String} canvasId
* @param {String} annotationId
* @param {Object} annotationJson
* @memberof ActionCreators
*/
export function receiveAnnotation(canvasId, annotationId, annotationJson) {
return {
type: ActionTypes.RECEIVE_ANNOTATION,
canvasId,
annotationId,
annotationJson,
};
}
/**
* receiveAnnotationFailure - action creator
*
* @param {String} canvasId
* @param {String} annotationId
* @param {String} error
* @memberof ActionCreators
*/
export function receiveAnnotationFailure(canvasId, annotationId, error) {
return {
type: ActionTypes.RECEIVE_ANNOTATION_FAILURE,
canvasId,
annotationId,
error,
};
}
/**
* fetchAnnotation - action creator
*
* @param {String} annotationId
* @memberof ActionCreators
*/
export function fetchAnnotation(canvasId, annotationId) {
return ((dispatch) => {
dispatch(requestAnnotation(canvasId, annotationId));
return fetch(annotationId)
.then(response => response.json())
.then(json => dispatch(receiveAnnotation(canvasId, annotationId, json)))
.catch(error => dispatch(receiveAnnotationFailure(canvasId, annotationId, error)));
});
}
......@@ -9,3 +9,4 @@ export * from './manifest';
export * from './infoResponse';
export * from './canvas';
export * from './workspace';
export * from './annotation';
import ActionTypes from '../actions/action-types';
/**
* annotationReducer
*/
export const annotationsReducer = (state = {}, action) => {
switch (action.type) {
case ActionTypes.REQUEST_ANNOTATION:
return {
...state,
[action.canvasId]: {
[action.annotationId]: {
id: action.annotationId,
isFetching: true,
},
},
};
case ActionTypes.RECEIVE_ANNOTATION:
return {
...state,
[action.canvasId]: {
[action.annotationId]: {
id: action.annotationId,
json: action.annotationJson,
isFetching: false,
},
},
};
case ActionTypes.RECEIVE_ANNOTATION_FAILURE:
return {
...state,
[action.canvasId]: {
[action.annotationId]: {
id: action.annotationId,
error: action.error,
isFetching: false,
},
},
};
default: return state;
}
};
......@@ -5,3 +5,4 @@ export * from './manifests';
export * from './infoResponses';
export * from './config';
export * from './viewers';
export * from './annotations';
......@@ -7,6 +7,7 @@ import {
viewersReducer,
windowsReducer,
workspaceReducer,
annotationsReducer,
} from '.';
/**
......@@ -23,6 +24,7 @@ export default function createRootReducer(pluginReducers) {
infoResponses: infoResponsesReducer,
config: configReducer,
viewers: viewersReducer,
annotations: annotationsReducer,
...pluginReducers,
});
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment