Merge pull request #1477 from andrewn/chore/split-test-runners
Use React Testing Library instead of Enzyme for tests
This commit is contained in:
commit
6f1ac99a77
15 changed files with 6901 additions and 2401 deletions
|
@ -1,183 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { shallow } from 'enzyme';
|
|
||||||
import { FileNode } from '../../modules/IDE/components/FileNode';
|
|
||||||
|
|
||||||
describe('<FileNode />', () => {
|
|
||||||
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, 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(<FileNode {...props} />);
|
|
||||||
});
|
|
||||||
|
|
||||||
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',
|
|
||||||
name: 'test.jsx',
|
|
||||||
fileType: 'file',
|
|
||||||
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()
|
|
||||||
};
|
|
||||||
component = shallow(<FileNode {...props} />);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when changing name', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
input = component.find('.sidebar__file-item-input');
|
|
||||||
renameTriggerButton = component
|
|
||||||
.find('.sidebar__file-item-option')
|
|
||||||
.first();
|
|
||||||
component.setState({ isEditing: true });
|
|
||||||
});
|
|
||||||
it('should render', () => expect(component).toBeDefined());
|
|
||||||
|
|
||||||
// it('should debug', () => console.log(component.debug()));
|
|
||||||
|
|
||||||
describe('to a valid filename', () => {
|
|
||||||
const newName = 'newname.jsx';
|
|
||||||
beforeEach(() => changeName(newName));
|
|
||||||
|
|
||||||
it('should save the name', () => {
|
|
||||||
expect(props.updateFileName).toBeCalledWith(props.id, 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', () => 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(<FileNode {...props} />);
|
|
||||||
});
|
|
||||||
|
|
||||||
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));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { render } from '@testing-library/react';
|
||||||
import renderer from 'react-test-renderer';
|
|
||||||
|
|
||||||
import { NavComponent } from './../Nav';
|
|
||||||
|
import { NavComponent } from '../Nav';
|
||||||
|
|
||||||
describe('Nav', () => {
|
describe('Nav', () => {
|
||||||
const props = {
|
const props = {
|
||||||
|
@ -47,17 +47,9 @@ describe('Nav', () => {
|
||||||
},
|
},
|
||||||
t: jest.fn()
|
t: jest.fn()
|
||||||
};
|
};
|
||||||
const getWrapper = () => shallow(<NavComponent {...props} />);
|
|
||||||
|
|
||||||
test('it renders main navigation', () => {
|
|
||||||
const nav = getWrapper();
|
|
||||||
expect(nav.exists('.nav')).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders correctly', () => {
|
it('renders correctly', () => {
|
||||||
const tree = renderer
|
const { asFragment } = render(<NavComponent {...props} />);
|
||||||
.create(<NavComponent {...props} />)
|
expect(asFragment()).toMatchSnapshot();
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
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('<ToolbarComponent />', () => {
|
|
||||||
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(<ToolbarComponent {...props} />);
|
|
||||||
});
|
|
||||||
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(<ToolbarComponent {...props} />);
|
|
||||||
});
|
|
||||||
|
|
||||||
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({}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,312 +1,219 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Nav renders correctly 1`] = `
|
exports[`Nav renders correctly 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
<header>
|
<header>
|
||||||
<nav
|
<nav
|
||||||
className="nav"
|
class="nav"
|
||||||
title="main-navigation"
|
title="main-navigation"
|
||||||
>
|
>
|
||||||
<ul
|
<ul
|
||||||
className="nav__items-left"
|
class="nav__items-left"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
className="nav__item-logo"
|
class="nav__item-logo"
|
||||||
>
|
>
|
||||||
<test-file-stub
|
<test-file-stub
|
||||||
aria-label="p5.js Logo"
|
aria-label="p5.js Logo"
|
||||||
className="svg__logo"
|
classname="svg__logo"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
role="img"
|
role="img"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__item"
|
class="nav__item"
|
||||||
>
|
|
||||||
<button
|
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
onMouseOver={[Function]}
|
|
||||||
>
|
>
|
||||||
|
<button>
|
||||||
<span
|
<span
|
||||||
className="nav__item-header"
|
class="nav__item-header"
|
||||||
/>
|
/>
|
||||||
<test-file-stub
|
<test-file-stub
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className="nav__item-header-triangle"
|
classname="nav__item-header-triangle"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<ul
|
<ul
|
||||||
className="nav__dropdown"
|
class="nav__dropdown"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
>
|
||||||
<button
|
<button />
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
>
|
||||||
<button
|
<button />
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
>
|
||||||
<button
|
<button />
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
>
|
||||||
<button
|
<button />
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
>
|
||||||
<a
|
<a />
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
style={Object {}}
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__item"
|
class="nav__item"
|
||||||
>
|
|
||||||
<button
|
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
onMouseOver={[Function]}
|
|
||||||
>
|
>
|
||||||
|
<button>
|
||||||
<span
|
<span
|
||||||
className="nav__item-header"
|
class="nav__item-header"
|
||||||
/>
|
/>
|
||||||
<test-file-stub
|
<test-file-stub
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className="nav__item-header-triangle"
|
classname="nav__item-header-triangle"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<ul
|
<ul
|
||||||
className="nav__dropdown"
|
class="nav__dropdown"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
|
||||||
<button
|
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
>
|
>
|
||||||
|
<button>
|
||||||
<span
|
<span
|
||||||
className="nav__keyboard-shortcut"
|
class="nav__keyboard-shortcut"
|
||||||
>
|
>
|
||||||
⇧
|
⇧+Tab
|
||||||
+Tab
|
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
|
||||||
<button
|
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
>
|
>
|
||||||
|
<button>
|
||||||
<span
|
<span
|
||||||
className="nav__keyboard-shortcut"
|
class="nav__keyboard-shortcut"
|
||||||
>
|
>
|
||||||
⌃
|
⌃+F
|
||||||
+F
|
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
|
||||||
<button
|
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
>
|
>
|
||||||
|
<button>
|
||||||
<span
|
<span
|
||||||
className="nav__keyboard-shortcut"
|
class="nav__keyboard-shortcut"
|
||||||
>
|
>
|
||||||
⌃
|
⌃+G
|
||||||
+G
|
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
|
||||||
<button
|
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
>
|
>
|
||||||
|
<button>
|
||||||
<span
|
<span
|
||||||
className="nav__keyboard-shortcut"
|
class="nav__keyboard-shortcut"
|
||||||
>
|
>
|
||||||
⇧
|
⇧+⌃+G
|
||||||
+
|
|
||||||
⌃
|
|
||||||
+G
|
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__item"
|
class="nav__item"
|
||||||
>
|
|
||||||
<button
|
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
onMouseOver={[Function]}
|
|
||||||
>
|
>
|
||||||
|
<button>
|
||||||
<span
|
<span
|
||||||
className="nav__item-header"
|
class="nav__item-header"
|
||||||
/>
|
/>
|
||||||
<test-file-stub
|
<test-file-stub
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className="nav__item-header-triangle"
|
classname="nav__item-header-triangle"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<ul
|
<ul
|
||||||
className="nav__dropdown"
|
class="nav__dropdown"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
>
|
||||||
<button
|
<button />
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
>
|
||||||
<button
|
<button />
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
|
||||||
<button
|
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
>
|
>
|
||||||
|
<button>
|
||||||
<span
|
<span
|
||||||
className="nav__keyboard-shortcut"
|
class="nav__keyboard-shortcut"
|
||||||
>
|
>
|
||||||
⌃
|
⌃+Enter
|
||||||
+Enter
|
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
|
||||||
<button
|
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
>
|
>
|
||||||
|
<button>
|
||||||
<span
|
<span
|
||||||
className="nav__keyboard-shortcut"
|
class="nav__keyboard-shortcut"
|
||||||
>
|
>
|
||||||
⇧
|
⇧+⌃+Enter
|
||||||
+
|
|
||||||
⌃
|
|
||||||
+Enter
|
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__item"
|
class="nav__item"
|
||||||
>
|
|
||||||
<button
|
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
onMouseOver={[Function]}
|
|
||||||
>
|
>
|
||||||
|
<button>
|
||||||
<span
|
<span
|
||||||
className="nav__item-header"
|
class="nav__item-header"
|
||||||
/>
|
/>
|
||||||
<test-file-stub
|
<test-file-stub
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className="nav__item-header-triangle"
|
classname="nav__item-header-triangle"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<ul
|
<ul
|
||||||
className="nav__dropdown"
|
class="nav__dropdown"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
>
|
||||||
<button
|
<button />
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="https://p5js.org/reference/"
|
href="https://p5js.org/reference/"
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="nav__dropdown-item"
|
class="nav__dropdown-item"
|
||||||
>
|
>
|
||||||
<a
|
<a />
|
||||||
onBlur={[Function]}
|
|
||||||
onClick={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
style={Object {}}
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
</DocumentFragment>
|
||||||
`;
|
`;
|
||||||
|
|
5
client/jest.setup.js
Normal file
5
client/jest.setup.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import '@babel/polyfill';
|
||||||
|
|
||||||
|
// See: https://github.com/testing-library/jest-dom
|
||||||
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
|
import '@testing-library/jest-dom';
|
|
@ -206,12 +206,14 @@ export class FileNode extends React.Component {
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<button
|
<button
|
||||||
|
aria-label="Name"
|
||||||
className="sidebar__file-item-name"
|
className="sidebar__file-item-name"
|
||||||
onClick={this.handleFileClick}
|
onClick={this.handleFileClick}
|
||||||
>
|
>
|
||||||
{this.state.updatedName}
|
{this.state.updatedName}
|
||||||
</button>
|
</button>
|
||||||
<input
|
<input
|
||||||
|
data-testid="input"
|
||||||
type="text"
|
type="text"
|
||||||
className="sidebar__file-item-input"
|
className="sidebar__file-item-input"
|
||||||
value={this.state.updatedName}
|
value={this.state.updatedName}
|
||||||
|
|
31
client/modules/IDE/components/FileNode.stories.jsx
Normal file
31
client/modules/IDE/components/FileNode.stories.jsx
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { action } from '@storybook/addon-actions';
|
||||||
|
|
||||||
|
import { FileNode } from './FileNode';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'IDE/FileNode',
|
||||||
|
component: FileNode
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Show = () => (
|
||||||
|
<FileNode
|
||||||
|
id="nodeId"
|
||||||
|
parantId="parentId"
|
||||||
|
name="File name"
|
||||||
|
fileType="jpeg"
|
||||||
|
isSelectedFile
|
||||||
|
isFolderClosed={false}
|
||||||
|
setSelectedFile={action('setSelectedFile')}
|
||||||
|
deleteFile={action('deleteFile')}
|
||||||
|
updateFileName={action('updateFileName')}
|
||||||
|
resetSelectedFile={action('resetSelectedFile')}
|
||||||
|
newFile={action('newFile')}
|
||||||
|
newFolder={action('newFolder')}
|
||||||
|
showFolderChildren={action('showFolderChildren')}
|
||||||
|
hideFolderChildren={action('hideFolderChildren')}
|
||||||
|
openUploadFileModal={action('openUploadFileModal')}
|
||||||
|
canEdit
|
||||||
|
authenticated
|
||||||
|
/>
|
||||||
|
);
|
127
client/modules/IDE/components/FileNode.test.jsx
Normal file
127
client/modules/IDE/components/FileNode.test.jsx
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { fireEvent, render, screen, waitFor, within } from '@testing-library/react';
|
||||||
|
import { FileNode } from './FileNode';
|
||||||
|
|
||||||
|
describe('<FileNode />', () => {
|
||||||
|
const changeName = (newFileName) => {
|
||||||
|
const renameButton = screen.getByText(/Rename/i);
|
||||||
|
fireEvent.click(renameButton);
|
||||||
|
|
||||||
|
const input = screen.getByTestId('input');
|
||||||
|
fireEvent.change(input, { target: { value: newFileName } });
|
||||||
|
fireEvent.blur(input);
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectFileNameToBe = async (expectedName) => {
|
||||||
|
const name = screen.getByLabelText(/Name/i);
|
||||||
|
await waitFor(() => within(name).queryByText(expectedName));
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderFileNode = (fileType, extraProps = {}) => {
|
||||||
|
const props = {
|
||||||
|
...extraProps,
|
||||||
|
id: '0',
|
||||||
|
name: fileType === 'folder' ? 'afolder' : '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(),
|
||||||
|
};
|
||||||
|
|
||||||
|
render(<FileNode {...props} />);
|
||||||
|
|
||||||
|
return props;
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('fileType: file', () => {
|
||||||
|
it('cannot change to an empty name', async () => {
|
||||||
|
const props = renderFileNode('file');
|
||||||
|
|
||||||
|
changeName('');
|
||||||
|
|
||||||
|
await waitFor(() => expect(props.updateFileName).not.toHaveBeenCalled());
|
||||||
|
await expectFileNameToBe(props.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can change to a valid filename', async () => {
|
||||||
|
const newName = 'newname.jsx';
|
||||||
|
const props = renderFileNode('file');
|
||||||
|
|
||||||
|
changeName(newName);
|
||||||
|
|
||||||
|
await waitFor(() => expect(props.updateFileName).toHaveBeenCalledWith(props.id, newName));
|
||||||
|
await expectFileNameToBe(newName);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('must have an extension', async () => {
|
||||||
|
const newName = 'newname';
|
||||||
|
const props = renderFileNode('file');
|
||||||
|
|
||||||
|
changeName(newName);
|
||||||
|
|
||||||
|
await waitFor(() => expect(props.updateFileName).not.toHaveBeenCalled());
|
||||||
|
await expectFileNameToBe(props.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can change to a different extension', async () => {
|
||||||
|
const newName = 'newname.gif';
|
||||||
|
const props = renderFileNode('file');
|
||||||
|
|
||||||
|
changeName(newName);
|
||||||
|
|
||||||
|
await waitFor(() => expect(props.updateFileName).not.toHaveBeenCalled());
|
||||||
|
await expectFileNameToBe(props.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cannot be just an extension', async () => {
|
||||||
|
const newName = '.jsx';
|
||||||
|
const props = renderFileNode('file');
|
||||||
|
|
||||||
|
changeName(newName);
|
||||||
|
|
||||||
|
await waitFor(() => expect(props.updateFileName).not.toHaveBeenCalled());
|
||||||
|
await expectFileNameToBe(props.name);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('fileType: folder', () => {
|
||||||
|
it('cannot change to an empty name', async () => {
|
||||||
|
const props = renderFileNode('folder');
|
||||||
|
|
||||||
|
changeName('');
|
||||||
|
|
||||||
|
await waitFor(() => expect(props.updateFileName).not.toHaveBeenCalled());
|
||||||
|
await expectFileNameToBe(props.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can change to another name', async () => {
|
||||||
|
const newName = 'foldername';
|
||||||
|
const props = renderFileNode('folder');
|
||||||
|
|
||||||
|
changeName(newName);
|
||||||
|
|
||||||
|
await waitFor(() => expect(props.updateFileName).toHaveBeenCalledWith(props.id, newName));
|
||||||
|
await expectFileNameToBe(newName);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cannot have a file extension', async () => {
|
||||||
|
const newName = 'foldername.jsx';
|
||||||
|
const props = renderFileNode('folder');
|
||||||
|
|
||||||
|
changeName(newName);
|
||||||
|
|
||||||
|
await waitFor(() => expect(props.updateFileName).not.toHaveBeenCalled());
|
||||||
|
await expectFileNameToBe(props.name);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -17,21 +17,36 @@ class Toolbar extends React.Component {
|
||||||
super(props);
|
super(props);
|
||||||
this.handleKeyPress = this.handleKeyPress.bind(this);
|
this.handleKeyPress = this.handleKeyPress.bind(this);
|
||||||
this.handleProjectNameChange = this.handleProjectNameChange.bind(this);
|
this.handleProjectNameChange = this.handleProjectNameChange.bind(this);
|
||||||
|
this.handleProjectNameSave = this.handleProjectNameSave.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
projectNameInputValue: props.project.name,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKeyPress(event) {
|
handleKeyPress(event) {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter') {
|
||||||
this.props.hideEditProjectName();
|
this.props.hideEditProjectName();
|
||||||
|
this.projectNameInput.blur();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleProjectNameChange(event) {
|
handleProjectNameChange(event) {
|
||||||
this.props.setProjectName(event.target.value);
|
this.setState({ projectNameInputValue: event.target.value });
|
||||||
}
|
}
|
||||||
|
|
||||||
validateProjectName() {
|
handleProjectNameSave() {
|
||||||
if ((this.props.project.name.trim()).length === 0) {
|
const newProjectName = this.state.projectNameInputValue.trim();
|
||||||
this.props.setProjectName(this.originalProjectName);
|
if (newProjectName.length === 0) {
|
||||||
|
this.setState({
|
||||||
|
projectNameInputValue: this.props.project.name,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.props.setProjectName(newProjectName);
|
||||||
|
this.props.hideEditProjectName();
|
||||||
|
if (this.props.project.id) {
|
||||||
|
this.props.saveProject();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +123,6 @@ class Toolbar extends React.Component {
|
||||||
className="toolbar__project-name"
|
className="toolbar__project-name"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (canEditProjectName) {
|
if (canEditProjectName) {
|
||||||
this.originalProjectName = this.props.project.name;
|
|
||||||
this.props.showEditProjectName();
|
this.props.showEditProjectName();
|
||||||
setTimeout(() => this.projectNameInput.focus(), 0);
|
setTimeout(() => this.projectNameInput.focus(), 0);
|
||||||
}
|
}
|
||||||
|
@ -130,16 +144,11 @@ class Toolbar extends React.Component {
|
||||||
type="text"
|
type="text"
|
||||||
maxLength="128"
|
maxLength="128"
|
||||||
className="toolbar__project-name-input"
|
className="toolbar__project-name-input"
|
||||||
value={this.props.project.name}
|
aria-label="New sketch name"
|
||||||
|
value={this.state.projectNameInputValue}
|
||||||
onChange={this.handleProjectNameChange}
|
onChange={this.handleProjectNameChange}
|
||||||
ref={(element) => { this.projectNameInput = element; }}
|
ref={(element) => { this.projectNameInput = element; }}
|
||||||
onBlur={() => {
|
onBlur={this.handleProjectNameSave}
|
||||||
this.validateProjectName();
|
|
||||||
this.props.hideEditProjectName();
|
|
||||||
if (this.props.project.id) {
|
|
||||||
this.props.saveProject();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onKeyPress={this.handleKeyPress}
|
onKeyPress={this.handleKeyPress}
|
||||||
/>
|
/>
|
||||||
{(() => { // eslint-disable-line
|
{(() => { // eslint-disable-line
|
||||||
|
|
84
client/modules/IDE/components/Toolbar.test.jsx
Normal file
84
client/modules/IDE/components/Toolbar.test.jsx
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||||
|
import lodash from 'lodash';
|
||||||
|
|
||||||
|
|
||||||
|
import { ToolbarComponent } from './Toolbar';
|
||||||
|
|
||||||
|
const renderComponent = (extraProps = {}) => {
|
||||||
|
const props = lodash.merge({
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
}, extraProps);
|
||||||
|
|
||||||
|
render(<ToolbarComponent {...props} />);
|
||||||
|
|
||||||
|
return props;
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('<ToolbarComponent />', () => {
|
||||||
|
it('sketch owner can switch to sketch name editing mode', async () => {
|
||||||
|
const props = renderComponent();
|
||||||
|
const sketchName = screen.getByLabelText('Edit sketch name');
|
||||||
|
|
||||||
|
fireEvent.click(sketchName);
|
||||||
|
|
||||||
|
await waitFor(() => expect(props.showEditProjectName).toHaveBeenCalled());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('non-owner can\t switch to sketch editing mode', async () => {
|
||||||
|
const props = renderComponent({ currentUser: 'not-me' });
|
||||||
|
const sketchName = screen.getByLabelText('Edit sketch name');
|
||||||
|
|
||||||
|
fireEvent.click(sketchName);
|
||||||
|
|
||||||
|
expect(sketchName).toBeDisabled();
|
||||||
|
await waitFor(() => expect(props.showEditProjectName).not.toHaveBeenCalled());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sketch owner can change name', async () => {
|
||||||
|
const props = renderComponent({ project: { isEditingName: true } });
|
||||||
|
|
||||||
|
const sketchNameInput = screen.getByLabelText('New sketch name');
|
||||||
|
fireEvent.change(sketchNameInput, { target: { value: 'my new sketch name' } });
|
||||||
|
fireEvent.blur(sketchNameInput);
|
||||||
|
|
||||||
|
await waitFor(() => expect(props.setProjectName).toHaveBeenCalledWith('my new sketch name'));
|
||||||
|
await waitFor(() => expect(props.saveProject).toHaveBeenCalled());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sketch owner can\'t change to empty name', async () => {
|
||||||
|
const props = renderComponent({ project: { isEditingName: true } });
|
||||||
|
|
||||||
|
const sketchNameInput = screen.getByLabelText('New sketch name');
|
||||||
|
fireEvent.change(sketchNameInput, { target: { value: '' } });
|
||||||
|
fireEvent.blur(sketchNameInput);
|
||||||
|
|
||||||
|
await waitFor(() => expect(props.setProjectName).not.toHaveBeenCalled());
|
||||||
|
await waitFor(() => expect(props.saveProject).not.toHaveBeenCalled());
|
||||||
|
});
|
||||||
|
});
|
|
@ -216,7 +216,7 @@ class IDEView extends React.Component {
|
||||||
warnIfUnsavedChanges={this.warnIfUnsavedChanges}
|
warnIfUnsavedChanges={this.warnIfUnsavedChanges}
|
||||||
cmController={this.cmController}
|
cmController={this.cmController}
|
||||||
/>
|
/>
|
||||||
<Toolbar />
|
<Toolbar key={this.props.project.id} />
|
||||||
{this.props.ide.preferencesIsVisible &&
|
{this.props.ide.preferencesIsVisible &&
|
||||||
<Overlay
|
<Overlay
|
||||||
title={this.props.t('Settings')}
|
title={this.props.t('Settings')}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { configure } from 'enzyme'
|
|
||||||
import Adapter from 'enzyme-adapter-react-16'
|
|
||||||
import '@babel/polyfill'
|
|
||||||
import mongoose from 'mongoose'
|
|
||||||
|
|
||||||
mongoose.Promise = global.Promise;
|
|
||||||
|
|
||||||
configure({ adapter: new Adapter() })
|
|
8194
package-lock.json
generated
8194
package-lock.json
generated
File diff suppressed because it is too large
Load diff
31
package.json
31
package.json
|
@ -36,12 +36,30 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"setupFiles": [
|
"projects": [
|
||||||
"<rootDir>/jest.setup.js"
|
{
|
||||||
|
"displayName": "server",
|
||||||
|
"testEnvironment": "node",
|
||||||
|
"setupFilesAfterEnv": [
|
||||||
|
"<rootDir>/server/jest.setup.js"
|
||||||
|
],
|
||||||
|
"testMatch": [
|
||||||
|
"<rootDir>/server/**/*.test.(js|jsx)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "client",
|
||||||
|
"setupFilesAfterEnv": [
|
||||||
|
"<rootDir>/client/jest.setup.js"
|
||||||
],
|
],
|
||||||
"moduleNameMapper": {
|
"moduleNameMapper": {
|
||||||
"^.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/client/__test__/mocks/fileMock.js"
|
"^.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/client/__test__/mocks/fileMock.js"
|
||||||
|
},
|
||||||
|
"testMatch": [
|
||||||
|
"<rootDir>/client/**/*.test.(js|jsx)"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"author": "Cassie Tarakajian",
|
"author": "Cassie Tarakajian",
|
||||||
|
@ -78,15 +96,14 @@
|
||||||
"@storybook/addons": "^5.3.6",
|
"@storybook/addons": "^5.3.6",
|
||||||
"@storybook/react": "^5.3.6",
|
"@storybook/react": "^5.3.6",
|
||||||
"@svgr/webpack": "^5.4.0",
|
"@svgr/webpack": "^5.4.0",
|
||||||
|
"@testing-library/jest-dom": "^5.10.1",
|
||||||
|
"@testing-library/react": "^10.2.1",
|
||||||
"babel-core": "^7.0.0-bridge.0",
|
"babel-core": "^7.0.0-bridge.0",
|
||||||
"babel-eslint": "^9.0.0",
|
"babel-eslint": "^9.0.0",
|
||||||
"babel-jest": "^24.9.0",
|
|
||||||
"babel-loader": "^8.0.0",
|
"babel-loader": "^8.0.0",
|
||||||
"babel-plugin-transform-react-remove-prop-types": "^0.2.12",
|
"babel-plugin-transform-react-remove-prop-types": "^0.2.12",
|
||||||
"css-loader": "^3.4.2",
|
"css-loader": "^3.4.2",
|
||||||
"cssnano": "^4.1.10",
|
"cssnano": "^4.1.10",
|
||||||
"enzyme": "^3.11.0",
|
|
||||||
"enzyme-adapter-react-16": "^1.15.2",
|
|
||||||
"eslint": "^4.19.1",
|
"eslint": "^4.19.1",
|
||||||
"eslint-config-airbnb": "^16.1.0",
|
"eslint-config-airbnb": "^16.1.0",
|
||||||
"eslint-plugin-import": "^2.20.2",
|
"eslint-plugin-import": "^2.20.2",
|
||||||
|
@ -94,10 +111,10 @@
|
||||||
"eslint-plugin-react": "^7.18.3",
|
"eslint-plugin-react": "^7.18.3",
|
||||||
"file-loader": "^2.0.0",
|
"file-loader": "^2.0.0",
|
||||||
"husky": "^4.2.5",
|
"husky": "^4.2.5",
|
||||||
"jest": "^24.9.0",
|
"jest": "^26.0.1",
|
||||||
"lint-staged": "^10.1.3",
|
"lint-staged": "^10.1.3",
|
||||||
"mini-css-extract-plugin": "^0.8.2",
|
"mini-css-extract-plugin": "^0.8.2",
|
||||||
"node-sass": "^4.13.1",
|
"node-sass": "^4.14.1",
|
||||||
"nodemon": "^1.19.4",
|
"nodemon": "^1.19.4",
|
||||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||||
"postcss-cssnext": "^3.1.0",
|
"postcss-cssnext": "^3.1.0",
|
||||||
|
|
4
server/jest.setup.js
Normal file
4
server/jest.setup.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import '@babel/polyfill';
|
||||||
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
|
mongoose.Promise = global.Promise;
|
Loading…
Reference in a new issue