123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- import {initializeOrg} from 'sentry-test/initializeOrg';
- import {render, screen, waitFor} from 'sentry-test/reactTestingLibrary';
- import {openSudo} from 'sentry/actionCreators/modal';
- import * as OrganizationActionCreator from 'sentry/actionCreators/organization';
- import ConfigStore from 'sentry/stores/configStore';
- import OrganizationStore from 'sentry/stores/organizationStore';
- import ProjectsStore from 'sentry/stores/projectsStore';
- import TeamStore from 'sentry/stores/teamStore';
- import {MockConfig} from 'sentry/types/__fixtures__/MockConfig';
- import useOrganization from 'sentry/utils/useOrganization';
- import {OrganizationLegacyContext} from 'sentry/views/organizationContextContainer';
- jest.mock('sentry/stores/configStore', () => ({
- get: jest.fn(),
- }));
- jest.mock('sentry/actionCreators/modal', () => ({
- openSudo: jest.fn(),
- }));
- describe('OrganizationContextContainer', function () {
- const {organization, projects, routerProps} = initializeOrg();
- const teams = [TestStubs.Team()];
- const api = new MockApiClient();
- let getOrgMock: jest.Mock;
- let getProjectsMock: jest.Mock;
- let getTeamsMock: jest.Mock;
- function DisplayOrg() {
- const contextOrg = useOrganization();
- return <div>{contextOrg.slug}</div>;
- }
- type Props = Partial<React.ComponentProps<typeof OrganizationLegacyContext>>;
- function makeComponent(props?: Props) {
- return (
- <OrganizationLegacyContext
- {...routerProps}
- api={api}
- params={{orgId: 'org-slug'}}
- location={TestStubs.location({query: {}})}
- useLastOrganization={false}
- organizationsLoading={false}
- organizations={[]}
- includeSidebar={false}
- {...props}
- >
- <DisplayOrg />
- </OrganizationLegacyContext>
- );
- }
- function renderComponent(props?: Props) {
- return render(makeComponent(props));
- }
- beforeEach(function () {
- MockApiClient.clearMockResponses();
- getOrgMock = MockApiClient.addMockResponse({
- url: '/organizations/org-slug/',
- body: organization,
- });
- getProjectsMock = MockApiClient.addMockResponse({
- url: '/organizations/org-slug/projects/',
- body: projects,
- });
- getTeamsMock = MockApiClient.addMockResponse({
- url: '/organizations/org-slug/teams/',
- body: teams,
- });
- jest.spyOn(TeamStore, 'loadInitialData');
- jest.spyOn(ProjectsStore, 'loadInitialData');
- jest.spyOn(OrganizationActionCreator, 'fetchOrganizationDetails');
- });
- afterEach(function () {
- OrganizationStore.reset();
- jest.restoreAllMocks();
- });
- it('renders and fetches org, projects, and teams', async function () {
- renderComponent();
- await waitFor(() => expect(getOrgMock).toHaveBeenCalled());
- expect(getProjectsMock).toHaveBeenCalled();
- expect(getTeamsMock).toHaveBeenCalled();
- expect(screen.queryByRole('loading-indicator')).not.toBeInTheDocument();
- expect(screen.getByText(organization.slug)).toBeInTheDocument();
- expect(
- screen.queryByText('The organization you were looking for was not found.')
- ).not.toBeInTheDocument();
- expect(TeamStore.loadInitialData).toHaveBeenCalledWith(teams);
- expect(ProjectsStore.loadInitialData).toHaveBeenCalledWith(projects);
- expect(OrganizationActionCreator.fetchOrganizationDetails).toHaveBeenCalledWith(
- api,
- 'org-slug',
- true,
- true
- );
- });
- it('fetches new org when router params change', async function () {
- const newOrg = TestStubs.Organization({slug: 'new-slug'});
- const {rerender} = renderComponent();
- expect(await screen.findByText(organization.slug)).toBeInTheDocument();
- const mock = MockApiClient.addMockResponse({
- url: '/organizations/new-slug/',
- body: newOrg,
- });
- const projectsMock = MockApiClient.addMockResponse({
- url: '/organizations/new-slug/projects/',
- body: projects,
- });
- const teamsMock = MockApiClient.addMockResponse({
- url: '/organizations/new-slug/teams/',
- body: teams,
- });
- // Re-render with new org slug
- rerender(makeComponent({params: {orgId: newOrg.slug}}));
- // Loads new org
- expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
- // Renders new org
- expect(await screen.findByText(newOrg.slug)).toBeInTheDocument();
- expect(mock).toHaveBeenLastCalledWith('/organizations/new-slug/', expect.anything());
- expect(projectsMock).toHaveBeenCalled();
- expect(teamsMock).toHaveBeenCalled();
- });
- it('shows loading error for non-superusers on 403s', async function () {
- getOrgMock = MockApiClient.addMockResponse({
- url: '/organizations/org-slug/',
- statusCode: 403,
- });
- jest.spyOn(console, 'error').mockImplementation(jest.fn()); // eslint-disable-line no-console
- renderComponent();
- expect(
- await screen.findByText('There was an error loading data.')
- ).toBeInTheDocument();
- // eslint-disable-next-line no-console
- expect(console.error).toHaveBeenCalled();
- });
- it('opens sudo modal for superusers on 403s', async function () {
- jest.mocked(ConfigStore.get).mockImplementation(
- key =>
- MockConfig({
- user: TestStubs.User({isSuperuser: true}),
- })[key]
- );
- getOrgMock = MockApiClient.addMockResponse({
- url: '/organizations/org-slug/',
- statusCode: 403,
- });
- renderComponent();
- await waitFor(() => expect(openSudo).toHaveBeenCalled());
- });
- it('uses last organization from ConfigStore', function () {
- getOrgMock = MockApiClient.addMockResponse({
- url: '/organizations/last-org/',
- body: organization,
- });
- MockApiClient.addMockResponse({
- url: '/organizations/last-org/projects/',
- body: projects,
- });
- MockApiClient.addMockResponse({
- url: '/organizations/last-org/teams/',
- body: teams,
- });
- // mocking `.get('lastOrganization')`
- jest.mocked(ConfigStore.get).mockImplementation(() => 'last-org');
- renderComponent({useLastOrganization: true, params: {orgId: ''}});
- expect(getOrgMock).toHaveBeenLastCalledWith(
- '/organizations/last-org/',
- expect.anything()
- );
- });
- it('uses last organization from `organizations` prop', async function () {
- MockApiClient.addMockResponse({
- url: '/organizations/foo/environments/',
- body: TestStubs.Environments(),
- });
- getOrgMock = MockApiClient.addMockResponse({
- url: '/organizations/foo/',
- body: organization,
- });
- getProjectsMock = MockApiClient.addMockResponse({
- url: '/organizations/foo/projects/',
- body: projects,
- });
- getTeamsMock = MockApiClient.addMockResponse({
- url: '/organizations/foo/teams/',
- body: teams,
- });
- jest.mocked(ConfigStore.get).mockImplementation(() => '');
- const {rerender} = renderComponent({
- params: {orgId: ''},
- useLastOrganization: true,
- organizationsLoading: true,
- organizations: [],
- });
- expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
- rerender(
- makeComponent({
- params: {orgId: ''},
- useLastOrganization: true,
- organizationsLoading: false,
- organizations: [
- TestStubs.Organization({slug: 'foo'}),
- TestStubs.Organization({slug: 'bar'}),
- ],
- })
- );
- expect(await screen.findByText(organization.slug)).toBeInTheDocument();
- expect(getOrgMock).toHaveBeenCalled();
- expect(getProjectsMock).toHaveBeenCalled();
- expect(getTeamsMock).toHaveBeenCalled();
- });
- it('uses last organization when no orgId in URL - and fetches org details once', async function () {
- jest.mocked(ConfigStore.get).mockImplementation(() => 'my-last-org');
- getOrgMock = MockApiClient.addMockResponse({
- url: '/organizations/my-last-org/',
- body: TestStubs.Organization({slug: 'my-last-org'}),
- });
- getProjectsMock = MockApiClient.addMockResponse({
- url: '/organizations/my-last-org/projects/',
- body: projects,
- });
- getTeamsMock = MockApiClient.addMockResponse({
- url: '/organizations/my-last-org/teams/',
- body: teams,
- });
- const {rerender} = renderComponent({
- params: {orgId: ''},
- useLastOrganization: true,
- organizations: [],
- });
- expect(await screen.findByText('my-last-org')).toBeInTheDocument();
- expect(getOrgMock).toHaveBeenCalledTimes(1);
- // Simulate OrganizationsStore being loaded *after* `OrganizationContext` finishes
- // org details fetch
- rerender(
- makeComponent({
- params: {orgId: ''},
- useLastOrganization: true,
- organizationsLoading: false,
- organizations: [
- TestStubs.Organization({slug: 'foo'}),
- TestStubs.Organization({slug: 'bar'}),
- ],
- })
- );
- expect(getOrgMock).toHaveBeenCalledTimes(1);
- expect(getProjectsMock).toHaveBeenCalledTimes(1);
- expect(getTeamsMock).toHaveBeenCalledTimes(1);
- });
- it('fetches org details only once if organizations loading store changes', async function () {
- const {rerender} = renderComponent({
- params: {orgId: 'org-slug'},
- organizationsLoading: true,
- organizations: [],
- });
- expect(await screen.findByText(organization.slug)).toBeInTheDocument();
- expect(getOrgMock).toHaveBeenCalledTimes(1);
- // Simulate OrganizationsStore being loaded *after* `OrganizationContext` finishes
- // org details fetch
- rerender(
- makeComponent({
- params: {orgId: 'org-slug'},
- organizationsLoading: false,
- organizations: [
- TestStubs.Organization({slug: 'foo'}),
- TestStubs.Organization({slug: 'bar'}),
- ],
- })
- );
- expect(getOrgMock).toHaveBeenCalledTimes(1);
- expect(getProjectsMock).toHaveBeenCalledTimes(1);
- expect(getTeamsMock).toHaveBeenCalledTimes(1);
- });
- });
|