diff --git a/client/components/__test__/FileNode.test.jsx b/client/components/__test__/FileNode.test.jsx index 60eededb..b78d6ab2 100644 --- a/client/components/__test__/FileNode.test.jsx +++ b/client/components/__test__/FileNode.test.jsx @@ -2,19 +2,74 @@ import React from 'react'; import { shallow } from 'enzyme'; import { FileNode } from '../../modules/IDE/components/FileNode'; -beforeAll(() => {}); describe('', () => { let component; let props = {}; + let input; + let renameTriggerButton; + const changeName = (newFileName) => { + renameTriggerButton.simulate('click'); + input.simulate('change', { target: { value: newFileName } }); + input.simulate('blur'); + }; + const getState = () => component.state(); + const getUpdatedName = () => getState().updatedName; - describe('with valid props', () => { + describe('with valid props, regardless of filetype', () => { + ['folder', 'file'].forEach((fileType) => { + beforeEach(() => { + props = { + ...props, + id: '0', + name: 'test.jsx', + fileType, + canEdit: true, + children: [], + authenticated: false, + setSelectedFile: jest.fn(), + deleteFile: jest.fn(), + updateFileName: jest.fn(), + resetSelectedFile: jest.fn(), + newFile: jest.fn(), + newFolder: jest.fn(), + showFolderChildren: jest.fn(), + hideFolderChildren: jest.fn(), + openUploadFileModal: jest.fn(), + setProjectName: jest.fn(), + }; + component = shallow(); + }); + + describe('when changing name', () => { + beforeEach(() => { + input = component.find('.sidebar__file-item-input'); + renameTriggerButton = component + .find('.sidebar__file-item-option') + .first(); + component.setState({ isEditing: true }); + }); + + describe('to an empty name', () => { + const newName = ''; + beforeEach(() => changeName(newName)); + + it('should not save', () => expect(props.updateFileName).not.toHaveBeenCalled()); + it('should reset name', () => expect(getUpdatedName()).toEqual(props.name)); + }); + }); + }); + }); + + describe('as file with valid props', () => { beforeEach(() => { props = { ...props, id: '0', - children: [], name: 'test.jsx', - fileType: 'dunno', + fileType: 'file', + canEdit: true, + children: [], + authenticated: false, setSelectedFile: jest.fn(), deleteFile: jest.fn(), updateFileName: jest.fn(), @@ -23,22 +78,12 @@ describe('', () => { newFolder: jest.fn(), showFolderChildren: jest.fn(), hideFolderChildren: jest.fn(), - canEdit: true, - authenticated: false, openUploadFileModal: jest.fn() }; component = shallow(); }); describe('when changing name', () => { - let input; - let renameTriggerButton; - const changeName = (newFileName) => { - renameTriggerButton.simulate('click'); - input.simulate('change', { target: { value: newFileName } }); - input.simulate('blur'); - }; - beforeEach(() => { input = component.find('.sidebar__file-item-input'); renameTriggerButton = component @@ -59,13 +104,79 @@ describe('', () => { }); }); - describe('to an empty filename', () => { - const newName = ''; + // Failure Scenarios + + describe('to an extensionless filename', () => { + const newName = 'extensionless'; + beforeEach(() => changeName(newName)); + }); + it('should not save', () => expect(props.setProjectName).not.toHaveBeenCalled()); + it('should reset name', () => expect(getUpdatedName()).toEqual(props.name)); + describe('to different extension', () => { + const newName = 'name.gif'; beforeEach(() => changeName(newName)); - it('should not save the name', () => { - expect(props.updateFileName).not.toHaveBeenCalled(); - }); + it('should not save', () => expect(props.setProjectName).not.toHaveBeenCalled()); + it('should reset name', () => expect(getUpdatedName()).toEqual(props.name)); + }); + + describe('to just an extension', () => { + const newName = '.jsx'; + beforeEach(() => changeName(newName)); + + it('should not save', () => expect(props.updateFileName).not.toHaveBeenCalled()); + it('should reset name', () => expect(getUpdatedName()).toEqual(props.name)); + }); + }); + }); + + + describe('as folder with valid props', () => { + beforeEach(() => { + props = { + ...props, + id: '0', + children: [], + name: 'filename', + fileType: 'folder', + canEdit: true, + authenticated: false, + setSelectedFile: jest.fn(), + deleteFile: jest.fn(), + updateFileName: jest.fn(), + resetSelectedFile: jest.fn(), + newFile: jest.fn(), + newFolder: jest.fn(), + showFolderChildren: jest.fn(), + hideFolderChildren: jest.fn(), + openUploadFileModal: jest.fn() + }; + component = shallow(); + }); + + describe('when changing name', () => { + beforeEach(() => { + input = component.find('.sidebar__file-item-input'); + renameTriggerButton = component + .find('.sidebar__file-item-option') + .first(); + component.setState({ isEditing: true }); + }); + + describe('to a foldername', () => { + const newName = 'newfoldername'; + beforeEach(() => changeName(newName)); + + it('should save', () => expect(props.updateFileName).toBeCalledWith(props.id, newName)); + it('should update name', () => expect(getUpdatedName()).toEqual(newName)); + }); + + describe('to a filename', () => { + const newName = 'filename.jsx'; + beforeEach(() => changeName(newName)); + + it('should not save', () => expect(props.updateFileName).not.toHaveBeenCalled()); + it('should reset name', () => expect(getUpdatedName()).toEqual(props.name)); }); }); }); diff --git a/client/components/__test__/Toolbar.test.jsx b/client/components/__test__/Toolbar.test.jsx new file mode 100644 index 00000000..a64f6f2d --- /dev/null +++ b/client/components/__test__/Toolbar.test.jsx @@ -0,0 +1,105 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { ToolbarComponent } from '../../modules/IDE/components/Toolbar'; + + +const initialProps = { + isPlaying: false, + preferencesIsVisible: false, + stopSketch: jest.fn(), + setProjectName: jest.fn(), + openPreferences: jest.fn(), + showEditProjectName: jest.fn(), + hideEditProjectName: jest.fn(), + infiniteLoop: false, + autorefresh: false, + setAutorefresh: jest.fn(), + setTextOutput: jest.fn(), + setGridOutput: jest.fn(), + startSketch: jest.fn(), + startAccessibleSketch: jest.fn(), + saveProject: jest.fn(), + currentUser: 'me', + originalProjectName: 'testname', + + owner: { + username: 'me' + }, + project: { + name: 'testname', + isEditingName: false, + id: 'id', + }, +}; + + +describe('', () => { + let component; + let props = initialProps; + let input; + let renameTriggerButton; + const changeName = (newFileName) => { + component.find('.toolbar__project-name').simulate('click', { preventDefault: jest.fn() }); + input = component.find('.toolbar__project-name-input'); + renameTriggerButton = component.find('.toolbar__edit-name-button'); + renameTriggerButton.simulate('click'); + input.simulate('change', { target: { value: newFileName } }); + input.simulate('blur'); + }; + const setProps = (additionalProps) => { + props = { + ...props, + ...additionalProps, + + project: { + ...props.project, + ...(additionalProps || {}).project + }, + }; + }; + + // Test Cases + + describe('with valid props', () => { + beforeEach(() => { + setProps(); + component = shallow(); + }); + it('renders', () => expect(component).toBeDefined()); + + describe('when use owns sketch', () => { + beforeEach(() => setProps({ currentUser: props.owner.username })); + + describe('when changing sketch name', () => { + beforeEach(() => { + setProps({ + project: { isEditingName: true, name: 'testname' }, + setProjectName: jest.fn(name => component.setProps({ project: { name } })), + }); + component = shallow(); + }); + + describe('to a valid name', () => { + beforeEach(() => changeName('hello')); + it('should save', () => expect(props.setProjectName).toBeCalledWith('hello')); + }); + + + describe('to an empty name', () => { + beforeEach(() => changeName('')); + it('should set name to empty', () => expect(props.setProjectName).toBeCalledWith('')); + it( + 'should detect empty name and revert to original', + () => expect(props.setProjectName).toHaveBeenLastCalledWith(initialProps.project.name) + ); + }); + }); + }); + + describe('when user does not own sketch', () => { + beforeEach(() => setProps({ currentUser: 'not-the-owner' })); + + it('should disable edition', () => expect(component.find('.toolbar__edit-name-button')).toEqual({})); + }); + }); +}); diff --git a/client/modules/IDE/components/Toolbar.jsx b/client/modules/IDE/components/Toolbar.jsx index dd5010ca..b3d13364 100644 --- a/client/modules/IDE/components/Toolbar.jsx +++ b/client/modules/IDE/components/Toolbar.jsx @@ -214,4 +214,5 @@ const mapDispatchToProps = { ...projectActions, }; +export const ToolbarComponent = Toolbar; export default connect(mapStateToProps, mapDispatchToProps)(Toolbar);