123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- import {OrganizationFixture} from 'sentry-fixture/organization';
- import {RouteComponentPropsFixture} from 'sentry-fixture/routeComponentPropsFixture';
- import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
- import {logout} from 'sentry/actionCreators/account';
- import ConfigStore from 'sentry/stores/configStore';
- import {browserHistory} from 'sentry/utils/browserHistory';
- import AcceptOrganizationInvite from 'sentry/views/acceptOrganizationInvite';
- jest.mock('sentry/actionCreators/account');
- const addMock = body =>
- MockApiClient.addMockResponse({
- url: '/accept-invite/org-slug/1/abc/',
- method: 'GET',
- body,
- });
- const getJoinButton = () => {
- const maybeButton = screen.queryByRole('button', {
- name: 'Join the org-slug organization',
- });
- return maybeButton;
- };
- describe('AcceptOrganizationInvite', function () {
- const organization = OrganizationFixture({slug: 'org-slug'});
- const configState = ConfigStore.getState();
- afterEach(() => {
- ConfigStore.loadInitialData(configState);
- });
- it('can accept invitation', async function () {
- addMock({
- orgSlug: organization.slug,
- needsAuthentication: false,
- needs2fa: false,
- hasAuthProvider: false,
- requireSso: false,
- existingMember: false,
- });
- render(
- <AcceptOrganizationInvite
- {...RouteComponentPropsFixture()}
- params={{orgId: 'org-slug', memberId: '1', token: 'abc'}}
- />
- );
- const acceptMock = MockApiClient.addMockResponse({
- url: '/accept-invite/org-slug/1/abc/',
- method: 'POST',
- });
- const joinButton = getJoinButton();
- await userEvent.click(joinButton!);
- expect(acceptMock).toHaveBeenCalled();
- expect(browserHistory.replace).toHaveBeenCalledWith('/org-slug/');
- });
- it('can accept invitation on customer-domains', async function () {
- ConfigStore.set('customerDomain', {
- subdomain: 'org-slug',
- organizationUrl: 'https://org-slug.sentry.io',
- sentryUrl: 'https://sentry.io',
- });
- ConfigStore.set('links', {
- ...configState.links,
- sentryUrl: 'https://sentry.io',
- });
- addMock({
- orgSlug: organization.slug,
- needsAuthentication: false,
- needs2fa: false,
- hasAuthProvider: false,
- requireSso: false,
- existingMember: false,
- });
- render(
- <AcceptOrganizationInvite
- {...RouteComponentPropsFixture()}
- params={{memberId: '1', token: 'abc'}}
- />
- );
- const acceptMock = MockApiClient.addMockResponse({
- url: '/accept-invite/org-slug/1/abc/',
- method: 'POST',
- });
- const joinButton = getJoinButton();
- await userEvent.click(joinButton!);
- expect(acceptMock).toHaveBeenCalled();
- expect(browserHistory.replace).toHaveBeenCalledWith('/org-slug/');
- });
- it('renders error message', function () {
- MockApiClient.addMockResponse({
- url: '/accept-invite/1/abc/',
- method: 'GET',
- statusCode: 400,
- body: {detail: 'uh oh'},
- });
- render(
- <AcceptOrganizationInvite
- {...RouteComponentPropsFixture()}
- params={{memberId: '1', token: 'abc'}}
- />
- );
- expect(getJoinButton()).not.toBeInTheDocument();
- expect(
- screen.getByRole('link', {name: 'sign in with a different account'})
- ).toBeInTheDocument();
- });
- it('requires authentication to join', function () {
- addMock({
- orgSlug: organization.slug,
- needsAuthentication: true,
- needs2fa: false,
- hasAuthProvider: false,
- requireSso: false,
- existingMember: false,
- });
- render(
- <AcceptOrganizationInvite
- {...RouteComponentPropsFixture()}
- params={{orgId: 'org-slug', memberId: '1', token: 'abc'}}
- />
- );
- expect(getJoinButton()).not.toBeInTheDocument();
- expect(screen.getByTestId('action-info-general')).toBeInTheDocument();
- expect(screen.queryByTestId('action-info-sso')).not.toBeInTheDocument();
- expect(
- screen.getByRole('button', {name: 'Create a new account'})
- ).toBeInTheDocument();
- expect(
- screen.getByRole('link', {name: 'Login using an existing account'})
- ).toBeInTheDocument();
- });
- it('suggests sso authentication to login', function () {
- addMock({
- orgSlug: organization.slug,
- needsAuthentication: true,
- needs2fa: false,
- hasAuthProvider: true,
- requireSso: false,
- existingMember: false,
- ssoProvider: 'SSO',
- });
- render(
- <AcceptOrganizationInvite
- {...RouteComponentPropsFixture()}
- params={{orgId: 'org-slug', memberId: '1', token: 'abc'}}
- />
- );
- expect(getJoinButton()).not.toBeInTheDocument();
- expect(screen.getByTestId('action-info-general')).toBeInTheDocument();
- expect(screen.getByTestId('action-info-sso')).toBeInTheDocument();
- expect(screen.getByRole('button', {name: 'Join with SSO'})).toBeInTheDocument();
- expect(
- screen.getByRole('button', {name: 'Create a new account'})
- ).toBeInTheDocument();
- expect(
- screen.getByRole('link', {name: 'Login using an existing account'})
- ).toBeInTheDocument();
- });
- it('enforce required sso authentication', function () {
- addMock({
- orgSlug: organization.slug,
- needsAuthentication: true,
- needs2fa: false,
- hasAuthProvider: true,
- requireSso: true,
- existingMember: false,
- ssoProvider: 'SSO',
- });
- render(
- <AcceptOrganizationInvite
- {...RouteComponentPropsFixture()}
- params={{orgId: 'org-slug', memberId: '1', token: 'abc'}}
- />
- );
- expect(getJoinButton()).not.toBeInTheDocument();
- expect(screen.queryByTestId('action-info-general')).not.toBeInTheDocument();
- expect(screen.getByTestId('action-info-sso')).toBeInTheDocument();
- expect(screen.getByRole('button', {name: 'Join with SSO'})).toBeInTheDocument();
- expect(
- screen.queryByRole('button', {name: 'Create a new account'})
- ).not.toBeInTheDocument();
- expect(
- screen.queryByRole('link', {name: 'Login using an existing account'})
- ).not.toBeInTheDocument();
- });
- it('enforce required sso authentication for logged in users', function () {
- addMock({
- orgSlug: organization.slug,
- needsAuthentication: false,
- needs2fa: false,
- hasAuthProvider: true,
- requireSso: true,
- existingMember: false,
- ssoProvider: 'SSO',
- });
- render(
- <AcceptOrganizationInvite
- {...RouteComponentPropsFixture()}
- params={{orgId: 'org-slug', memberId: '1', token: 'abc'}}
- />
- );
- expect(getJoinButton()).not.toBeInTheDocument();
- expect(screen.queryByTestId('action-info-general')).not.toBeInTheDocument();
- expect(screen.getByTestId('action-info-sso')).toBeInTheDocument();
- expect(screen.getByRole('button', {name: 'Join with SSO'})).toBeInTheDocument();
- expect(
- screen.queryByRole('button', {name: 'Create a new account'})
- ).not.toBeInTheDocument();
- expect(
- screen.queryByRole('link', {name: 'Login using an existing account'})
- ).not.toBeInTheDocument();
- });
- it('show logout button for logged in users w/ sso and membership', async function () {
- addMock({
- orgSlug: organization.slug,
- needsAuthentication: false,
- needs2fa: false,
- hasAuthProvider: true,
- requireSso: true,
- existingMember: true,
- ssoProvider: 'SSO',
- });
- render(
- <AcceptOrganizationInvite
- {...RouteComponentPropsFixture()}
- params={{orgId: 'org-slug', memberId: '1', token: 'abc'}}
- />
- );
- expect(screen.getByTestId('existing-member')).toBeInTheDocument();
- await userEvent.click(screen.getByTestId('existing-member-link'));
- await waitFor(() => expect(logout).toHaveBeenCalled());
- });
- it('shows right options for logged in user and optional SSO', function () {
- addMock({
- orgSlug: organization.slug,
- needsAuthentication: false,
- needs2fa: false,
- hasAuthProvider: true,
- requireSso: false,
- existingMember: false,
- ssoProvider: 'SSO',
- });
- render(
- <AcceptOrganizationInvite
- {...RouteComponentPropsFixture()}
- params={{orgId: 'org-slug', memberId: '1', token: 'abc'}}
- />
- );
- expect(screen.getByTestId('action-info-sso')).toBeInTheDocument();
- expect(getJoinButton()).toBeInTheDocument();
- });
- it('shows a logout button for existing members', async function () {
- addMock({
- orgSlug: organization.slug,
- needsAuthentication: false,
- needs2fa: false,
- hasAuthProvider: false,
- requireSso: false,
- existingMember: true,
- });
- render(
- <AcceptOrganizationInvite
- {...RouteComponentPropsFixture()}
- params={{orgId: 'org-slug', memberId: '1', token: 'abc'}}
- />
- );
- expect(screen.getByTestId('existing-member')).toBeInTheDocument();
- await userEvent.click(screen.getByTestId('existing-member-link'));
- await waitFor(() => expect(logout).toHaveBeenCalled());
- });
- it('shows 2fa warning', function () {
- addMock({
- orgSlug: organization.slug,
- needsAuthentication: false,
- needs2fa: true,
- hasAuthProvider: false,
- requireSso: false,
- existingMember: false,
- });
- render(
- <AcceptOrganizationInvite
- {...RouteComponentPropsFixture()}
- params={{orgId: 'org-slug', memberId: '1', token: 'abc'}}
- />
- );
- expect(
- screen.getByRole('button', {name: 'Configure Two-Factor Auth'})
- ).toBeInTheDocument();
- });
- });
|