import React from 'react';
import {mount, shallow} from 'enzyme';
import IncidentStore from 'app/stores/incidentStore';
import ConfigStore from 'app/stores/configStore';
import SidebarContainer, {Sidebar} from 'app/components/sidebar';
describe('Sidebar', function() {
let wrapper;
let routerContext = TestStubs.routerContext();
let {organization, router} = routerContext.context;
let user = TestStubs.User();
let apiMocks = {};
let createWrapper = props =>
mount(
,
routerContext
);
beforeEach(function() {
apiMocks.broadcasts = MockApiClient.addMockResponse({
url: '/broadcasts/',
body: [TestStubs.Broadcast()],
});
apiMocks.broadcastsMarkAsSeen = MockApiClient.addMockResponse({
url: '/broadcasts/',
method: 'PUT',
});
});
it('renders', function() {
wrapper = shallow(
,
TestStubs.routerContext()
);
expect(wrapper.find('StyledSidebar')).toHaveLength(1);
});
it('renders without org and router', function() {
wrapper = createWrapper({
organization: null,
router: null,
});
// no org displays user details
expect(wrapper.find('OrgOrUserName').text()).toContain(user.name);
expect(wrapper.find('UserNameOrEmail').text()).toContain(user.email);
wrapper.find('SidebarDropdownActor').simulate('click');
expect(wrapper.find('OrgAndUserMenu')).toMatchSnapshot();
});
it('can toggle collapsed state', async function() {
wrapper = mount(
,
routerContext
);
expect(wrapper.find('OrgOrUserName').text()).toContain(organization.name);
expect(wrapper.find('UserNameOrEmail').text()).toContain(user.name);
wrapper.find('SidebarCollapseItem').simulate('click');
await tick();
wrapper.update();
// Because of HoCs, we can't access the collapsed prop
// Instead check for `SidebarItemLabel` which doesn't exist in collapsed state
expect(wrapper.find('SidebarItemLabel')).toHaveLength(0);
wrapper.find('SidebarCollapseItem').simulate('click');
await tick();
wrapper.update();
expect(wrapper.find('SidebarItemLabel').length).toBeGreaterThan(0);
});
it('can have onboarding feature', function() {
wrapper = mount(
,
routerContext
);
expect(wrapper.find('[data-test-id="onboarding-progress-bar"]')).toHaveLength(1);
wrapper.find('[data-test-id="onboarding-progress-bar"]').simulate('click');
wrapper.update();
expect(wrapper.find('OnboardingStatus SidebarPanel')).toMatchSnapshot();
});
describe('SidebarHelp', function() {
it('can toggle help menu', function() {
wrapper = createWrapper();
wrapper.find('HelpActor').simulate('click');
let menu = wrapper.find('HelpMenu');
expect(menu).toHaveLength(1);
expect(menu).toMatchSnapshot();
expect(menu.find('SidebarMenuItem')).toHaveLength(3);
wrapper.find('HelpActor').simulate('click');
expect(wrapper.find('HelpMenu')).toHaveLength(0);
});
});
describe('SidebarDropdown', function() {
it('can open Sidebar org/name dropdown menu', function() {
wrapper = createWrapper();
wrapper.find('SidebarDropdownActor').simulate('click');
expect(wrapper.find('OrgAndUserMenu')).toHaveLength(1);
expect(wrapper.find('OrgAndUserMenu')).toMatchSnapshot();
});
it('has link to Members settings with `member:write`', function() {
let org = TestStubs.Organization();
org = {
...org,
access: [...org.access, 'member:read'],
};
wrapper = createWrapper({
organization: org,
});
wrapper.find('SidebarDropdownActor').simulate('click');
expect(wrapper.find('OrgAndUserMenu')).toHaveLength(1);
expect(
wrapper.find('SidebarMenuItem[to="/settings/org-slug/members/"]')
).toHaveLength(1);
});
it('can open "Switch Organization" sub-menu', function() {
ConfigStore.set('features', new Set(['organizations:create']));
jest.useFakeTimers();
wrapper = createWrapper();
wrapper.find('SidebarDropdownActor').simulate('click');
wrapper.find('SwitchOrganizationMenuActor').simulate('mouseEnter');
jest.advanceTimersByTime(500);
wrapper.update();
expect(wrapper.find('SwitchOrganizationMenu')).toHaveLength(1);
expect(wrapper.find('SwitchOrganizationMenu')).toMatchSnapshot();
jest.useRealTimers();
});
it('has can logout', function() {
let mock = MockApiClient.addMockResponse({
url: '/auth/',
method: 'DELETE',
status: 204,
});
let org = TestStubs.Organization();
org = {
...org,
access: [...org.access, 'member:read'],
};
wrapper = createWrapper({
organization: org,
user: TestStubs.User(),
});
wrapper.find('SidebarDropdownActor').simulate('click');
wrapper.find('SidebarMenuItem[data-test-id="sidebarSignout"]').simulate('click');
expect(mock).toHaveBeenCalled();
});
});
describe('SidebarPanel', function() {
it('displays empty panel when there are no Broadcasts', async function() {
MockApiClient.addMockResponse({
url: '/broadcasts/',
body: [],
});
wrapper = createWrapper();
await wrapper.find('Broadcasts SidebarItem').simulate('click');
wrapper.update();
expect(wrapper.find('SidebarPanel')).toHaveLength(1);
expect(wrapper.find('SidebarPanelItem')).toHaveLength(0);
expect(wrapper.find('SidebarPanelEmpty')).toHaveLength(1);
});
it('can display Broadcasts panel and mark as seen', async function() {
jest.useFakeTimers();
wrapper = createWrapper();
expect(apiMocks.broadcasts).toHaveBeenCalled();
await wrapper.find('Broadcasts SidebarItem').simulate('click');
wrapper.update();
expect(wrapper.find('SidebarPanel')).toHaveLength(1);
expect(wrapper.find('SidebarPanelItem')).toHaveLength(1);
expect(wrapper.find('SidebarPanelItem').prop('hasSeen')).toBe(false);
expect(wrapper.find('SidebarPanelItem')).toMatchSnapshot();
// Should mark as seen after a delay
jest.advanceTimersByTime(2000);
expect(apiMocks.broadcastsMarkAsSeen).toHaveBeenCalledWith(
'/broadcasts/',
expect.objectContaining({
data: {
hasSeen: '1',
},
query: {
id: ['8'],
},
})
);
jest.useRealTimers();
});
it('can toggle display of Broadcasts SidebarPanel', function() {
wrapper = createWrapper();
// Show Broadcasts Panel
wrapper.find('Broadcasts SidebarItem').simulate('click');
wrapper.update();
expect(wrapper.find('SidebarPanel')).toHaveLength(1);
// Hide Broadcasts Panel
wrapper.find('Broadcasts SidebarItem').simulate('click');
wrapper.update();
expect(wrapper.find('SidebarPanel')).toHaveLength(0);
});
it('can unmount Sidebar (and Broadcasts) and kills Broadcast timers', async function() {
jest.useFakeTimers();
wrapper = createWrapper();
let broadcasts = wrapper.find('Broadcasts').instance();
// This will start timer to mark as seen
await wrapper.find('Broadcasts SidebarItem').simulate('click');
wrapper.update();
jest.advanceTimersByTime(500);
expect(broadcasts.poller).toBeDefined();
expect(broadcasts.timer).toBeDefined();
// Unmounting will cancel timers
wrapper.unmount();
expect(broadcasts.poller).toBe(null);
expect(broadcasts.timer).toBe(null);
// This advances timers enough so that mark as seen should be called if it wasn't unmounted
jest.advanceTimersByTime(600);
expect(apiMocks.broadcastsMarkAsSeen).not.toHaveBeenCalled();
});
it('can show Incidents in Sidebar Panel', async function() {
wrapper = createWrapper();
IncidentStore.onUpdateSuccess({
status: {incidents: [TestStubs.Incident()]},
});
wrapper.update();
wrapper.find('Incidents').simulate('click');
wrapper.update();
expect(wrapper.find('SidebarPanel')).toHaveLength(1);
expect(wrapper.find('IncidentList')).toMatchSnapshot();
});
it('hides when path changes', async function() {
wrapper = createWrapper();
wrapper.update();
wrapper.find('Broadcasts SidebarItem').simulate('click');
wrapper.update();
expect(wrapper.find('SidebarPanel')).toHaveLength(1);
wrapper.setProps({
location: {
pathname: 'new-path-name',
},
});
wrapper.update();
expect(wrapper.find('SidebarPanel')).toHaveLength(0);
});
it('hides assigned, bookmarks, history, activity and stats for sentry10', function() {
const sentry10Org = TestStubs.Organization({features: ['sentry10']});
wrapper = createWrapper();
wrapper.setProps({organization: sentry10Org});
wrapper.update();
const labels = wrapper.find('SidebarItemLabel').map(node => node.text());
expect(labels).toHaveLength(10);
expect(labels).not.toContain('Assigned to me');
expect(labels).not.toContain('Bookmarked issues');
expect(labels).not.toContain('Recently viewed');
});
});
});