Skip to content

Commit 03b440b

Browse files
authored
Merge pull request #3350 from rschamp/hoc-tests
Add project loading HOC tests
2 parents 44dc609 + 055899e commit 03b440b

File tree

5 files changed

+122
-3
lines changed

5 files changed

+122
-3
lines changed

src/lib/hash-parser-hoc.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ const HashParserHOC = function (WrappedComponent) {
7979
const mapDispatchToProps = dispatch => ({
8080
setProjectId: projectId => dispatch(setProjectId(projectId))
8181
});
82+
// Allow incoming props to override redux-provided props. Used to mock in tests.
8283
const mergeProps = (stateProps, dispatchProps, ownProps) => Object.assign(
8384
{}, stateProps, dispatchProps, ownProps
8485
);

src/lib/project-fetcher-hoc.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ const ProjectFetcherHOC = function (WrappedComponent) {
126126
dispatch(onFetchedProjectData(projectData, loadingState)),
127127
setProjectId: projectId => dispatch(setProjectId(projectId))
128128
});
129+
// Allow incoming props to override redux-provided props. Used to mock in tests.
129130
const mergeProps = (stateProps, dispatchProps, ownProps) => Object.assign(
130131
{}, stateProps, dispatchProps, ownProps
131132
);

src/lib/vm-manager-hoc.jsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,15 @@ const vmManagerHOC = function (WrappedComponent) {
104104
onLoadedProject: loadingState => dispatch(onLoadedProject(loadingState))
105105
});
106106

107+
// Allow incoming props to override redux-provided props. Used to mock in tests.
108+
const mergeProps = (stateProps, dispatchProps, ownProps) => Object.assign(
109+
{}, stateProps, dispatchProps, ownProps
110+
);
111+
107112
return connect(
108113
mapStateToProps,
109-
mapDispatchToProps
114+
mapDispatchToProps,
115+
mergeProps
110116
)(VMManager);
111117
};
112118

test/unit/util/project-fetcher-hoc.test.jsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,30 @@ describe('ProjectFetcherHOC', () => {
3535
expect(mockSetProjectIdFunc.mock.calls[0][0]).toBe('100');
3636
});
3737
test('when there is a reduxProjectId and isFetchingWithProjectId is true, it loads the project', () => {
38+
const mockedOnFetchedProject = jest.fn();
3839
const originalLoad = storage.load;
3940
storage.load = jest.fn((type, id) => Promise.resolve({data: id}));
4041
const Component = ({projectId}) => <div>{projectId}</div>;
4142
const WrappedComponent = ProjectFetcherHOC(Component);
42-
const mounted = mountWithIntl(<WrappedComponent store={store} />);
43+
const mounted = mountWithIntl(
44+
<WrappedComponent
45+
store={store}
46+
onFetchedProjectData={mockedOnFetchedProject}
47+
/>
48+
);
4349
mounted.setProps({
4450
reduxProjectId: '100',
4551
isFetchingWithId: true,
4652
loadingState: LoadingState.FETCHING_WITH_ID
4753
});
48-
mounted.update();
4954
expect(storage.load).toHaveBeenLastCalledWith(
5055
storage.AssetType.Project, '100', storage.DataFormat.JSON
5156
);
5257
storage.load = originalLoad;
58+
// nextTick needed since storage.load is async, and onFetchedProject is called in its then()
59+
process.nextTick(
60+
() => expect(mockedOnFetchedProject)
61+
.toHaveBeenLastCalledWith('100', LoadingState.FETCHING_WITH_ID)
62+
);
5363
});
5464
});
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import 'web-audio-test-api';
2+
3+
import React from 'react';
4+
import configureStore from 'redux-mock-store';
5+
import {mount} from 'enzyme';
6+
import VM from 'scratch-vm';
7+
import {LoadingState} from '../../../src/reducers/project-state';
8+
9+
import vmManagerHOC from '../../../src/lib/vm-manager-hoc.jsx';
10+
11+
describe('VMManagerHOC', () => {
12+
const mockStore = configureStore();
13+
let store;
14+
let vm;
15+
16+
beforeEach(() => {
17+
store = mockStore({
18+
scratchGui: {
19+
projectState: {}
20+
}
21+
});
22+
vm = new VM();
23+
vm.attachAudioEngine = jest.fn();
24+
vm.setCompatibilityMode = jest.fn();
25+
vm.start = jest.fn();
26+
});
27+
test('when it mounts, the vm is initialized', () => {
28+
const Component = () => (<div />);
29+
const WrappedComponent = vmManagerHOC(Component);
30+
mount(
31+
<WrappedComponent
32+
store={store}
33+
vm={vm}
34+
/>
35+
);
36+
expect(vm.attachAudioEngine.mock.calls.length).toBe(1);
37+
expect(vm.setCompatibilityMode.mock.calls.length).toBe(1);
38+
expect(vm.start.mock.calls.length).toBe(1);
39+
expect(vm.initialized).toBe(true);
40+
});
41+
test('if it mounts with an initialized vm, it does not reinitialize the vm', () => {
42+
const Component = () => <div />;
43+
const WrappedComponent = vmManagerHOC(Component);
44+
vm.initialized = true;
45+
mount(
46+
<WrappedComponent
47+
store={store}
48+
vm={vm}
49+
/>
50+
);
51+
expect(vm.attachAudioEngine.mock.calls.length).toBe(0);
52+
expect(vm.setCompatibilityMode.mock.calls.length).toBe(0);
53+
expect(vm.start.mock.calls.length).toBe(0);
54+
expect(vm.initialized).toBe(true);
55+
});
56+
test('if the isLoadingWithId prop becomes true, it loads project data into the vm', () => {
57+
vm.loadProject = jest.fn(() => Promise.resolve());
58+
const mockedOnLoadedProject = jest.fn();
59+
const Component = () => <div />;
60+
const WrappedComponent = vmManagerHOC(Component);
61+
const mounted = mount(
62+
<WrappedComponent
63+
isLoadingWithId={false}
64+
store={store}
65+
vm={vm}
66+
onLoadedProject={mockedOnLoadedProject}
67+
/>
68+
);
69+
mounted.setProps({
70+
isLoadingWithId: true,
71+
loadingState: LoadingState.LOADING_VM_WITH_ID,
72+
projectData: '100'
73+
});
74+
expect(vm.loadProject).toHaveBeenLastCalledWith('100');
75+
// nextTick needed since vm.loadProject is async, and we have to wait for it :/
76+
process.nextTick(() => expect(mockedOnLoadedProject).toHaveBeenLastCalledWith(LoadingState.LOADING_VM_WITH_ID));
77+
});
78+
test('if there is projectData, the child is rendered', () => {
79+
const Component = () => <div />;
80+
const WrappedComponent = vmManagerHOC(Component);
81+
const mounted = mount(
82+
<WrappedComponent
83+
projectData="100"
84+
store={store}
85+
vm={vm}
86+
/>
87+
);
88+
expect(mounted.find('div').length).toBe(1);
89+
});
90+
test('if there is no projectData, nothing is rendered', () => {
91+
const Component = () => <div />;
92+
const WrappedComponent = vmManagerHOC(Component);
93+
const mounted = mount(
94+
<WrappedComponent
95+
store={store}
96+
vm={vm}
97+
/>
98+
);
99+
expect(mounted.find('div').length).toBe(0);
100+
});
101+
});

0 commit comments

Comments
 (0)