import {LocationFixture} from 'sentry-fixture/locationFixture';
import {OrganizationFixture} from 'sentry-fixture/organization';
import {UserFixture} from 'sentry-fixture/user';
import {act, render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
import ConfigStore from 'sentry/stores/configStore';
import {trackAnalytics} from 'sentry/utils/analytics';
import {NewIssueExperienceButton} from 'sentry/views/issueDetails/actions/newIssueExperienceButton';
jest.mock('sentry/utils/analytics');
const mockFeedbackForm = jest.fn();
jest.mock('sentry/utils/useFeedbackForm', () => ({
useFeedbackForm: () => mockFeedbackForm(),
}));
describe('NewIssueExperienceButton', function () {
const organization = OrganizationFixture({features: ['issue-details-streamline']});
const user = UserFixture();
user.options.prefersIssueDetailsStreamlinedUI = true;
const location = LocationFixture({query: {streamline: '1'}});
beforeEach(() => {
ConfigStore.init();
jest.clearAllMocks();
});
it('does not appear by default', function () {
render(
);
expect(screen.getByTestId('test-id')).toBeEmptyDOMElement();
});
it('appears when organization has flag', function () {
render(
,
{organization}
);
expect(screen.getByTestId('test-id')).not.toBeEmptyDOMElement();
});
it('does not appear even if user prefers this UI', function () {
act(() => ConfigStore.set('user', user));
render(
);
expect(screen.getByTestId('test-id')).toBeEmptyDOMElement();
});
it('does not appear when query param is set', function () {
render(
,
{router: {location}}
);
expect(screen.getByTestId('test-id')).toBeEmptyDOMElement();
});
it('triggers changes to the user config and location', async function () {
const mockChangeUserSettings = MockApiClient.addMockResponse({
url: '/users/me/',
method: 'PUT',
});
render(, {organization});
const button = screen.getByRole('button', {
name: 'Switch to the new issue experience',
});
await userEvent.click(button);
// Text should change immediately
expect(
screen.getByRole('button', {name: 'Switch to the old issue experience'})
).toBeInTheDocument();
// User option should be saved
await waitFor(() => {
expect(mockChangeUserSettings).toHaveBeenCalledWith(
'/users/me/',
expect.objectContaining({
data: {
options: {
prefersIssueDetailsStreamlinedUI: true,
},
},
})
);
});
expect(trackAnalytics).toHaveBeenCalledTimes(1);
// Clicking again toggles it off
await userEvent.click(button);
// Old text should be back
expect(
screen.getByRole('button', {name: 'Switch to the new issue experience'})
).toBeInTheDocument();
// And save the option as false
await waitFor(() => {
expect(mockChangeUserSettings).toHaveBeenCalledWith(
'/users/me/',
expect.objectContaining({
data: {
options: {
prefersIssueDetailsStreamlinedUI: false,
},
},
})
);
});
expect(trackAnalytics).toHaveBeenCalledTimes(2);
});
it('can switch back to the old UI via dropdown', async function () {
const mockFormCallback = jest.fn();
mockFeedbackForm.mockReturnValue(mockFormCallback);
const mockChangeUserSettings = MockApiClient.addMockResponse({
url: '/users/me/',
method: 'PUT',
});
render(, {organization});
await userEvent.click(
screen.getByRole('button', {
name: 'Switch to the new issue experience',
})
);
expect(
screen.getByRole('button', {
name: 'Switch issue experience',
})
).toBeInTheDocument();
const dropdownButton = screen.getByRole('button', {
name: 'Switch issue experience',
});
await userEvent.click(dropdownButton);
await userEvent.click(
await screen.findByRole('menuitemradio', {name: 'Give feedback on new UI'})
);
expect(mockFeedbackForm).toHaveBeenCalled();
await userEvent.click(dropdownButton);
await userEvent.click(
screen.getByRole('menuitemradio', {
name: 'Switch to the old issue experience',
})
);
expect(mockChangeUserSettings).toHaveBeenCalledTimes(2);
});
});