| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- import { screen, render, waitFor } from '@testing-library/react'
- import { expect } from 'chai'
- import fetchMock from 'fetch-mock'
- import userEvent from '@testing-library/user-event'
- import { EditorProviders, PROJECT_ID } from '../../../helpers/editor-providers'
- import { SettingsModalProvider } from '@/features/settings/context/settings-modal-context'
- import ProjectNotificationsSetting from '@/features/settings/components/editor-settings/project-notifications-setting'
- const preferencesUrl = `/notifications/preferences/project/${PROJECT_ID}`
- const allNotificationsOn = {
- commentOnOwnProject: true,
- commentOnInvitedProject: true,
- repliesOnAuthoredThread: true,
- repliesOnParticipatingThread: true,
- commentResolvedOnAuthoredThread: true,
- commentResolvedOnParticipatingThread: true,
- commentReopenedOnAuthoredThread: true,
- commentReopenedOnParticipatingThread: true,
- trackedChangesOnOwnProject: true,
- trackedChangesOnInvitedProject: true,
- trackChangesAcceptedOnAuthoredChange: true,
- trackChangesRejectedOnAuthoredChange: true,
- }
- const repliesOnlyPreferences = {
- commentOnOwnProject: false,
- commentOnInvitedProject: false,
- repliesOnAuthoredThread: true,
- repliesOnParticipatingThread: true,
- commentResolvedOnAuthoredThread: true,
- commentResolvedOnParticipatingThread: true,
- commentReopenedOnAuthoredThread: true,
- commentReopenedOnParticipatingThread: true,
- trackedChangesOnOwnProject: false,
- trackedChangesOnInvitedProject: false,
- trackChangesAcceptedOnAuthoredChange: true,
- trackChangesRejectedOnAuthoredChange: true,
- }
- const globallyMutedPreferences = {
- trackedChangesOnOwnProject: false,
- trackedChangesOnInvitedProject: false,
- commentOnOwnProject: false,
- commentOnInvitedProject: false,
- repliesOnAuthoredThread: false,
- repliesOnParticipatingThread: false,
- muteAllNotifications: true,
- commentResolvedOnAuthoredThread: false,
- commentResolvedOnParticipatingThread: false,
- commentReopenedOnAuthoredThread: false,
- commentReopenedOnParticipatingThread: false,
- trackChangesAcceptedOnAuthoredChange: false,
- trackChangesRejectedOnAuthoredChange: false,
- }
- const allNotificationsOff = {
- commentOnOwnProject: false,
- commentOnInvitedProject: false,
- repliesOnAuthoredThread: false,
- repliesOnParticipatingThread: false,
- commentResolvedOnAuthoredThread: false,
- commentResolvedOnParticipatingThread: false,
- commentReopenedOnAuthoredThread: false,
- commentReopenedOnParticipatingThread: false,
- trackedChangesOnOwnProject: false,
- trackedChangesOnInvitedProject: false,
- trackChangesAcceptedOnAuthoredChange: false,
- trackChangesRejectedOnAuthoredChange: false,
- }
- const defaultPreferences = {
- trackedChangesOnOwnProject: true,
- trackedChangesOnInvitedProject: false,
- commentOnOwnProject: true,
- commentOnInvitedProject: false,
- repliesOnAuthoredThread: true,
- repliesOnParticipatingThread: true,
- muteAllNotifications: false,
- commentResolvedOnAuthoredThread: true,
- commentResolvedOnParticipatingThread: true,
- commentReopenedOnAuthoredThread: true,
- commentReopenedOnParticipatingThread: true,
- trackChangesAcceptedOnAuthoredChange: true,
- }
- function renderComponent(props: { permissionsLevel?: string } = {}) {
- return render(
- <EditorProviders permissionsLevel={props.permissionsLevel as any}>
- <SettingsModalProvider>
- <ProjectNotificationsSetting />
- </SettingsModalProvider>
- </EditorProviders>
- )
- }
- describe('<ProjectNotificationsSetting />', function () {
- afterEach(function () {
- fetchMock.removeRoutes().clearHistory()
- })
- it('shows loading indicator while preferences are loading', async function () {
- fetchMock.get(preferencesUrl, new Promise(() => {}))
- renderComponent()
- expect(await screen.findByRole('status')).to.exist
- expect(screen.queryByLabelText('All project activity', { exact: false })).to
- .not.exist
- })
- it('selects "All project activity" when all notifications are on', async function () {
- fetchMock.get(preferencesUrl, allNotificationsOn)
- renderComponent()
- await waitFor(
- () =>
- expect(
- (
- screen.getByLabelText('All project activity', {
- exact: false,
- }) as HTMLInputElement
- ).checked
- ).to.be.true
- )
- expect(
- (
- screen.getByLabelText('Replies to your activity only', {
- exact: false,
- }) as HTMLInputElement
- ).checked
- ).to.be.false
- expect(
- (screen.getByLabelText('Off', { exact: false }) as HTMLInputElement)
- .checked
- ).to.be.false
- })
- it('selects "Replies to your activity only" when only reply notifications are on', async function () {
- fetchMock.get(preferencesUrl, repliesOnlyPreferences)
- renderComponent()
- await waitFor(
- () =>
- expect(
- (
- screen.getByLabelText('Replies to your activity only', {
- exact: false,
- }) as HTMLInputElement
- ).checked
- ).to.be.true
- )
- expect(
- (
- screen.getByLabelText('All project activity', {
- exact: false,
- }) as HTMLInputElement
- ).checked
- ).to.be.false
- expect(
- (screen.getByLabelText('Off', { exact: false }) as HTMLInputElement)
- .checked
- ).to.be.false
- })
- it('selects "Off" when all notifications are off', async function () {
- fetchMock.get(preferencesUrl, allNotificationsOff)
- renderComponent()
- await waitFor(
- () =>
- expect(
- (screen.getByLabelText('Off', { exact: false }) as HTMLInputElement)
- .checked
- ).to.be.true
- )
- expect(
- (
- screen.getByLabelText('All project activity', {
- exact: false,
- }) as HTMLInputElement
- ).checked
- ).to.be.false
- expect(
- (
- screen.getByLabelText('Replies to your activity only', {
- exact: false,
- }) as HTMLInputElement
- ).checked
- ).to.be.false
- })
- it('shows muted message and hides radio buttons when muteAllNotifications is true', async function () {
- fetchMock.get(preferencesUrl, globallyMutedPreferences)
- renderComponent()
- await waitFor(
- () =>
- expect(
- screen.getByText(
- 'You are not receiving any notifications, as you have disabled all project notifications.',
- { exact: false }
- )
- ).to.exist
- )
- expect(
- screen.getByRole('link', { name: 'Change settings' }).getAttribute('href')
- ).to.equal('/user/notification-preferences')
- expect(screen.queryByLabelText('All project activity', { exact: false })).to
- .not.exist
- expect(
- screen.queryByLabelText('Replies to your activity only', { exact: false })
- ).to.not.exist
- expect(screen.queryByLabelText('Off', { exact: false })).to.not.exist
- })
- it('POSTs "replies" preferences when "Replies to your activity only" is selected', async function () {
- fetchMock.get(preferencesUrl, allNotificationsOn)
- const saveMock = fetchMock.post(preferencesUrl, { status: 200 })
- renderComponent()
- await waitFor(
- () =>
- expect(
- (
- screen.getByLabelText('All project activity', {
- exact: false,
- }) as HTMLInputElement
- ).checked
- ).to.be.true
- )
- await userEvent.click(
- screen.getByLabelText('Replies to your activity only', { exact: false })
- )
- expect(
- saveMock.callHistory.called(preferencesUrl, {
- body: repliesOnlyPreferences,
- })
- ).to.be.true
- })
- it('POSTs "off" preferences when "Off" is selected', async function () {
- fetchMock.get(preferencesUrl, allNotificationsOn)
- const saveMock = fetchMock.post(preferencesUrl, { status: 200 })
- renderComponent()
- await waitFor(
- () =>
- expect(
- (
- screen.getByLabelText('All project activity', {
- exact: false,
- }) as HTMLInputElement
- ).checked
- ).to.be.true
- )
- await userEvent.click(screen.getByLabelText('Off', { exact: false }))
- expect(
- saveMock.callHistory.called(preferencesUrl, {
- body: allNotificationsOff,
- })
- ).to.be.true
- })
- it('shows "all" for owner with default preferences', async function () {
- fetchMock.get(preferencesUrl, defaultPreferences)
- renderComponent({ permissionsLevel: 'owner' })
- await waitFor(
- () =>
- expect(
- (
- screen.getByLabelText('All project activity', {
- exact: false,
- }) as HTMLInputElement
- ).checked
- ).to.be.true
- )
- })
- it('shows "replies" for invitee with default preferences', async function () {
- fetchMock.get(preferencesUrl, defaultPreferences)
- renderComponent({ permissionsLevel: 'readAndWrite' })
- await waitFor(
- () =>
- expect(
- (
- screen.getByLabelText('Replies to your activity only', {
- exact: false,
- }) as HTMLInputElement
- ).checked
- ).to.be.true
- )
- })
- it('POSTs "all" preferences when "All project activity" is selected', async function () {
- fetchMock.get(preferencesUrl, allNotificationsOff)
- const saveMock = fetchMock.post(preferencesUrl, { status: 200 })
- renderComponent()
- await waitFor(
- () =>
- expect(
- (screen.getByLabelText('Off', { exact: false }) as HTMLInputElement)
- .checked
- ).to.be.true
- )
- await userEvent.click(
- screen.getByLabelText('All project activity', { exact: false })
- )
- expect(
- saveMock.callHistory.called(preferencesUrl, {
- body: allNotificationsOn,
- })
- ).to.be.true
- })
- })
|