import {mountWithTheme} from 'sentry-test/enzyme'; import {act} from 'sentry-test/reactTestingLibrary'; import * as TeamKeyTransactionManager from 'sentry/components/performance/teamKeyTransactionsManager'; import ProjectsStore from 'sentry/stores/projectsStore'; import TeamStore from 'sentry/stores/teamStore'; import TeamKeyTransactionField from 'sentry/utils/discover/teamKeyTransactionField'; async function clickTeamKeyTransactionDropdown(wrapper) { wrapper.find('IconStar').simulate('click'); await tick(); wrapper.update(); } describe('TeamKeyTransactionField', function () { const organization = TestStubs.Organization(); const teams = [ TestStubs.Team({id: '1', slug: 'team1', name: 'Team 1'}), TestStubs.Team({id: '2', slug: 'team2', name: 'Team 2'}), ]; const project = TestStubs.Project({teams}); beforeEach(function () { MockApiClient.clearMockResponses(); act(() => ProjectsStore.loadInitialData([project])); act(() => TeamStore.loadInitialData(teams)); }); it('renders with all teams checked', async function () { const getTeamKeyTransactionsMock = MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/key-transactions-list/`, body: teams.map(({id}) => ({ team: id, count: 1, keyed: [{project_id: String(project.id), transaction: 'transaction'}], })), }); const wrapper = mountWithTheme( ); await tick(); wrapper.update(); expect(getTeamKeyTransactionsMock).toHaveBeenCalledTimes(1); expect(wrapper.find('IconStar').exists()).toBeTruthy(); expect(wrapper.find('IconStar').props().isSolid).toBeTruthy(); clickTeamKeyTransactionDropdown(wrapper); // header should show the checked state const header = wrapper.find('DropdownMenuHeader'); expect(header.exists()).toBeTruthy(); expect(header.find('CheckboxFancy').props().isChecked).toBeTruthy(); expect(header.find('CheckboxFancy').props().isIndeterminate).toBeFalsy(); // all teams should be checked const entries = wrapper.find('DropdownMenuItem'); expect(entries.length).toBe(2); entries.forEach((entry, i) => { expect(entry.text()).toEqual(teams[i].slug); expect(entry.find('CheckboxFancy').props().isChecked).toBeTruthy(); }); }); it('renders with some teams checked', async function () { const getTeamKeyTransactionsMock = MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/key-transactions-list/`, body: teams.map(({id}) => ({ team: id, count: id === teams[0].id ? 1 : 0, keyed: id === teams[0].id ? [{project_id: String(project.id), transaction: 'transaction'}] : [], })), }); const wrapper = mountWithTheme( ); await tick(); wrapper.update(); expect(getTeamKeyTransactionsMock).toHaveBeenCalledTimes(1); expect(wrapper.find('IconStar').exists()).toBeTruthy(); expect(wrapper.find('IconStar').props().isSolid).toBeTruthy(); clickTeamKeyTransactionDropdown(wrapper); // header should show the indeterminate state const header = wrapper.find('DropdownMenuHeader'); expect(header.exists()).toBeTruthy(); expect(header.find('CheckboxFancy').props().isChecked).toBeFalsy(); expect(header.find('CheckboxFancy').props().isIndeterminate).toBeTruthy(); // all teams should be checked const entries = wrapper.find('DropdownMenuItem'); expect(entries.length).toBe(2); entries.forEach((entry, i) => { expect(entry.text()).toEqual(teams[i].slug); }); expect(entries.at(0).find('CheckboxFancy').props().isChecked).toBeTruthy(); expect(entries.at(1).find('CheckboxFancy').props().isChecked).toBeFalsy(); }); it('renders with no teams checked', async function () { const getTeamKeyTransactionsMock = MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/key-transactions-list/`, body: teams.map(({id}) => ({ team: id, count: 0, keyed: [], })), }); const wrapper = mountWithTheme( ); await tick(); wrapper.update(); expect(getTeamKeyTransactionsMock).toHaveBeenCalledTimes(1); expect(wrapper.find('IconStar').exists()).toBeTruthy(); expect(wrapper.find('IconStar').props().isSolid).toBeFalsy(); clickTeamKeyTransactionDropdown(wrapper); // header should show the unchecked state const header = wrapper.find('DropdownMenuHeader'); expect(header.exists()).toBeTruthy(); expect(header.find('CheckboxFancy').props().isChecked).toBeFalsy(); expect(header.find('CheckboxFancy').props().isIndeterminate).toBeFalsy(); // all teams should be unchecked const entries = wrapper.find('DropdownMenuItem'); expect(entries.length).toBe(2); entries.forEach((entry, i) => { expect(entry.text()).toEqual(teams[i].slug); expect(entry.find('CheckboxFancy').props().isChecked).toBeFalsy(); }); }); it('should be able to check one team', async function () { MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/key-transactions-list/`, body: teams.map(({id}) => ({ team: id, count: 0, keyed: [], })), }); const postTeamKeyTransactionsMock = MockApiClient.addMockResponse({ method: 'POST', url: '/organizations/org-slug/key-transactions/', body: [], match: [ MockApiClient.matchQuery({project: [project.id]}), MockApiClient.matchData({team: [teams[0].id], transaction: 'transaction'}), ], }); const wrapper = mountWithTheme( ); await tick(); wrapper.update(); clickTeamKeyTransactionDropdown(wrapper); expect( wrapper.find('DropdownMenuItem CheckboxFancy').first().props().isChecked ).toBeFalsy(); wrapper.find('DropdownMenuItem CheckboxFancy').first().simulate('click'); await tick(); wrapper.update(); expect( wrapper.find('DropdownMenuItem CheckboxFancy').first().props().isChecked ).toBeTruthy(); expect(postTeamKeyTransactionsMock).toHaveBeenCalledTimes(1); }); it('should be able to uncheck one team', async function () { MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/key-transactions-list/`, body: teams.map(({id}) => ({ team: id, count: 1, keyed: [{project_id: String(project.id), transaction: 'transaction'}], })), }); const deleteTeamKeyTransactionsMock = MockApiClient.addMockResponse({ method: 'DELETE', url: '/organizations/org-slug/key-transactions/', body: [], match: [ MockApiClient.matchQuery({project: [project.id]}), MockApiClient.matchData({team: [teams[0].id], transaction: 'transaction'}), ], }); const wrapper = mountWithTheme( ); await tick(); wrapper.update(); clickTeamKeyTransactionDropdown(wrapper); expect( wrapper.find('DropdownMenuItem CheckboxFancy').first().props().isChecked ).toBeTruthy(); wrapper.find('DropdownMenuItem CheckboxFancy').first().simulate('click'); await tick(); wrapper.update(); expect( wrapper.find('DropdownMenuItem CheckboxFancy').first().props().isChecked ).toBeFalsy(); expect(deleteTeamKeyTransactionsMock).toHaveBeenCalledTimes(1); }); it('should be able to check all with my teams', async function () { MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/key-transactions-list/`, body: teams.map(({id}) => ({ team: id, count: 0, keyed: [], })), }); const postTeamKeyTransactionsMock = MockApiClient.addMockResponse({ method: 'POST', url: '/organizations/org-slug/key-transactions/', body: [], match: [ MockApiClient.matchQuery({project: [project.id]}), MockApiClient.matchData({ team: [teams[0].id, teams[1].id], transaction: 'transaction', }), ], }); const wrapper = mountWithTheme( ); await tick(); wrapper.update(); clickTeamKeyTransactionDropdown(wrapper); wrapper.find('DropdownMenuHeader CheckboxFancy').simulate('click'); await tick(); wrapper.update(); const headerCheckbox = wrapper.find('DropdownMenuHeader CheckboxFancy'); expect(headerCheckbox.props().isChecked).toBeTruthy(); expect(headerCheckbox.props().isIndeterminate).toBeFalsy(); expect(postTeamKeyTransactionsMock).toHaveBeenCalledTimes(1); }); it('should be able to uncheck all with my teams', async function () { MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/key-transactions-list/`, body: teams.map(({id}) => ({ team: id, count: 1, keyed: [{project_id: String(project.id), transaction: 'transaction'}], })), }); const deleteTeamKeyTransactionsMock = MockApiClient.addMockResponse({ method: 'DELETE', url: '/organizations/org-slug/key-transactions/', body: [], match: [ MockApiClient.matchQuery({project: [project.id]}), MockApiClient.matchData({ team: [teams[0].id, teams[1].id], transaction: 'transaction', }), ], }); const wrapper = mountWithTheme( ); await tick(); wrapper.update(); clickTeamKeyTransactionDropdown(wrapper); wrapper.find('DropdownMenuHeader CheckboxFancy').simulate('click'); await tick(); wrapper.update(); const headerCheckbox = wrapper.find('DropdownMenuHeader CheckboxFancy'); expect(headerCheckbox.props().isChecked).toBeFalsy(); expect(headerCheckbox.props().isIndeterminate).toBeFalsy(); expect(deleteTeamKeyTransactionsMock).toHaveBeenCalledTimes(1); }); it('should render teams without access separately', async function () { const myTeams = [...teams, TestStubs.Team({id: '3', slug: 'team3', name: 'Team 3'})]; act(() => { TeamStore.loadInitialData(myTeams); }); MockApiClient.addMockResponse({ method: 'GET', url: `/organizations/${organization.slug}/key-transactions-list/`, body: myTeams.map(({id}) => ({ team: id, count: 0, keyed: [], })), }); const wrapper = mountWithTheme( ); await tick(); wrapper.update(); clickTeamKeyTransactionDropdown(wrapper); const headers = wrapper.find('DropdownMenuHeader'); expect(headers.length).toEqual(2); expect(headers.at(0).text()).toEqual('My Teams with Access'); expect(headers.at(1).text()).toEqual('My Teams without Access'); const entries = wrapper.find('DropdownMenuItem'); expect(entries.length).toEqual(3); entries.forEach((entry, i) => { expect(entry.text()).toEqual(myTeams[i].slug); }); expect(entries.at(0).find('CheckboxFancy').exists()).toBeTruthy(); expect(entries.at(1).find('CheckboxFancy').exists()).toBeTruthy(); // this team does not have access so there is no checkbox expect(entries.at(2).find('CheckboxFancy').exists()).toBeFalsy(); }); });