diff --git a/client/src/store/reducer.test.ts b/client/src/store/reducer.test.ts index 6f35c0f4..1ac5057b 100644 --- a/client/src/store/reducer.test.ts +++ b/client/src/store/reducer.test.ts @@ -6,9 +6,11 @@ import {validFeatureModel} from '../fixtures'; import FeatureModel from '../modeling/FeatureModel'; import {initialState, FeatureDiagramCollaborativeSession, State} from './types'; import logger from '../helpers/logger'; +import {getCurrentArtifactPath} from '../router'; jest.mock('../helpers/logger'); jest.mock('../modeling/Kernel'); +jest.mock('../router'); describe('reducer', () => { const artifactPath = {project: 'project', artifact: 'artifact'}, @@ -23,10 +25,11 @@ describe('reducer', () => { selectedFeatureIDs: [], kernelFeatureModel: kernelFeatureModel, kernelContext: {} // assume no kernel in the unit tests - }], - currentArtifactPath: artifactPath + }] }); + beforeEach(() => (getCurrentArtifactPath as jest.Mock).mockReturnValue(artifactPath)); + it('returns the initial state', () => { expect(reducer()).toBe(initialState); }); @@ -145,9 +148,8 @@ describe('reducer', () => { expect((state.collaborativeSessions[0]).isSelectMultipleFeatures).toBe(true); }); - it('does nothing if no feature model is available', () => { - const state = reducer(undefined, actions.ui.featureDiagram.feature.selectAll()); - expect(state).toEqual(initialState); + it('throws if no feature model is available', () => { + expect(() => reducer(undefined, actions.ui.featureDiagram.feature.selectAll())).toThrow(); }); }); @@ -166,9 +168,8 @@ describe('reducer', () => { expect((state.collaborativeSessions[0]).isSelectMultipleFeatures).toBe(false); }); - it('does nothing if no feature model is available', () => { - const state = reducer(undefined, actions.ui.featureDiagram.feature.deselectAll()); - expect(state).toEqual(initialState); + it('throws if no feature model is available', () => { + expect(() => reducer(undefined, actions.ui.featureDiagram.feature.deselectAll())).toThrow(); }); }); @@ -184,9 +185,8 @@ describe('reducer', () => { expect((state.collaborativeSessions[0]).selectedFeatureIDs).not.toContain('FeatureHouse'); }); - it('does nothing if no feature model is available', () => { - const state = reducer(undefined, actions.ui.featureDiagram.feature.collapseAll()); - expect(state).toEqual(initialState); + it('throws if no feature model is available', () => { + expect(() => reducer(undefined, actions.ui.featureDiagram.feature.collapseAll())).toThrow(); }); }); @@ -198,9 +198,8 @@ describe('reducer', () => { expect((state.collaborativeSessions[0]).collapsedFeatureIDs).toHaveLength(0); }); - it('does nothing if no feature model is available', () => { - const state = reducer(undefined, actions.ui.featureDiagram.feature.expandAll()); - expect(state).toEqual(initialState); + it('throws if no feature model is available', () => { + expect(() => reducer(undefined, actions.ui.featureDiagram.feature.expandAll())).toThrow(); }); }); }); @@ -208,12 +207,14 @@ describe('reducer', () => { describe('overlay', () => { describe('show overlay', () => { it('shows the about panel', () => { + (getCurrentArtifactPath as jest.Mock).mockReturnValue(undefined); const state = reducer(undefined, actions.ui.overlay.show({overlay: OverlayType.aboutPanel, overlayProps: {}})); expect(state.overlay).toBe(OverlayType.aboutPanel); expect(state.overlayProps).toEqual({}); }); it('shows a feature callout', () => { + (getCurrentArtifactPath as jest.Mock).mockReturnValue(undefined); let state = reducer(undefined, actions.ui.overlay.show({overlay: OverlayType.featureCallout, overlayProps: {featureID: 'FeatureIDE'}})); expect(state.overlay).toBe(OverlayType.featureCallout); expect(state.overlayProps).toEqual({featureID: 'FeatureIDE'}); @@ -231,6 +232,7 @@ describe('reducer', () => { describe('hide overlay', () => { it('hides an overlay after showing it', () => { + (getCurrentArtifactPath as jest.Mock).mockReturnValue(undefined); let state = reducer(undefined, actions.ui.overlay.show({overlay: OverlayType.aboutPanel, overlayProps: {}})); expect(state.overlay).toBe(OverlayType.aboutPanel); expect(state.overlayProps).toEqual({}); @@ -240,6 +242,7 @@ describe('reducer', () => { }); it('does nothing if the currently shown overlay is of another type', () => { + (getCurrentArtifactPath as jest.Mock).mockReturnValue(undefined); let state = reducer(undefined, actions.ui.overlay.show({overlay: OverlayType.aboutPanel, overlayProps: {}})); expect(state.overlay).toBe(OverlayType.aboutPanel); expect(state.overlayProps).toEqual({}); diff --git a/client/src/store/selectors.test.ts b/client/src/store/selectors.test.ts deleted file mode 100644 index 3b02f280..00000000 --- a/client/src/store/selectors.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -/*import {getCurrentFeatureModel} from './selectors'; -import {validFeatureModel, invalidFeatureModel} from '../fixtures'; -import FeatureModel from '../modeling/FeatureModel'; -import {initialState} from './types';*/ - -describe('selectors', () => { - /*describe('getCurrentFeatureModel', () => { - it('gets no feature model from the initial store state', () => { - expect(getCurrentFeatureModel(initialState)).toBeUndefined(); - }); - - it('gets a feature model from a loaded store state', () => { - const state = { - collaborativeSessions: [{ - artifactPath: {project: 'project', artifact: 'artifact'}, - kernelContext: {}, - kernelFeatureModel: validFeatureModel, - collapsedFeatureIDs: [] - }], - currentArtifactPath: {project: 'project', artifact: 'artifact'} - }; - expect(getCurrentFeatureModel(state)!.kernelFeatureModel) - .toEqual(FeatureModel.fromKernel(validFeatureModel).toKernel()); - }); - - it('recomputes when the store state changes', () => { - const collaborativeSessions = [{ - artifactPath: {project: 'project', artifact: 'artifact'}, - kernelContext: {}, - kernelFeatureModel: invalidFeatureModel, - collapsedFeatureIDs: ['test1'] - }], - currentArtifactPath = {project: 'project', artifact: 'artifact'}; - getCurrentFeatureModel.resetRecomputations(); - - let state: any = {collaborativeSessions, currentArtifactPath}; - getCurrentFeatureModel(state); - expect(getCurrentFeatureModel.recomputations()).toBe(1); - - state = {collaborativeSessions, currentArtifactPath}; - getCurrentFeatureModel(state); - expect(getCurrentFeatureModel.recomputations()).toBe(1); - - state = {collaborativeSessions, currentArtifactPath}; - state.collaborativeSessions = [{ - artifactPath: {project: 'project', artifact: 'artifact'}, - kernelContext: {}, - kernelFeatureModel: validFeatureModel, - collapsedFeatureIDs: ['test1'] - }]; - getCurrentFeatureModel(state); - expect(getCurrentFeatureModel.recomputations()).toBe(2); - - state = {collaborativeSessions: state.collaborativeSessions, currentArtifactPath}; - state.collaborativeSessions = [state.collaborativeSessions[0]]; - getCurrentFeatureModel(state); - expect(getCurrentFeatureModel.recomputations()).toBe(2); - - state = {collaborativeSessions: state.collaborativeSessions, currentArtifactPath}; - state.collaborativeSessions = [{ - artifactPath: {project: 'project', artifact: 'artifact'}, - kernelContext: {}, - kernelFeatureModel: validFeatureModel, - collapsedFeatureIDs: [] - }]; - getCurrentFeatureModel(state); - expect(getCurrentFeatureModel.recomputations()).toBe(3); - - state = {collaborativeSessions: state.collaborativeSessions, currentArtifactPath}; - state.collaborativeSessions = [{ - artifactPath: {project: 'project', artifact: 'artifact'}, - kernelContext: {}, - kernelFeatureModel: validFeatureModel, - collapsedFeatureIDs: state.collaborativeSessions[0].collapsedFeatureIDs - }]; - getCurrentFeatureModel(state); - expect(getCurrentFeatureModel.recomputations()).toBe(3); - }); - });*/ -}); \ No newline at end of file diff --git a/client/src/store/selectors.ts b/client/src/store/selectors.ts index e06bf28a..e79bf87c 100644 --- a/client/src/store/selectors.ts +++ b/client/src/store/selectors.ts @@ -8,7 +8,7 @@ import createCachedSelector from 're-reselect'; import FeatureModel from '../modeling/FeatureModel'; import {State, CollaborativeSession, FeatureDiagramCollaborativeSession} from './types'; import logger from '../helpers/logger'; -import {ArtifactPath, isArtifactPathEqual, artifactPathToString} from '../types'; +import {ArtifactPath, isArtifactPathEqual, artifactPathToString, artifactPathCacheKey} from '../types'; import {KernelFeatureModel} from '../modeling/types'; import {getCurrentArtifactPath} from '../router'; @@ -36,7 +36,7 @@ const lookupCollaborativeSession = (collaborativeSessions: CollaborativeSession[ export const getCollaborativeSession = createCachedSelector( (state: State, artifactPath: ArtifactPath) => lookupCollaborativeSession(state.collaborativeSessions, artifactPath), collaborativeSession => collaborativeSession)( - (_state: State, artifactPath: ArtifactPath) => artifactPathToString(artifactPath)); + (_state: State, artifactPath: ArtifactPath) => artifactPathCacheKey(artifactPath)); export function getCurrentCollaborativeSession(state: State): CollaborativeSession | undefined { const currentArtifactPath = getCurrentArtifactPath(state.collaborativeSessions); @@ -59,7 +59,7 @@ export const getFeatureModel = createCachedSelector( return undefined; return FeatureModel.fromKernel(kernelFeatureModel).collapse(collapsedFeatureIDs); } -)((_state: State, artifactPath: ArtifactPath) => artifactPathToString(artifactPath)); +)((_state: State, artifactPath: ArtifactPath) => artifactPathCacheKey(artifactPath)); export function getCurrentFeatureModel(state: State): FeatureModel | undefined { const currentArtifactPath = getCurrentArtifactPath(state.collaborativeSessions); diff --git a/client/src/types.ts b/client/src/types.ts index 6bb93d22..59dae032 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -65,6 +65,10 @@ export function artifactPathToString(artifactPath: ArtifactPath): string { return artifactPath ? `${artifactPath.project}/${artifactPath.artifact}` : `(unknown artifact)`; } +export function artifactPathCacheKey(artifactPath: ArtifactPath): string { + return artifactPath ? `${artifactPath.project.toLowerCase()}/${artifactPath.artifact.toLowerCase()}` : ''; +} + export function isArtifactPathEqual(a?: ArtifactPath, b?: ArtifactPath): boolean { return typeof a !== 'undefined' && typeof b !== 'undefined' && a.project.toLowerCase() === b.project.toLowerCase() && a.artifact.toLowerCase() === b.artifact.toLowerCase();