Skip to content

Commit 67f9824

Browse files
authored
Merge pull request #1410 from ghalestrilo/test/file-node
Write tests for name verification logic (<ToolBar />, <FileNode />)
2 parents ec16905 + 914e48b commit 67f9824

File tree

3 files changed

+236
-19
lines changed

3 files changed

+236
-19
lines changed

client/components/__test__/FileNode.test.jsx

Lines changed: 130 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,74 @@ import React from 'react';
22
import { shallow } from 'enzyme';
33
import { FileNode } from '../../modules/IDE/components/FileNode';
44

5-
beforeAll(() => {});
65
describe('<FileNode />', () => {
76
let component;
87
let props = {};
8+
let input;
9+
let renameTriggerButton;
10+
const changeName = (newFileName) => {
11+
renameTriggerButton.simulate('click');
12+
input.simulate('change', { target: { value: newFileName } });
13+
input.simulate('blur');
14+
};
15+
const getState = () => component.state();
16+
const getUpdatedName = () => getState().updatedName;
917

10-
describe('with valid props', () => {
18+
describe('with valid props, regardless of filetype', () => {
19+
['folder', 'file'].forEach((fileType) => {
20+
beforeEach(() => {
21+
props = {
22+
...props,
23+
id: '0',
24+
name: 'test.jsx',
25+
fileType,
26+
canEdit: true,
27+
children: [],
28+
authenticated: false,
29+
setSelectedFile: jest.fn(),
30+
deleteFile: jest.fn(),
31+
updateFileName: jest.fn(),
32+
resetSelectedFile: jest.fn(),
33+
newFile: jest.fn(),
34+
newFolder: jest.fn(),
35+
showFolderChildren: jest.fn(),
36+
hideFolderChildren: jest.fn(),
37+
openUploadFileModal: jest.fn(),
38+
setProjectName: jest.fn(),
39+
};
40+
component = shallow(<FileNode {...props} />);
41+
});
42+
43+
describe('when changing name', () => {
44+
beforeEach(() => {
45+
input = component.find('.sidebar__file-item-input');
46+
renameTriggerButton = component
47+
.find('.sidebar__file-item-option')
48+
.first();
49+
component.setState({ isEditing: true });
50+
});
51+
52+
describe('to an empty name', () => {
53+
const newName = '';
54+
beforeEach(() => changeName(newName));
55+
56+
it('should not save', () => expect(props.updateFileName).not.toHaveBeenCalled());
57+
it('should reset name', () => expect(getUpdatedName()).toEqual(props.name));
58+
});
59+
});
60+
});
61+
});
62+
63+
describe('as file with valid props', () => {
1164
beforeEach(() => {
1265
props = {
1366
...props,
1467
id: '0',
15-
children: [],
1668
name: 'test.jsx',
17-
fileType: 'dunno',
69+
fileType: 'file',
70+
canEdit: true,
71+
children: [],
72+
authenticated: false,
1873
setSelectedFile: jest.fn(),
1974
deleteFile: jest.fn(),
2075
updateFileName: jest.fn(),
@@ -23,22 +78,12 @@ describe('<FileNode />', () => {
2378
newFolder: jest.fn(),
2479
showFolderChildren: jest.fn(),
2580
hideFolderChildren: jest.fn(),
26-
canEdit: true,
27-
authenticated: false,
2881
openUploadFileModal: jest.fn()
2982
};
3083
component = shallow(<FileNode {...props} />);
3184
});
3285

3386
describe('when changing name', () => {
34-
let input;
35-
let renameTriggerButton;
36-
const changeName = (newFileName) => {
37-
renameTriggerButton.simulate('click');
38-
input.simulate('change', { target: { value: newFileName } });
39-
input.simulate('blur');
40-
};
41-
4287
beforeEach(() => {
4388
input = component.find('.sidebar__file-item-input');
4489
renameTriggerButton = component
@@ -59,13 +104,79 @@ describe('<FileNode />', () => {
59104
});
60105
});
61106

62-
describe('to an empty filename', () => {
63-
const newName = '';
107+
// Failure Scenarios
108+
109+
describe('to an extensionless filename', () => {
110+
const newName = 'extensionless';
111+
beforeEach(() => changeName(newName));
112+
});
113+
it('should not save', () => expect(props.setProjectName).not.toHaveBeenCalled());
114+
it('should reset name', () => expect(getUpdatedName()).toEqual(props.name));
115+
describe('to different extension', () => {
116+
const newName = 'name.gif';
64117
beforeEach(() => changeName(newName));
65118

66-
it('should not save the name', () => {
67-
expect(props.updateFileName).not.toHaveBeenCalled();
68-
});
119+
it('should not save', () => expect(props.setProjectName).not.toHaveBeenCalled());
120+
it('should reset name', () => expect(getUpdatedName()).toEqual(props.name));
121+
});
122+
123+
describe('to just an extension', () => {
124+
const newName = '.jsx';
125+
beforeEach(() => changeName(newName));
126+
127+
it('should not save', () => expect(props.updateFileName).not.toHaveBeenCalled());
128+
it('should reset name', () => expect(getUpdatedName()).toEqual(props.name));
129+
});
130+
});
131+
});
132+
133+
134+
describe('as folder with valid props', () => {
135+
beforeEach(() => {
136+
props = {
137+
...props,
138+
id: '0',
139+
children: [],
140+
name: 'filename',
141+
fileType: 'folder',
142+
canEdit: true,
143+
authenticated: false,
144+
setSelectedFile: jest.fn(),
145+
deleteFile: jest.fn(),
146+
updateFileName: jest.fn(),
147+
resetSelectedFile: jest.fn(),
148+
newFile: jest.fn(),
149+
newFolder: jest.fn(),
150+
showFolderChildren: jest.fn(),
151+
hideFolderChildren: jest.fn(),
152+
openUploadFileModal: jest.fn()
153+
};
154+
component = shallow(<FileNode {...props} />);
155+
});
156+
157+
describe('when changing name', () => {
158+
beforeEach(() => {
159+
input = component.find('.sidebar__file-item-input');
160+
renameTriggerButton = component
161+
.find('.sidebar__file-item-option')
162+
.first();
163+
component.setState({ isEditing: true });
164+
});
165+
166+
describe('to a foldername', () => {
167+
const newName = 'newfoldername';
168+
beforeEach(() => changeName(newName));
169+
170+
it('should save', () => expect(props.updateFileName).toBeCalledWith(props.id, newName));
171+
it('should update name', () => expect(getUpdatedName()).toEqual(newName));
172+
});
173+
174+
describe('to a filename', () => {
175+
const newName = 'filename.jsx';
176+
beforeEach(() => changeName(newName));
177+
178+
it('should not save', () => expect(props.updateFileName).not.toHaveBeenCalled());
179+
it('should reset name', () => expect(getUpdatedName()).toEqual(props.name));
69180
});
70181
});
71182
});
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import React from 'react';
2+
import { shallow } from 'enzyme';
3+
import { ToolbarComponent } from '../../modules/IDE/components/Toolbar';
4+
5+
6+
const initialProps = {
7+
isPlaying: false,
8+
preferencesIsVisible: false,
9+
stopSketch: jest.fn(),
10+
setProjectName: jest.fn(),
11+
openPreferences: jest.fn(),
12+
showEditProjectName: jest.fn(),
13+
hideEditProjectName: jest.fn(),
14+
infiniteLoop: false,
15+
autorefresh: false,
16+
setAutorefresh: jest.fn(),
17+
setTextOutput: jest.fn(),
18+
setGridOutput: jest.fn(),
19+
startSketch: jest.fn(),
20+
startAccessibleSketch: jest.fn(),
21+
saveProject: jest.fn(),
22+
currentUser: 'me',
23+
originalProjectName: 'testname',
24+
25+
owner: {
26+
username: 'me'
27+
},
28+
project: {
29+
name: 'testname',
30+
isEditingName: false,
31+
id: 'id',
32+
},
33+
};
34+
35+
36+
describe('<ToolbarComponent />', () => {
37+
let component;
38+
let props = initialProps;
39+
let input;
40+
let renameTriggerButton;
41+
const changeName = (newFileName) => {
42+
component.find('.toolbar__project-name').simulate('click', { preventDefault: jest.fn() });
43+
input = component.find('.toolbar__project-name-input');
44+
renameTriggerButton = component.find('.toolbar__edit-name-button');
45+
renameTriggerButton.simulate('click');
46+
input.simulate('change', { target: { value: newFileName } });
47+
input.simulate('blur');
48+
};
49+
const setProps = (additionalProps) => {
50+
props = {
51+
...props,
52+
...additionalProps,
53+
54+
project: {
55+
...props.project,
56+
...(additionalProps || {}).project
57+
},
58+
};
59+
};
60+
61+
// Test Cases
62+
63+
describe('with valid props', () => {
64+
beforeEach(() => {
65+
setProps();
66+
component = shallow(<ToolbarComponent {...props} />);
67+
});
68+
it('renders', () => expect(component).toBeDefined());
69+
70+
describe('when use owns sketch', () => {
71+
beforeEach(() => setProps({ currentUser: props.owner.username }));
72+
73+
describe('when changing sketch name', () => {
74+
beforeEach(() => {
75+
setProps({
76+
project: { isEditingName: true, name: 'testname' },
77+
setProjectName: jest.fn(name => component.setProps({ project: { name } })),
78+
});
79+
component = shallow(<ToolbarComponent {...props} />);
80+
});
81+
82+
describe('to a valid name', () => {
83+
beforeEach(() => changeName('hello'));
84+
it('should save', () => expect(props.setProjectName).toBeCalledWith('hello'));
85+
});
86+
87+
88+
describe('to an empty name', () => {
89+
beforeEach(() => changeName(''));
90+
it('should set name to empty', () => expect(props.setProjectName).toBeCalledWith(''));
91+
it(
92+
'should detect empty name and revert to original',
93+
() => expect(props.setProjectName).toHaveBeenLastCalledWith(initialProps.project.name)
94+
);
95+
});
96+
});
97+
});
98+
99+
describe('when user does not own sketch', () => {
100+
beforeEach(() => setProps({ currentUser: 'not-the-owner' }));
101+
102+
it('should disable edition', () => expect(component.find('.toolbar__edit-name-button')).toEqual({}));
103+
});
104+
});
105+
});

client/modules/IDE/components/Toolbar.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,5 @@ const mapDispatchToProps = {
214214
...projectActions,
215215
};
216216

217+
export const ToolbarComponent = Toolbar;
217218
export default connect(mapStateToProps, mapDispatchToProps)(Toolbar);

0 commit comments

Comments
 (0)