diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 7056a786e..831b8c3ce 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -35,6 +35,7 @@ "@emotion/babel-preset-css-prop": "10.0.27", "@emotion/core": "10.0.35", "@types/enzyme": "3.10.6", + "@types/enzyme-adapter-react-16": "1.0.9", "@types/jest": "26.0.14", "@types/node": "14.11.1", "@types/react": "16.9.49", @@ -5214,6 +5215,15 @@ "@types/react": "*" } }, + "node_modules/@types/enzyme-adapter-react-16": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.9.tgz", + "integrity": "sha512-z24MMxGtUL8HhXdye3tWzjp+19QTsABqLaX2oOZpxMPHRJgLfahQmOeTTrEBQd9ogW20+UmPBXD9j+XOasFHvw==", + "dev": true, + "dependencies": { + "@types/enzyme": "*" + } + }, "node_modules/@types/graceful-fs": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", @@ -27616,6 +27626,15 @@ "@types/react": "*" } }, + "@types/enzyme-adapter-react-16": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.9.tgz", + "integrity": "sha512-z24MMxGtUL8HhXdye3tWzjp+19QTsABqLaX2oOZpxMPHRJgLfahQmOeTTrEBQd9ogW20+UmPBXD9j+XOasFHvw==", + "dev": true, + "requires": { + "@types/enzyme": "*" + } + }, "@types/graceful-fs": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", diff --git a/webapp/package.json b/webapp/package.json index 5446b233d..87ccc27c2 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -27,6 +27,7 @@ "@emotion/babel-preset-css-prop": "10.0.27", "@emotion/core": "10.0.35", "@types/enzyme": "3.10.6", + "@types/enzyme-adapter-react-16": "1.0.9", "@types/jest": "26.0.14", "@types/node": "14.11.1", "@types/react": "16.9.49", @@ -115,6 +116,9 @@ "setupFiles": [ "jest-canvas-mock" ], + "setupFilesAfterEnv": [ + "/tests/setup.tsx" + ], "testURL": "http://localhost:8065" } } diff --git a/webapp/src/components/modals/create_issue/__snapshots__/create_issue.test.jsx.snap b/webapp/src/components/modals/create_issue/__snapshots__/create_issue.test.jsx.snap new file mode 100644 index 000000000..d277fc594 --- /dev/null +++ b/webapp/src/components/modals/create_issue/__snapshots__/create_issue.test.jsx.snap @@ -0,0 +1,105 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CreateIssueModal should render correctly with default props 1`] = ` + + + + Create GitHub Issue + + +
+ +
+ + + +
+
+ + + + Submit + + +
+
+`; diff --git a/webapp/src/components/modals/create_issue/create_issue.test.jsx b/webapp/src/components/modals/create_issue/create_issue.test.jsx new file mode 100644 index 000000000..ce94adcf9 --- /dev/null +++ b/webapp/src/components/modals/create_issue/create_issue.test.jsx @@ -0,0 +1,112 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import CreateIssueModal from './create_issue'; + +jest.mock('utils/user_utils', () => ({ + getErrorMessage: jest.fn(() => 'Error occurred'), +})); + +describe('CreateIssueModal', () => { + const defaultProps = { + close: jest.fn(), + create: jest.fn(() => Promise.resolve({})), + post: null, + theme: { + centerChannelColor: '#000', + centerChannelBg: '#fff', + }, + visible: true, + }; + + it('should render correctly with default props', () => { + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); + + it('should call close prop when handleClose is called', () => { + const wrapper = shallow(); + wrapper.instance().handleClose(); + expect(defaultProps.close).toHaveBeenCalled(); + }); + + it('should call create prop when form is submitted with valid data', async () => { + const wrapper = shallow(); + wrapper.setState({issueTitle: 'Test Issue'}); + + await wrapper.instance().handleCreate({preventDefault: jest.fn()}); + expect(defaultProps.create).toHaveBeenCalled(); + }); + + it('should display error message when create returns an error', async () => { + const mockCreateFunction = jest.fn().mockResolvedValue({error: {message: 'Some error'}}); + const errorProps = { + ...defaultProps, + create: mockCreateFunction, + }; + + const wrapper = shallow(); + wrapper.setState({issueTitle: 'Test Issue'}); + + await wrapper.instance().handleCreate({preventDefault: jest.fn()}); + wrapper.update(); + + expect(wrapper.find('.help-text.error-text').text()).toEqual('Error occurred'); + }); + + it('should show validation error when issueTitle is empty', async () => { + const wrapper = shallow(); + wrapper.setState({issueTitle: ''}); + + await wrapper.instance().handleCreate({preventDefault: jest.fn()}); + expect(wrapper.state('issueTitleValid')).toBe(false); + expect(wrapper.state('showErrors')).toBe(true); + }); + + it('should update repo state when handleRepoChange is called', () => { + const wrapper = shallow(); + const repo = {name: 'repo-name'}; + + wrapper.instance().handleRepoChange(repo); + expect(wrapper.state('repo')).toEqual(repo); + }); + + it('should update labels state when handleLabelsChange is called', () => { + const wrapper = shallow(); + const labels = ['label1', 'label2']; + + wrapper.instance().handleLabelsChange(labels); + expect(wrapper.state('labels')).toEqual(labels); + }); + + it('should update assignees state when handleAssigneesChange is called', () => { + const wrapper = shallow(); + const assignees = ['user1', 'user2']; + + wrapper.instance().handleAssigneesChange(assignees); + expect(wrapper.state('assignees')).toEqual(assignees); + }); + + it('should set issueDescription state when post prop is updated', () => { + const wrapper = shallow(); + const post = {message: 'test post'}; + wrapper.setProps({post}); + + expect(wrapper.state('issueDescription')).toEqual(post.message); + }); + + it('should not display attribute selectors when repo does not have push permissions', () => { + const wrapper = shallow(); + wrapper.setState({repo: {name: 'repo-name', permissions: {push: false}}}); + + expect(wrapper.instance().renderIssueAttributeSelectors()).toBeNull(); + }); + + it('should display attribute selectors when repo has push permissions', () => { + const wrapper = shallow(); + wrapper.setState({repo: {name: 'repo-name', permissions: {push: true}}}); + + const selectors = wrapper.instance().renderIssueAttributeSelectors(); + expect(selectors).not.toBeNull(); + }); +}); diff --git a/webapp/tests/setup.tsx b/webapp/tests/setup.tsx new file mode 100644 index 000000000..75f1d053f --- /dev/null +++ b/webapp/tests/setup.tsx @@ -0,0 +1,4 @@ +import Adapter from 'enzyme-adapter-react-16'; +import {configure} from 'enzyme'; + +configure({adapter: new Adapter()});