import {browserHistory} from 'react-router'; import {mount} from 'enzyme'; import React from 'react'; import OrganizationGeneralSettings from 'app/views/settings/organizationGeneralSettings'; jest.mock('jquery'); jest.mock('react-router', () => { return { browserHistory: { push: jest.fn(), replace: jest.fn(), }, }; }); describe('OrganizationGeneralSettings', function() { const org = TestStubs.Organization(); const ENDPOINT = `/organizations/${org.slug}/`; beforeEach(function() { MockApiClient.clearMockResponses(); MockApiClient.addMockResponse({ url: ENDPOINT, body: TestStubs.Organization(), }); browserHistory.push.mockReset(); browserHistory.replace.mockReset(); }); it('has LoadingError on error', async function() { MockApiClient.clearMockResponses(); MockApiClient.addMockResponse({ url: ENDPOINT, statusCode: 500, body: {}, }); let wrapper = mount( , TestStubs.routerContext() ); await tick(); wrapper.update(); expect(wrapper.find('LoadingIndicator')).toHaveLength(0); expect(wrapper.find('LoadingError')).toHaveLength(1); }); it('can enable "early adopter"', async function() { let wrapper = mount( , TestStubs.routerContext() ); let mock = MockApiClient.addMockResponse({ url: ENDPOINT, method: 'PUT', }); wrapper.setState({loading: false}); await tick(); wrapper.update(); wrapper.find('Switch[id="isEarlyAdopter"]').simulate('click'); expect(mock).toHaveBeenCalledWith( ENDPOINT, expect.objectContaining({ data: {isEarlyAdopter: true}, }) ); }); it('changes org slug and redirects to new slug', async function() { let wrapper = mount( , TestStubs.routerContext() ); let mock = MockApiClient.addMockResponse({ url: ENDPOINT, method: 'PUT', }); wrapper.setState({loading: false}); await tick(); wrapper.update(); // Change slug wrapper .find('input[id="slug"]') .simulate('change', {target: {value: 'new-slug'}}) .simulate('blur'); wrapper.find('SaveButton').simulate('click'); expect(mock).toHaveBeenCalledWith( ENDPOINT, expect.objectContaining({ data: {slug: 'new-slug'}, }) ); await tick(); // Not sure why this needs to be async, but it does expect(browserHistory.replace).toHaveBeenCalledWith('/settings/new-slug/'); }); it('disables the entire form if user does not have write access', async function() { const readOnlyOrg = TestStubs.Organization({access: ['org:read']}); MockApiClient.clearMockResponses(); MockApiClient.addMockResponse({ url: ENDPOINT, body: readOnlyOrg, }); let wrapper = mount( , TestStubs.routerContext([{organization: readOnlyOrg}]) ); wrapper.setState({loading: false}); await tick(); wrapper.update(); expect(wrapper.find('Form FormField[disabled=false]')).toHaveLength(0); expect( wrapper .find('PermissionAlert') .first() .text() ).toEqual( 'These settings can only be edited by users with the owner or manager role.' ); }); it('does not have remove organization button', async function() { MockApiClient.clearMockResponses(); MockApiClient.addMockResponse({ url: ENDPOINT, body: TestStubs.Organization({ projects: [{slug: 'project'}], access: ['org:write'], }), }); let wrapper = mount( , TestStubs.routerContext() ); wrapper.setState({loading: false}); await tick(); wrapper.update(); expect(wrapper.find('Confirm[priority="danger"]')).toHaveLength(0); }); it('can remove organization when org admin', async function() { MockApiClient.clearMockResponses(); MockApiClient.addMockResponse({ url: ENDPOINT, body: TestStubs.Organization({ projects: [{slug: 'project'}], access: ['org:admin'], }), }); let wrapper = mount( , TestStubs.routerContext() ); let mock = MockApiClient.addMockResponse({ url: ENDPOINT, method: 'DELETE', }); wrapper.setState({loading: false}); await tick(); wrapper.update(); wrapper.find('Confirm[priority="danger"]').simulate('click'); // Lists projects in modal expect(wrapper.find('Modal .ref-projects')).toHaveLength(1); expect(wrapper.find('Modal .ref-projects li').text()).toBe('project'); // Confirm delete wrapper.find('Modal Portal Button[priority="danger"]').simulate('click'); expect(mock).toHaveBeenCalledWith( ENDPOINT, expect.objectContaining({ method: 'DELETE', }) ); }); it('shows require2fa switch w/ feature flag', async function() { let wrapper = mount( , TestStubs.routerContext([ { organization: TestStubs.Organization({ features: ['require-2fa'], }), }, ]) ); wrapper.setState({loading: false}); await tick(); wrapper.update(); expect(wrapper.find('Switch[name="require2FA"]')).toHaveLength(1); }); it('enables require2fa but cancels confirm modal', async function() { let mock = MockApiClient.addMockResponse({ url: '/organizations/org-slug/', method: 'PUT', }); let wrapper = mount( , TestStubs.routerContext([ { organization: TestStubs.Organization({ features: ['require-2fa'], }), }, ]) ); wrapper.setState({loading: false}); await tick(); wrapper.update(); expect(wrapper.find('Switch[name="require2FA"]')).toHaveLength(1); wrapper.find('Switch[name="require2FA"]').simulate('click'); expect(wrapper.find('Field[name="require2FA"] ModalDialog')).toHaveLength(1); // Cancel wrapper .find('Field[name="require2FA"] ModalDialog .modal-footer Button') .first() .simulate('click'); expect(wrapper.find('Field[name="require2FA"] ModalDialog')).toHaveLength(0); expect(wrapper.find('Switch[name="require2FA"]').prop('isActive')).toBe(false); expect(mock).not.toHaveBeenCalled(); }); it('enables require2fa with confirm modal', async function() { let mock = MockApiClient.addMockResponse({ url: '/organizations/org-slug/', method: 'PUT', }); let wrapper = mount( , TestStubs.routerContext([ { organization: TestStubs.Organization({ features: ['require-2fa'], }), }, ]) ); wrapper.setState({loading: false}); await tick(); wrapper.update(); expect(wrapper.find('Switch[name="require2FA"]')).toHaveLength(1); wrapper.find('Switch[name="require2FA"]').simulate('click'); expect(wrapper.find('Field[name="require2FA"] ModalDialog')).toHaveLength(1); // Confirm wrapper .find( 'Field[name="require2FA"] ModalDialog .modal-footer Button[priority="primary"]' ) .simulate('click'); expect(wrapper.find('Field[name="require2FA"] ModalDialog')).toHaveLength(0); expect(wrapper.find('Switch[name="require2FA"]').prop('isActive')).toBe(true); expect(mock).toHaveBeenCalledWith( '/organizations/org-slug/', expect.objectContaining({ method: 'PUT', data: { require2FA: true, }, }) ); }); it('returns to "off" if switch enable fails (e.g. API error)', async function() { MockApiClient.addMockResponse({ url: '/organizations/org-slug/', method: 'PUT', statusCode: 500, }); let wrapper = mount( , TestStubs.routerContext([ { organization: TestStubs.Organization({ features: ['require-2fa'], }), }, ]) ); wrapper.setState({loading: false}); await tick(); wrapper.update(); wrapper.find('Switch[name="require2FA"]').simulate('click'); // hide console.error for this test sinon.stub(console, 'error'); // Confirm but has API failure wrapper .find( 'Field[name="require2FA"] ModalDialog .modal-footer Button[priority="primary"]' ) .simulate('click'); await tick(); wrapper.update(); expect(wrapper.find('Switch[name="require2FA"]').prop('isActive')).toBe(false); // eslint-disable-next-line no-console console.error.restore(); }); });