Spaces:
Runtime error
Runtime error
| import 'web-audio-test-api'; | |
| import React from 'react'; | |
| import configureStore from 'redux-mock-store'; | |
| import {mount} from 'enzyme'; | |
| import {LoadingState} from '../../../src/reducers/project-state'; | |
| import VM from 'scratch-vm'; | |
| import projectSaverHOC from '../../../src/lib/project-saver-hoc.jsx'; | |
| describe('projectSaverHOC', () => { | |
| const mockStore = configureStore(); | |
| let store; | |
| let vm; | |
| beforeEach(() => { | |
| store = mockStore({ | |
| scratchGui: { | |
| projectChanged: false, | |
| projectState: {}, | |
| projectTitle: 'Scratch Project', | |
| timeout: { | |
| autoSaveTimeoutId: null | |
| } | |
| }, | |
| locales: { | |
| locale: 'en' | |
| } | |
| }); | |
| vm = new VM(); | |
| jest.useFakeTimers(); | |
| }); | |
| test('if canSave becomes true when showing a project with an id, project will be saved', () => { | |
| const mockedUpdateProject = jest.fn(); | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mounted = mount( | |
| <WrappedComponent | |
| isShowingWithId | |
| canSave={false} | |
| isCreatingNew={false} | |
| isShowingSaveable={false} // set explicitly because it relies on ownProps.canSave | |
| isShowingWithoutId={false} | |
| isUpdating={false} | |
| loadingState={LoadingState.SHOWING_WITH_ID} | |
| store={store} | |
| vm={vm} | |
| onAutoUpdateProject={mockedUpdateProject} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| canSave: true, | |
| isShowingSaveable: true | |
| }); | |
| expect(mockedUpdateProject).toHaveBeenCalled(); | |
| }); | |
| test('if canSave is already true and we show a project with an id, project will NOT be saved', () => { | |
| const mockedSaveProject = jest.fn(); | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mounted = mount( | |
| <WrappedComponent | |
| canSave | |
| isCreatingNew={false} | |
| isShowingWithId={false} | |
| isShowingWithoutId={false} | |
| isUpdating={false} | |
| loadingState={LoadingState.LOADING_VM_WITH_ID} | |
| store={store} | |
| vm={vm} | |
| onAutoUpdateProject={mockedSaveProject} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| canSave: true, | |
| isShowingWithId: true, | |
| loadingState: LoadingState.SHOWING_WITH_ID | |
| }); | |
| expect(mockedSaveProject).not.toHaveBeenCalled(); | |
| }); | |
| test('if canSave is false when showing a project without an id, project will NOT be created', () => { | |
| const mockedCreateProject = jest.fn(); | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mounted = mount( | |
| <WrappedComponent | |
| isShowingWithoutId | |
| canSave={false} | |
| isCreatingNew={false} | |
| isShowingWithId={false} | |
| isUpdating={false} | |
| loadingState={LoadingState.LOADING_VM_NEW_DEFAULT} | |
| store={store} | |
| vm={vm} | |
| onCreateProject={mockedCreateProject} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| isShowingWithoutId: true, | |
| loadingState: LoadingState.SHOWING_WITHOUT_ID | |
| }); | |
| expect(mockedCreateProject).not.toHaveBeenCalled(); | |
| }); | |
| test('if canCreateNew becomes true when showing a project without an id, project will be created', () => { | |
| const mockedCreateProject = jest.fn(); | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mounted = mount( | |
| <WrappedComponent | |
| isShowingWithoutId | |
| canCreateNew={false} | |
| isCreatingNew={false} | |
| isShowingWithId={false} | |
| isUpdating={false} | |
| loadingState={LoadingState.SHOWING_WITHOUT_ID} | |
| store={store} | |
| vm={vm} | |
| onCreateProject={mockedCreateProject} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| canCreateNew: true | |
| }); | |
| expect(mockedCreateProject).toHaveBeenCalled(); | |
| }); | |
| test('if canCreateNew is true and we transition to showing new project, project will be created', () => { | |
| const mockedCreateProject = jest.fn(); | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mounted = mount( | |
| <WrappedComponent | |
| canCreateNew | |
| isCreatingNew={false} | |
| isShowingWithId={false} | |
| isShowingWithoutId={false} | |
| isUpdating={false} | |
| loadingState={LoadingState.LOADING_VM_NEW_DEFAULT} | |
| store={store} | |
| vm={vm} | |
| onCreateProject={mockedCreateProject} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| isShowingWithoutId: true, | |
| loadingState: LoadingState.SHOWING_WITHOUT_ID | |
| }); | |
| expect(mockedCreateProject).toHaveBeenCalled(); | |
| }); | |
| test('if we enter creating new state, vm project should be requested', () => { | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mockedStoreProject = jest.fn(() => Promise.resolve()); | |
| // The first wrapper is redux's Connect HOC | |
| WrappedComponent.WrappedComponent.prototype.storeProject = mockedStoreProject; | |
| const mounted = mount( | |
| <WrappedComponent | |
| canSave | |
| isCreatingCopy={false} | |
| isCreatingNew={false} | |
| isRemixing={false} | |
| isShowingWithId={false} | |
| isShowingWithoutId={false} | |
| isUpdating={false} | |
| loadingState={LoadingState.LOADING_VM_NEW_DEFAULT} | |
| reduxProjectId={'100'} | |
| store={store} | |
| vm={vm} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| isCreatingNew: true, | |
| loadingState: LoadingState.CREATING_NEW | |
| }); | |
| expect(mockedStoreProject).toHaveBeenCalled(); | |
| }); | |
| test('if we enter remixing state, vm project should be requested, and alert should show', () => { | |
| const mockedShowCreatingRemixAlert = jest.fn(); | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mockedStoreProject = jest.fn(() => Promise.resolve()); | |
| // The first wrapper is redux's Connect HOC | |
| WrappedComponent.WrappedComponent.prototype.storeProject = mockedStoreProject; | |
| const mounted = mount( | |
| <WrappedComponent | |
| canSave | |
| isCreatingCopy={false} | |
| isCreatingNew={false} | |
| isRemixing={false} | |
| isShowingWithId={false} | |
| isShowingWithoutId={false} | |
| isUpdating={false} | |
| loadingState={LoadingState.SHOWING_WITH_ID} | |
| reduxProjectId={'100'} | |
| store={store} | |
| vm={vm} | |
| onShowCreatingRemixAlert={mockedShowCreatingRemixAlert} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| isRemixing: true, | |
| loadingState: LoadingState.REMIXING | |
| }); | |
| expect(mockedStoreProject).toHaveBeenCalled(); | |
| expect(mockedShowCreatingRemixAlert).toHaveBeenCalled(); | |
| }); | |
| test('if we enter creating copy state, vm project should be requested, and alert should show', () => { | |
| const mockedShowCreatingCopyAlert = jest.fn(); | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mockedStoreProject = jest.fn(() => Promise.resolve()); | |
| // The first wrapper is redux's Connect HOC | |
| WrappedComponent.WrappedComponent.prototype.storeProject = mockedStoreProject; | |
| const mounted = mount( | |
| <WrappedComponent | |
| canSave | |
| isCreatingCopy={false} | |
| isCreatingNew={false} | |
| isRemixing={false} | |
| isShowingWithId={false} | |
| isShowingWithoutId={false} | |
| isUpdating={false} | |
| loadingState={LoadingState.SHOWING_WITH_ID} | |
| reduxProjectId={'100'} | |
| store={store} | |
| vm={vm} | |
| onShowCreatingCopyAlert={mockedShowCreatingCopyAlert} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| isCreatingCopy: true, | |
| loadingState: LoadingState.CREATING_COPY | |
| }); | |
| expect(mockedStoreProject).toHaveBeenCalled(); | |
| expect(mockedShowCreatingCopyAlert).toHaveBeenCalled(); | |
| }); | |
| test('if we enter updating/saving state, vm project should be requested', () => { | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mockedStoreProject = jest.fn(() => Promise.resolve()); | |
| // The first wrapper is redux's Connect HOC | |
| WrappedComponent.WrappedComponent.prototype.storeProject = mockedStoreProject; | |
| const mounted = mount( | |
| <WrappedComponent | |
| canSave | |
| isCreatingNew={false} | |
| isShowingWithId={false} | |
| isShowingWithoutId={false} | |
| isUpdating={false} | |
| loadingState={LoadingState.LOADING_VM_WITH_ID} | |
| reduxProjectId={'100'} | |
| store={store} | |
| vm={vm} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| isUpdating: true, | |
| loadingState: LoadingState.MANUAL_UPDATING | |
| }); | |
| expect(mockedStoreProject).toHaveBeenCalled(); | |
| }); | |
| test('if we are already in updating/saving state, vm project ' + | |
| 'should NOT requested, alert should NOT show', () => { | |
| const mockedShowCreatingAlert = jest.fn(); | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mockedStoreProject = jest.fn(() => Promise.resolve()); | |
| // The first wrapper is redux's Connect HOC | |
| WrappedComponent.WrappedComponent.prototype.storeProject = mockedStoreProject; | |
| const mounted = mount( | |
| <WrappedComponent | |
| canSave | |
| isUpdating | |
| isCreatingNew={false} | |
| isShowingWithId={false} | |
| isShowingWithoutId={false} | |
| loadingState={LoadingState.MANUAL_UPDATING} | |
| reduxProjectId={'100'} | |
| store={store} | |
| vm={vm} | |
| onShowCreatingAlert={mockedShowCreatingAlert} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| isUpdating: true, | |
| loadingState: LoadingState.AUTO_UPDATING, | |
| reduxProjectId: '99' // random change to force a re-render and componentDidUpdate | |
| }); | |
| expect(mockedStoreProject).not.toHaveBeenCalled(); | |
| expect(mockedShowCreatingAlert).not.toHaveBeenCalled(); | |
| }); | |
| test('if user saves, inline saving alert should show', () => { | |
| const mockedShowSavingAlert = jest.fn(); | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mounted = mount( | |
| <WrappedComponent | |
| canSave | |
| isShowingWithoutId | |
| canCreateNew={false} | |
| isCreatingNew={false} | |
| isManualUpdating={false} | |
| isShowingWithId={false} | |
| isUpdating={false} | |
| loadingState={LoadingState.SHOWING_WITH_ID} | |
| store={store} | |
| vm={vm} | |
| onShowSavingAlert={mockedShowSavingAlert} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| isManualUpdating: true, | |
| isUpdating: true | |
| }); | |
| expect(mockedShowSavingAlert).toHaveBeenCalled(); | |
| }); | |
| test('if project is changed, it should autosave after interval', () => { | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mockedAutoUpdate = jest.fn(() => Promise.resolve()); | |
| const mounted = mount( | |
| <WrappedComponent | |
| canSave | |
| isShowingSaveable | |
| isShowingWithId | |
| loadingState={LoadingState.SHOWING_WITH_ID} | |
| store={store} | |
| vm={vm} | |
| onAutoUpdateProject={mockedAutoUpdate} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| projectChanged: true | |
| }); | |
| // Fast-forward until all timers have been executed | |
| jest.runAllTimers(); | |
| expect(mockedAutoUpdate).toHaveBeenCalled(); | |
| }); | |
| test('if project is changed several times in a row, it should only autosave once', () => { | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mockedAutoUpdate = jest.fn(() => Promise.resolve()); | |
| const mounted = mount( | |
| <WrappedComponent | |
| canSave | |
| isShowingSaveable | |
| isShowingWithId | |
| loadingState={LoadingState.SHOWING_WITH_ID} | |
| store={store} | |
| vm={vm} | |
| onAutoUpdateProject={mockedAutoUpdate} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| projectChanged: true, | |
| reduxProjectTitle: 'a' | |
| }); | |
| mounted.setProps({ | |
| projectChanged: true, | |
| reduxProjectTitle: 'b' | |
| }); | |
| mounted.setProps({ | |
| projectChanged: true, | |
| reduxProjectTitle: 'c' | |
| }); | |
| // Fast-forward until all timers have been executed | |
| jest.runAllTimers(); | |
| expect(mockedAutoUpdate).toHaveBeenCalledTimes(1); | |
| }); | |
| test('if project is not changed, it should not autosave after interval', () => { | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const mockedAutoUpdate = jest.fn(() => Promise.resolve()); | |
| const mounted = mount( | |
| <WrappedComponent | |
| canSave | |
| isShowingSaveable | |
| isShowingWithId | |
| loadingState={LoadingState.SHOWING_WITH_ID} | |
| store={store} | |
| vm={vm} | |
| onAutoUpdateProject={mockedAutoUpdate} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| projectChanged: false | |
| }); | |
| // Fast-forward until all timers have been executed | |
| jest.runAllTimers(); | |
| expect(mockedAutoUpdate).not.toHaveBeenCalled(); | |
| }); | |
| test('when starting to remix, onRemixing should be called with param true', () => { | |
| const mockedOnRemixing = jest.fn(); | |
| const mockedStoreProject = jest.fn(() => Promise.resolve()); | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| WrappedComponent.WrappedComponent.prototype.storeProject = mockedStoreProject; | |
| const mounted = mount( | |
| <WrappedComponent | |
| isRemixing={false} | |
| store={store} | |
| vm={vm} | |
| onRemixing={mockedOnRemixing} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| isRemixing: true | |
| }); | |
| expect(mockedOnRemixing).toHaveBeenCalledWith(true); | |
| }); | |
| test('when starting to remix, onRemixing should be called with param false', () => { | |
| const mockedOnRemixing = jest.fn(); | |
| const mockedStoreProject = jest.fn(() => Promise.resolve()); | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| WrappedComponent.WrappedComponent.prototype.storeProject = mockedStoreProject; | |
| const mounted = mount( | |
| <WrappedComponent | |
| isRemixing | |
| store={store} | |
| vm={vm} | |
| onRemixing={mockedOnRemixing} | |
| /> | |
| ); | |
| mounted.setProps({ | |
| isRemixing: false | |
| }); | |
| expect(mockedOnRemixing).toHaveBeenCalledWith(false); | |
| }); | |
| test('uses onSetProjectThumbnailer on mount/unmount', () => { | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const setThumb = jest.fn(); | |
| const mounted = mount( | |
| <WrappedComponent | |
| store={store} | |
| vm={vm} | |
| onSetProjectThumbnailer={setThumb} | |
| /> | |
| ); | |
| // Set project thumbnailer should be called on mount | |
| expect(setThumb).toHaveBeenCalledTimes(1); | |
| // And it should not pass that function on to wrapped element | |
| expect(mounted.find(Component).props().onSetProjectThumbnailer).toBeUndefined(); | |
| // Unmounting should call it again with null | |
| mounted.unmount(); | |
| expect(setThumb).toHaveBeenCalledTimes(2); | |
| expect(setThumb.mock.calls[1][0]).toBe(null); | |
| }); | |
| test('uses onSetProjectSaver on mount/unmount', () => { | |
| const Component = () => <div />; | |
| const WrappedComponent = projectSaverHOC(Component); | |
| const setSaver = jest.fn(); | |
| const mounted = mount( | |
| <WrappedComponent | |
| store={store} | |
| vm={vm} | |
| onSetProjectSaver={setSaver} | |
| /> | |
| ); | |
| // Set project saver should be called on mount | |
| expect(setSaver).toHaveBeenCalledTimes(1); | |
| // And it should not pass that function on to wrapped element | |
| expect(mounted.find(Component).props().onSetProjectSaver).toBeUndefined(); | |
| // Unmounting should call it again with null | |
| mounted.unmount(); | |
| expect(setSaver).toHaveBeenCalledTimes(2); | |
| expect(setSaver.mock.calls[1][0]).toBe(null); | |
| }); | |
| }); | |