import React from 'react'; import {mount} from 'enzyme'; import ProjectSelector from 'app/components/projectSelector'; import ProjectsStore from 'app/stores/projectsStore'; describe('ProjectSelector', function() { const testTeam = TestStubs.Team({ id: 'test-team', slug: 'test-team', isMember: true, }); const testProject = TestStubs.Project({ id: 'test-project', slug: 'test-project', isBookmarked: true, isMember: true, teams: [testTeam], }); const anotherProject = TestStubs.Project({ id: 'another-project', slug: 'another-project', isMember: true, teams: [testTeam], }); const mockOrg = TestStubs.Organization({ id: 'org', slug: 'org', teams: [testTeam], projects: [testProject, anotherProject], features: ['new-teams'], access: [], }); const routerContext = TestStubs.routerContext([{organization: mockOrg}]); const openMenu = wrapper => wrapper.find('[data-test-id="test-actor"]').simulate('click'); const actorRenderer = jest.fn(() =>
); const props = { organization: mockOrg, projectId: '', children: actorRenderer, }; beforeEach(function() { ProjectsStore.loadInitialData(mockOrg.projects); }); it('should show empty message with no projects button, when no projects, and has no "project:write" access', function() { const wrapper = mount( , routerContext ); ProjectsStore.loadInitialData([]); openMenu(wrapper); expect(wrapper.find('EmptyMessage').prop('children')).toBe('You have no projects'); // Should not have "Create Project" button expect(wrapper.find('CreateProjectButton')).toHaveLength(0); }); it('should show empty message and create project button, when no projects and has "project:write" access', function() { const wrapper = mount( , routerContext ); ProjectsStore.loadInitialData([]); openMenu(wrapper); expect(wrapper.find('EmptyMessage').prop('children')).toBe('You have no projects'); // Should not have "Create Project" button expect(wrapper.find('CreateProjectButton')).toHaveLength(1); }); it('lists projects and has filter', function() { const wrapper = mount(, routerContext); openMenu(wrapper); expect(wrapper.find('AutoCompleteItem')).toHaveLength(2); }); it('can filter projects by project name', function() { const wrapper = mount(, routerContext); openMenu(wrapper); wrapper.find('StyledInput').simulate('change', {target: {value: 'TEST'}}); const result = wrapper.find('AutoCompleteItem ProjectBadge'); expect(result).toHaveLength(1); expect(result.prop('project').slug).toBe('test-project'); }); it('does not close dropdown when input is clicked', async function() { const wrapper = mount(, routerContext); openMenu(wrapper); wrapper.find('StyledInput').simulate('click'); await tick(); wrapper.update(); expect(wrapper.find('DropdownMenu').prop('isOpen')).toBe(true); }); it('closes dropdown when project is selected', function() { const wrapper = mount(, routerContext); openMenu(wrapper); // Select first project wrapper .find('AutoCompleteItem') .first() .simulate('click'); expect(wrapper.find('DropdownMenu').prop('isOpen')).toBe(false); }); it('calls callback when project is selected', function() { const mock = jest.fn(); const wrapper = mount(, routerContext); openMenu(wrapper); // Select first project wrapper .find('AutoCompleteItem') .first() .simulate('click'); expect(mock).toHaveBeenCalledWith( expect.objectContaining({ slug: 'test-project', }) ); }); it('shows empty filter message when filtering has no results', function() { const wrapper = mount(, routerContext); openMenu(wrapper); wrapper.find('StyledInput').simulate('change', {target: {value: 'Foo'}}); expect(wrapper.find('EmptyMessage').prop('children')).toBe('No projects found'); }); it('does not call `onSelect` when using multi select', function() { const mock = jest.fn(); const wrapper = mount( , routerContext ); openMenu(wrapper); // Select first project wrapper .find('CheckboxWrapper') .first() .simulate('click'); // onSelect callback should NOT be called expect(mock).not.toHaveBeenCalled(); }); it('calls `onMultiSelect` and render prop when using multi select as an uncontrolled component', async function() { const mock = jest.fn(); const wrapper = mount( , routerContext ); openMenu(wrapper); // Select first project wrapper .find('CheckboxWrapper') .at(0) .simulate('click', {target: {checked: true}}); expect(mock).toHaveBeenLastCalledWith( [ expect.objectContaining({ slug: 'test-project', }), ], expect.anything() ); expect(actorRenderer).toHaveBeenLastCalledWith( expect.objectContaining({ selectedProjects: [expect.objectContaining({slug: 'test-project'})], }) ); expect( Array.from( wrapper .find('ProjectSelectorItem') .filterWhere(p => p.prop('isChecked')) .map(p => p.prop('project').slug) ) ).toEqual(['test-project']); // second project wrapper .find('CheckboxWrapper') .at(1) .simulate('click', {target: {checked: true}}); expect(mock).toHaveBeenLastCalledWith( [ expect.objectContaining({ slug: 'test-project', }), expect.objectContaining({ slug: 'another-project', }), ], expect.anything() ); expect(actorRenderer).toHaveBeenLastCalledWith( expect.objectContaining({ selectedProjects: [ expect.objectContaining({slug: 'test-project'}), expect.objectContaining({slug: 'another-project'}), ], }) ); expect( Array.from( wrapper .find('ProjectSelectorItem') .filterWhere(p => p.prop('isChecked')) .map(p => p.prop('project').slug) ) ).toEqual(['test-project', 'another-project']); // Can unselect item wrapper .find('CheckboxWrapper') .at(1) .simulate('click', {target: {checked: false}}); expect(mock).toHaveBeenLastCalledWith( [ expect.objectContaining({ slug: 'test-project', }), ], expect.anything() ); expect(actorRenderer).toHaveBeenLastCalledWith( expect.objectContaining({ selectedProjects: [expect.objectContaining({slug: 'test-project'})], }) ); expect( Array.from( wrapper .find('ProjectSelectorItem') .filterWhere(p => p.prop('isChecked')) .map(p => p.prop('project').slug) ) ).toEqual(['test-project']); }); it('displays multi projects', function() { const project = TestStubs.Project(); const multiProjectProps = {...props, multiProjects: [project]}; const wrapper = mount(, routerContext); openMenu(wrapper); expect(wrapper.find('AutoCompleteItem')).toHaveLength(1); expect(wrapper.text()).not.toContain("Projects I don't belong to"); }); it('displays multi projects with non member projects', function() { const project = TestStubs.Project({id: '1'}); const nonMemberProject = TestStubs.Project({id: '2'}); const multiProjectProps = { ...props, multiProjects: [project], nonMemberProjects: [nonMemberProject], }; const wrapper = mount(, routerContext); openMenu(wrapper); expect(wrapper.text()).toContain("Projects I don't belong to"); expect(wrapper.find('AutoCompleteItem')).toHaveLength(2); }); });