diff --git a/webapp/channels/src/components/about_build_modal/about_build_modal.test.tsx b/webapp/channels/src/components/about_build_modal/about_build_modal.test.tsx index 207620a417..17c72c7451 100644 --- a/webapp/channels/src/components/about_build_modal/about_build_modal.test.tsx +++ b/webapp/channels/src/components/about_build_modal/about_build_modal.test.tsx @@ -7,7 +7,7 @@ import type {ClientConfig, ClientLicense} from '@mattermost/types/config'; import AboutBuildModal from 'components/about_build_modal/about_build_modal'; -import {renderWithFullContext, screen, userEvent} from 'tests/react_testing_utils'; +import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils'; import {AboutLinks} from 'utils/constants'; import AboutBuildModalCloud from './about_build_modal_cloud/about_build_modal_cloud'; @@ -94,7 +94,7 @@ describe('components/AboutBuildModal', () => { license.Cloud = 'true'; } - renderWithFullContext( + renderWithContext( { }, }; - renderWithFullContext( + renderWithContext( { }, }, }; - renderWithFullContext( + renderWithContext( { ...props, }; - return renderWithFullContext(); + return renderWithContext(); } }); diff --git a/webapp/channels/src/components/admin_console/admin_navbar_dropdown/menu_item_blockable_link.test.tsx b/webapp/channels/src/components/admin_console/admin_navbar_dropdown/menu_item_blockable_link.test.tsx index be0856b742..5a519f7ffd 100644 --- a/webapp/channels/src/components/admin_console/admin_navbar_dropdown/menu_item_blockable_link.test.tsx +++ b/webapp/channels/src/components/admin_console/admin_navbar_dropdown/menu_item_blockable_link.test.tsx @@ -3,13 +3,13 @@ import React from 'react'; -import {renderWithFullContext, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {MenuItemBlockableLinkImpl} from './menu_item_blockable_link'; describe('components/MenuItemBlockableLink', () => { test('should render my link', () => { - renderWithFullContext( + renderWithContext( { test('should match default snapshot', () => { const props = defaultProps; - const {container} = renderWithIntl(); + const {container} = renderWithContext(); screen.getByText(props.user.first_name, {exact: false}); screen.getByText(props.user.last_name, {exact: false}); screen.getByText(props.user.nickname, {exact: false}); @@ -38,7 +38,7 @@ describe('components/admin_console/admin_user_card/admin_user_card', () => { nickname: null, }, }; - const {container} = renderWithIntl(); + const {container} = renderWithContext(); screen.getByText(props.user.first_name, {exact: false}); screen.getByText(props.user.last_name, {exact: false}); expect(screen.queryByText(defaultProps.user.nickname)).not.toBeInTheDocument(); @@ -55,7 +55,7 @@ describe('components/admin_console/admin_user_card/admin_user_card', () => { last_name: null, }, }; - const {container} = renderWithIntl(); + const {container} = renderWithContext(); expect(screen.queryByText(defaultProps.user.first_name)).not.toBeInTheDocument(); expect(screen.queryByText(defaultProps.user.last_name)).not.toBeInTheDocument(); screen.getByText(props.user.nickname, {exact: false}); @@ -73,7 +73,7 @@ describe('components/admin_console/admin_user_card/admin_user_card', () => { nickname: null, }, }; - const {container} = renderWithIntl(); + const {container} = renderWithContext(); expect(screen.queryByText(defaultProps.user.first_name)).not.toBeInTheDocument(); expect(screen.queryByText(defaultProps.user.last_name)).not.toBeInTheDocument(); expect(screen.queryByText(defaultProps.user.nickname)).not.toBeInTheDocument(); diff --git a/webapp/channels/src/components/admin_console/billing/billing_history.test.tsx b/webapp/channels/src/components/admin_console/billing/billing_history.test.tsx index 7d243f9748..e518500c6f 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_history.test.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_history.test.tsx @@ -2,17 +2,16 @@ // See LICENSE.txt for license information. import React from 'react'; -import {Provider} from 'react-redux'; -import {renderWithIntl, renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; -import mockStore from 'tests/test_store'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {CloudLinks, HostedCustomerLinks} from 'utils/constants'; +import {TestHelper} from 'utils/test_helper'; import BillingHistory, {NoBillingHistorySection} from './billing_history'; const NO_INVOICES_LEGEND = 'All of your invoices will be shown here'; -const invoiceA = { +const invoiceA = TestHelper.getInvoiceMock({ id: 'in_1KNb3DI67GP2qpb4ueaJYBt8', number: '87030375-0015', create_at: 1643540071000, @@ -35,8 +34,8 @@ const invoiceA = { metadata: {}, }, ], -}; -const invoiceB = { +}); +const invoiceB = TestHelper.getInvoiceMock({ id: 'in_1KIWNTI67GP2qpb4KjGj1KAy', number: '87030375-0013', create_at: 1642330467000, @@ -59,7 +58,7 @@ const invoiceB = { metadata: {}, }, ], -}; +}); describe('components/admin_console/billing/billing_history', () => { // required state to mount using the provider @@ -91,13 +90,10 @@ describe('components/admin_console/billing/billing_history', () => { views: {}, }; - const store = mockStore(state); - test('should match the default state of the component with given props', () => { - renderWithIntl( - - - , + renderWithContext( + , + state, ); expect(screen.queryByText('Billing History')).toBeInTheDocument(); @@ -115,11 +111,9 @@ describe('components/admin_console/billing/billing_history', () => { ...state, entities: {...state.entities, cloud: {invoices: {}, errors: {}}}, }; - const storeNoBillingHistory = mockStore(noBillingHistoryState); - renderWithIntl( - - - , + renderWithContext( + , + noBillingHistoryState, ); expect(screen.queryByText('Date')).not.toBeInTheDocument(); @@ -139,10 +133,9 @@ describe('components/admin_console/billing/billing_history', () => { }); test('Billing history section shows two invoices to download', () => { - renderWithIntl( - - - , + renderWithContext( + , + state, ); expect(screen.queryByText('Date')).toBeInTheDocument(); @@ -154,10 +147,9 @@ describe('components/admin_console/billing/billing_history', () => { }); test('Billing history section download button has the target property set as _self so it works well in desktop app', () => { - renderWithIntl( - - - , + renderWithContext( + , + state, ); expect(screen.getByTestId(`billingHistoryLink-${invoiceA.id}`)).toHaveAttribute('target', '_self'); @@ -205,11 +197,9 @@ describe('BillingHistory -- self-hosted', () => { ...state, entities: {...state.entities, hostedCustomer: {invoices: {invoices: {}, invoicesLoaded: true}, errors: {}}}, }; - const storeNoBillingHistory = mockStore(noBillingHistoryState); - renderWithIntl( - - - , + renderWithContext( + , + noBillingHistoryState, ); expect(screen.queryByText('Date')).not.toBeInTheDocument(); @@ -229,12 +219,9 @@ describe('BillingHistory -- self-hosted', () => { }); test('Billing history section shows two invoices to download', () => { - const store = mockStore(state); - - renderWithIntl( - - - , + renderWithContext( + , + state, ); expect(screen.queryByText('Date')).toBeInTheDocument(); @@ -248,12 +235,18 @@ describe('BillingHistory -- self-hosted', () => { describe('NoBillingHistorySection', () => { const state = {entities: {users: {}, general: {config: {}, license: {}}}} as any; test('goes to cloud docs on cloud', () => { - renderWithIntlAndStore(, state); + renderWithContext( + , + state, + ); expect((screen.getByRole('link') as HTMLAnchorElement).href).toContain(CloudLinks.BILLING_DOCS); }); test('goes to self-hosted docs on self-hosted', () => { - renderWithIntlAndStore(, state); + renderWithContext( + , + state, + ); expect((screen.getByRole('link') as HTMLAnchorElement).href).toContain(HostedCustomerLinks.SELF_HOSTED_BILLING); }); }); diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limit_reached_banner.test.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limit_reached_banner.test.tsx index 10c8ad42b2..95b7f3cfb9 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limit_reached_banner.test.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limit_reached_banner.test.tsx @@ -15,7 +15,7 @@ import * as useOpenPricingModal from 'components/common/hooks/useOpenPricingModa import * as useOpenSalesLink from 'components/common/hooks/useOpenSalesLink'; import * as useSaveBool from 'components/common/hooks/useSavePreferences'; -import {fireEvent, renderWithFullContext, screen} from 'tests/react_testing_utils'; +import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils'; import {CloudProducts} from 'utils/constants'; import LimitReachedBanner from './limit_reached_banner'; @@ -119,7 +119,7 @@ describe('limits_reached_banner', () => { const spies = makeSpies(); spies.useGetUsageDeltas.mockReturnValue(someLimitReached); - renderWithFullContext(, state); + renderWithContext(, state); expect(screen.queryByText(titleFree)).not.toBeInTheDocument(); expect(screen.queryByText(titleProfessional)).not.toBeInTheDocument(); @@ -143,7 +143,7 @@ describe('limits_reached_banner', () => { const spies = makeSpies(); spies.useGetUsageDeltas.mockReturnValue(someLimitReached); - renderWithFullContext(, myState); + renderWithContext(, myState); expect(screen.queryByText(titleFree)).not.toBeInTheDocument(); expect(screen.queryByText(titleProfessional)).not.toBeInTheDocument(); @@ -153,7 +153,7 @@ describe('limits_reached_banner', () => { const spies = makeSpies(); spies.useGetUsageDeltas.mockReturnValue(noLimitReached); - renderWithFullContext(, state); + renderWithContext(, state); expect(screen.queryByText(titleFree)).not.toBeInTheDocument(); expect(screen.queryByText(titleProfessional)).not.toBeInTheDocument(); @@ -165,7 +165,7 @@ describe('limits_reached_banner', () => { spies.useOpenPricingModal.mockReturnValue(mockOpenPricingModal); spies.useGetUsageDeltas.mockReturnValue(someLimitReached); - renderWithFullContext(, state); + renderWithContext(, state); screen.getByText(titleFree); expect(screen.queryByText(titleProfessional)).not.toBeInTheDocument(); @@ -181,7 +181,7 @@ describe('limits_reached_banner', () => { spies.useOpenSalesLink.mockReturnValue([mockOpenSalesLink, '']); spies.useGetUsageDeltas.mockReturnValue(someLimitReached); - renderWithFullContext(, state); + renderWithContext(, state); screen.getByText(titleFree); expect(screen.queryByText(titleProfessional)).not.toBeInTheDocument(); diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limits.test.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limits.test.tsx index 1a2e6af03d..cd1c7f4ca8 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limits.test.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limits.test.tsx @@ -3,16 +3,15 @@ import React from 'react'; import * as redux from 'react-redux'; -import {Provider} from 'react-redux'; import type {Subscription, Product} from '@mattermost/types/cloud'; import type {GlobalState} from '@mattermost/types/store'; import type {UserProfile, UsersState} from '@mattermost/types/users'; +import type {DeepPartial} from '@mattermost/types/utilities'; import * as cloudActions from 'actions/cloud'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; -import mockStore from 'tests/test_store'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {Constants, CloudProducts} from 'utils/constants'; import {FileSizes} from 'utils/file_utils'; @@ -37,7 +36,7 @@ const freeLimits = { interface SetupOptions { isEnterprise?: boolean; } -function setupStore(setupOptions: SetupOptions) { +function setupState(setupOptions: SetupOptions): DeepPartial { const state = { entities: { cloud: { @@ -92,29 +91,28 @@ function setupStore(setupOptions: SetupOptions) { config: {}, }, }, - } as GlobalState; + }; if (setupOptions.isEnterprise) { state.entities.cloud.subscription!.is_free_trial = 'true'; } - const store = mockStore(state); - return store; + return state; } describe('Limits', () => { const defaultOptions = {}; test('message limit rendered in K', () => { - const store = setupStore(defaultOptions); + const state = setupState(defaultOptions); - renderWithIntl(); + renderWithContext(, state); screen.getByText('Message History'); screen.getByText(/of 10K/); }); test('storage limit rendered in GB', () => { - const store = setupStore(defaultOptions); + const state = setupState(defaultOptions); - renderWithIntl(); + renderWithContext(, state); screen.getByText('File Storage'); screen.getByText(/of 1GB/); }); @@ -123,9 +121,9 @@ describe('Limits', () => { const mockGetLimits = jest.fn(); jest.spyOn(cloudActions, 'getCloudLimits').mockImplementation(mockGetLimits); jest.spyOn(redux, 'useDispatch').mockImplementation(jest.fn(() => jest.fn())); - const store = setupStore({isEnterprise: true}); + const state = setupState({isEnterprise: true}); - renderWithIntl(); + renderWithContext(, state); expect(screen.queryByTestId('limits-panel-title')).not.toBeInTheDocument(); }); @@ -133,9 +131,9 @@ describe('Limits', () => { const mockGetLimits = jest.fn(); jest.spyOn(cloudActions, 'getCloudLimits').mockImplementation(mockGetLimits); jest.spyOn(redux, 'useDispatch').mockImplementation(jest.fn(() => jest.fn())); - const store = setupStore(defaultOptions); + const state = setupState(defaultOptions); - renderWithIntl(); + renderWithContext(, state); screen.getByTestId('limits-panel-title'); }); }); diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner.test.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner.test.tsx index 5036395c61..899993c9f9 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner.test.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; -import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {CloudProducts} from 'utils/constants'; import {ToPaidNudgeBanner, ToPaidPlanBannerDismissable} from './to_paid_plan_nudge_banner'; @@ -60,7 +60,7 @@ describe('ToPaidPlanBannerDismissable', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); screen.getByTestId('cloud-free-deprecation-announcement-bar'); }); @@ -84,7 +84,7 @@ describe('ToPaidPlanBannerDismissable', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-free-deprecation-announcement-bar')).toThrow(); }); @@ -108,7 +108,7 @@ describe('ToPaidPlanBannerDismissable', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-free-deprecation-announcement-bar')).toThrow(); }); @@ -132,7 +132,7 @@ describe('ToPaidPlanBannerDismissable', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-free-deprecation-announcement-bar')).toThrow(); }); @@ -166,7 +166,7 @@ describe('ToPaidPlanBannerDismissable', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-free-deprecation-announcement-bar')).toThrow(); }); @@ -189,7 +189,7 @@ describe('ToPaidNudgeBanner', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); screen.getByTestId('cloud-free-deprecation-alert-banner'); }); @@ -210,7 +210,7 @@ describe('ToPaidNudgeBanner', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-free-deprecation-alert-banner')).toThrow(); }); @@ -231,7 +231,7 @@ describe('ToPaidNudgeBanner', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-free-deprecation-alert-banner')).toThrow(); }); diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_yearly_nudge_banner.test.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_yearly_nudge_banner.test.tsx index 9922dc734b..a1988be7df 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_yearly_nudge_banner.test.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_yearly_nudge_banner.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; -import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen, waitFor} from 'tests/react_testing_utils'; import {CloudProducts, RecurringIntervals} from 'utils/constants'; import {ToYearlyNudgeBanner, ToYearlyNudgeBannerDismissable} from './to_yearly_nudge_banner'; @@ -60,7 +60,7 @@ describe('ToYearlyNudgeBannerDismissable', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar'); }); @@ -85,7 +85,7 @@ describe('ToYearlyNudgeBannerDismissable', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow(); }); @@ -110,7 +110,7 @@ describe('ToYearlyNudgeBannerDismissable', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow(); }); @@ -135,7 +135,7 @@ describe('ToYearlyNudgeBannerDismissable', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow(); }); @@ -159,12 +159,12 @@ describe('ToYearlyNudgeBannerDismissable', () => { }, }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow(); }); - test('should NOT show for admins when banner was dismissed in preferences', () => { + test('should NOT show for admins when banner was dismissed in preferences', async () => { const state = JSON.parse(JSON.stringify(initialState)); state.entities.users.profiles = { current_user_id: {roles: 'system_admin'}, @@ -192,7 +192,9 @@ describe('ToYearlyNudgeBannerDismissable', () => { }, }, }; - renderWithIntlAndStore(, state); + await waitFor(() => { + renderWithContext(, state, {useMockedStore: true}); + }); expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow(); }); @@ -218,7 +220,7 @@ describe('ToYearlyNudgeBannerDismissable', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow(); }); @@ -244,7 +246,7 @@ describe('ToYearlyNudgeBannerDismissable', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow(); }); @@ -268,7 +270,7 @@ describe('ToYearlyNudgeBanner', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); screen.getByTestId('cloud-pro-monthly-deprecation-alert-banner'); }); @@ -290,7 +292,7 @@ describe('ToYearlyNudgeBanner', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-alert-banner')).toThrow(); }); @@ -312,7 +314,7 @@ describe('ToYearlyNudgeBanner', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-alert-banner')).toThrow(); }); @@ -335,7 +337,7 @@ describe('ToYearlyNudgeBanner', () => { }, }; - renderWithIntlAndStore(, state); + renderWithContext(, state, {useMockedStore: true}); expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-alert-banner')).toThrow(); }); diff --git a/webapp/channels/src/components/admin_console/color_setting.test.tsx b/webapp/channels/src/components/admin_console/color_setting.test.tsx index 31d748dac6..20b67f19cc 100644 --- a/webapp/channels/src/components/admin_console/color_setting.test.tsx +++ b/webapp/channels/src/components/admin_console/color_setting.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import ColorSetting from './color_setting'; @@ -11,7 +11,7 @@ describe('components/ColorSetting', () => { test('should match snapshot, all', () => { function emptyFunction() {} //eslint-disable-line no-empty-function - const {container} = renderWithIntl( + const {container} = renderWithContext( { test('should match snapshot, no help text', () => { function emptyFunction() {} //eslint-disable-line no-empty-function - const {container} = renderWithIntl( + const {container} = renderWithContext( { test('should match snapshot, disabled', () => { function emptyFunction() {} //eslint-disable-line no-empty-function - const {container} = renderWithIntl( + const {container} = renderWithContext( { test('should match snapshot, clicked on color setting', () => { function emptyFunction() {} //eslint-disable-line no-empty-function - const {container} = renderWithIntl( + const {container} = renderWithContext( { const getCloudSubscription = jest.fn(); const openModal = jest.fn(); - renderWithIntl( - - } - // eslint-disable-next-line @typescript-eslint/naming-convention - stats={{TOTAL_USERS: 20}} - prevTrialLicense={{IsLicensed: 'false'}} - isCloud={false} - isCloudTrial={false} - hadPrevCloudTrial={false} - isSubscriptionLoaded={true} - isPaidSubscription={false} - cloudFreeDeprecated={false} - actions={{ - getPrevTrialLicense, - getCloudSubscription, - openModal, - }} - /> - , + renderWithContext( + } + // eslint-disable-next-line @typescript-eslint/naming-convention + stats={{TOTAL_USERS: 20}} + prevTrialLicense={{IsLicensed: 'false'}} + isCloud={false} + isCloudTrial={false} + hadPrevCloudTrial={false} + isSubscriptionLoaded={true} + isPaidSubscription={false} + cloudFreeDeprecated={false} + actions={{ + getPrevTrialLicense, + getCloudSubscription, + openModal, + }} + />, ); expect(screen.queryByText('Bar')).toBeInTheDocument(); @@ -76,39 +71,38 @@ describe('components/feature_discovery', () => { expect(getCloudSubscription).not.toHaveBeenCalled(); expect(openModal).not.toHaveBeenCalled(); }); + test('should match component state when is cloud environment', async () => { const getPrevTrialLicense = jest.fn(); const getCloudSubscription = jest.fn(); const openModal = jest.fn(); await waitFor(() => { - renderWithIntl( - - } - // eslint-disable-next-line @typescript-eslint/naming-convention - stats={{TOTAL_USERS: 20}} - prevTrialLicense={{IsLicensed: 'false'}} - isCloud={true} - isCloudTrial={false} - hadPrevCloudTrial={false} - isPaidSubscription={false} - isSubscriptionLoaded={true} - cloudFreeDeprecated={false} - actions={{ - getPrevTrialLicense, - getCloudSubscription, - openModal, - }} - /> - , + renderWithContext( + } + // eslint-disable-next-line @typescript-eslint/naming-convention + stats={{TOTAL_USERS: 20}} + prevTrialLicense={{IsLicensed: 'false'}} + isCloud={true} + isCloudTrial={false} + hadPrevCloudTrial={false} + isPaidSubscription={false} + isSubscriptionLoaded={true} + cloudFreeDeprecated={false} + actions={{ + getPrevTrialLicense, + getCloudSubscription, + openModal, + }} + />, ); }); @@ -144,33 +138,31 @@ describe('components/feature_discovery', () => { const getCloudSubscription = jest.fn(); const openModal = jest.fn(); - renderWithIntl( - - } - // eslint-disable-next-line @typescript-eslint/naming-convention - stats={{TOTAL_USERS: 20}} - prevTrialLicense={{IsLicensed: 'false'}} - isCloud={true} - isCloudTrial={false} - hadPrevCloudTrial={false} - isSubscriptionLoaded={false} - isPaidSubscription={false} - cloudFreeDeprecated={false} - actions={{ - getPrevTrialLicense, - getCloudSubscription, - openModal, - }} - /> - , + renderWithContext( + } + // eslint-disable-next-line @typescript-eslint/naming-convention + stats={{TOTAL_USERS: 20}} + prevTrialLicense={{IsLicensed: 'false'}} + isCloud={true} + isCloudTrial={false} + hadPrevCloudTrial={false} + isSubscriptionLoaded={false} + isPaidSubscription={false} + cloudFreeDeprecated={false} + actions={{ + getPrevTrialLicense, + getCloudSubscription, + openModal, + }} + />, ); // when is cloud and subscription is not loaded yet, then only loading spinner is visible diff --git a/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.test.tsx b/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.test.tsx index 5a3541c9cc..bdfa09c4b1 100644 --- a/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.test.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.test.tsx @@ -12,8 +12,9 @@ import {General} from 'mattermost-redux/constants'; import * as useCanSelfHostedExpand from 'components/common/hooks/useCanSelfHostedExpand'; +import mergeObjects from 'packages/mattermost-redux/test/merge_objects'; import {mountWithIntl} from 'tests/helpers/intl-test-helper'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import mockStore from 'tests/test_store'; import {OverActiveUserLimits, SelfHostedProducts} from 'utils/constants'; import {TestHelper} from 'utils/test_helper'; @@ -91,28 +92,25 @@ describe('components/admin_console/license_settings/enterprise_edition/enterpris }, }; - const props = { + const baseProps: EnterpriseEditionProps = { license, openEELicenseModal: jest.fn(), upgradedFromTE: false, isTrialLicense: false, - issued: <>, - startsAt: <>, - expiresAt: <>, handleRemove: jest.fn(), isDisabled: false, removing: false, handleChange: jest.fn(), fileInputRef: React.createRef(), statsActiveUsers: 1, - } as EnterpriseEditionProps; + }; - test('should format the Users field', async () => { - const store = await mockStore(initialState); + test('should format the Users field', () => { + const store = mockStore(initialState); const wrapper = mountWithIntl( , ); @@ -127,35 +125,34 @@ describe('components/admin_console/license_settings/enterprise_edition/enterpris expect(item.text()).toContain('1,000'); }); - test('should not add any class if active users is lower than the minimal', async () => { - const store = await mockStore(initialState); - renderWithIntl( - - - , + test('should not add any class if active users is lower than the minimal', () => { + renderWithContext( + , + initialState, ); - expect(screen.getByText(Intl.NumberFormat('en').format(props.statsActiveUsers))).toHaveClass('value'); - expect(screen.getByText(Intl.NumberFormat('en').format(props.statsActiveUsers))).not.toHaveClass('value--warning-over-seats-purchased'); - expect(screen.getByText(Intl.NumberFormat('en').format(props.statsActiveUsers))).not.toHaveClass('value--over-seats-purchased'); + expect(screen.getByText(Intl.NumberFormat('en').format(baseProps.statsActiveUsers))).toHaveClass('value'); + expect(screen.getByText(Intl.NumberFormat('en').format(baseProps.statsActiveUsers))).not.toHaveClass('value--warning-over-seats-purchased'); + expect(screen.getByText(Intl.NumberFormat('en').format(baseProps.statsActiveUsers))).not.toHaveClass('value--over-seats-purchased'); expect(screen.getByText('ACTIVE USERS:')).toHaveClass('legend'); expect(screen.getByText('ACTIVE USERS:')).not.toHaveClass('legend--warning-over-seats-purchased'); expect(screen.getByText('ACTIVE USERS:')).not.toHaveClass('legend--over-seats-purchased'); }); - test('should add warning class to active users', async () => { + test('should add warning class to active users', () => { const minWarning = Math.ceil(parseInt(license.Users, 10) * OverActiveUserLimits.MIN) + parseInt(license.Users, 10); - const store = await mockStore(initialState); - props.statsActiveUsers = minWarning; + const props = { + ...baseProps, + statsActiveUsers: minWarning, + }; - renderWithIntl( - - - , + renderWithContext( + , + initialState, ); expect(screen.getByText(Intl.NumberFormat('en').format(minWarning))).toHaveClass('value'); @@ -166,16 +163,18 @@ describe('components/admin_console/license_settings/enterprise_edition/enterpris expect(screen.getByText('ACTIVE USERS:')).not.toHaveClass('legend--over-seats-purchased'); }); - test('should add over-seats-purchased class to active users', async () => { + test('should add over-seats-purchased class to active users', () => { const exceedHighLimitExtraUsersError = Math.ceil(parseInt(license.Users, 10) * OverActiveUserLimits.MAX) + parseInt(license.Users, 10); - props.statsActiveUsers = exceedHighLimitExtraUsersError; - const store = await mockStore(initialState); - renderWithIntl( - - - , + const props = { + ...baseProps, + statsActiveUsers: exceedHighLimitExtraUsersError, + }; + + renderWithContext( + , + initialState, ); expect(screen.getByText(Intl.NumberFormat('en').format(exceedHighLimitExtraUsersError))).toHaveClass('value'); @@ -186,44 +185,87 @@ describe('components/admin_console/license_settings/enterprise_edition/enterpris expect(screen.getByText('ACTIVE USERS:')).toHaveClass('legend--over-seats-purchased'); }); - test('should add warning class to days expired indicator when there are more than 5 days until expiry', async () => { - license.ExpiresAt = moment().add(6, 'days').valueOf().toString(); - const store = await mockStore(initialState); - renderWithIntl( - - - , + test('should add warning class to days expired indicator when there are more than 5 days until expiry', () => { + const testLicense = { + ...license, + ExpiresAt: moment().add(6, 'days').valueOf().toString(), + }; + + const testState = mergeObjects(initialState, { + entities: { + general: { + license: testLicense, + }, + }, + }); + const props = { + ...baseProps, + license: testLicense, + }; + + renderWithContext( + , + testState, ); expect(screen.getByText('Expires in 6 days')).toHaveClass('expiration-days-warning'); }); - test('should add danger class to days expired indicator when there are at least 5 days until expiry', async () => { - license.ExpiresAt = moment().add(5, 'days').valueOf().toString(); - const store = await mockStore(initialState); - renderWithIntl( - - - , + test('should add danger class to days expired indicator when there are at least 5 days until expiry', () => { + const testLicense = { + ...license, + ExpiresAt: moment().add(5, 'days').valueOf().toString(), + }; + + const testState = mergeObjects(initialState, { + entities: { + general: { + license: testLicense, + }, + }, + }); + const props = { + ...baseProps, + license: testLicense, + }; + + renderWithContext( + , + testState, ); expect(screen.getByText('Expires in 5 days')).toHaveClass('expiration-days-danger'); }); - test('should display add seats button when there are more than 60 days until expiry and self hosted expansion is available', async () => { - license.ExpiresAt = moment().add(61, 'days').valueOf().toString(); - const store = await mockStore(initialState); + test('should display add seats button when there are more than 60 days until expiry and self hosted expansion is available', () => { + const testLicense = { + ...license, + ExpiresAt: moment().add(61, 'days').valueOf().toString(), + }; + + const testState = mergeObjects(initialState, { + entities: { + general: { + license: testLicense, + }, + }, + }); + const props = { + ...baseProps, + license: testLicense, + }; + jest.spyOn(useCanSelfHostedExpand, 'default').mockImplementation(() => true); - renderWithIntl( - - - , + + renderWithContext( + , + testState, ); expect(screen.getByText('+ Add seats')).toBeVisible(); diff --git a/webapp/channels/src/components/admin_console/text_setting.test.tsx b/webapp/channels/src/components/admin_console/text_setting.test.tsx index d87d25f102..203e58eb2b 100644 --- a/webapp/channels/src/components/admin_console/text_setting.test.tsx +++ b/webapp/channels/src/components/admin_console/text_setting.test.tsx @@ -3,13 +3,13 @@ import React from 'react'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import AdminTextSetting from './text_setting'; describe('components/admin_console/TextSetting', () => { test('render component with required props', () => { - renderWithIntl( + renderWithContext( { describe('keyDown behavior', () => { it('Enter should call postMsgKeyPress', () => { const postMsgKeyPress = jest.fn(); - renderWithFullContext( - - - , mergeObjects(initialState, { + renderWithContext( + , + mergeObjects(initialState, { entities: { roles: { roles: { @@ -167,7 +164,8 @@ describe('components/avanced_text_editor/advanced_text_editor', () => { }, }, }, - })); + }), + ); userEvent.type(screen.getByTestId('post_textbox'), '{enter}'); expect(postMsgKeyPress).toHaveBeenCalledTimes(1); @@ -175,13 +173,12 @@ describe('components/avanced_text_editor/advanced_text_editor', () => { it('Ctrl+up should call loadPrevMessage', () => { const loadPrevMessage = jest.fn(); - renderWithFullContext( - - - , mergeObjects(initialState, { + renderWithContext( + , + mergeObjects(initialState, { entities: { roles: { roles: { @@ -189,20 +186,20 @@ describe('components/avanced_text_editor/advanced_text_editor', () => { }, }, }, - })); + }), + ); userEvent.type(screen.getByTestId('post_textbox'), '{ctrl}{arrowup}'); expect(loadPrevMessage).toHaveBeenCalledTimes(1); }); it('up should call onEditLatestPost', () => { const onEditLatestPost = jest.fn(); - renderWithFullContext( - - - , mergeObjects(initialState, { + renderWithContext( + , + mergeObjects(initialState, { entities: { roles: { roles: { @@ -210,18 +207,18 @@ describe('components/avanced_text_editor/advanced_text_editor', () => { }, }, }, - })); + }), + ); userEvent.type(screen.getByTestId('post_textbox'), '{arrowup}'); expect(onEditLatestPost).toHaveBeenCalledTimes(1); }); it('ESC should blur the input', () => { - renderWithFullContext( - - - , mergeObjects(initialState, { + renderWithContext( + , + mergeObjects(initialState, { entities: { roles: { roles: { @@ -229,7 +226,8 @@ describe('components/avanced_text_editor/advanced_text_editor', () => { }, }, }, - })); + }), + ); const textbox = screen.getByTestId('post_textbox'); userEvent.type(textbox, 'something{esc}'); expect(textbox).not.toHaveFocus(); @@ -261,14 +259,13 @@ describe('components/avanced_text_editor/advanced_text_editor', () => { const selectionStart = 5; const selectionEnd = 10; - renderWithFullContext( - - - , mergeObjects(initialState, { + renderWithContext( + , + mergeObjects(initialState, { entities: { roles: { roles: { @@ -276,7 +273,8 @@ describe('components/avanced_text_editor/advanced_text_editor', () => { }, }, }, - })); + }), + ); const textbox = screen.getByTestId('post_textbox'); userEvent.type(textbox, tc.input, {initialSelectionStart: selectionStart, initialSelectionEnd: selectionEnd}); expect(applyMarkdown).toHaveBeenCalledWith({ diff --git a/webapp/channels/src/components/analytics/true_up_review.test.tsx b/webapp/channels/src/components/analytics/true_up_review.test.tsx index c211736bc2..5e703b2ae4 100644 --- a/webapp/channels/src/components/analytics/true_up_review.test.tsx +++ b/webapp/channels/src/components/analytics/true_up_review.test.tsx @@ -8,14 +8,14 @@ import type {DeepPartial} from '@mattermost/types/utilities'; import * as useCWSAvailabilityCheckAll from 'components/common/hooks/useCWSAvailabilityCheck'; -import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {LicenseSkus} from 'utils/constants'; import {TestHelper as TH} from 'utils/test_helper'; import TrueUpReview from './true_up_review'; describe('TrueUpReview', () => { - const showsTrueUpReviewStore: DeepPartial = { + const showsTrueUpReviewState: DeepPartial = { entities: { general: { license: TH.getLicenseMock({ @@ -58,16 +58,16 @@ describe('TrueUpReview', () => { it('regular self hosted license in the true up window sees content', () => { jest.spyOn(useCWSAvailabilityCheckAll, 'default').mockImplementation(() => true); - renderWithIntlAndStore(, showsTrueUpReviewStore); + renderWithContext(, showsTrueUpReviewState); screen.getByText('Share to Mattermost'); }); it('gov sku self-hosted license does not see true up content', () => { - const store = JSON.parse(JSON.stringify(showsTrueUpReviewStore)); + const store = JSON.parse(JSON.stringify(showsTrueUpReviewState)); store.entities.general.license.IsGovSku = 'true'; jest.spyOn(useCWSAvailabilityCheckAll, 'default').mockImplementation(() => true); - renderWithIntlAndStore(, store); + renderWithContext(, store); expect(screen.queryByText('Share to Mattermost')).not.toBeInTheDocument(); }); }); diff --git a/webapp/channels/src/components/announcement_bar/notify_admin_downgrade_delinquency_bar/notify_admin_downgrade_delinquency_bar.test.tsx b/webapp/channels/src/components/announcement_bar/notify_admin_downgrade_delinquency_bar/notify_admin_downgrade_delinquency_bar.test.tsx index 5e9586df45..a082a013b2 100644 --- a/webapp/channels/src/components/announcement_bar/notify_admin_downgrade_delinquency_bar/notify_admin_downgrade_delinquency_bar.test.tsx +++ b/webapp/channels/src/components/announcement_bar/notify_admin_downgrade_delinquency_bar/notify_admin_downgrade_delinquency_bar.test.tsx @@ -2,18 +2,15 @@ // See LICENSE.txt for license information. import React from 'react'; -import type {ComponentProps} from 'react'; -import * as reactRedux from 'react-redux'; import {savePreferences} from 'mattermost-redux/actions/preferences'; import {Client4} from 'mattermost-redux/client'; import {trackEvent} from 'actions/telemetry_actions'; -import configureStore from 'store'; import { fireEvent, - renderWithIntl, + renderWithContext, screen, waitFor, } from 'tests/react_testing_utils'; @@ -22,11 +19,6 @@ import {TestHelper} from 'utils/test_helper'; import NotifyAdminDowngradeDeliquencyBar, {BannerPreferenceName} from './index'; -type RenderComponentArgs = { - props?: Partial>; - store?: any; -} - jest.mock('actions/telemetry_actions', () => ({ trackEvent: jest.fn(), })); @@ -93,14 +85,6 @@ describe('components/announcement_bar/notify_admin_downgrade_delinquency_bar', ( }, }; - const renderComponent = ({store = initialState}: RenderComponentArgs) => { - return renderWithIntl( - - - , - ); - }; - beforeEach(() => { jest.clearAllMocks(); }); @@ -113,7 +97,7 @@ describe('components/announcement_bar/notify_admin_downgrade_delinquency_bar', ( is_free_trial: 'false', }; - renderComponent({store: state}); + renderWithContext(, state); expect(screen.queryByText('Your workspace has been downgraded. Notify your admin to fix billing issues')).not.toBeInTheDocument(); }); @@ -121,7 +105,7 @@ describe('components/announcement_bar/notify_admin_downgrade_delinquency_bar', ( it('Should not show banner when deliquency is less than 90 days', () => { jest.useFakeTimers().setSystemTime(new Date('2022-06-20')); - renderComponent({}); + renderWithContext(, initialState); expect(screen.queryByText('Your workspace has been downgraded. Notify your admin to fix billing issues')).not.toBeInTheDocument(); }); @@ -138,7 +122,7 @@ describe('components/announcement_bar/notify_admin_downgrade_delinquency_bar', ( ], ); - renderComponent({store: state}); + renderWithContext(, state); expect(screen.queryByText('Your workspace has been downgraded. Notify your admin to fix billing issues')).not.toBeInTheDocument(); }); @@ -155,7 +139,7 @@ describe('components/announcement_bar/notify_admin_downgrade_delinquency_bar', ( ], ); - renderComponent({store: state}); + renderWithContext(, state); expect(screen.queryByText('Your workspace has been downgraded. Notify your admin to fix billing issues')).not.toBeInTheDocument(); }); @@ -165,7 +149,7 @@ describe('components/announcement_bar/notify_admin_downgrade_delinquency_bar', ( const state = JSON.parse(JSON.stringify(initialState)); state.entities.users.profiles.current_user_id = {roles: 'system_admin'}; - renderComponent({store: state}); + renderWithContext(, state); expect(screen.queryByText('Your workspace has been downgraded. Notify your admin to fix billing issues')).not.toBeInTheDocument(); }); @@ -174,7 +158,7 @@ describe('components/announcement_bar/notify_admin_downgrade_delinquency_bar', ( jest.useFakeTimers().setSystemTime(new Date('2022-08-17')); Client4.notifyAdmin = jest.fn(); - renderComponent({}); + renderWithContext(, initialState); expect(savePreferences).not.toBeCalled(); }); @@ -182,7 +166,7 @@ describe('components/announcement_bar/notify_admin_downgrade_delinquency_bar', ( it('Should show banner when deliquency is higher than 90 days', () => { jest.useFakeTimers().setSystemTime(new Date('2022-08-17')); - renderComponent({}); + renderWithContext(, initialState); expect(screen.getByText('Your workspace has been downgraded. Notify your admin to fix billing issues')).toBeInTheDocument(); }); @@ -190,7 +174,7 @@ describe('components/announcement_bar/notify_admin_downgrade_delinquency_bar', ( it('Should save the preferences if the user close the banner', async () => { jest.useFakeTimers().setSystemTime(new Date('2022-08-17')); - renderComponent({}); + renderWithContext(, initialState); fireEvent.click(screen.getByRole('link')); @@ -207,7 +191,7 @@ describe('components/announcement_bar/notify_admin_downgrade_delinquency_bar', ( jest.useFakeTimers().setSystemTime(new Date('2022-08-17')); Client4.notifyAdmin = jest.fn(); - renderComponent({}); + renderWithContext(, initialState); fireEvent.click(screen.getByText('Notify admin')); diff --git a/webapp/channels/src/components/announcement_bar/overage_users_banner/overage_users_banner.test.tsx b/webapp/channels/src/components/announcement_bar/overage_users_banner/overage_users_banner.test.tsx index 5a9feb3812..4c6a8389d7 100644 --- a/webapp/channels/src/components/announcement_bar/overage_users_banner/overage_users_banner.test.tsx +++ b/webapp/channels/src/components/announcement_bar/overage_users_banner/overage_users_banner.test.tsx @@ -11,7 +11,7 @@ import {General} from 'mattermost-redux/constants'; import {trackEvent} from 'actions/telemetry_actions'; -import {fireEvent, renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils'; import {OverActiveUserLimits, Preferences, SelfHostedProducts, StatTypes} from 'utils/constants'; import {TestHelper} from 'utils/test_helper'; import {generateId} from 'utils/utils'; @@ -20,13 +20,6 @@ import type {GlobalState} from 'types/store'; import OverageUsersBanner from './index'; -type ComponentProps = React.ComponentProps; - -type RenderComponentArgs = { - props?: Partial; - store?: any; -} - jest.mock('react-redux', () => ({ ...jest.requireActual('react-redux'), useDispatch: jest.fn().mockReturnValue(() => {}), @@ -137,20 +130,15 @@ describe('components/overage_users_banner', () => { windowSpy.mockRestore(); }); - const renderComponent = ({store}: RenderComponentArgs = {props: {}, store: initialState}) => { - return renderWithIntlAndStore( - , store); - }; - it('should not render the banner because we are not on overage state', () => { - renderComponent(); + renderWithContext(); expect(screen.queryByText('(Only visible to admins) Your workspace user count has exceeded your paid license seat count by', {exact: false})).not.toBeInTheDocument(); expect(getLicenseSelfServeStatus).not.toBeCalled(); }); it('should not render the banner because we are not admins', () => { - const store: GlobalState = JSON.parse(JSON.stringify(initialState)); + const store = JSON.parse(JSON.stringify(initialState)); store.entities.users = { ...store.entities.users, @@ -163,32 +151,28 @@ describe('components/overage_users_banner', () => { }, }; - renderComponent({ - store, - }); + renderWithContext(, store); expect(screen.queryByText('Your workspace user count has exceeded your paid license seat count by', {exact: false})).not.toBeInTheDocument(); expect(getLicenseSelfServeStatus).not.toBeCalled(); }); it('should not render the banner because it\'s cloud licenese', () => { - const store: GlobalState = JSON.parse(JSON.stringify(initialState)); + const store = JSON.parse(JSON.stringify(initialState)); store.entities.general.license = { ...store.entities.general.license, Cloud: 'true', }; - renderComponent({ - store, - }); + renderWithContext(, store); expect(screen.queryByText('Your workspace user count has exceeded your paid license seat count by', {exact: false})).not.toBeInTheDocument(); expect(getLicenseSelfServeStatus).not.toBeCalled(); }); it('should not render the 5% banner because we have dissmised it', () => { - const store: GlobalState = JSON.parse(JSON.stringify(initialState)); + const store = JSON.parse(JSON.stringify(initialState)); store.entities.preferences.myPreferences = TestHelper.getPreferencesMock( [ @@ -207,16 +191,14 @@ describe('components/overage_users_banner', () => { }, }; - renderComponent({ - store, - }); + renderWithContext(, store); expect(screen.queryByText(text5PercentageState)).not.toBeInTheDocument(); expect(getLicenseSelfServeStatus).not.toBeCalled(); }); it('should render the banner because we are over 5% and we don\'t have any preferences', () => { - const store: GlobalState = JSON.parse(JSON.stringify(initialState)); + const store = JSON.parse(JSON.stringify(initialState)); store.entities.cloud = { ...store.entities.cloud, @@ -233,16 +215,14 @@ describe('components/overage_users_banner', () => { }, }; - renderComponent({ - store, - }); + renderWithContext(, store); expect(screen.getByText(text5PercentageState)).toBeInTheDocument(); expect(screen.getByText(contactSalesTextLink)).toBeInTheDocument(); }); it('should track if the admin click Contact Sales CTA in a 10% overage state', () => { - const store: GlobalState = JSON.parse(JSON.stringify(initialState)); + const store = JSON.parse(JSON.stringify(initialState)); store.entities.cloud = { ...store.entities.cloud, @@ -259,9 +239,7 @@ describe('components/overage_users_banner', () => { }, }; - renderComponent({ - store, - }); + renderWithContext(, store); fireEvent.click(screen.getByText(contactSalesTextLink)); expect(windowSpy).toBeCalledTimes(1); @@ -277,7 +255,7 @@ describe('components/overage_users_banner', () => { }); it('should render the banner because we are over 5% and we have preferences from one old banner', () => { - const store: GlobalState = JSON.parse(JSON.stringify(initialState)); + const store = JSON.parse(JSON.stringify(initialState)); store.entities.cloud = { ...store.entities.cloud, @@ -304,16 +282,14 @@ describe('components/overage_users_banner', () => { }, }; - renderComponent({ - store, - }); + renderWithContext(, store); expect(screen.getByText(text5PercentageState)).toBeInTheDocument(); expect(screen.getByText(contactSalesTextLink)).toBeInTheDocument(); }); it('should save the preferences for 5% banner if admin click on close', () => { - const store: GlobalState = JSON.parse(JSON.stringify(initialState)); + const store = JSON.parse(JSON.stringify(initialState)); store.entities.admin = { ...store.entities.admin, @@ -322,9 +298,7 @@ describe('components/overage_users_banner', () => { }, }; - renderComponent({ - store, - }); + renderWithContext(, store); fireEvent.click(screen.getByRole('link')); @@ -338,7 +312,7 @@ describe('components/overage_users_banner', () => { }); it('should render the banner because we are over 10%', () => { - const store: GlobalState = JSON.parse(JSON.stringify(initialState)); + const store = JSON.parse(JSON.stringify(initialState)); store.entities.cloud = { ...store.entities.cloud, @@ -355,16 +329,14 @@ describe('components/overage_users_banner', () => { }, }; - renderComponent({ - store, - }); + renderWithContext(, store); expect(screen.getByText(text10PercentageState)).toBeInTheDocument(); expect(screen.getByText(contactSalesTextLink)).toBeInTheDocument(); }); it('should track if the admin click Contact Sales CTA in a 10% overage state', () => { - const store: GlobalState = JSON.parse(JSON.stringify(initialState)); + const store = JSON.parse(JSON.stringify(initialState)); store.entities.cloud = { ...store.entities.cloud, @@ -381,9 +353,7 @@ describe('components/overage_users_banner', () => { }, }; - renderComponent({ - store, - }); + renderWithContext(, store); fireEvent.click(screen.getByText(contactSalesTextLink)); expect(windowSpy).toBeCalledTimes(1); @@ -399,7 +369,7 @@ describe('components/overage_users_banner', () => { }); it('should render the warning banner with expansion seats CTA if the license is expandable', () => { - const store: GlobalState = JSON.parse(JSON.stringify(initialState)); + const store = JSON.parse(JSON.stringify(initialState)); store.entities.cloud = { ...store.entities.cloud, @@ -417,15 +387,13 @@ describe('components/overage_users_banner', () => { }, }; - renderComponent({ - store, - }); + renderWithContext(, store); expect(screen.getByText(expandSeatsTextLink)).toBeInTheDocument(); }); it('should track if the admin click expansion seats CTA in a 5% overage state', () => { - const store: GlobalState = JSON.parse(JSON.stringify(initialState)); + const store = JSON.parse(JSON.stringify(initialState)); store.entities.cloud = { ...store.entities.cloud, @@ -443,9 +411,7 @@ describe('components/overage_users_banner', () => { }, }; - renderComponent({ - store, - }); + renderWithContext(, store); fireEvent.click(screen.getByText(expandSeatsTextLink)); expect(windowSpy).toBeCalledTimes(1); @@ -458,7 +424,7 @@ describe('components/overage_users_banner', () => { }); it('should render the error banner with expansion seats CTA if the license is be expandable', () => { - const store: GlobalState = JSON.parse(JSON.stringify(initialState)); + const store = JSON.parse(JSON.stringify(initialState)); store.entities.cloud = { ...store.entities.cloud, @@ -476,15 +442,13 @@ describe('components/overage_users_banner', () => { }, }; - renderComponent({ - store, - }); + renderWithContext(, store); expect(screen.getByText(expandSeatsTextLink)).toBeInTheDocument(); }); it('should track if the admin click expansion seats CTA in a 10% overage state', () => { - const store: GlobalState = JSON.parse(JSON.stringify(initialState)); + const store = JSON.parse(JSON.stringify(initialState)); store.entities.cloud = { ...store.entities.cloud, @@ -502,9 +466,7 @@ describe('components/overage_users_banner', () => { }, }; - renderComponent({ - store, - }); + renderWithContext(, store); fireEvent.click(screen.getByText(expandSeatsTextLink)); expect(windowSpy).toBeCalledTimes(1); diff --git a/webapp/channels/src/components/announcement_bar/payment_announcement_bar/index.test.tsx b/webapp/channels/src/components/announcement_bar/payment_announcement_bar/index.test.tsx index 0332b89820..999e683af4 100644 --- a/webapp/channels/src/components/announcement_bar/payment_announcement_bar/index.test.tsx +++ b/webapp/channels/src/components/announcement_bar/payment_announcement_bar/index.test.tsx @@ -5,7 +5,7 @@ import React from 'react'; import * as cloudActions from 'mattermost-redux/actions/cloud'; -import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {CloudProducts} from 'utils/constants'; import PaymentAnnouncementBar from './'; @@ -68,7 +68,7 @@ describe('PaymentAnnouncementBar', () => { }; it('when most recent payment failed, shows that', () => { - renderWithIntlAndStore(, happyPathStore); + renderWithContext(, happyPathStore); screen.getByText('Your most recent payment failed'); }); @@ -76,7 +76,7 @@ describe('PaymentAnnouncementBar', () => { const store = JSON.parse(JSON.stringify(happyPathStore)); store.entities.cloud.customer.payment_method.exp_year = (new Date()).getFullYear() - 1; store.entities.cloud.subscription.last_invoice.status = 'success'; - renderWithIntlAndStore(, store); + renderWithContext(, store); screen.getByText('Your credit card has expired', {exact: false}); }); @@ -84,14 +84,14 @@ describe('PaymentAnnouncementBar', () => { const store = JSON.parse(JSON.stringify(happyPathStore)); store.entities.cloud.customer = null; store.entities.cloud.subscription.last_invoice.status = 'success'; - renderWithIntlAndStore(, store); + renderWithContext(, store); expect(cloudActions.getCloudCustomer).toHaveBeenCalled(); }); it('when not an admin, does not fetch customer', () => { const store = JSON.parse(JSON.stringify(happyPathStore)); store.entities.users.profiles.me.roles = ''; - renderWithIntlAndStore(, store); + renderWithContext(, store); expect(cloudActions.getCloudCustomer).not.toHaveBeenCalled(); }); }); diff --git a/webapp/channels/src/components/center_message_lock/index.test.tsx b/webapp/channels/src/components/center_message_lock/index.test.tsx index e730186cdb..ba3c81ecdb 100644 --- a/webapp/channels/src/components/center_message_lock/index.test.tsx +++ b/webapp/channels/src/components/center_message_lock/index.test.tsx @@ -2,13 +2,11 @@ // See LICENSE.txt for license information. import React from 'react'; -import {Provider} from 'react-redux'; import {emptyLimits} from 'tests/constants/cloud'; import {emptyTeams} from 'tests/constants/teams'; import {adminUsersState, endUsersState} from 'tests/constants/users'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; -import testConfigureStore from 'tests/test_store'; +import {screen, renderWithContext} from 'tests/react_testing_utils'; import {makeEmptyUsage} from 'utils/limits_test'; import {TestHelper} from 'utils/test_helper'; @@ -102,38 +100,34 @@ const endUserLimitExceeded = { describe('CenterMessageLock', () => { it('returns null if limits not loaded', () => { - renderWithIntl( - - - , + renderWithContext( + , + initialState, ); expect(screen.queryByText('Notify Admin')).not.toBeInTheDocument(); expect(screen.queryByText('Upgrade now')).not.toBeInTheDocument(); }); it('Admins have a call to upgrade', () => { - renderWithIntl( - - - , + renderWithContext( + , + exceededLimitsState, ); screen.getByText('Upgrade now'); }); it('End users have a call to notify admin', () => { - renderWithIntl( - - - , + renderWithContext( + , + endUserLimitExceeded, ); screen.getByText('Notify Admin'); }); it('Filtered messages over one year old display year', () => { - renderWithIntl( - - - , + renderWithContext( + , + exceededLimitsState, ); screen.getByText('January 1, 1970', {exact: false}); }); @@ -145,10 +139,9 @@ describe('CenterMessageLock', () => { const expectedDate = firstOfMonth.toLocaleString('en', {month: 'long', day: 'numeric'}); state.entities.posts.posts.c.create_at = Date.parse(firstOfMonth.toUTCString()); - renderWithIntl( - - - , + renderWithContext( + , + state, ); screen.getByText(expectedDate, {exact: false}); }); @@ -158,13 +151,12 @@ describe('CenterMessageLock', () => { const secondOfMonth = new Date(now + (1000 * 60 * 60 * 24)); const expectedDate = secondOfMonth.toLocaleString('en', {month: 'long', day: 'numeric'}); - renderWithIntl( - - - , + renderWithContext( + , + exceededLimitsStateNoAccessiblePosts, ); screen.getByText(expectedDate, {exact: false}); }); diff --git a/webapp/channels/src/components/channel_info_rhs/about_area_channel.test.tsx b/webapp/channels/src/components/channel_info_rhs/about_area_channel.test.tsx index bf07b42af3..85ccaf64f2 100644 --- a/webapp/channels/src/components/channel_info_rhs/about_area_channel.test.tsx +++ b/webapp/channels/src/components/channel_info_rhs/about_area_channel.test.tsx @@ -2,16 +2,17 @@ // See LICENSE.txt for license information. import React from 'react'; -import {Provider} from 'react-redux'; import type {Channel} from '@mattermost/types/channels'; +import type {DeepPartial} from '@mattermost/types/utilities'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; -import mockStore from 'tests/test_store'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; + +import type {GlobalState} from 'types/store'; import AboutAreaChannel from './about_area_channel'; -const initialState = { +const initialState: DeepPartial = { entities: { channels: { currentChannelId: 'current_channel_id', @@ -38,7 +39,7 @@ const initialState = { name: 'current_user_id__existingId', display_name: 'Default', delete_at: 0, - type: '0', + type: 'D', team_id: 'team_id', }, }, @@ -56,7 +57,7 @@ const initialState = { 'team-id': { id: 'team_id', name: 'team-1', - displayName: 'Team 1', + display_name: 'Team 1', }, }, myMembers: { @@ -102,7 +103,7 @@ const initialState = { general: { license: {IsLicensed: 'false'}, serverVersion: '5.4.0', - config: {PostEditTimeLimit: -1}, + config: {PostEditTimeLimit: '-1'}, }, }, }; @@ -122,28 +123,23 @@ describe('channel_info_rhs/about_area_channel', () => { }, }; - test('should display channel purpose', async () => { - const store = await mockStore(initialState); - - renderWithIntl( - - - , + test('should display channel purpose', () => { + renderWithContext( + , + initialState, ); expect(screen.getByText('my channel purpose')).toBeInTheDocument(); }); - test('should display channel header', async () => { - const store = await mockStore(initialState); - renderWithIntl( - - - , + test('should display channel header', () => { + renderWithContext( + , + initialState, ); expect(screen.getByText('my channel header')).toBeInTheDocument(); diff --git a/webapp/channels/src/components/channel_info_rhs/about_area_dm.test.tsx b/webapp/channels/src/components/channel_info_rhs/about_area_dm.test.tsx index 22e94adf01..5e60389099 100644 --- a/webapp/channels/src/components/channel_info_rhs/about_area_dm.test.tsx +++ b/webapp/channels/src/components/channel_info_rhs/about_area_dm.test.tsx @@ -2,18 +2,19 @@ // See LICENSE.txt for license information. import React from 'react'; -import {Provider} from 'react-redux'; import type {Channel} from '@mattermost/types/channels'; import type {UserProfile} from '@mattermost/types/users'; +import type {DeepPartial} from '@mattermost/types/utilities'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; -import mockStore from 'tests/test_store'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import Constants from 'utils/constants'; +import type {GlobalState} from 'types/store'; + import AboutAreaDM from './about_area_dm'; -const initialState = { +const initialState: DeepPartial = { entities: { channels: { currentChannelId: 'current_channel_id', @@ -40,7 +41,7 @@ const initialState = { name: 'current_user_id__existingId', display_name: 'Default', delete_at: 0, - type: '0', + type: 'D', team_id: 'team_id', }, }, @@ -58,7 +59,7 @@ const initialState = { 'team-id': { id: 'team_id', name: 'team-1', - displayName: 'Team 1', + display_name: 'Team 1', }, }, myMembers: { @@ -104,7 +105,7 @@ const initialState = { general: { license: {IsLicensed: 'false'}, serverVersion: '5.4.0', - config: {PostEditTimeLimit: -1}, + config: {PostEditTimeLimit: '-1'}, }, }, }; @@ -133,50 +134,40 @@ describe('channel_info_rhs/about_area_dm', () => { }, }; - test('should display user avatar', async () => { - const store = await mockStore(initialState); - - renderWithIntl( - - - , + test('should display user avatar', () => { + renderWithContext( + , + initialState, ); expect(screen.getByAltText('my_username profile image')).toBeInTheDocument(); }); - test('should display user name', async () => { - const store = await mockStore(initialState); - - renderWithIntl( - - - , + test('should display user name', () => { + renderWithContext( + , + initialState, ); expect(screen.getByText('my_username')).toBeInTheDocument(); }); - test('should display user position', async () => { - const store = await mockStore(initialState); - - renderWithIntl( - - - , + test('should display user position', () => { + renderWithContext( + , + initialState, ); expect(screen.getByText('my position')).toBeInTheDocument(); }); - test('should display bot tag', async () => { - const store = await mockStore(initialState); + test('should display bot tag', () => { const props = { ...defaultProps, dmUser: { @@ -187,19 +178,17 @@ describe('channel_info_rhs/about_area_dm', () => { }, }, }; - const {container} = renderWithIntl( - - - , + const {container} = renderWithContext( + , + initialState, ); expect(container.querySelector('.Tag')).toBeInTheDocument(); expect(container.querySelector('.Tag')).toHaveTextContent('BOT'); }); - test('should display guest tag', async () => { - const store = await mockStore(initialState); + test('should display guest tag', () => { const props = { ...defaultProps, dmUser: { @@ -207,19 +196,17 @@ describe('channel_info_rhs/about_area_dm', () => { is_guest: true, }, }; - const {container} = renderWithIntl( - - - , + const {container} = renderWithContext( + , + initialState, ); expect(container.querySelector('.Tag')).toBeInTheDocument(); expect(container.querySelector('.Tag')).toHaveTextContent('GUEST'); }); - test('should display bot description', async () => { - const store = await mockStore(initialState); + test('should display bot description', () => { const props = { ...defaultProps, dmUser: { @@ -230,32 +217,28 @@ describe('channel_info_rhs/about_area_dm', () => { }, }, }; - renderWithIntl( - - - , + renderWithContext( + , + initialState, ); expect(screen.getByText('my bot description')).toBeInTheDocument(); }); - test('should display channel header', async () => { - const store = await mockStore(initialState); - renderWithIntl( - - - , + test('should display channel header', () => { + renderWithContext( + , + initialState, ); expect(screen.getByText('my channel header')).toBeInTheDocument(); }); - test('should not display channel header for bots', async () => { - const store = await mockStore(initialState); + test('should not display channel header for bots', () => { const props = { ...defaultProps, dmUser: { @@ -266,12 +249,11 @@ describe('channel_info_rhs/about_area_dm', () => { }, }, }; - renderWithIntl( - - - , + renderWithContext( + , + initialState, ); expect(screen.queryByText('my channel header')).not.toBeInTheDocument(); diff --git a/webapp/channels/src/components/channel_info_rhs/about_area_gm.test.tsx b/webapp/channels/src/components/channel_info_rhs/about_area_gm.test.tsx index 603dbc00ad..2aa6371749 100644 --- a/webapp/channels/src/components/channel_info_rhs/about_area_gm.test.tsx +++ b/webapp/channels/src/components/channel_info_rhs/about_area_gm.test.tsx @@ -2,17 +2,18 @@ // See LICENSE.txt for license information. import React from 'react'; -import {Provider} from 'react-redux'; import type {Channel} from '@mattermost/types/channels'; import type {UserProfile} from '@mattermost/types/users'; +import type {DeepPartial} from '@mattermost/types/utilities'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; -import mockStore from 'tests/test_store'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; + +import type {GlobalState} from 'types/store'; import AboutAreaGM from './about_area_gm'; -const initialState = { +const initialState: DeepPartial = { entities: { channels: { currentChannelId: 'current_channel_id', @@ -39,7 +40,7 @@ const initialState = { name: 'current_user_id__existingId', display_name: 'Default', delete_at: 0, - type: '0', + type: 'D', team_id: 'team_id', }, }, @@ -57,7 +58,7 @@ const initialState = { 'team-id': { id: 'team_id', name: 'team-1', - displayName: 'Team 1', + display_name: 'Team 1', }, }, myMembers: { @@ -105,7 +106,7 @@ const initialState = { general: { license: {IsLicensed: 'false'}, serverVersion: '5.4.0', - config: {PostEditTimeLimit: -1}, + config: {PostEditTimeLimit: '-1'}, }, }, views: { @@ -138,43 +139,35 @@ describe('channel_info_rhs/about_area_gm', () => { }, }; - test('should display users avatar', async () => { - const store = await mockStore(initialState); - - renderWithIntl( - - - , + test('should display users avatar', () => { + renderWithContext( + , + initialState, ); expect(screen.getByAltText('my username profile image')).toBeInTheDocument(); expect(screen.getByAltText('my username2 profile image')).toBeInTheDocument(); }); - test('should display user names', async () => { - const store = await mockStore(initialState); - - renderWithIntl( - - - , + test('should display user names', () => { + renderWithContext( + , + initialState, ); expect(screen.getByLabelText('my username')).toBeInTheDocument(); }); - test('should display channel header', async () => { - const store = await mockStore(initialState); - renderWithIntl( - - - , + test('should display channel header', () => { + renderWithContext( + , + initialState, ); expect(screen.getByText('my channel header')).toBeInTheDocument(); diff --git a/webapp/channels/src/components/channel_info_rhs/channel_info_rhs.test.tsx b/webapp/channels/src/components/channel_info_rhs/channel_info_rhs.test.tsx index 1e46250e8c..79d1a899d6 100644 --- a/webapp/channels/src/components/channel_info_rhs/channel_info_rhs.test.tsx +++ b/webapp/channels/src/components/channel_info_rhs/channel_info_rhs.test.tsx @@ -7,7 +7,7 @@ import type {Channel, ChannelStats} from '@mattermost/types/channels'; import type {Team} from '@mattermost/types/teams'; import type {UserProfile} from '@mattermost/types/users'; -import {act, renderWithIntl} from 'tests/react_testing_utils'; +import {act, renderWithContext} from 'tests/react_testing_utils'; import ChannelInfoRHS from './channel_info_rhs'; @@ -52,7 +52,7 @@ describe('channel_info_rhs', () => { describe('about area', () => { test('should be editable', async () => { - renderWithIntl( + renderWithContext( , @@ -71,7 +71,7 @@ describe('channel_info_rhs', () => { test('should not be editable in archived channel', async () => { props.isArchived = true; - renderWithIntl( + renderWithContext( , diff --git a/webapp/channels/src/components/channel_info_rhs/components/editable_area.test.tsx b/webapp/channels/src/components/channel_info_rhs/components/editable_area.test.tsx index b32aa5e05e..cb2fbead5c 100644 --- a/webapp/channels/src/components/channel_info_rhs/components/editable_area.test.tsx +++ b/webapp/channels/src/components/channel_info_rhs/components/editable_area.test.tsx @@ -3,13 +3,13 @@ import React from 'react'; -import {fireEvent, renderWithIntl, screen} from 'tests/react_testing_utils'; +import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils'; import EditableArea from './editable_area'; describe('channel_info_rhs/components/editable_area', () => { test('should be able to see content', async () => { - renderWithIntl( + renderWithContext( { test('should be able to edit content', async () => { const mockOnEdit = jest.fn(); - renderWithIntl( + renderWithContext( { }); test('should be able prevent edition', async () => { - renderWithIntl( + renderWithContext( { test('should show the empty label when there\'s no content', async () => { const mockOnEdit = jest.fn(); - renderWithIntl( + renderWithContext( { test('should the current channel name', () => { - renderWithIntl( + renderWithContext(
{ test('should call onClose when clicking on the close icon', () => { const onClose = jest.fn(); - renderWithIntl( + renderWithContext(
{ test('should call onClose when clicking on the back icon', () => { const onClose = jest.fn(); - renderWithIntl( + renderWithContext(
{ expect(onClose).toHaveBeenCalled(); }); test('should have archived icon when channel is archived', () => { - const {container} = renderWithIntl( + const {container} = renderWithContext(
{ expect(container.querySelector('i.icon-archive-outline')).toBeInTheDocument(); }); test('should not have archived icon when channel is archived', () => { - const {container} = renderWithIntl( + const {container} = renderWithContext(
{ const props = {...defaultProps}; props.actions.openNotificationSettings = jest.fn(); - renderWithIntl( + renderWithContext( , @@ -65,7 +65,7 @@ describe('channel_info_rhs/menu', () => { channel: {type: Constants.DM_CHANNEL} as Channel, }; - renderWithIntl( + renderWithContext( , @@ -84,7 +84,7 @@ describe('channel_info_rhs/menu', () => { isArchived: true, }; - renderWithIntl( + renderWithContext( , @@ -101,7 +101,7 @@ describe('channel_info_rhs/menu', () => { const props = {...defaultProps}; props.actions.showChannelFiles = jest.fn(); - renderWithIntl( + renderWithContext( , @@ -123,7 +123,7 @@ describe('channel_info_rhs/menu', () => { const props = {...defaultProps}; props.actions.showPinnedPosts = jest.fn(); - renderWithIntl( + renderWithContext( , @@ -145,7 +145,7 @@ describe('channel_info_rhs/menu', () => { const props = {...defaultProps}; props.actions.showChannelMembers = jest.fn(); - renderWithIntl( + renderWithContext( , @@ -169,7 +169,7 @@ describe('channel_info_rhs/menu', () => { channel: {type: Constants.DM_CHANNEL} as Channel, }; - renderWithIntl( + renderWithContext( , diff --git a/webapp/channels/src/components/channel_info_rhs/top_buttons.test.tsx b/webapp/channels/src/components/channel_info_rhs/top_buttons.test.tsx index 4aef6c3998..1cc0ca7669 100644 --- a/webapp/channels/src/components/channel_info_rhs/top_buttons.test.tsx +++ b/webapp/channels/src/components/channel_info_rhs/top_buttons.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; -import {fireEvent, renderWithIntl, screen} from 'tests/react_testing_utils'; +import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils'; import Constants from 'utils/constants'; import TopButtons from './top_buttons'; @@ -47,7 +47,7 @@ describe('channel_info_rhs/top_buttons', () => { }, }; - renderWithIntl( + renderWithContext( , @@ -60,7 +60,7 @@ describe('channel_info_rhs/top_buttons', () => { // Favorited to Favorite toggleFavorite.mockReset(); testProps.isFavorite = true; - renderWithIntl( + renderWithContext( , @@ -83,7 +83,7 @@ describe('channel_info_rhs/top_buttons', () => { }, }; - renderWithIntl( + renderWithContext( , @@ -96,7 +96,7 @@ describe('channel_info_rhs/top_buttons', () => { // Muted to Mute toggleMute.mockReset(); testProps.isMuted = true; - renderWithIntl( + renderWithContext( , @@ -118,7 +118,7 @@ describe('channel_info_rhs/top_buttons', () => { }, }; - renderWithIntl( + renderWithContext( , @@ -134,7 +134,7 @@ describe('channel_info_rhs/top_buttons', () => { channelType: Constants.DM_CHANNEL, }; - renderWithIntl( + renderWithContext( , @@ -149,7 +149,7 @@ describe('channel_info_rhs/top_buttons', () => { canAddPeople: false, }; - renderWithIntl( + renderWithContext( , @@ -159,7 +159,7 @@ describe('channel_info_rhs/top_buttons', () => { }); test('can copy link', () => { - renderWithIntl( + renderWithContext( , @@ -179,7 +179,7 @@ describe('channel_info_rhs/top_buttons', () => { ...topButtonDefaultProps, channelType, }; - renderWithIntl( + renderWithContext( , diff --git a/webapp/channels/src/components/channel_members_rhs/action_bar.test.tsx b/webapp/channels/src/components/channel_members_rhs/action_bar.test.tsx index 486feb8376..a6a9977beb 100644 --- a/webapp/channels/src/components/channel_members_rhs/action_bar.test.tsx +++ b/webapp/channels/src/components/channel_members_rhs/action_bar.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; -import {fireEvent, renderWithIntl, screen} from 'tests/react_testing_utils'; +import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils'; import Constants from 'utils/constants'; import ActionBar from './action_bar'; @@ -33,7 +33,7 @@ describe('channel_members_rhs/action_bar', () => { test('should display the members count', () => { const testProps: Props = {...actionBarDefaultProps}; - renderWithIntl( + renderWithContext( , @@ -45,7 +45,7 @@ describe('channel_members_rhs/action_bar', () => { test('should display Add button', () => { const testProps: Props = {...actionBarDefaultProps}; - renderWithIntl( + renderWithContext( , @@ -59,7 +59,7 @@ describe('channel_members_rhs/action_bar', () => { test('should not display Add button to members', () => { const testProps: Props = {...actionBarDefaultProps, canManageMembers: false}; - renderWithIntl( + renderWithContext( , @@ -71,7 +71,7 @@ describe('channel_members_rhs/action_bar', () => { test('should display Manage', () => { const testProps: Props = {...actionBarDefaultProps}; - renderWithIntl( + renderWithContext( , @@ -88,7 +88,7 @@ describe('channel_members_rhs/action_bar', () => { editing: true, }; - renderWithIntl( + renderWithContext( , @@ -102,7 +102,7 @@ describe('channel_members_rhs/action_bar', () => { test('should not display manage button to members', () => { const testProps: Props = {...actionBarDefaultProps, canManageMembers: false}; - renderWithIntl( + renderWithContext( , diff --git a/webapp/channels/src/components/cloud_usage_modal/index.test.tsx b/webapp/channels/src/components/cloud_usage_modal/index.test.tsx index fc230a320d..5939fa901e 100644 --- a/webapp/channels/src/components/cloud_usage_modal/index.test.tsx +++ b/webapp/channels/src/components/cloud_usage_modal/index.test.tsx @@ -3,13 +3,12 @@ import React from 'react'; import * as redux from 'react-redux'; -import {Provider} from 'react-redux'; import type {Subscription} from '@mattermost/types/cloud'; import type {GlobalState} from '@mattermost/types/store'; +import type {DeepPartial} from '@mattermost/types/utilities'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; -import mockStore from 'tests/test_store'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {Constants} from 'utils/constants'; import {FileSizes} from 'utils/file_utils'; @@ -29,8 +28,8 @@ const freeLimits = { }, }; -function setupStore(hasLimits: boolean) { - const state = { +function setupState(hasLimits: boolean) { + const state: DeepPartial = { entities: { cloud: { limits: { @@ -77,10 +76,9 @@ function setupStore(hasLimits: boolean) { }, } as unknown as GlobalState['entities']['users'], }, - } as GlobalState; - const store = mockStore(state); + }; - return store; + return state; } let props: Props = { @@ -98,36 +96,34 @@ describe('CloudUsageModal', () => { }); test('renders text elements', () => { - const store = setupStore(true); + const state = setupState(true); props.title = 'very important title'; props.description = 'very important description'; - renderWithIntl( - - - , + renderWithContext( + , + state, ); screen.getByText(props.title as string); screen.getByText(props.description as string); }); test('renders primary modal action', () => { - const store = setupStore(true); + const state = setupState(true); props.primaryAction = { message: 'primary action', onClick: jest.fn(), }; - renderWithIntl( - - - , + renderWithContext( + , + state, ); expect(props.primaryAction.onClick).not.toHaveBeenCalled(); screen.getByText(props.primaryAction.message as string).click(); @@ -135,18 +131,17 @@ describe('CloudUsageModal', () => { }); test('renders secondary modal action', () => { - const store = setupStore(true); + const state = setupState(true); props.secondaryAction = { message: 'secondary action', }; - renderWithIntl( - - - , + renderWithContext( + , + state, ); expect(props.onClose).not.toHaveBeenCalled(); screen.getByText(props.secondaryAction.message as string).click(); @@ -154,14 +149,13 @@ describe('CloudUsageModal', () => { }); test('hides footer when there are no actions', () => { - const store = setupStore(true); + const state = setupState(true); - renderWithIntl( - - - , + renderWithContext( + , + state, ); expect(screen.queryByTestId('limits-modal-footer')).not.toBeInTheDocument(); }); diff --git a/webapp/channels/src/components/common/hooks/useShowAdminLimitReached.test.tsx b/webapp/channels/src/components/common/hooks/useShowAdminLimitReached.test.tsx index 5243976287..a7ba394ff5 100644 --- a/webapp/channels/src/components/common/hooks/useShowAdminLimitReached.test.tsx +++ b/webapp/channels/src/components/common/hooks/useShowAdminLimitReached.test.tsx @@ -3,15 +3,12 @@ import React from 'react'; import type {ReactPortal} from 'react'; -import {Provider} from 'react-redux'; - -import configureStore from 'store'; import * as useGetLimitsHook from 'components/common/hooks/useGetLimits'; import * as useGetUsageHook from 'components/common/hooks/useGetUsage'; import ModalController from 'components/modal_controller'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {Preferences} from 'utils/constants'; import {TestHelper} from 'utils/test_helper'; @@ -102,13 +99,13 @@ jest.mock('react-dom', () => ({ describe('useShowAdminLimitReached', () => { it('opens cloud usage modal if admin has just logged in on a cloud instance, the instance has exceeded its message history limit, and the admin has not been shown the modal on log in before.', () => { const state = JSON.parse(JSON.stringify(openModalState)); - const store = configureStore(state); - renderWithIntl( - + renderWithContext( + <>
- , + , + state, ); screen.getByText(modalRegex); }); @@ -125,13 +122,13 @@ describe('useShowAdminLimitReached', () => { ], 'admin', ); - const store = configureStore(state); - renderWithIntl( - + renderWithContext( + <>
- , + , + state, ); expect(screen.queryByText(modalRegex)).not.toBeInTheDocument(); }); @@ -139,13 +136,13 @@ describe('useShowAdminLimitReached', () => { it('does not open cloud usage modal if workspace has not exceeded limit', () => { const state = JSON.parse(JSON.stringify(openModalState)); state.entities.usage.messages.history = 10000; - const store = configureStore(state); - renderWithIntl( - + renderWithContext( + <>
- , + , + state, ); expect(screen.queryByText(modalRegex)).not.toBeInTheDocument(); }); @@ -153,13 +150,13 @@ describe('useShowAdminLimitReached', () => { it('does not open cloud usage modal if there is no message limit', () => { const state = JSON.parse(JSON.stringify(openModalState)); state.entities.cloud.limits = {}; - const store = configureStore(state); - renderWithIntl( - + renderWithContext( + <>
- , + , + state, ); expect(screen.queryByText(modalRegex)).not.toBeInTheDocument(); }); @@ -167,13 +164,13 @@ describe('useShowAdminLimitReached', () => { it('does not open cloud usage modal if there is no message limit', () => { const state = JSON.parse(JSON.stringify(openModalState)); state.entities.cloud.limits = {}; - const store = configureStore(state); - renderWithIntl( - + renderWithContext( + <>
- , + , + state, ); expect(screen.queryByText(modalRegex)).not.toBeInTheDocument(); }); @@ -181,13 +178,13 @@ describe('useShowAdminLimitReached', () => { it('does not open cloud usage modal if admin was already logged in', () => { const state = JSON.parse(JSON.stringify(openModalState)); state.views.admin.needsLoggedInLimitReachedCheck = false; - const store = configureStore(state); - renderWithIntl( - + renderWithContext( + <>
- , + , + state, ); expect(screen.queryByText(modalRegex)).not.toBeInTheDocument(); }); @@ -195,17 +192,17 @@ describe('useShowAdminLimitReached', () => { it('does not open cloud usage modal if limits are not yet loaded', () => { const state = JSON.parse(JSON.stringify(openModalState)); state.entities.cloud.limits.limitsLoaded = false; - const store = configureStore(state); jest.spyOn(useGetLimitsHook, 'default').mockImplementation(() => ([ state.entities.cloud.limits.limits, false, ])); - renderWithIntl( - + renderWithContext( + <>
- , + , + state, ); expect(screen.queryByText(modalRegex)).not.toBeInTheDocument(); }); @@ -216,14 +213,14 @@ describe('useShowAdminLimitReached', () => { history: 0, historyLoaded: false, }; - const store = configureStore(state); jest.spyOn(useGetUsageHook, 'default').mockImplementation(() => state.entities.usage); - renderWithIntl( - + renderWithContext( + <>
- , + , + state, ); expect(screen.queryByText(modalRegex)).not.toBeInTheDocument(); }); diff --git a/webapp/channels/src/components/convert_gm_to_channel_modal/convert_gm_to_channel_modal.test.tsx b/webapp/channels/src/components/convert_gm_to_channel_modal/convert_gm_to_channel_modal.test.tsx index 024452c066..2e2601b4ce 100644 --- a/webapp/channels/src/components/convert_gm_to_channel_modal/convert_gm_to_channel_modal.test.tsx +++ b/webapp/channels/src/components/convert_gm_to_channel_modal/convert_gm_to_channel_modal.test.tsx @@ -17,7 +17,7 @@ import {Preferences} from 'mattermost-redux/constants'; import ConvertGmToChannelModal from 'components/convert_gm_to_channel_modal/convert_gm_to_channel_modal'; import TestHelper from 'packages/mattermost-redux/test/test_helper'; -import {renderWithFullContext, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import type {GlobalState} from 'types/store'; @@ -61,7 +61,7 @@ describe('component/ConvertGmToChannelModal', () => { {id: 'team_id_2', display_name: 'Team 2', name: 'team_2'}, ]); - renderWithFullContext( + renderWithContext( , baseState, ); @@ -87,7 +87,7 @@ describe('component/ConvertGmToChannelModal', () => { {id: 'team_id_1', display_name: 'Team 1', name: 'team_1'}, ]); - renderWithFullContext( + renderWithContext( , baseState, ); @@ -110,7 +110,7 @@ describe('component/ConvertGmToChannelModal', () => { get('/channels/channel_id_1/common_teams'). reply(200, []); - renderWithFullContext( + renderWithContext( , baseState, ); @@ -138,7 +138,7 @@ describe('component/ConvertGmToChannelModal', () => { baseProps.actions.convertGroupMessageToPrivateChannel.mockResolvedValueOnce({}); - renderWithFullContext( + renderWithContext( , baseState, ); @@ -191,7 +191,7 @@ describe('component/ConvertGmToChannelModal', () => { }, }); - renderWithFullContext( + renderWithContext( , baseState, ); diff --git a/webapp/channels/src/components/delinquency_modal/delinquency_modal.test.tsx b/webapp/channels/src/components/delinquency_modal/delinquency_modal.test.tsx index eba181d92d..feef3fe25f 100644 --- a/webapp/channels/src/components/delinquency_modal/delinquency_modal.test.tsx +++ b/webapp/channels/src/components/delinquency_modal/delinquency_modal.test.tsx @@ -3,22 +3,15 @@ import React from 'react'; import type {ComponentProps} from 'react'; -import * as reactRedux from 'react-redux'; import {savePreferences} from 'mattermost-redux/actions/preferences'; import {trackEvent} from 'actions/telemetry_actions'; -import configureStore from 'store'; -import {fireEvent, renderWithIntl, screen} from 'tests/react_testing_utils'; +import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils'; import {ModalIdentifiers, Preferences, TELEMETRY_CATEGORIES} from 'utils/constants'; -import DeliquencyModal from './delinquency_modal'; - -type RenderComponentArgs = { - props?: Partial>; - store?: any; -} +import DelinquencyModal from './delinquency_modal'; jest.mock('mattermost-redux/actions/preferences', () => ({ savePreferences: jest.fn(), @@ -38,7 +31,7 @@ jest.mock('react-redux', () => ({ })); describe('components/deliquency_modal/deliquency_modal', () => { - const initialStates = { + const initialState = { views: { modals: { modalState: { @@ -50,7 +43,7 @@ describe('components/deliquency_modal/deliquency_modal', () => { closeModal: () => {}, isAdminConsole: false, }, - dialogType: React.Fragment, + dialogType: React.Fragment as any, }, }, showLaunchingWorkspace: false, @@ -66,38 +59,23 @@ describe('components/deliquency_modal/deliquency_modal', () => { }, }; - const renderComponent = ({props = {}, store = configureStore(initialStates)}: RenderComponentArgs) => { - const defaultProps: ComponentProps = { - closeModal: jest.fn(), - onExited: jest.fn(), - planName: 'planName', - isAdminConsole: false, - }; - - return renderWithIntl( - - - , - ); + const baseProps: ComponentProps = { + closeModal: jest.fn(), + onExited: jest.fn(), + planName: 'planName', + isAdminConsole: false, }; - afterEach(() => { - jest.clearAllMocks(); - }); - it('should save preferences and track stayOnFremium if admin click Stay on Free', () => { - renderComponent({}); + renderWithContext(, initialState); fireEvent.click(screen.getByText('Stay on Free')); expect(savePreferences).toBeCalledTimes(1); - expect(savePreferences).toBeCalledWith(initialStates.entities.users.profiles.current_user_id.id, [{ + expect(savePreferences).toBeCalledWith(initialState.entities.users.profiles.current_user_id.id, [{ category: Preferences.DELINQUENCY_MODAL_CONFIRMED, name: ModalIdentifiers.DELINQUENCY_MODAL_DOWNGRADE, - user_id: initialStates.entities.users.profiles.current_user_id.id, + user_id: initialState.entities.users.profiles.current_user_id.id, value: 'stayOnFremium', }]); @@ -106,15 +84,15 @@ describe('components/deliquency_modal/deliquency_modal', () => { }); it('should save preferences and track update Billing if admin click Update Billing', () => { - renderComponent({}); + renderWithContext(, initialState); fireEvent.click(screen.getByText('Update Billing')); expect(savePreferences).toBeCalledTimes(1); - expect(savePreferences).toBeCalledWith(initialStates.entities.users.profiles.current_user_id.id, [{ + expect(savePreferences).toBeCalledWith(initialState.entities.users.profiles.current_user_id.id, [{ category: Preferences.DELINQUENCY_MODAL_CONFIRMED, name: ModalIdentifiers.DELINQUENCY_MODAL_DOWNGRADE, - user_id: initialStates.entities.users.profiles.current_user_id.id, + user_id: initialState.entities.users.profiles.current_user_id.id, value: 'updateBilling', }]); diff --git a/webapp/channels/src/components/delinquency_modal/delinquency_modal_controller.test.tsx b/webapp/channels/src/components/delinquency_modal/delinquency_modal_controller.test.tsx index 3af0d98a5b..a132cd5599 100644 --- a/webapp/channels/src/components/delinquency_modal/delinquency_modal_controller.test.tsx +++ b/webapp/channels/src/components/delinquency_modal/delinquency_modal_controller.test.tsx @@ -2,32 +2,29 @@ // See LICENSE.txt for license information. import React from 'react'; -import * as reactRedux from 'react-redux'; + +import type {DeepPartial} from '@mattermost/types/utilities'; import * as cloudActions from 'mattermost-redux/actions/cloud'; import * as StorageSelectors from 'selectors/storage'; -import configureStore from 'store'; import ModalController from 'components/modal_controller'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {CloudProducts, ModalIdentifiers, Preferences} from 'utils/constants'; import {TestHelper} from 'utils/test_helper'; +import type {GlobalState} from 'types/store'; + import DelinquencyModalController from './index'; jest.mock('selectors/storage'); (StorageSelectors.makeGetItem as jest.Mock).mockReturnValue(() => false); -jest.mock('react-dom', () => ({ - ...jest.requireActual('react-dom'), - createPortal: (node: any) => node, -})); - describe('components/delinquency_modal/delinquency_modal_controller', () => { - const initialState = { + const initialState: DeepPartial = { views: { modals: { modalState: {}, @@ -50,31 +47,31 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { }, }, cloud: { - subscription: { + subscription: TestHelper.getSubscriptionMock({ product_id: 'test_prod_1', trial_end_at: 1652807380, is_free_trial: 'false', delinquent_since: 1652807380, // may 17 2022 - }, + }), products: { - test_prod_1: { + test_prod_1: TestHelper.getProductMock({ id: 'test_prod_1', sku: CloudProducts.STARTER, price_per_seat: 0, name: 'testProd1', - }, - test_prod_2: { + }), + test_prod_2: TestHelper.getProductMock({ id: 'test_prod_2', sku: CloudProducts.ENTERPRISE, price_per_seat: 0, name: 'testProd2', - }, - test_prod_3: { + }), + test_prod_3: TestHelper.getProductMock({ id: 'test_prod_3', sku: CloudProducts.PROFESSIONAL, price_per_seat: 0, name: 'testProd3', - }, + }), }, }, }, @@ -83,14 +80,13 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { it('Should show the modal if the admin hasn\'t a preference', () => { jest.useFakeTimers().setSystemTime(new Date('2022-12-20')); - const store = configureStore(initialState); - - renderWithIntl( - + renderWithContext( + <>
- , + , + initialState, ); expect(screen.queryByText('Your workspace has been downgraded')).toBeInTheDocument(); @@ -110,14 +106,13 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { jest.useFakeTimers().setSystemTime(new Date('2022-12-20')); - const store = configureStore(state); - - renderWithIntl( - + renderWithContext( + <>
- , + , + state, ); expect(screen.queryByText('Your workspace has been downgraded')).not.toBeInTheDocument(); @@ -126,14 +121,13 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { it('Should show the modal if the deliquency_since is equal 90 days', () => { jest.useFakeTimers().setSystemTime(new Date('2022-08-16')); - const store = configureStore(initialState); - - renderWithIntl( - + renderWithContext( + <>
- , + , + initialState, ); expect(screen.queryByText('Your workspace has been downgraded')).toBeInTheDocument(); @@ -142,14 +136,13 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { it('Should show the modal if the deliquency_since is more than 90 days', () => { jest.useFakeTimers().setSystemTime(new Date('2022-08-17')); - const store = configureStore(initialState); - - renderWithIntl( - + renderWithContext( + <>
- , + , + initialState, ); expect(screen.queryByText('Your workspace has been downgraded')).toBeInTheDocument(); @@ -158,14 +151,13 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { it('Shouldn\'t show the modal if the deliqeuncy_since is less than 90 days', () => { jest.useFakeTimers().setSystemTime(new Date('2022-08-15')); - const store = configureStore(initialState); - - renderWithIntl( - + renderWithContext( + <>
- , + , + initialState, ); expect(screen.queryByText('Your workspace has been downgraded')).not.toBeInTheDocument(); @@ -174,14 +166,13 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { it('Should show the modal if the license is cloud', () => { jest.useFakeTimers().setSystemTime(new Date('2022-08-17')); - const store = configureStore(initialState); - - renderWithIntl( - + renderWithContext( + <>
- , + , + initialState, ); expect(screen.queryByText('Your workspace has been downgraded')).toBeInTheDocument(); @@ -196,14 +187,13 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { jest.useFakeTimers().setSystemTime(new Date('2022-12-20')); - const store = configureStore(state); - - renderWithIntl( - + renderWithContext( + <>
- , + , + state, ); expect(screen.queryByText('Your workspace has been downgraded')).not.toBeInTheDocument(); @@ -218,14 +208,13 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { jest.useFakeTimers().setSystemTime(new Date('2022-12-20')); - const store = configureStore(state); - - renderWithIntl( - + renderWithContext( + <>
- , + , + state, ); expect(screen.queryByText('Your workspace has been downgraded')).not.toBeInTheDocument(); @@ -234,14 +223,13 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { it('Should show the modal if the user is an admin', () => { jest.useFakeTimers().setSystemTime(new Date('2022-08-17')); - const store = configureStore(initialState); - - renderWithIntl( - + renderWithContext( + <>
- , + , + initialState, ); expect(screen.queryByText('Your workspace has been downgraded')).toBeInTheDocument(); @@ -257,14 +245,13 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { }; jest.useFakeTimers().setSystemTime(new Date('2022-12-20')); - const store = configureStore(state); - - renderWithIntl( - + renderWithContext( + <>
- , + , + state, ); expect(screen.queryByText('Your workspace has been downgraded')).not.toBeInTheDocument(); @@ -273,14 +260,13 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { it('Should show the modal if the user just logged in', () => { jest.useFakeTimers().setSystemTime(new Date('2022-08-17')); - const store = configureStore(initialState); - - renderWithIntl( - + renderWithContext( + <>
- , + , + initialState, ); expect(screen.queryByText('Your workspace has been downgraded')).toBeInTheDocument(); @@ -289,14 +275,13 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { (StorageSelectors.makeGetItem as jest.Mock).mockReturnValue(() => true); jest.useFakeTimers().setSystemTime(new Date('2022-08-17')); - const store = configureStore(initialState); - - renderWithIntl( - + renderWithContext( + <>
- , + , + initialState, ); expect(screen.queryByText('Your workspace has been downgraded')).not.toBeInTheDocument(); @@ -308,15 +293,15 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { const newState = JSON.parse(JSON.stringify(initialState)); newState.entities.cloud.products = {}; - const store = configureStore(newState); const getCloudProds = jest.spyOn(cloudActions, 'getCloudProducts').mockImplementationOnce(jest.fn().mockReturnValue({type: 'mock_impl'})); - renderWithIntl( - + renderWithContext( + <>
- , + , + newState, ); expect(getCloudProds).toHaveBeenCalledTimes(1); @@ -332,15 +317,15 @@ describe('components/delinquency_modal/delinquency_modal_controller', () => { Cloud: 'false', }; - const store = configureStore(newState); const getCloudProds = jest.spyOn(cloudActions, 'getCloudProducts').mockImplementationOnce(jest.fn().mockReturnValue({type: 'mock_impl'})); - renderWithIntl( - + renderWithContext( + <>
- , + , + newState, ); expect(getCloudProds).toHaveBeenCalledTimes(0); diff --git a/webapp/channels/src/components/delinquency_modal/freemium_modal.test.tsx b/webapp/channels/src/components/delinquency_modal/freemium_modal.test.tsx index 82c3baa947..0ef03a791b 100644 --- a/webapp/channels/src/components/delinquency_modal/freemium_modal.test.tsx +++ b/webapp/channels/src/components/delinquency_modal/freemium_modal.test.tsx @@ -3,23 +3,20 @@ import React from 'react'; import type {ComponentProps} from 'react'; -import * as reactRedux from 'react-redux'; + +import type {DeepPartial} from '@mattermost/types/utilities'; import {trackEvent} from 'actions/telemetry_actions'; -import configureStore from 'store'; import useGetMultiplesExceededCloudLimit from 'components/common/hooks/useGetMultiplesExceededCloudLimit'; -import {fireEvent, renderWithIntl, screen} from 'tests/react_testing_utils'; +import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils'; import {ModalIdentifiers, TELEMETRY_CATEGORIES} from 'utils/constants'; import {LimitTypes} from 'utils/limits'; -import {FreemiumModal} from './freemium_modal'; +import type {GlobalState} from 'types/store'; -type RenderComponentArgs = { - props?: Partial>; - store?: any; -} +import {FreemiumModal} from './freemium_modal'; jest.mock('actions/telemetry_actions', () => ({ trackEvent: jest.fn(), @@ -33,7 +30,7 @@ jest.mock('react-redux', () => ({ jest.mock('components/common/hooks/useGetMultiplesExceededCloudLimit'); describe('components/delinquency_modal/freemium_modal', () => { - const initialStates = { + const initialState: DeepPartial = { views: { modals: { modalState: { @@ -45,7 +42,7 @@ describe('components/delinquency_modal/freemium_modal', () => { closeModal: () => {}, isAdminConsole: false, }, - dialogType: React.Fragment, + dialogType: React.Fragment as any, }, }, showLaunchingWorkspace: false, @@ -61,36 +58,20 @@ describe('components/delinquency_modal/freemium_modal', () => { }, }; - const renderComponent = ({props = {}, store = configureStore(initialStates)}: RenderComponentArgs) => { - const defaultProps: ComponentProps = { - onClose: jest.fn(), - planName: 'planName', - isAdminConsole: false, - onExited: jest.fn(), - }; - - return renderWithIntl( - - - , - ); + const planName = 'Testing'; + const baseProps: ComponentProps = { + onClose: jest.fn(), + planName, + isAdminConsole: false, + onExited: jest.fn(), }; - afterEach(() => { - jest.clearAllMocks(); - }); - it('should track reactivate plan if admin click Re activate plan', () => { - const planName = 'Testing'; (useGetMultiplesExceededCloudLimit as jest.Mock).mockReturnValue([LimitTypes.fileStorage]); - renderComponent({ - props: { - planName, - }, - }); + renderWithContext( + , + initialState, + ); fireEvent.click(screen.getByText(`Re-activate ${planName}`)); @@ -102,13 +83,11 @@ describe('components/delinquency_modal/freemium_modal', () => { }); it('should not show reactivate plan if admin limits isn\'t surpassed', () => { - const planName = 'Testing'; (useGetMultiplesExceededCloudLimit as jest.Mock).mockReturnValue([]); - renderComponent({ - props: { - planName, - }, - }); + renderWithContext( + , + initialState, + ); expect(screen.queryByText(`Re-activate ${planName}`)).not.toBeInTheDocument(); @@ -116,42 +95,33 @@ describe('components/delinquency_modal/freemium_modal', () => { }); it('should display message history text when only message limit is surpassed', () => { - const planName = 'Testing'; - (useGetMultiplesExceededCloudLimit as jest.Mock).mockReturnValue([LimitTypes.messageHistory]); - renderComponent({ - props: { - planName, - }, - }); + renderWithContext( + , + initialState, + ); expect(screen.queryByText(`Re-activate ${planName}`)).toBeInTheDocument(); expect(screen.getByText('Some of your workspace\'s message history are no longer accessible. Upgrade to a paid plan and get unlimited access to your message history.')).toBeInTheDocument(); }); it('should display storage text when only storage is surpassed', () => { - const planName = 'Testing'; - (useGetMultiplesExceededCloudLimit as jest.Mock).mockReturnValue([LimitTypes.fileStorage]); - renderComponent({ - props: { - planName, - }, - }); + renderWithContext( + , + initialState, + ); expect(screen.queryByText(`Re-activate ${planName}`)).toBeInTheDocument(); expect(screen.getByText('Some of your workspace\'s files are no longer accessible. Upgrade to a paid plan and get unlimited access to your files.')).toBeInTheDocument(); }); it('should display update to paid plan text when only multiples limits is surpassed', () => { - const planName = 'Testing'; - (useGetMultiplesExceededCloudLimit as jest.Mock).mockReturnValue([LimitTypes.messageHistory, LimitTypes.fileStorage]); - renderComponent({ - props: { - planName, - }, - }); + renderWithContext( + , + initialState, + ); expect(screen.queryByText(`Re-activate ${planName}`)).toBeInTheDocument(); expect(screen.getByText('Your workspace has reached free plan limits. Upgrade to a paid plan.')).toBeInTheDocument(); diff --git a/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap b/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap index 1d6fe94b37..f457fb6834 100644 --- a/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap +++ b/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap @@ -102,8 +102,10 @@ Object { "queryByTestId": [Function], "queryByText": [Function], "queryByTitle": [Function], + "replaceStoreState": [Function], "rerender": [Function], "unmount": [Function], + "updateStoreState": [Function], } `; diff --git a/webapp/channels/src/components/dot_menu/dot_menu.test.tsx b/webapp/channels/src/components/dot_menu/dot_menu.test.tsx index fb2d484ecf..bc9998d75a 100644 --- a/webapp/channels/src/components/dot_menu/dot_menu.test.tsx +++ b/webapp/channels/src/components/dot_menu/dot_menu.test.tsx @@ -7,7 +7,7 @@ import type {PostType} from '@mattermost/types/posts'; import type {DeepPartial} from '@mattermost/types/utilities'; import {shallowWithIntl} from 'tests/helpers/intl-test-helper'; -import {fireEvent, renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils'; import {Locations} from 'utils/constants'; import {TestHelper} from 'utils/test_helper'; @@ -172,7 +172,7 @@ describe('components/dot_menu/DotMenu', () => { canEdit: true, canDelete: true, }; - const wrapper = renderWithIntlAndStore( + const wrapper = renderWithContext( , initialState, ); @@ -185,7 +185,7 @@ describe('components/dot_menu/DotMenu', () => { ...baseProps, location: Locations.CENTER, }; - renderWithIntlAndStore( + renderWithContext( , initialState, ); @@ -200,7 +200,7 @@ describe('components/dot_menu/DotMenu', () => { ...baseProps, channelIsArchived: true, }; - renderWithIntlAndStore( + renderWithContext( , initialState, ); @@ -215,7 +215,7 @@ describe('components/dot_menu/DotMenu', () => { ...baseProps, location: Locations.SEARCH, }; - renderWithIntlAndStore( + renderWithContext( , initialState, ); @@ -235,7 +235,7 @@ describe('components/dot_menu/DotMenu', () => { ...baseProps, ...caseProps, }; - renderWithIntlAndStore( + renderWithContext( , initialState, ); @@ -256,7 +256,7 @@ describe('components/dot_menu/DotMenu', () => { ...baseProps, ...caseProps, }; - renderWithIntlAndStore( + renderWithContext( , initialState, ); @@ -277,7 +277,7 @@ describe('components/dot_menu/DotMenu', () => { ...caseProps, location: Locations.RHS_ROOT, }; - renderWithIntlAndStore( + renderWithContext( , initialState, ); diff --git a/webapp/channels/src/components/error_page/error_page.test.tsx b/webapp/channels/src/components/error_page/error_page.test.tsx index fc0d4c750d..e165be3811 100644 --- a/webapp/channels/src/components/error_page/error_page.test.tsx +++ b/webapp/channels/src/components/error_page/error_page.test.tsx @@ -2,11 +2,10 @@ // See LICENSE.txt for license information. import React from 'react'; -import {BrowserRouter} from 'react-router-dom'; import type {GlobalState} from '@mattermost/types/store'; -import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {ErrorPageTypes} from 'utils/constants'; import {TestHelper} from 'utils/test_helper'; @@ -14,15 +13,13 @@ import ErrorPage from './error_page'; describe('ErrorPage', () => { it('displays cloud archived page correctly', () => { - renderWithIntlAndStore( + renderWithContext( ( - - - + ), { entities: { diff --git a/webapp/channels/src/components/external_link/external_link.test.tsx b/webapp/channels/src/components/external_link/external_link.test.tsx index 5ea1e9fa3c..a8b30ed33b 100644 --- a/webapp/channels/src/components/external_link/external_link.test.tsx +++ b/webapp/channels/src/components/external_link/external_link.test.tsx @@ -6,7 +6,7 @@ import React from 'react'; import {Provider} from 'react-redux'; import type {DeepPartial} from 'redux'; -import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import mockStore from 'tests/test_store'; import type {GlobalState} from 'types/store'; @@ -55,7 +55,7 @@ describe('components/external_link', () => { }, }, }; - renderWithIntlAndStore( + renderWithContext( {'Click Me'} , @@ -81,7 +81,7 @@ describe('components/external_link', () => { }, }, }; - renderWithIntlAndStore( + renderWithContext( {'Click Me'} , @@ -107,7 +107,7 @@ describe('components/external_link', () => { }, }, }; - renderWithIntlAndStore( + renderWithContext( {'Click Me'} , @@ -133,7 +133,7 @@ describe('components/external_link', () => { }, }, }; - renderWithIntlAndStore( + renderWithContext( { }, }, }; - renderWithIntlAndStore( + renderWithContext( diff --git a/webapp/channels/src/components/file_attachment/file_attachment.test.tsx b/webapp/channels/src/components/file_attachment/file_attachment.test.tsx index 3c2e53c5d1..6eb6d4d113 100644 --- a/webapp/channels/src/components/file_attachment/file_attachment.test.tsx +++ b/webapp/channels/src/components/file_attachment/file_attachment.test.tsx @@ -5,9 +5,10 @@ import {shallow} from 'enzyme'; import React from 'react'; import type {GlobalState} from '@mattermost/types/store'; +import type {DeepPartial} from '@mattermost/types/utilities'; import {mountWithIntl} from 'tests/helpers/intl-test-helper'; -import {renderWithIntl, renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import FileAttachment from './file_attachment'; @@ -69,7 +70,7 @@ describe('FileAttachment', () => { }); test('non archived file does not show archived elements', () => { - const reduxState = { + const reduxState: DeepPartial = { entities: { general: { config: {}, @@ -78,15 +79,15 @@ describe('FileAttachment', () => { currentUserId: 'currentUserId', }, }, - } as GlobalState; - renderWithIntlAndStore(, reduxState); + }; + renderWithContext(, reduxState); expect(screen.queryByTestId('archived-file-icon')).not.toBeInTheDocument(); expect(screen.queryByText(/This file is archived/)).not.toBeInTheDocument(); }); test('non archived file does not show archived elements in compact display mode', () => { - renderWithIntl(); + renderWithContext(); expect(screen.queryByTestId('archived-file-icon')).not.toBeInTheDocument(); expect(screen.queryByText(/archived/)).not.toBeInTheDocument(); @@ -188,7 +189,7 @@ describe('FileAttachment', () => { }, compactDisplay: true, }; - renderWithIntl(); + renderWithContext(); screen.getByTestId('archived-file-icon'); screen.getByText(baseProps.fileInfo.name); screen.getByText(/archived/); @@ -203,7 +204,7 @@ describe('FileAttachment', () => { }, compactDisplay: false, }; - renderWithIntl(); + renderWithContext(); screen.getByTestId('archived-file-icon'); screen.getByText(baseProps.fileInfo.name); screen.getByText(/This file is archived/); diff --git a/webapp/channels/src/components/header_footer_template/__snapshots__/header_footer_template.test.tsx.snap b/webapp/channels/src/components/header_footer_template/__snapshots__/header_footer_template.test.tsx.snap index 4665eb90be..4e95953834 100644 --- a/webapp/channels/src/components/header_footer_template/__snapshots__/header_footer_template.test.tsx.snap +++ b/webapp/channels/src/components/header_footer_template/__snapshots__/header_footer_template.test.tsx.snap @@ -1,10 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`components/HeaderFooterTemplate should match snapshot with about link 1`] = ` -
+
@@ -59,10 +56,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with about link 1 `; exports[`components/HeaderFooterTemplate should match snapshot with all links 1`] = ` -
+
@@ -147,10 +141,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with all links 1` `; exports[`components/HeaderFooterTemplate should match snapshot with children 1`] = ` -
+
@@ -198,10 +189,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with children 1`] `; exports[`components/HeaderFooterTemplate should match snapshot with help link 1`] = ` -
+
@@ -256,10 +244,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with help link 1` `; exports[`components/HeaderFooterTemplate should match snapshot with privacy policy link 1`] = ` -
+
@@ -314,10 +299,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with privacy poli `; exports[`components/HeaderFooterTemplate should match snapshot with term of service link 1`] = ` -
+
@@ -372,10 +354,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with term of serv `; exports[`components/HeaderFooterTemplate should match snapshot without children 1`] = ` -
+
@@ -419,10 +398,7 @@ exports[`components/HeaderFooterTemplate should match snapshot without children `; exports[`components/HeaderFooterTemplate should set classes on body and #root on mount and unset on unmount 1`] = ` -
+
@@ -506,9 +482,4 @@ exports[`components/HeaderFooterTemplate should set classes on body and #root on
`; -exports[`components/HeaderFooterTemplate should set classes on body and #root on mount and unset on unmount 2`] = ` -
-`; +exports[`components/HeaderFooterTemplate should set classes on body and #root on mount and unset on unmount 2`] = `
`; diff --git a/webapp/channels/src/components/header_footer_template/header_footer_template.test.tsx b/webapp/channels/src/components/header_footer_template/header_footer_template.test.tsx index 4234bd7019..52e3dbc20e 100644 --- a/webapp/channels/src/components/header_footer_template/header_footer_template.test.tsx +++ b/webapp/channels/src/components/header_footer_template/header_footer_template.test.tsx @@ -5,7 +5,8 @@ import React from 'react'; import type {DeepPartial} from '@mattermost/types/utilities'; -import {renderWithIntlAndStore} from 'tests/react_testing_utils'; +import mergeObjects from 'packages/mattermost-redux/test/merge_objects'; +import {renderWithContext} from 'tests/react_testing_utils'; import type {GlobalState} from 'types/store'; @@ -22,7 +23,7 @@ describe('components/HeaderFooterTemplate', () => { global.Date = mock as any; } - const state = { + const initialState: DeepPartial = { entities: { general: { config: {}, @@ -42,7 +43,7 @@ describe('components/HeaderFooterTemplate', () => { team1: { id: 'team1', name: 'team-1', - displayName: 'Team 1', + display_name: 'Team 1', }, }, myMembers: { @@ -53,19 +54,6 @@ describe('components/HeaderFooterTemplate', () => { storage: { initialized: true, }, - } as unknown as GlobalState; - - const renderComponent = (component: React.ReactNode, state: DeepPartial) => { - const rootDiv = document.createElement('div'); - rootDiv.id = 'root'; - rootDiv.setAttribute('data-testid', 'root-testid'); - - return renderWithIntlAndStore( - component, - state, - 'en', - rootDiv, - ); }; beforeEach(() => { @@ -77,69 +65,113 @@ describe('components/HeaderFooterTemplate', () => { }); test('should match snapshot without children', () => { - const {container} = renderComponent(, state as DeepPartial); + const {container} = renderWithContext(, initialState); expect(container).toMatchSnapshot(); }); test('should match snapshot with children', () => { - const {container} = renderComponent( + const {container} = renderWithContext(

{'test'}

, - state as DeepPartial, + initialState, ); expect(container).toMatchSnapshot(); }); test('should match snapshot with help link', () => { - state.entities.general.config = {HelpLink: 'http://testhelplink'}; + const state = mergeObjects(initialState, { + entities: { + general: { + config: { + HelpLink: 'http://testhelplink', + }, + }, + }, + }); - const {container} = renderComponent(, state as DeepPartial); + const {container} = renderWithContext(, state); expect(container).toMatchSnapshot(); }); test('should match snapshot with term of service link', () => { - state.entities.general.config = {TermsOfServiceLink: 'http://testtermsofservicelink'}; + const state = mergeObjects(initialState, { + entities: { + general: { + config: { + TermsOfServiceLink: 'http://testtermsofservicelink', + }, + }, + }, + }); - const {container} = renderComponent(, state as DeepPartial); + const {container} = renderWithContext(, state); expect(container).toMatchSnapshot(); }); test('should match snapshot with privacy policy link', () => { - state.entities.general.config = {PrivacyPolicyLink: 'http://testprivacypolicylink'}; + const state = mergeObjects(initialState, { + entities: { + general: { + config: { + PrivacyPolicyLink: 'http://testprivacypolicylink', + }, + }, + }, + }); - const {container} = renderComponent(, state as DeepPartial); + const {container} = renderWithContext(, state); expect(container).toMatchSnapshot(); }); test('should match snapshot with about link', () => { - state.entities.general.config = {AboutLink: 'http://testaboutlink'}; + const state = mergeObjects(initialState, { + entities: { + general: { + config: { + AboutLink: 'http://testaboutlink', + }, + }, + }, + }); - const {container} = renderComponent(, state as DeepPartial); + const {container} = renderWithContext(, state); expect(container).toMatchSnapshot(); }); test('should match snapshot with all links', () => { - state.entities.general.config = { - HelpLink: 'http://testhelplink', - TermsOfServiceLink: 'http://testtermsofservicelink', - PrivacyPolicyLink: 'http://testprivacypolicylink', - AboutLink: 'http://testaboutlink', - }; + const state = mergeObjects(initialState, { + entities: { + general: { + config: { + HelpLink: 'http://testhelplink', + TermsOfServiceLink: 'http://testtermsofservicelink', + PrivacyPolicyLink: 'http://testprivacypolicylink', + AboutLink: 'http://testaboutlink', + }, + }, + }, + }); - const {container} = renderComponent(, state as DeepPartial); + const {container} = renderWithContext(, state); expect(container).toMatchSnapshot(); }); test('should set classes on body and #root on mount and unset on unmount', () => { - state.entities.general.config = { - HelpLink: 'http://testhelplink', - TermsOfServiceLink: 'http://testtermsofservicelink', - PrivacyPolicyLink: 'http://testprivacypolicylink', - AboutLink: 'http://testaboutlink', - }; + const state = mergeObjects(initialState, { + entities: { + general: { + config: { + HelpLink: 'http://testhelplink', + TermsOfServiceLink: 'http://testtermsofservicelink', + PrivacyPolicyLink: 'http://testprivacypolicylink', + AboutLink: 'http://testaboutlink', + }, + }, + }, + }); expect(document.body.classList.contains('sticky')).toBe(false); - const {container, unmount} = renderComponent(, state as DeepPartial); + const {container, unmount} = renderWithContext(, state); expect(container).toMatchSnapshot(); expect(document.body.classList.contains('sticky')).toBe(true); diff --git a/webapp/channels/src/components/integrations/confirm_integration/confirm_integration.test.tsx b/webapp/channels/src/components/integrations/confirm_integration/confirm_integration.test.tsx index b8aeed7ec4..a25cd41d62 100644 --- a/webapp/channels/src/components/integrations/confirm_integration/confirm_integration.test.tsx +++ b/webapp/channels/src/components/integrations/confirm_integration/confirm_integration.test.tsx @@ -3,7 +3,6 @@ import {shallow} from 'enzyme'; import React from 'react'; -import {Router} from 'react-router-dom'; import type {Bot} from '@mattermost/types/bots'; import type {IncomingWebhook, OAuthApp, OutgoingWebhook} from '@mattermost/types/integrations'; @@ -11,8 +10,7 @@ import type {IDMappedObjects} from '@mattermost/types/utilities'; import ConfirmIntegration from 'components/integrations/confirm_integration/confirm_integration'; -import {renderWithIntlAndStore} from 'tests/react_testing_utils'; -import {getHistory} from 'utils/browser_history'; +import {renderWithContext} from 'tests/react_testing_utils'; import {TestHelper} from 'utils/test_helper'; describe('components/integrations/ConfirmIntegration', () => { @@ -76,10 +74,8 @@ describe('components/integrations/ConfirmIntegration', () => { test('should match callback URLs of OAuth Apps', () => { props.location.search = getSearchString('oauth2-apps'); - const {container} = renderWithIntlAndStore( - - - , + const {container} = renderWithContext( + , initialState, ); diff --git a/webapp/channels/src/components/invitation_modal/add_to_channels.test.tsx b/webapp/channels/src/components/invitation_modal/add_to_channels.test.tsx index 3385488b3e..316cc9edb5 100644 --- a/webapp/channels/src/components/invitation_modal/add_to_channels.test.tsx +++ b/webapp/channels/src/components/invitation_modal/add_to_channels.test.tsx @@ -10,12 +10,12 @@ import deepFreeze from 'mattermost-redux/utils/deep_freeze'; import CloseCircleIcon from 'components/widgets/icons/close_circle_icon'; import {mountWithIntl} from 'tests/helpers/intl-test-helper'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import AddToChannels from './add_to_channels'; import type {Props} from './add_to_channels'; -const defaultProps: Props = deepFreeze({ +const baseProps: Props = deepFreeze({ customMessage: { message: '', open: false, @@ -35,35 +35,30 @@ const defaultProps: Props = deepFreeze({ townSquareDisplayName: 'Town Square', }); -let props = defaultProps; - describe('AddToChannels', () => { - beforeEach(() => { - props = defaultProps; - }); - describe('placeholder selection', () => { it('should use townSquareDisplayName when not in a channel', () => { - props = {...props, currentChannel: undefined}; - renderWithIntl(); + const props = {...baseProps, currentChannel: undefined}; + renderWithContext(); expect(screen.getByText(props.townSquareDisplayName, {exact: false})).toBeInTheDocument(); }); it('should use townSqureDisplayName when not in a public or private channel', () => { - props = {...props, currentChannel: {type: 'D', display_name: ''} as Channel}; - renderWithIntl(); + const props = {...baseProps, currentChannel: {type: 'D', display_name: ''} as Channel}; + renderWithContext(); expect(screen.getByText(props.townSquareDisplayName, {exact: false})).toBeInTheDocument(); }); it('should use the currentChannel display_name when in a channel', () => { - props = {...props, currentChannel: {type: 'O', display_name: 'My Awesome Channel'} as Channel}; - renderWithIntl(); + const props = {...baseProps, currentChannel: {type: 'O', display_name: 'My Awesome Channel'} as Channel}; + renderWithContext(); expect(screen.getByText('My Awesome Channel', {exact: false})).toBeInTheDocument(); }); }); describe('custom message', () => { it('UI to toggle custom message opens it when closed', () => { + const props = baseProps; const wrapper = mountWithIntl(); expect(props.toggleCustomMessage).not.toHaveBeenCalled(); wrapper.find('a').at(0).simulate('click'); @@ -71,10 +66,10 @@ describe('AddToChannels', () => { }); it('UI to toggle custom message closes it when opened', () => { - props = { - ...props, + const props = { + ...baseProps, customMessage: { - ...props.customMessage, + ...baseProps.customMessage, open: true, }, }; @@ -85,10 +80,10 @@ describe('AddToChannels', () => { }); it('UI to write custom message calls the on change handler with its input', () => { - props = { - ...props, + const props = { + ...baseProps, customMessage: { - ...props.customMessage, + ...baseProps.customMessage, open: true, }, }; diff --git a/webapp/channels/src/components/invitation_modal/overage_users_banner_notice/overage_users_banner_notice.test.tsx b/webapp/channels/src/components/invitation_modal/overage_users_banner_notice/overage_users_banner_notice.test.tsx index 57f1d8a9da..cbc46b3951 100644 --- a/webapp/channels/src/components/invitation_modal/overage_users_banner_notice/overage_users_banner_notice.test.tsx +++ b/webapp/channels/src/components/invitation_modal/overage_users_banner_notice/overage_users_banner_notice.test.tsx @@ -11,9 +11,8 @@ import {General} from 'mattermost-redux/constants'; import {trackEvent} from 'actions/telemetry_actions'; import { - act, fireEvent, - renderWithIntlAndStore, + renderWithContext, screen, } from 'tests/react_testing_utils'; import {LicenseLinks, OverActiveUserLimits, Preferences, SelfHostedProducts, StatTypes} from 'utils/constants'; @@ -24,10 +23,6 @@ import type {GlobalState} from 'types/store'; import OverageUsersBannerNotice from './index'; -type RenderComponentArgs = { - store?: any; -} - jest.mock('react-redux', () => ({ ...jest.requireActual('react-redux'), useDispatch: jest.fn().mockReturnValue(() => {}), @@ -128,13 +123,8 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { windowSpy.mockRestore(); }); - const renderComponent = ({store}: RenderComponentArgs = {store: initialState}) => { - return renderWithIntlAndStore( - , store); - }; - it('should not render the banner because we are not on overage state', () => { - renderComponent(); + renderWithContext(); expect(screen.queryByText(notifyText, {exact: false})).not.toBeInTheDocument(); }); @@ -153,9 +143,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }, }; - renderComponent({ + renderWithContext( + , store, - }); + ); expect(screen.queryByText(notifyText, {exact: false})).not.toBeInTheDocument(); }); @@ -168,9 +159,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { Cloud: 'true', }; - renderComponent({ + renderWithContext( + , store, - }); + ); expect(screen.queryByText(notifyText, {exact: false})).not.toBeInTheDocument(); }); @@ -195,9 +187,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }, }; - renderComponent({ + renderWithContext( + , store, - }); + ); expect(screen.queryByText(text5PercentageState)).not.toBeInTheDocument(); }); @@ -212,9 +205,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }, }; - renderComponent({ + renderWithContext( + , store, - }); + ); expect(screen.getByText(text5PercentageState)).toBeInTheDocument(); expect(screen.getByText(notifyText, {exact: false})).toBeInTheDocument(); @@ -238,9 +232,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }, }; - renderComponent({ + renderWithContext( + , store, - }); + ); fireEvent.click(screen.getByText(contactSalesTextLink)); expect(screen.getByRole('link')).toHaveAttribute( @@ -275,9 +270,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }, }; - renderComponent({ + renderWithContext( + , store, - }); + ); expect(screen.getByText(text5PercentageState)).toBeInTheDocument(); expect(screen.getByText(notifyText, {exact: false})).toBeInTheDocument(); @@ -293,9 +289,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }, }; - renderComponent({ + renderWithContext( + , store, - }); + ); fireEvent.click(screen.getByRole('button')); @@ -318,9 +315,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }, }; - renderComponent({ + renderWithContext( + , store, - }); + ); expect(screen.getByText(text10PercentageState)).toBeInTheDocument(); expect(screen.getByText(notifyText, {exact: false})).toBeInTheDocument(); @@ -344,9 +342,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }, }; - renderComponent({ + renderWithContext( + , store, - }); + ); fireEvent.click(screen.getByText(contactSalesTextLink)); expect(screen.getByRole('link')).toHaveAttribute( @@ -381,9 +380,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }, }; - renderComponent({ + renderWithContext( + , store, - }); + ); expect(screen.getByText(text10PercentageState)).toBeInTheDocument(); expect(screen.getByText(notifyText, {exact: false})).toBeInTheDocument(); @@ -409,9 +409,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }, }; - renderComponent({ + renderWithContext( + , store, - }); + ); expect(screen.queryByText(text10PercentageState)).not.toBeInTheDocument(); expect(screen.queryByText(notifyText, {exact: false})).not.toBeInTheDocument(); @@ -427,9 +428,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }, }; - renderComponent({ + renderWithContext( + , store, - }); + ); fireEvent.click(screen.getByRole('button')); @@ -460,9 +462,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }, }; - renderComponent({ + renderWithContext( + , store, - }); + ); fireEvent.click(screen.getByText(expandSeatsTextLink)); expect(screen.getByRole('link')).toHaveAttribute('href', `http://testing/subscribe/expand?licenseId=${licenseId}`); @@ -491,9 +494,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }, }; - renderComponent({ + renderWithContext( + , store, - }); + ); fireEvent.click(screen.getByText(expandSeatsTextLink)); expect(screen.getByRole('link')).toHaveAttribute('href', `http://testing/subscribe/expand?licenseId=${licenseId}`); @@ -523,11 +527,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { }; store.entities.general.license.IsGovSku = 'true'; - await act(async () => { - renderComponent({ - store, - }); - }); + renderWithContext( + , + store, + ); screen.getByText(text10PercentageState); expect(screen.queryByText(notifyText)).not.toBeInTheDocument(); diff --git a/webapp/channels/src/components/menu/menu.test.tsx b/webapp/channels/src/components/menu/menu.test.tsx index b628e957f7..b0b06108eb 100644 --- a/webapp/channels/src/components/menu/menu.test.tsx +++ b/webapp/channels/src/components/menu/menu.test.tsx @@ -7,7 +7,7 @@ import {DotsVerticalIcon} from '@mattermost/compass-icons/components'; import {GenericModal} from '@mattermost/components'; import { - renderWithFullContext, + renderWithContext, screen, userEvent, waitForElementToBeRemoved, @@ -19,7 +19,7 @@ import {SubMenu} from './sub_menu'; describe('menu click handlers', () => { test('should be able to open a React Bootstrap modal with the mouse', async () => { - renderWithFullContext( + renderWithContext( , ); @@ -42,7 +42,7 @@ describe('menu click handlers', () => { for (const enterOrSpace of ['enter', 'space']) { test(`should be able to open a React Bootstrap modal with the keyboard using the ${enterOrSpace} key`, async () => { - renderWithFullContext( + renderWithContext( , ); @@ -77,7 +77,7 @@ describe('menu click handlers', () => { } test('should be able to open a React Bootstrap modal from a submenu with the mouse', async () => { - renderWithFullContext( + renderWithContext( , ); @@ -108,7 +108,7 @@ describe('menu click handlers', () => { for (const enterOrSpace of ['enter', 'space']) { test(`should be able to open a React Bootstrap modal with the keyboard using the ${enterOrSpace} key`, async () => { - renderWithFullContext( + renderWithContext( , ); diff --git a/webapp/channels/src/components/new_channel_modal/new_channel_modal.test.tsx b/webapp/channels/src/components/new_channel_modal/new_channel_modal.test.tsx index b23e5eed73..91330fc406 100644 --- a/webapp/channels/src/components/new_channel_modal/new_channel_modal.test.tsx +++ b/webapp/channels/src/components/new_channel_modal/new_channel_modal.test.tsx @@ -9,7 +9,7 @@ import Permissions from 'mattermost-redux/constants/permissions'; import { render, - renderWithIntl, + renderWithContext, screen, userEvent, waitFor, @@ -404,7 +404,7 @@ describe('components/new_channel_modal', () => { test('should request team creation on submit', async () => { const name = 'Channel name'; - renderWithIntl( + renderWithContext( , ); diff --git a/webapp/channels/src/components/payment_form/gather_intent/gather_intent.test.tsx b/webapp/channels/src/components/payment_form/gather_intent/gather_intent.test.tsx index b4528c5062..06d114fb40 100644 --- a/webapp/channels/src/components/payment_form/gather_intent/gather_intent.test.tsx +++ b/webapp/channels/src/components/payment_form/gather_intent/gather_intent.test.tsx @@ -7,11 +7,12 @@ import * as reactRedux from 'react-redux'; import { act, fireEvent, - renderWithIntlAndStore, + renderWithContext, screen, } from 'tests/react_testing_utils'; import {TestHelper} from 'utils/test_helper'; +import type {GatherIntentProps} from './gather_intent'; import {GatherIntent} from './gather_intent'; import type {GatherIntentModalProps} from './gather_intent_modal'; @@ -42,10 +43,6 @@ describe('components/gather_intent/gather_intent.tsx', () => { const gatherIntentText = 'gatherIntentText'; const useDispatchMock = jest.spyOn(reactRedux, 'useDispatch'); - beforeEach(() => { - useDispatchMock.mockClear(); - }); - const initialState = { entities: { cloud: { @@ -54,20 +51,17 @@ describe('components/gather_intent/gather_intent.tsx', () => { }, }; - //Any because renderWithIntlAndStore doesn't have the store parameter typed as deep partial. - const renderComponent = ({store}: {store: any} = {store: initialState}) => { - return renderWithIntlAndStore( - , - store, - ); + const baseProps: GatherIntentProps = { + modalComponent: DummyModal as any, + gatherIntentText, + typeGatherIntent: 'monthlySubscription', }; it('should display modal if the user click on the modal opener', () => { - renderComponent(); + renderWithContext( + , + initialState, + ); fireEvent.click(screen.getByText(gatherIntentText)); @@ -75,7 +69,10 @@ describe('components/gather_intent/gather_intent.tsx', () => { }); it('should display the modal opener after close the modal', () => { - renderComponent(); + renderWithContext( + , + initialState, + ); fireEvent.click(screen.getByText(gatherIntentText)); fireEvent.click(screen.getByLabelText('Close')); @@ -87,7 +84,10 @@ describe('components/gather_intent/gather_intent.tsx', () => { useDispatchMock.mockReturnValue(jest.fn().mockImplementation(() => new Promise((resolve) => { resolve({}); }))); - renderComponent(); + renderWithContext( + , + initialState, + ); fireEvent.click(screen.getByText(gatherIntentText)); @@ -102,7 +102,10 @@ describe('components/gather_intent/gather_intent.tsx', () => { useDispatchMock.mockReturnValue(jest.fn().mockImplementation(() => new Promise((resolve) => { resolve({}); }))); - renderComponent(); + renderWithContext( + , + initialState, + ); fireEvent.click(screen.getByText(gatherIntentText)); @@ -126,9 +129,10 @@ describe('components/gather_intent/gather_intent.tsx', () => { monthly_subscription_alt_payment_method: 'Dummy feedback', }; - renderComponent({ - store: newState, - }); + renderWithContext( + , + newState, + ); fireEvent.click(screen.getByText(gatherIntentText)); diff --git a/webapp/channels/src/components/payment_form/gather_intent/gather_intent.tsx b/webapp/channels/src/components/payment_form/gather_intent/gather_intent.tsx index 44049f7700..3cb3a81e8e 100644 --- a/webapp/channels/src/components/payment_form/gather_intent/gather_intent.tsx +++ b/webapp/channels/src/components/payment_form/gather_intent/gather_intent.tsx @@ -14,7 +14,7 @@ import {useGatherIntent} from './useGatherIntent'; import './gather_intent.scss'; -interface GatherIntentProps { +export interface GatherIntentProps { typeGatherIntent: keyof typeof TypePurchases; gatherIntentText: React.ReactNode; modalComponent: JSXElementConstructor; diff --git a/webapp/channels/src/components/payment_form/gather_intent/gather_intent_modal.test.tsx b/webapp/channels/src/components/payment_form/gather_intent/gather_intent_modal.test.tsx index 6b269ad501..08902e84b9 100644 --- a/webapp/channels/src/components/payment_form/gather_intent/gather_intent_modal.test.tsx +++ b/webapp/channels/src/components/payment_form/gather_intent/gather_intent_modal.test.tsx @@ -3,36 +3,27 @@ import React from 'react'; -import {fireEvent, renderWithIntl, screen} from 'tests/react_testing_utils'; +import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils'; import {GatherIntentModal} from './gather_intent_modal'; import type {GatherIntentModalProps} from './gather_intent_modal'; describe('components/gather_intent/gather_intent_modal.tsx', () => { - const renderComponent = (props: Partial | undefined = {}) => { - const defaultProps: GatherIntentModalProps = { - onClose: jest.fn(), - onSave: jest.fn(), - isSubmitting: false, - showError: false, - }; - - return renderWithIntl( - , - ); + const baseProps: GatherIntentModalProps = { + onClose: jest.fn(), + onSave: jest.fn(), + isSubmitting: false, + showError: false, }; it('shouldn\'t be able to save the feedback if the user don\'t click on any option', () => { - renderComponent(); + renderWithContext(); expect(screen.queryByText('Save')).toBeDisabled(); }); it('shouldn\'t be able to save the feedback if the user only click in other and leave the input empty', () => { - renderComponent(); + renderWithContext(); fireEvent.click(screen.getByText('Other')); @@ -40,7 +31,7 @@ describe('components/gather_intent/gather_intent_modal.tsx', () => { }); it('shouldn\'t be able to save the feedback if the user only click in other and write only white spaces in the input', () => { - renderComponent(); + renderWithContext(); fireEvent.click(screen.getByText('Other')); fireEvent.change(screen.getByPlaceholderText('Enter payment option here'), {target: {value: ' \n\t'}}); @@ -49,7 +40,7 @@ describe('components/gather_intent/gather_intent_modal.tsx', () => { }); it('should be able to save the feedback if the user only click in other, leave the input empty and press other option', () => { - renderComponent(); + renderWithContext(); fireEvent.click(screen.getByText('Other')); fireEvent.click(screen.getByText('Wire')); @@ -58,7 +49,7 @@ describe('components/gather_intent/gather_intent_modal.tsx', () => { }); it('should be able save the feedback if the user click in Wire option', () => { - renderComponent(); + renderWithContext(); fireEvent.click(screen.getByText('Wire')); @@ -66,7 +57,7 @@ describe('components/gather_intent/gather_intent_modal.tsx', () => { }); it('should be able save the feedback if the user click in ACH option', () => { - renderComponent(); + renderWithContext(); fireEvent.click(screen.getByText('ACH')); @@ -74,7 +65,7 @@ describe('components/gather_intent/gather_intent_modal.tsx', () => { }); it('should be able save the feedback if the user click in other option and fill the option', () => { - renderComponent(); + renderWithContext(); fireEvent.click(screen.getByText('Other')); fireEvent.change(screen.getByPlaceholderText('Enter payment option here'), {target: {value: 'Test'}}); diff --git a/webapp/channels/src/components/post/post_component.test.tsx b/webapp/channels/src/components/post/post_component.test.tsx index f8b6ae25e9..0deeaee63b 100644 --- a/webapp/channels/src/components/post/post_component.test.tsx +++ b/webapp/channels/src/components/post/post_component.test.tsx @@ -6,7 +6,7 @@ import React from 'react'; import type {DeepPartial} from '@mattermost/types/utilities'; import mergeObjects from 'packages/mattermost-redux/test/merge_objects'; -import {renderWithFullContext, screen, userEvent} from 'tests/react_testing_utils'; +import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils'; import {getHistory} from 'utils/browser_history'; import {Locations} from 'utils/constants'; import {TestHelper} from 'utils/test_helper'; @@ -65,7 +65,7 @@ describe('PostComponent', () => { }; test('should show reactions in the center channel', () => { - renderWithFullContext(, baseState); + renderWithContext(, baseState); expect(screen.getByLabelText('reactions')).toBeInTheDocument(); }); @@ -83,7 +83,7 @@ describe('PostComponent', () => { ...baseProps, location: Locations.RHS_ROOT, }; - const {rerender} = renderWithFullContext(, state); + const {rerender} = renderWithContext(, state); expect(screen.getByLabelText('reactions')).toBeInTheDocument(); @@ -101,7 +101,7 @@ describe('PostComponent', () => { ...baseProps, location: Locations.SEARCH, }; - const {rerender} = renderWithFullContext(, baseState); + const {rerender} = renderWithContext(, baseState); expect(screen.queryByLabelText('reactions')).not.toBeInTheDocument(); @@ -128,7 +128,7 @@ describe('PostComponent', () => { describe('thread footer', () => { test('should never show thread footer for a post that isn\'t part of a thread', () => { let props: Props = baseProps; - const {rerender} = renderWithFullContext(); + const {rerender} = renderWithContext(); expect(screen.queryByText(/Follow|Following/)).not.toBeInTheDocument(); @@ -164,7 +164,7 @@ describe('PostComponent', () => { post: rootPost, replyCount: 1, }; - const {rerender} = renderWithFullContext(, state); + const {rerender} = renderWithContext(, state); expect(screen.queryByText(/Follow|Following/)).toBeInTheDocument(); @@ -194,7 +194,7 @@ describe('PostComponent', () => { root_id: 'some_other_post_id', }, }; - const {rerender} = renderWithFullContext(); + const {rerender} = renderWithContext(); expect(screen.queryByText(/Follow|Following/)).not.toBeInTheDocument(); @@ -238,7 +238,7 @@ describe('PostComponent', () => { post: rootPost, replyCount: 1, }; - const {rerender} = renderWithFullContext(, state); + const {rerender} = renderWithContext(, state); expect(screen.queryByText(/Follow|Following/)).not.toBeInTheDocument(); @@ -275,7 +275,7 @@ describe('PostComponent', () => { }; test('should select post in RHS when clicked in center channel', () => { - renderWithFullContext(, state); + renderWithContext(, state); userEvent.click(screen.getByText('1 reply')); @@ -288,7 +288,7 @@ describe('PostComponent', () => { ...propsForRootPost, team: undefined, }; - renderWithFullContext(, state); + renderWithContext(, state); userEvent.click(screen.getByText('1 reply')); @@ -302,7 +302,7 @@ describe('PostComponent', () => { ...propsForRootPost, location: Locations.SEARCH, }; - renderWithFullContext(, state); + renderWithContext(, state); userEvent.click(screen.getByText('1 reply')); @@ -316,7 +316,7 @@ describe('PostComponent', () => { location: Locations.SEARCH, team: TestHelper.getTeamMock({id: 'another_team'}), }; - renderWithFullContext(, state); + renderWithContext(, state); userEvent.click(screen.getByText('1 reply')); diff --git a/webapp/channels/src/components/post_edit_history/post_edit_history.test.tsx b/webapp/channels/src/components/post_edit_history/post_edit_history.test.tsx index 1009b791c0..365a6d84d1 100644 --- a/webapp/channels/src/components/post_edit_history/post_edit_history.test.tsx +++ b/webapp/channels/src/components/post_edit_history/post_edit_history.test.tsx @@ -6,7 +6,7 @@ import type {ComponentProps} from 'react'; import {Client4} from 'mattermost-redux/client'; -import {act, renderWithIntlAndStore} from 'tests/react_testing_utils'; +import {renderWithContext, waitFor} from 'tests/react_testing_utils'; import {TestHelper} from 'utils/test_helper'; import PostEditHistory from './post_edit_history'; @@ -35,31 +35,23 @@ describe('components/post_edit_history', () => { ]; mock.mockResolvedValue(data); - let wrapper: HTMLElement; + const wrapper = await waitFor(() => { + return renderWithContext(); + }); - await act(async () => { - const {container} = renderWithIntlAndStore(, {}); - wrapper = container; - }); - await act(async () => { - expect(wrapper).toMatchSnapshot(); - expect(mock).toBeCalledWith(baseProps.originalPost.id); - }); + expect(wrapper.container).toMatchSnapshot(); + expect(mock).toBeCalledWith(baseProps.originalPost.id); }); test('should display error screen if errors are present', async () => { const error = new Error('An example error'); mock.mockRejectedValue(error); - let wrapper: HTMLElement; + const wrapper = await waitFor(() => { + return renderWithContext(); + }); - await act(async () => { - const {container} = renderWithIntlAndStore(, {}); - wrapper = container; - }); - await act(async () => { - expect(wrapper).toMatchSnapshot(); - expect(mock).toBeCalledWith(baseProps.originalPost.id); - }); + expect(wrapper.container).toMatchSnapshot(); + expect(mock).toBeCalledWith(baseProps.originalPost.id); }); }); diff --git a/webapp/channels/src/components/post_markdown/post_markdown.test.tsx b/webapp/channels/src/components/post_markdown/post_markdown.test.tsx index e1dd7f8e9a..33bf5d361b 100644 --- a/webapp/channels/src/components/post_markdown/post_markdown.test.tsx +++ b/webapp/channels/src/components/post_markdown/post_markdown.test.tsx @@ -7,7 +7,7 @@ import type {Post, PostType} from '@mattermost/types/posts'; import {Posts} from 'mattermost-redux/constants'; -import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {TestHelper} from 'utils/test_helper'; import PostMarkdown from './post_markdown'; @@ -56,13 +56,13 @@ describe('components/PostMarkdown', () => { const props = {...baseProps}; Reflect.deleteProperty(props, 'post'); - renderWithIntlAndStore(, state); + renderWithContext(, state); expect(screen.getByText('message')).toBeInTheDocument(); }); test('should render properly with an empty post', () => { - renderWithIntlAndStore( + renderWithContext( { }, }), }; - renderWithIntlAndStore(, state); + renderWithContext(, state); const link = screen.getByRole('link'); @@ -115,7 +115,7 @@ describe('components/PostMarkdown', () => { }, }), }; - renderWithIntlAndStore(, state); + renderWithContext(, state); expect(screen.getByText('No highlight')).toBeInTheDocument(); expect(screen.queryByRole('link')).not.toBeInTheDocument(); @@ -132,7 +132,7 @@ describe('components/PostMarkdown', () => { }, }), }; - renderWithIntlAndStore(, state); + renderWithContext(, state); const groupMention = screen.getByText('@group'); @@ -152,7 +152,7 @@ describe('components/PostMarkdown', () => { id: 'post_id', }), }; - renderWithIntlAndStore(, state); + renderWithContext(, state); expect(screen.getByText('message')).toBeInTheDocument(); }); @@ -176,7 +176,7 @@ describe('components/PostMarkdown', () => { }), }; - renderWithIntlAndStore(, state); + renderWithContext(, state); expect(screen.getByText('@user')).toBeInTheDocument(); expect(screen.getByText('updated the channel header')).toBeInTheDocument(); expect(screen.getByText('From:')).toBeInTheDocument(); @@ -226,7 +226,7 @@ describe('components/PostMarkdown', () => { }, ], }; - renderWithIntlAndStore(, state); + renderWithContext(, state); expect(screen.queryByText('world', {exact: true})).not.toBeInTheDocument(); // hook message @@ -260,7 +260,7 @@ describe('components/PostMarkdown', () => { }, ], }; - renderWithIntlAndStore(, state); + renderWithContext(, state); expect(screen.queryByText('world', {exact: true})).not.toBeInTheDocument(); expect(screen.queryByText('world!', {exact: true})).toBeInTheDocument(); }); diff --git a/webapp/channels/src/components/post_view/channel_intro_message/channel_intro_message.test.tsx b/webapp/channels/src/components/post_view/channel_intro_message/channel_intro_message.test.tsx index fb576194e8..d6dd85f22b 100644 --- a/webapp/channels/src/components/post_view/channel_intro_message/channel_intro_message.test.tsx +++ b/webapp/channels/src/components/post_view/channel_intro_message/channel_intro_message.test.tsx @@ -6,7 +6,7 @@ import React from 'react'; import type {Channel, ChannelType} from '@mattermost/types/channels'; import type {UserProfile} from '@mattermost/types/users'; -import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {Constants} from 'utils/constants'; import {TestHelper} from 'utils/test_helper'; @@ -85,7 +85,7 @@ describe('components/post_view/ChannelIntroMessages', () => { describe('test Open Channel', () => { test('should match component state, without boards', () => { - renderWithIntlAndStore( + renderWithContext( , initialState, ); @@ -110,7 +110,7 @@ describe('components/post_view/ChannelIntroMessages', () => { }; test('should match component state, no profiles', () => { - renderWithIntlAndStore( + renderWithContext( , initialState, @@ -126,7 +126,7 @@ describe('components/post_view/ChannelIntroMessages', () => { }); test('should match component state, with profiles', () => { - renderWithIntlAndStore( + renderWithContext( { }; test('should match component state, without teammate', () => { - renderWithIntlAndStore( + renderWithContext( , initialState, @@ -183,7 +183,7 @@ describe('components/post_view/ChannelIntroMessages', () => { }); test('should match component state, with teammate', () => { - renderWithIntlAndStore( + renderWithContext( { }; test('should match component state, readonly', () => { - renderWithIntlAndStore( + renderWithContext( { }); test('should match component state without any permission', () => { - renderWithIntlAndStore( + renderWithContext( { }; test('should match component state', () => { - renderWithIntlAndStore( + renderWithContext( , initialState, diff --git a/webapp/channels/src/components/post_view/combined_system_message/last_users.test.tsx b/webapp/channels/src/components/post_view/combined_system_message/last_users.test.tsx index c4e8b6fedc..5dfe91f6ca 100644 --- a/webapp/channels/src/components/post_view/combined_system_message/last_users.test.tsx +++ b/webapp/channels/src/components/post_view/combined_system_message/last_users.test.tsx @@ -5,7 +5,7 @@ import React from 'react'; import {Posts} from 'mattermost-redux/constants'; -import {renderWithIntlAndStore, screen, userEvent} from 'tests/react_testing_utils'; +import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils'; import {TestHelper} from 'utils/test_helper'; import LastUsers from './last_users'; @@ -49,7 +49,7 @@ describe('components/post_view/combined_system_message/LastUsers', () => { } as any; test('should match component state', () => { - renderWithIntlAndStore( + renderWithContext( , initialState, ); @@ -66,7 +66,7 @@ describe('components/post_view/combined_system_message/LastUsers', () => { }); test('should match component state, expanded', () => { - renderWithIntlAndStore( + renderWithContext( , initialState, ); diff --git a/webapp/channels/src/components/post_view/commented_on_files_message/commented_on_files_message.test.tsx b/webapp/channels/src/components/post_view/commented_on_files_message/commented_on_files_message.test.tsx index e6a357d60b..7789ea7509 100644 --- a/webapp/channels/src/components/post_view/commented_on_files_message/commented_on_files_message.test.tsx +++ b/webapp/channels/src/components/post_view/commented_on_files_message/commented_on_files_message.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; -import {render, renderWithIntl, screen} from 'tests/react_testing_utils'; +import {render, renderWithContext, screen} from 'tests/react_testing_utils'; import CommentedOnFilesMessage from './commented_on_files_message'; @@ -45,7 +45,7 @@ describe('components/CommentedOnFilesMessage', () => { fileInfos, }; - renderWithIntl( + renderWithContext( , ); diff --git a/webapp/channels/src/components/post_view/date_separator/date_separator.test.tsx b/webapp/channels/src/components/post_view/date_separator/date_separator.test.tsx index 385e18a57d..8c406229b8 100644 --- a/webapp/channels/src/components/post_view/date_separator/date_separator.test.tsx +++ b/webapp/channels/src/components/post_view/date_separator/date_separator.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; -import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import DateSeparator from './date_separator'; @@ -20,7 +20,7 @@ describe('components/post_view/DateSeparator', () => { } as any; test('should render Timestamp inside of a BasicSeparator and pass date/value to it', () => { const value = new Date('Fri Jan 12 2018 20:15:13 GMT+1200 (+12)'); - renderWithIntlAndStore( + renderWithContext( , initialState, diff --git a/webapp/channels/src/components/post_view/embedded_bindings/button_binding/button_binding.test.tsx b/webapp/channels/src/components/post_view/embedded_bindings/button_binding/button_binding.test.tsx index a0671149dd..9aadd07392 100644 --- a/webapp/channels/src/components/post_view/embedded_bindings/button_binding/button_binding.test.tsx +++ b/webapp/channels/src/components/post_view/embedded_bindings/button_binding/button_binding.test.tsx @@ -7,13 +7,13 @@ import type {AppBinding, AppCallResponse} from '@mattermost/types/apps'; import type {Post} from '@mattermost/types/posts'; import { - renderWithIntlAndStore, + renderWithContext, screen, userEvent, waitFor, } from 'tests/react_testing_utils'; -import ButtonBinding, {ButtonBinding as ButtonBindingUnwrapped} from './button_binding'; +import ButtonBinding from './button_binding'; describe('components/post_view/embedded_bindings/button_binding/', () => { const post = { @@ -80,25 +80,14 @@ describe('components/post_view/embedded_bindings/button_binding/', () => { }, }; - const intl = { - formatMessage: (message: {id: string; defaultMessage: string}) => { - return message.defaultMessage; - }, - } as any; - test('should match default component state', () => { - renderWithIntlAndStore(, initialState); + renderWithContext(, initialState); screen.getByText('some_label'); }); test('should call doAppSubmit on click', async () => { - const props = { - ...baseProps, - intl, - }; - - renderWithIntlAndStore(, initialState); + renderWithContext(, initialState); screen.getByText('some_label'); @@ -144,10 +133,9 @@ describe('components/post_view/embedded_bindings/button_binding/', () => { postEphemeralCallResponseForPost: jest.fn(), openAppsModal: jest.fn(), }, - intl, }; - renderWithIntlAndStore(, initialState); + renderWithContext(, initialState); screen.getByText('some_label'); diff --git a/webapp/channels/src/components/post_view/embedded_bindings/button_binding/button_binding.tsx b/webapp/channels/src/components/post_view/embedded_bindings/button_binding/button_binding.tsx index 9b30e026d3..6108b86918 100644 --- a/webapp/channels/src/components/post_view/embedded_bindings/button_binding/button_binding.tsx +++ b/webapp/channels/src/components/post_view/embedded_bindings/button_binding/button_binding.tsx @@ -35,7 +35,7 @@ type State = { executing: boolean; } -export class ButtonBinding extends React.PureComponent { +class ButtonBinding extends React.PureComponent { constructor(props: Props) { super(props); this.state = { diff --git a/webapp/channels/src/components/post_view/failed_post_options/failed_post_options.test.tsx b/webapp/channels/src/components/post_view/failed_post_options/failed_post_options.test.tsx index 92ab616082..c2b8066c90 100644 --- a/webapp/channels/src/components/post_view/failed_post_options/failed_post_options.test.tsx +++ b/webapp/channels/src/components/post_view/failed_post_options/failed_post_options.test.tsx @@ -5,7 +5,7 @@ import React from 'react'; import FailedPostOptions from 'components/post_view/failed_post_options/failed_post_options'; -import {renderWithIntl, screen, userEvent} from 'tests/react_testing_utils'; +import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils'; import {TestHelper} from 'utils/test_helper'; describe('components/post_view/FailedPostOptions', () => { @@ -18,7 +18,7 @@ describe('components/post_view/FailedPostOptions', () => { }; test('should match default component state', () => { - renderWithIntl(); + renderWithContext(); const retryLink = screen.getByText('Retry'); const cancelLink = screen.getByText('Cancel'); @@ -43,7 +43,7 @@ describe('components/post_view/FailedPostOptions', () => { }, }; - renderWithIntl(); + renderWithContext(); const retryLink = screen.getByText('Retry'); @@ -65,7 +65,7 @@ describe('components/post_view/FailedPostOptions', () => { }, }; - renderWithIntl(); + renderWithContext(); const cancelLink = screen.getByText('Cancel'); diff --git a/webapp/channels/src/components/post_view/floating_timestamp/floating_timestamp.test.tsx b/webapp/channels/src/components/post_view/floating_timestamp/floating_timestamp.test.tsx index 89292712ab..a54846b8eb 100644 --- a/webapp/channels/src/components/post_view/floating_timestamp/floating_timestamp.test.tsx +++ b/webapp/channels/src/components/post_view/floating_timestamp/floating_timestamp.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; -import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import FloatingTimestamp from './floating_timestamp'; @@ -26,7 +26,7 @@ describe('components/post_view/FloatingTimestamp', () => { }; test('should match component state with given props', () => { - renderWithIntlAndStore(, initialState); + renderWithContext(, initialState); const floatingTimeStamp = screen.getByTestId('floatingTimestamp'); const time = screen.getByText('January 01, 1970'); diff --git a/webapp/channels/src/components/post_view/message_attachments/action_button/action_button.test.tsx b/webapp/channels/src/components/post_view/message_attachments/action_button/action_button.test.tsx index d4510304f7..917d908e34 100644 --- a/webapp/channels/src/components/post_view/message_attachments/action_button/action_button.test.tsx +++ b/webapp/channels/src/components/post_view/message_attachments/action_button/action_button.test.tsx @@ -7,7 +7,7 @@ import {Preferences} from 'mattermost-redux/constants'; import type {Theme} from 'mattermost-redux/selectors/entities/preferences'; import {changeOpacity} from 'mattermost-redux/utils/theme_utils'; -import {screen, userEvent, renderWithIntl} from 'tests/react_testing_utils'; +import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils'; import ActionButton from './action_button'; @@ -19,7 +19,7 @@ describe('components/post_view/message_attachments/action_button.jsx', () => { }; test('should match default component state with given props', () => { - renderWithIntl(); + renderWithContext(); const button = screen.getByRole('button'); expect(button).toHaveAttribute('data-action-cookie', 'cookie-contents'); @@ -30,7 +30,7 @@ describe('components/post_view/message_attachments/action_button.jsx', () => { }); test('should call handleAction on click', () => { - renderWithIntl(); + renderWithContext(); const button = screen.getByRole('button'); @@ -45,7 +45,7 @@ describe('components/post_view/message_attachments/action_button.jsx', () => { action: {...baseProps.action, style: 'onlineIndicator'}, }; - renderWithIntl(); + renderWithContext(); const button = screen.getByRole('button'); @@ -60,7 +60,7 @@ describe('components/post_view/message_attachments/action_button.jsx', () => { action: {...baseProps.action, style: 'danger'}, }; - renderWithIntl(); + renderWithContext(); const button = screen.getByRole('button'); @@ -74,7 +74,7 @@ describe('components/post_view/message_attachments/action_button.jsx', () => { action: {...baseProps.action, style: 'success'}, }; - renderWithIntl(); + renderWithContext(); const button = screen.getByRole('button'); expect(button).toHaveStyle(`background-color: ${changeOpacity('#339970', 0.08)}`); @@ -87,7 +87,7 @@ describe('components/post_view/message_attachments/action_button.jsx', () => { action: {...baseProps.action, style: '#28a745'}, }; - renderWithIntl(); + renderWithContext(); const button = screen.getByRole('button'); expect(button).toHaveStyle(`background-color: ${changeOpacity(props.action.style, 0.08)}`); @@ -100,7 +100,7 @@ describe('components/post_view/message_attachments/action_button.jsx', () => { action: {...baseProps.action, style: '#wrong'}, }; - renderWithIntl(); + renderWithContext(); const button = screen.getByRole('button'); expect(button.style.length).toBe(0); @@ -112,7 +112,7 @@ describe('components/post_view/message_attachments/action_button.jsx', () => { action: {...baseProps.action, style: undefined}, }; - renderWithIntl(); + renderWithContext(); const button = screen.getByRole('button'); expect(button.style.length).toBe(0); diff --git a/webapp/channels/src/components/post_view/message_attachments/action_menu/action_menu.test.tsx b/webapp/channels/src/components/post_view/message_attachments/action_menu/action_menu.test.tsx index 473d3d9aee..2dc292c83f 100644 --- a/webapp/channels/src/components/post_view/message_attachments/action_menu/action_menu.test.tsx +++ b/webapp/channels/src/components/post_view/message_attachments/action_menu/action_menu.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; -import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import ActionMenu from './action_menu'; @@ -32,7 +32,7 @@ describe('components/post_view/message_attachments/ActionMenu', () => { }; test('should start with nothing selected', async () => { - renderWithIntlAndStore(, {}); + renderWithContext(); const autoCompleteSelector = screen.getByTestId('autoCompleteSelector'); const input = screen.getByPlaceholderText('action'); @@ -55,7 +55,7 @@ describe('components/post_view/message_attachments/ActionMenu', () => { default_option: '2', }, }; - renderWithIntlAndStore(, {}); + renderWithContext(); const input = screen.getByPlaceholderText('action'); diff --git a/webapp/channels/src/components/post_view/new_message_separator/new_message_separator.test.tsx b/webapp/channels/src/components/post_view/new_message_separator/new_message_separator.test.tsx index 039636a5f1..b10a5e2112 100644 --- a/webapp/channels/src/components/post_view/new_message_separator/new_message_separator.test.tsx +++ b/webapp/channels/src/components/post_view/new_message_separator/new_message_separator.test.tsx @@ -3,13 +3,13 @@ import React from 'react'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import NewMessageSeparator from './new_message_separator'; describe('components/post_view/new_message_separator', () => { test('should render new_message_separator', () => { - renderWithIntl( + renderWithContext( { }; test('should render correctly', () => { - renderWithIntlAndStore( + renderWithContext( , initialState, ); diff --git a/webapp/channels/src/components/post_view/post_list_virtualized/latest_post_reader.test.tsx b/webapp/channels/src/components/post_view/post_list_virtualized/latest_post_reader.test.tsx index 2c788fb6e7..0a6c51cb0f 100644 --- a/webapp/channels/src/components/post_view/post_list_virtualized/latest_post_reader.test.tsx +++ b/webapp/channels/src/components/post_view/post_list_virtualized/latest_post_reader.test.tsx @@ -3,12 +3,10 @@ import React from 'react'; import {createIntl, useIntl} from 'react-intl'; -import {Provider} from 'react-redux'; import enMessages from 'i18n/en.json'; import esMessages from 'i18n/es.json'; -import {render, renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; -import {mockStore} from 'tests/test_store'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {TestHelper} from 'utils/test_helper'; import LatestPostReader from './latest_post_reader'; @@ -58,14 +56,11 @@ describe('LatestPostReader', () => { }; test('should render aria-label as a child in the given locale', () => { - const store = mockStore(baseState); - (useIntl as jest.Mock).mockImplementation(() => createIntl({locale: 'en', messages: enMessages, defaultLocale: 'en'})); - const {rerender} = render( - - - , + const {rerender} = renderWithContext( + , + baseState, ); const prevMessage = screen.getByText(`January 1, ${author.username} wrote, This is a test`, {exact: false}); @@ -74,7 +69,7 @@ describe('LatestPostReader', () => { (useIntl as jest.Mock).mockImplementation(() => createIntl({locale: 'es', messages: esMessages, defaultLocale: 'es'})); - rerender( ); + rerender(); const januaryInSpanish = 'enero'; const message = screen.getByText(`${januaryInSpanish}, ${author.username} wrote, This is a test`, {exact: false}); @@ -88,7 +83,7 @@ describe('LatestPostReader', () => { postIds: [], }; - renderWithIntlAndStore(, baseState); + renderWithContext(, baseState); // body should be empty const message = screen.queryByText('This is a test'); diff --git a/webapp/channels/src/components/purchase_in_progress_modal/index.test.tsx b/webapp/channels/src/components/purchase_in_progress_modal/index.test.tsx index fa3af68cec..7435fffa85 100644 --- a/webapp/channels/src/components/purchase_in_progress_modal/index.test.tsx +++ b/webapp/channels/src/components/purchase_in_progress_modal/index.test.tsx @@ -9,7 +9,7 @@ import {Client4} from 'mattermost-redux/client'; import {STORAGE_KEY_PURCHASE_IN_PROGRESS} from 'components/self_hosted_purchases/constants'; -import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {TestHelper as TH} from 'utils/test_helper'; import type {GlobalState} from 'types/store'; @@ -59,7 +59,7 @@ describe('PurchaseInProgressModal', () => { it('when purchaser and user emails are different, user is instructed to wait', () => { const stateOverride: DeepPartial = JSON.parse(JSON.stringify(initialState)); stateOverride.entities!.users!.currentUserId = 'otherUserId'; - renderWithIntlAndStore( + renderWithContext(
{ }); it('when purchaser and user emails are same, allows user to reset purchase flow', () => { - renderWithIntlAndStore( + renderWithContext(
{ it('informs customer that the subscription is under review', () => { - renderWithIntlAndStore(, {}); + renderWithContext(); screen.getByText('Your transaction is being reviewed'); }); @@ -19,7 +19,7 @@ describe('ScreeningInProgressModal', () => { const mockClose = jest.fn(); jest.spyOn(controlModalHooks, 'useControlScreeningInProgressModal').mockImplementation(() => ({close: mockClose, open: jest.fn()})); - renderWithIntlAndStore(, {}); + renderWithContext(); screen.getAllByText('Close')[1].click(); expect(mockClose).toHaveBeenCalled(); }); diff --git a/webapp/channels/src/components/search_bar/search_bar.test.tsx b/webapp/channels/src/components/search_bar/search_bar.test.tsx index e46df38249..50b30f9044 100644 --- a/webapp/channels/src/components/search_bar/search_bar.test.tsx +++ b/webapp/channels/src/components/search_bar/search_bar.test.tsx @@ -3,16 +3,12 @@ import React from 'react'; import type {ComponentProps} from 'react'; -import {IntlProvider} from 'react-intl'; -import {Provider} from 'react-redux'; import SearchChannelProvider from 'components/suggestion/search_channel_provider'; import SearchDateProvider from 'components/suggestion/search_date_provider'; import SearchUserProvider from 'components/suggestion/search_user_provider'; -import en from 'i18n/en.json'; -import {render} from 'tests/react_testing_utils'; -import mockStore from 'tests/test_store'; +import {renderWithContext} from 'tests/react_testing_utils'; import SearchBar from './search_bar'; @@ -22,24 +18,7 @@ const suggestionProviders = [ new SearchUserProvider(jest.fn()), ]; -const wrapIntl = (component: JSX.Element) => ( - - {component} - -); - describe('components/search_bar/SearchBar', () => { - const store = mockStore({}); - - const wrapStore = (component: JSX.Element) => ( - - {component} - - ); - const baseProps: ComponentProps = { suggestionProviders, searchTerms: '', @@ -61,54 +40,46 @@ describe('components/search_bar/SearchBar', () => { }; it('should match snapshot without search', () => { - const {container} = render( - wrapStore(wrapIntl()), + const {container} = renderWithContext( + , ); expect(container).toMatchSnapshot(); }); it('should match snapshot without search, without searchType', () => { - const {container} = render( - wrapStore(wrapIntl(( - - ))), + const {container} = renderWithContext( + , ); expect(container).toMatchSnapshot(); }); it('should match snapshot without search, with searchType', () => { - const {container} = render( - wrapStore(wrapIntl(( - - ))), + const {container} = renderWithContext( + , ); expect(container).toMatchSnapshot(); }); it('should match snapshot with search, with searchType', () => { - const {container} = render( - wrapStore(wrapIntl(( - - ))), + const {container} = renderWithContext( + , ); expect(container).toMatchSnapshot(); }); it('should match snapshot with search', () => { - const {container} = render( - wrapStore(wrapIntl(( - - ))), + const {container} = renderWithContext( + , ); expect(container).toMatchSnapshot(); }); diff --git a/webapp/channels/src/components/search_results_header/search_results_header.test.tsx b/webapp/channels/src/components/search_results_header/search_results_header.test.tsx index 0837a564be..ec6dd6aa64 100644 --- a/webapp/channels/src/components/search_results_header/search_results_header.test.tsx +++ b/webapp/channels/src/components/search_results_header/search_results_header.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {RHSStates} from 'utils/constants'; import type {RhsState} from 'types/store/rhs'; @@ -12,7 +12,7 @@ import Header from './search_results_header'; describe('search_results_header', () => { test('should display back button when the parent is channel info', () => { - renderWithIntl( + renderWithContext(
{ expect(screen.getByLabelText('Back Icon')).toBeInTheDocument(); }); test('should NOT diplay expand when the parent is channel info', () => { - renderWithIntl( + renderWithContext(
{ expect(screen.queryByLabelText('Expand Sidebar Icon')).not.toBeInTheDocument(); }); test('should diplay expand when the parent is NOT channel info', () => { - renderWithIntl( + renderWithContext(
{ it('renders the form', () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); screen.getByText('Provide your payment details'); screen.getByText('Add new seats'); @@ -283,13 +283,13 @@ describe('SelfHostedExpansionModal Open', () => { }); it('filling the form enables expansion', () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); expect(screen.getByText('Complete purchase')).toBeDisabled(); fillForm(defaultSuccessForm); }); it('happy path submit shows success screen when confirmation succeeds', async () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); expect(screen.getByText('Complete purchase')).toBeDisabled(); const upgradeButton = fillForm(defaultSuccessForm); @@ -299,7 +299,7 @@ describe('SelfHostedExpansionModal Open', () => { }); it('happy path submit shows submitting screen while requesting confirmation', async () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); expect(screen.getByText('Complete purchase')).toBeDisabled(); const upgradeButton = fillForm(defaultSuccessForm); @@ -309,7 +309,7 @@ describe('SelfHostedExpansionModal Open', () => { }); it('sad path submit shows error screen', async () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); expect(screen.getByText('Complete purchase')).toBeDisabled(); fillForm(defaultSuccessForm); changeByPlaceholder('Organization Name', failOrg); @@ -323,7 +323,7 @@ describe('SelfHostedExpansionModal Open', () => { describe('SelfHostedExpansionModal RHS Card', () => { it('New seats input should be pre-populated with the difference from the active users and licensed seats', () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); const expectedPrePopulatedSeats = (initialState.entities?.users?.filteredStats?.total_users_count || 1) - parseInt(initialState.entities?.general?.license?.Users || '1', 10); @@ -335,7 +335,7 @@ describe('SelfHostedExpansionModal RHS Card', () => { it('Seat input only allows users to fill input with the licensed seats and active users difference if it is not 0', () => { const expectedUserOverage = '50'; - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); fillForm(defaultSuccessForm); // The seat input should already have the expected value. @@ -362,7 +362,7 @@ describe('SelfHostedExpansionModal RHS Card', () => { const expectedAddNewSeats = '1'; - renderWithIntlAndStore(
, state); + renderWithContext(
, state); fillForm(defaultSuccessForm); // Try to set a negative value. @@ -375,7 +375,7 @@ describe('SelfHostedExpansionModal RHS Card', () => { }); it('Cost per User should be represented as the current subscription price multiplied by the remaining months', () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); const expectedCostPerUser = monthsUntilLicenseExpiry * mockProfessionalProduct.price_per_seat; @@ -389,7 +389,7 @@ describe('SelfHostedExpansionModal RHS Card', () => { }); it('Total cost User should be represented as the current subscription price multiplied by the remaining months multiplied by the number of users', () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); const seatsInputValue = 100; changeByTestId('seatsInput', seatsInputValue.toString()); diff --git a/webapp/channels/src/components/self_hosted_purchases/self_hosted_purchase_modal/index.test.tsx b/webapp/channels/src/components/self_hosted_purchases/self_hosted_purchase_modal/index.test.tsx index 53af4a5617..2a56b28849 100644 --- a/webapp/channels/src/components/self_hosted_purchases/self_hosted_purchase_modal/index.test.tsx +++ b/webapp/channels/src/components/self_hosted_purchases/self_hosted_purchase_modal/index.test.tsx @@ -9,7 +9,7 @@ import type {DeepPartial} from '@mattermost/types/utilities'; import { fireEvent, - renderWithIntlAndStore, + renderWithContext, screen, waitFor, } from 'tests/react_testing_utils'; @@ -254,7 +254,7 @@ function fillForm(form: PurchaseForm) { describe('SelfHostedPurchaseModal', () => { it('renders the form', () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); // check title, and some of the most prominent details and secondary actions screen.getByText('Provide your payment details'); @@ -267,13 +267,13 @@ describe('SelfHostedPurchaseModal', () => { }); it('filling the form enables signup', () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); expect(screen.getByText('Upgrade')).toBeDisabled(); fillForm(defaultSuccessForm); }); it('disables signup if too few seats chosen', () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); fillForm(defaultSuccessForm); const tooFewSeats = existingUsers - 1; @@ -283,7 +283,7 @@ describe('SelfHostedPurchaseModal', () => { }); it('Minimum of 10 seats is required for sign up', () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); fillForm(defaultSuccessForm); const tooFewSeats = 9; @@ -293,7 +293,7 @@ describe('SelfHostedPurchaseModal', () => { }); it('happy path submit shows success screen', async () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); expect(screen.getByText('Upgrade')).toBeDisabled(); const upgradeButton = fillForm(defaultSuccessForm); @@ -302,7 +302,7 @@ describe('SelfHostedPurchaseModal', () => { }); it('sad path submit shows error screen', async () => { - renderWithIntlAndStore(
, initialState); + renderWithContext(
, initialState); expect(screen.getByText('Upgrade')).toBeDisabled(); fillForm(defaultSuccessForm); changeByPlaceholder('Organization Name', failOrg); diff --git a/webapp/channels/src/components/sidebar/sidebar.test.tsx b/webapp/channels/src/components/sidebar/sidebar.test.tsx index 6aa9d3d1bf..b83ce9f01b 100644 --- a/webapp/channels/src/components/sidebar/sidebar.test.tsx +++ b/webapp/channels/src/components/sidebar/sidebar.test.tsx @@ -9,7 +9,7 @@ import type {DeepPartial} from '@mattermost/types/utilities'; import {Preferences} from 'mattermost-redux/constants'; import mergeObjects from 'packages/mattermost-redux/test/merge_objects'; -import {renderWithFullContext, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import Constants, {ModalIdentifiers} from 'utils/constants'; import {TestHelper} from 'utils/test_helper'; @@ -180,7 +180,7 @@ describe('components/sidebar', () => { }, }); - renderWithFullContext( + renderWithContext( , mergeObjects(baseState, testState), ); @@ -204,7 +204,7 @@ describe('components/sidebar', () => { }, }; - renderWithFullContext( + renderWithContext( , mergeObjects(baseState, testState), ); @@ -223,7 +223,7 @@ describe('components/sidebar', () => { }, }; - renderWithFullContext( + renderWithContext( , mergeObjects(baseState, testState), ); @@ -242,12 +242,12 @@ describe('components/sidebar', () => { }, views: { channel: { - lastUnreadChannel: {id: channel1.id}, + lastUnreadChannel: {id: channel1.id} as any, }, }, }; - renderWithFullContext( + renderWithContext( , mergeObjects(baseState, testState), ); diff --git a/webapp/channels/src/components/signup/signup.test.tsx b/webapp/channels/src/components/signup/signup.test.tsx index 79a7504fc1..0e389dd93e 100644 --- a/webapp/channels/src/components/signup/signup.test.tsx +++ b/webapp/channels/src/components/signup/signup.test.tsx @@ -18,7 +18,7 @@ import Input from 'components/widgets/inputs/input/input'; import PasswordInput from 'components/widgets/inputs/password_input/password_input'; import {mountWithIntl} from 'tests/helpers/intl-test-helper'; -import {act, renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {act, renderWithContext, screen} from 'tests/react_testing_utils'; import {WindowSizes} from 'utils/constants'; import type {GlobalState} from 'types/store'; @@ -293,10 +293,9 @@ describe('components/signup/Signup', () => { jest.spyOn(useCWSAvailabilityCheckAll, 'default').mockImplementation(() => true); mockLicense = {IsLicensed: 'true', Cloud: 'false'}; - const {container: signupContainer} = renderWithIntlAndStore( - - - , {}); + const {container: signupContainer} = renderWithContext( + , + ); screen.getByTestId('signup-body-card-form-check-newsletter'); const checkInput = screen.getByTestId('signup-body-card-form-check-newsletter'); @@ -309,10 +308,9 @@ describe('components/signup/Signup', () => { jest.spyOn(useCWSAvailabilityCheckAll, 'default').mockImplementation(() => false); mockLicense = {IsLicensed: 'true', Cloud: 'false'}; - const {container: signupContainer} = renderWithIntlAndStore( - - - , {}); + const {container: signupContainer} = renderWithContext( + , + ); expect(() => screen.getByTestId('signup-body-card-form-check-newsletter')).toThrow(); expect(signupContainer).toHaveTextContent('Interested in receiving Mattermost security, product, promotions, and company updates updates via newsletter?Sign up at https://mattermost.com/security-updates/.'); @@ -322,10 +320,9 @@ describe('components/signup/Signup', () => { jest.spyOn(useCWSAvailabilityCheckAll, 'default').mockImplementation(() => true); mockLicense = {IsLicensed: 'true', Cloud: 'true'}; - const {container: signupContainer} = renderWithIntlAndStore( - - - , {}); + const {container: signupContainer} = renderWithContext( + , + ); screen.getByTestId('signup-body-card-form-check-newsletter'); const checkInput = screen.getByTestId('signup-body-card-form-check-newsletter'); diff --git a/webapp/channels/src/components/start_trial_form_modal/__snapshots__/start_trial_form_modal.test.tsx.snap b/webapp/channels/src/components/start_trial_form_modal/__snapshots__/start_trial_form_modal.test.tsx.snap index 6bac4edee1..68e268327e 100644 --- a/webapp/channels/src/components/start_trial_form_modal/__snapshots__/start_trial_form_modal.test.tsx.snap +++ b/webapp/channels/src/components/start_trial_form_modal/__snapshots__/start_trial_form_modal.test.tsx.snap @@ -389,7 +389,9 @@ Object { "queryByTestId": [Function], "queryByText": [Function], "queryByTitle": [Function], + "replaceStoreState": [Function], "rerender": [Function], "unmount": [Function], + "updateStoreState": [Function], } `; diff --git a/webapp/channels/src/components/start_trial_form_modal/start_trial_form_modal.test.tsx b/webapp/channels/src/components/start_trial_form_modal/start_trial_form_modal.test.tsx index 9f8ebf064d..0d8163a9d9 100644 --- a/webapp/channels/src/components/start_trial_form_modal/start_trial_form_modal.test.tsx +++ b/webapp/channels/src/components/start_trial_form_modal/start_trial_form_modal.test.tsx @@ -2,21 +2,21 @@ // See LICENSE.txt for license information. import React from 'react'; -import {Provider} from 'react-redux'; import {BrowserRouter} from 'react-router-dom'; +import type {DeepPartial} from '@mattermost/types/utilities'; + import {trackEvent} from 'actions/telemetry_actions'; import { - act, - renderWithIntl, + renderWithContext, screen, + waitFor, } from 'tests/react_testing_utils'; -import type { - RenderResult} from 'tests/react_testing_utils'; -import mockStore from 'tests/test_store'; import {ModalIdentifiers} from 'utils/constants'; +import type {GlobalState} from 'types/store'; + import StartTrialFormModal from '.'; jest.mock('actions/telemetry_actions.jsx', () => { @@ -28,7 +28,7 @@ jest.mock('actions/telemetry_actions.jsx', () => { }); describe('components/start_trial_form_modal/start_trial_form_modal', () => { - const state = { + const state: DeepPartial = { entities: { users: { currentUserId: 'user1', @@ -54,7 +54,7 @@ describe('components/start_trial_form_modal/start_trial_form_modal', () => { modals: { modalState: { [ModalIdentifiers.START_TRIAL_FORM_MODAL]: { - open: 'true', + open: true, }, }, }, @@ -74,42 +74,38 @@ describe('components/start_trial_form_modal/start_trial_form_modal', () => { }; test('should match snapshot', async () => { - const store = await mockStore(state); - let wrapper: RenderResult | HTMLElement | null; - await act(async () => { - wrapper = await renderWithIntl( - - - - - ); + const wrapper = await waitFor(() => { + return renderWithContext( + + + , + state, + ); }); expect(wrapper!).toMatchSnapshot(); }); - test('should pre-fill email, fire trackEvent', async () => { - const store = await mockStore(state); - await act(async () => { - await renderWithIntl( - - - - - ); + test('should pre-fill email, fire trackEvent', () => { + waitFor(() => { + renderWithContext( + + + , + state, + ); }); expect(screen.getByDisplayValue('test@mattermost.com')).toBeInTheDocument(); expect(trackEvent).toHaveBeenCalled(); }); - test('Start trial button should be disabled on load', async () => { - const store = await mockStore(state); - await act(async () => { - await renderWithIntl( - - - - - ); + test('Start trial button should be disabled on load', () => { + waitFor(() => { + renderWithContext( + + + , + state, + ); }); expect(screen.getByRole('button', {name: 'Start trial'})).toBeDisabled(); }); diff --git a/webapp/channels/src/components/toast_wrapper/toast_wrapper.test.tsx b/webapp/channels/src/components/toast_wrapper/toast_wrapper.test.tsx index f5de26ced1..c5b4723ca6 100644 --- a/webapp/channels/src/components/toast_wrapper/toast_wrapper.test.tsx +++ b/webapp/channels/src/components/toast_wrapper/toast_wrapper.test.tsx @@ -12,7 +12,7 @@ import {HINT_TOAST_TESTID} from 'components/hint-toast/hint_toast'; import {SCROLL_TO_BOTTOM_DISMISS_BUTTON_TESTID, SCROLL_TO_BOTTOM_TOAST_TESTID} from 'components/scroll_to_bottom_toast/scroll_to_bottom_toast'; import {shallowWithIntl} from 'tests/helpers/intl-test-helper'; -import {renderWithIntlAndStore} from 'tests/react_testing_utils'; +import {renderWithContext} from 'tests/react_testing_utils'; import {getHistory} from 'utils/browser_history'; import {PostListRowListIds} from 'utils/constants'; @@ -630,7 +630,7 @@ describe('components/ToastWrapper', () => { newRecentMessagesCount: 5, showScrollToBottomToast: true, }; - renderWithIntlAndStore(); + renderWithContext(); const scrollToBottomToast = screen.queryByTestId(SCROLL_TO_BOTTOM_TOAST_TESTID); expect(scrollToBottomToast).not.toBeInTheDocument(); }); @@ -644,7 +644,7 @@ describe('components/ToastWrapper', () => { showScrollToBottomToast: true, }; - renderWithIntlAndStore(); + renderWithContext(); const scrollToBottomToast = screen.queryByTestId(SCROLL_TO_BOTTOM_TOAST_TESTID); expect(scrollToBottomToast).not.toBeInTheDocument(); @@ -656,7 +656,7 @@ describe('components/ToastWrapper', () => { showScrollToBottomToast: false, }; - renderWithIntlAndStore(); + renderWithContext(); const scrollToBottomToast = screen.queryByTestId(SCROLL_TO_BOTTOM_TOAST_TESTID); expect(scrollToBottomToast).not.toBeInTheDocument(); @@ -669,7 +669,7 @@ describe('components/ToastWrapper', () => { showScrollToBottomToast: true, }; - renderWithIntlAndStore(); + renderWithContext(); const scrollToBottomToast = screen.queryByTestId(SCROLL_TO_BOTTOM_TOAST_TESTID); expect(scrollToBottomToast).toBeInTheDocument(); @@ -682,7 +682,7 @@ describe('components/ToastWrapper', () => { showScrollToBottomToast: true, }; - renderWithIntlAndStore(); + renderWithContext(); const scrollToBottomToast = screen.queryByTestId(SCROLL_TO_BOTTOM_TOAST_TESTID); const hintToast = screen.queryByTestId(HINT_TOAST_TESTID); @@ -698,7 +698,7 @@ describe('components/ToastWrapper', () => { showScrollToBottomToast: true, }; - renderWithIntlAndStore(); + renderWithContext(); const scrollToBottomToast = screen.getByTestId(SCROLL_TO_BOTTOM_TOAST_TESTID); fireEvent.click(scrollToBottomToast); @@ -715,7 +715,7 @@ describe('components/ToastWrapper', () => { showScrollToBottomToast: true, }; - renderWithIntlAndStore(); + renderWithContext(); const scrollToBottomToastDismiss = screen.getByTestId(SCROLL_TO_BOTTOM_DISMISS_BUTTON_TESTID); fireEvent.click(scrollToBottomToastDismiss); diff --git a/webapp/channels/src/components/user_settings/display/user_settings_theme/user_settings_theme.test.tsx b/webapp/channels/src/components/user_settings/display/user_settings_theme/user_settings_theme.test.tsx index b59f32856a..c3598d347f 100644 --- a/webapp/channels/src/components/user_settings/display/user_settings_theme/user_settings_theme.test.tsx +++ b/webapp/channels/src/components/user_settings/display/user_settings_theme/user_settings_theme.test.tsx @@ -4,13 +4,10 @@ import {shallow} from 'enzyme'; import React from 'react'; import type {ComponentProps} from 'react'; -import {IntlProvider} from 'react-intl'; -import {Provider} from 'react-redux'; import {Preferences} from 'mattermost-redux/constants'; -import {render, fireEvent, screen} from 'tests/react_testing_utils'; -import mockStore from 'tests/test_store'; +import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils'; import UserSettingsTheme from './user_settings_theme'; @@ -34,7 +31,6 @@ describe('components/user_settings/display/user_settings_theme/user_settings_the }, }, }; - const store = mockStore(initialState); const requiredProps: ComponentProps = { theme: Preferences.THEMES.denim, @@ -105,12 +101,9 @@ describe('components/user_settings/display/user_settings_theme/user_settings_the selected: true, }; - render( - - - - - , + renderWithContext( + , + initialState, ); // Click the Slack Import button diff --git a/webapp/channels/src/components/user_settings/notifications/user_settings_notifications.test.tsx b/webapp/channels/src/components/user_settings/notifications/user_settings_notifications.test.tsx index 810621e81c..af98b1f601 100644 --- a/webapp/channels/src/components/user_settings/notifications/user_settings_notifications.test.tsx +++ b/webapp/channels/src/components/user_settings/notifications/user_settings_notifications.test.tsx @@ -4,7 +4,7 @@ import React from 'react'; import {type IntlShape} from 'react-intl'; -import {renderWithFullContext, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {TestHelper} from 'utils/test_helper'; import UserSettingsNotifications from './user_settings_notifications'; @@ -25,7 +25,7 @@ describe('components/user_settings/display/UserSettingsDisplay', () => { }; test('should match snapshot', () => { - const wrapper = renderWithFullContext( + const wrapper = renderWithContext( , ); @@ -35,7 +35,7 @@ describe('components/user_settings/display/UserSettingsDisplay', () => { test('should show reply notifications section when CRT off', () => { const props = {...defaultProps, isCollapsedThreadsEnabled: false}; - renderWithFullContext(); + renderWithContext(); expect(screen.getByText('Reply notifications')).toBeInTheDocument(); }); diff --git a/webapp/channels/src/components/widgets/menu/menu_items/useWords.test.tsx b/webapp/channels/src/components/widgets/menu/menu_items/useWords.test.tsx index fecf2949a4..aa4151485f 100644 --- a/webapp/channels/src/components/widgets/menu/menu_items/useWords.test.tsx +++ b/webapp/channels/src/components/widgets/menu/menu_items/useWords.test.tsx @@ -2,12 +2,10 @@ // See LICENSE.txt for license information. import React from 'react'; -import {Provider} from 'react-redux'; import type {LimitSummary} from 'components/common/hooks/useGetHighestThresholdCloudLimit'; -import {renderWithIntl, screen} from 'tests/react_testing_utils'; -import mockStore from 'tests/test_store'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import {FileSizes} from 'utils/file_utils'; import {LimitTypes} from 'utils/limits'; @@ -158,7 +156,7 @@ describe('useWords', () => { }, ]; - const store = mockStore({ + const initialState = { entities: { general: { license: { @@ -166,13 +164,12 @@ describe('useWords', () => { }, }, }, - }); + }; tests.forEach((t: Test) => { test(t.label, () => { - renderWithIntl( - - - , + renderWithContext( + , + initialState, ); if (t.expects.empty) { screen.getByText(emptyText); diff --git a/webapp/channels/src/components/widgets/tag/guest_tag.test.tsx b/webapp/channels/src/components/widgets/tag/guest_tag.test.tsx index 09332b8f62..ba231f0929 100644 --- a/webapp/channels/src/components/widgets/tag/guest_tag.test.tsx +++ b/webapp/channels/src/components/widgets/tag/guest_tag.test.tsx @@ -3,18 +3,18 @@ import React from 'react'; -import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils'; +import {renderWithContext, screen} from 'tests/react_testing_utils'; import GuestTag from './guest_tag'; describe('components/widgets/tag/GuestTag', () => { test('should match the snapshot', () => { - renderWithIntlAndStore(); + renderWithContext(); screen.getByText('GUEST'); }); test('should not render when hideTags is true', () => { - renderWithIntlAndStore(, {entities: {general: {config: {HideGuestTags: 'true'}}}}); + renderWithContext(, {entities: {general: {config: {HideGuestTags: 'true'}}}}); expect(() => screen.getByText('GUEST')).toThrow(); }); }); diff --git a/webapp/channels/src/tests/react_testing_utils.test.tsx b/webapp/channels/src/tests/react_testing_utils.test.tsx index a90d88cc76..ed05c50274 100644 --- a/webapp/channels/src/tests/react_testing_utils.test.tsx +++ b/webapp/channels/src/tests/react_testing_utils.test.tsx @@ -3,25 +3,37 @@ import React from 'react'; import {FormattedMessage, useIntl} from 'react-intl'; -import {connect, useSelector} from 'react-redux'; +import {connect, useDispatch, useSelector} from 'react-redux'; import {Link, Route} from 'react-router-dom'; +import {GenericModal} from '@mattermost/components'; + +import {UserTypes} from 'mattermost-redux/action_types'; import {getUser} from 'mattermost-redux/selectors/entities/users'; +import {openModal} from 'actions/views/modals'; + +import ModalController from 'components/modal_controller'; + import mergeObjects from 'packages/mattermost-redux/test/merge_objects'; import {TestHelper} from 'utils/test_helper'; import type {GlobalState} from 'types/store'; -import {renderWithFullContext, screen} from './react_testing_utils'; +import { + renderWithContext, + screen, + userEvent, + waitFor, +} from './react_testing_utils'; -describe('renderWithFullContext', () => { +describe('renderWithContext', () => { test('should be able to render anything', () => { const TestComponent = () => { return
{'Anything'}
; }; - renderWithFullContext( + renderWithContext( , {}, ); @@ -39,7 +51,7 @@ describe('renderWithFullContext', () => { ); }; - renderWithFullContext( + renderWithContext( , ); @@ -53,7 +65,7 @@ describe('renderWithFullContext', () => { return
{intl.formatMessage({id: 'about.hash', defaultMessage: 'Build Hash:'})}
; }; - renderWithFullContext( + renderWithContext( , ); @@ -76,7 +88,7 @@ describe('renderWithFullContext', () => { ); }; - renderWithFullContext( + renderWithContext( , ); @@ -92,7 +104,7 @@ describe('renderWithFullContext', () => { numProfiles: Object.keys(state.entities.users.profiles).length, }))(UnconnectedTestComponent); - renderWithFullContext( + renderWithContext( , ); @@ -105,7 +117,7 @@ describe('renderWithFullContext', () => { return
{`There are ${numProfiles} users loaded`}
; }; - renderWithFullContext( + renderWithContext( , ); @@ -125,7 +137,7 @@ describe('renderWithFullContext', () => { ); }; - const {rerender} = renderWithFullContext( + const {rerender} = renderWithContext( , ); @@ -157,7 +169,7 @@ describe('renderWithFullContext', () => { return
{`User1 is ${user1.username} and User2 is ${user2.username}!`}
; }; - const {replaceStoreState} = renderWithFullContext( + const {replaceStoreState} = renderWithContext( , initialState, ); @@ -209,7 +221,7 @@ describe('renderWithFullContext', () => { return
{`User1 is ${user1.username} and User2 is ${user2.username}!`}
; }; - const {updateStoreState} = renderWithFullContext( + const {updateStoreState} = renderWithContext( , initialState, ); @@ -240,4 +252,141 @@ describe('renderWithFullContext', () => { expect(screen.getByText('User1 is Golf and User2 is Hotel!')).toBeInTheDocument(); }); + + test('should be able to mix rerendering and updating store state', () => { + const initialState = { + entities: { + users: { + profiles: { + user1: TestHelper.getUserMock({id: 'user1', username: 'India'}), + }, + }, + }, + }; + + const TestComponent = (props: {greeting: string}) => { + const user1 = useSelector((state: GlobalState) => getUser(state, 'user1')); + + return
{`${props.greeting}, ${user1.username}!`}
; + }; + + const {rerender, updateStoreState} = renderWithContext( + , + initialState, + ); + + expect(screen.getByText('Hello, India!')).toBeInTheDocument(); + + updateStoreState({ + entities: { + users: { + profiles: { + user1: {username: 'Juliet'}, + }, + }, + }, + }); + + expect(screen.getByText('Hello, Juliet!')).toBeInTheDocument(); + + rerender(); + + expect(screen.getByText('Salutations, Juliet!')).toBeInTheDocument(); + + updateStoreState({ + entities: { + users: { + profiles: { + user1: {username: 'Kilo'}, + }, + }, + }, + }); + + expect(screen.getByText('Salutations, Kilo!')).toBeInTheDocument(); + + rerender(); + + expect(screen.getByText('Bonjour, Kilo!')).toBeInTheDocument(); + }); + + test('should be able to dispatch and handle redux actions', () => { + const TestComponent = () => { + const user1 = useSelector((state: GlobalState) => getUser(state, 'user1')); + const dispatch = useDispatch(); + + const username = user1 ? user1.username : 'NOT_LOADED'; + + const loadUser = () => { + dispatch({ + type: UserTypes.RECEIVED_PROFILE, + data: {id: 'user1', username: 'Lima'}, + }); + }; + + return ( +
+ {`User1 is ${username}!`} + +
+ ); + }; + + renderWithContext(); + + expect(screen.getByText('User1 is NOT_LOADED!')).toBeInTheDocument(); + + userEvent.click(screen.getByText('Load User')); + + expect(screen.getByText('User1 is Lima!')).toBeInTheDocument(); + }); + + test('should be able to render modals using a ModalController', async () => { + const TestComponent = () => { + const dispatch = useDispatch(); + + const openTestModal = () => { + dispatch(openModal({ + modalId: 'test_modal', + dialogType: TestModal, + })); + }; + + return ( +
+ +
+ ); + }; + + const TestModal = (props: {onExited: () => void}) => { + return ( + +

{'This is a modal!'}

+
+ ); + }; + + renderWithContext( + <> + + + , + ); + + expect(screen.getByText('Open Modal')).toBeVisible(); + + userEvent.click(screen.getByText('Open Modal')); + + // Use waitFor because the modal animates in and out + await waitFor(() => { + expect(screen.queryByText('This is a modal!')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByLabelText('Close')); + + await waitFor(() => { + expect(screen.queryByText('This is a modal!')).not.toBeInTheDocument(); + }); + }); }); diff --git a/webapp/channels/src/tests/react_testing_utils.tsx b/webapp/channels/src/tests/react_testing_utils.tsx index c1f75bd08b..47915988b7 100644 --- a/webapp/channels/src/tests/react_testing_utils.tsx +++ b/webapp/channels/src/tests/react_testing_utils.tsx @@ -22,50 +22,42 @@ import type {GlobalState} from 'types/store'; export * from '@testing-library/react'; export {userEvent}; -export const renderWithIntl = (component: React.ReactNode | React.ReactNodeArray, locale = 'en') => { - return render({component}); -}; +export type FullContextOptions = { + locale?: string; + useMockedStore?: boolean; +} -export const renderWithIntlAndStore = (component: React.ReactNode | React.ReactNodeArray, initialState: DeepPartial = {}, locale = 'en', divContainer?: HTMLDivElement) => { - // We use a redux-mock-store store for testing, but we set up a real store to ensure the initial state is complete - const realStore = configureStore(initialState); +export const renderWithContext = ( + component: React.ReactElement, + initialState: DeepPartial = {}, + partialOptions?: FullContextOptions, +) => { + const options = { + locale: partialOptions?.locale ?? 'en', + useMockedStore: partialOptions?.useMockedStore ?? false, + }; - const store = mockStore(realStore.getState()); - - return render( - - - {component} - - , - {container: divContainer}, - ); -}; - -export const renderWithFullContext = (component: React.ReactNode | React.ReactNodeArray, initialState: DeepPartial = {}, locale = 'en') => { - // We use a redux-mock-store store for testing, but we set up a real store to ensure the initial state is complete - const testState = configureStore(initialState).getState(); + const testStore = configureOrMockStore(initialState, options.useMockedStore); // Store these in an object so that they can be maintained through rerenders const renderState = { component, history: createBrowserHistory(), - locale, - state: testState, - store: mockStore(testState), + options, + store: testStore, }; // This should wrap the component in roughly the same providers used in App and RootProvider - function wrapComponent() { + function WrapComponent(props: {children: React.ReactElement}) { // Every time this is called, these values should be updated from `renderState` return ( - {renderState.component} + {props.children} @@ -73,36 +65,41 @@ export const renderWithFullContext = (component: React.ReactNode | React.ReactNo ); } - const results = render(wrapComponent()); + const results = render(component, {wrapper: WrapComponent}); return { ...results, - rerender: (newComponent: React.ReactNode | React.ReactNodeArray) => { + rerender: (newComponent: React.ReactElement) => { renderState.component = newComponent; - results.rerender(wrapComponent()); + results.rerender(renderState.component); }, /** * Rerenders the component after replacing the entire store state with the provided one. */ replaceStoreState: (newInitialState: DeepPartial) => { - const newTestState = configureStore(newInitialState).getState(); - renderState.state = newTestState; - renderState.store = mockStore(newTestState); + renderState.store = configureOrMockStore(newInitialState, renderState.options.useMockedStore); - results.rerender(wrapComponent()); + results.rerender(renderState.component); }, /** * Rerenders the component after merging the current store state with the provided one. */ updateStoreState: (stateDiff: DeepPartial) => { - const newTestState = mergeObjects(renderState.state, stateDiff); - renderState.state = newTestState; - renderState.store = mockStore(newTestState); + const newInitialState = mergeObjects(renderState.store.getState(), stateDiff); + renderState.store = configureOrMockStore(newInitialState, renderState.options.useMockedStore); - results.rerender(wrapComponent()); + results.rerender(renderState.component); }, }; }; + +function configureOrMockStore(initialState: DeepPartial, useMockedStore: boolean) { + let testStore = configureStore(initialState); + if (useMockedStore) { + testStore = mockStore(testStore.getState()); + } + return testStore; +} diff --git a/webapp/platform/types/src/utilities.ts b/webapp/platform/types/src/utilities.ts index 636f44a92f..b74b05e371 100644 --- a/webapp/platform/types/src/utilities.ts +++ b/webapp/platform/types/src/utilities.ts @@ -14,7 +14,14 @@ export type RelationOneToManyUnique = RelationOneToOne; export type DeepPartial = { - [P in keyof T]?: DeepPartial; + // For each field of T, make it optional and... + [K in keyof T]?: + // If that field is an object, make it a deep partial object + T[K] extends object ? DeepPartial : + // Else if that field is an optional object, make that a deep partial object + T[K] extends object | undefined ? DeepPartial : + // Else leave it as an optional primitive + T[K]; } export type ValueOf = T[keyof T]; @@ -26,4 +33,4 @@ export type RequireOnlyOne = Pick> & {[K in Keys]-?: Required> & Partial, undefined>>}[Keys]; export type Intersection = -Omit)>, keyof(Omit)>; \ No newline at end of file +Omit)>, keyof(Omit)>;