Run component tests with a real store and use renderWithContext everywhere (#25217)

* Change renderWithFullContext to not mock Redux store

* Remove renderWithIntl and renderWithIntlAndStore

* Rename renderWithFullContext to renderWithContext

* Use renderWithContext for WS context
Этот коммит содержится в:
Harrison Healey
2023-11-08 17:02:40 -05:00
коммит произвёл GitHub
родитель ab349946db
Коммит be34a5d2df
82 изменённых файлов: 1355 добавлений и 1421 удалений

Просмотреть файл

@@ -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(
<AboutBuildModalCloud
config={config}
license={license}
@@ -154,7 +154,7 @@ describe('components/AboutBuildModal', () => {
},
};
renderWithFullContext(
renderWithContext(
<AboutBuildModal
config={config}
license={license}
@@ -181,7 +181,7 @@ describe('components/AboutBuildModal', () => {
},
},
};
renderWithFullContext(
renderWithContext(
<AboutBuildModal
config={config}
license={license}
@@ -210,6 +210,6 @@ describe('components/AboutBuildModal', () => {
...props,
};
return renderWithFullContext(<AboutBuildModal {...allProps}/>);
return renderWithContext(<AboutBuildModal {...allProps}/>);
}
});

Просмотреть файл

@@ -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(
<MenuItemBlockableLinkImpl
to='/wherever'
text='Whatever'

Просмотреть файл

@@ -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 {TestHelper} from 'utils/test_helper';
import AdminUserCard from './admin_user_card';
@@ -22,7 +22,7 @@ describe('components/admin_console/admin_user_card/admin_user_card', () => {
test('should match default snapshot', () => {
const props = defaultProps;
const {container} = renderWithIntl(<AdminUserCard {...props}/>);
const {container} = renderWithContext(<AdminUserCard {...props}/>);
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(<AdminUserCard {...props}/>);
const {container} = renderWithContext(<AdminUserCard {...props}/>);
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(<AdminUserCard {...props}/>);
const {container} = renderWithContext(<AdminUserCard {...props}/>);
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(<AdminUserCard {...props}/>);
const {container} = renderWithContext(<AdminUserCard {...props}/>);
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();

Просмотреть файл

@@ -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(
<Provider store={store}>
<BillingHistory/>
</Provider>,
renderWithContext(
<BillingHistory/>,
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(
<Provider store={storeNoBillingHistory}>
<BillingHistory/>
</Provider>,
renderWithContext(
<BillingHistory/>,
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(
<Provider store={store}>
<BillingHistory/>
</Provider>,
renderWithContext(
<BillingHistory/>,
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(
<Provider store={store}>
<BillingHistory/>
</Provider>,
renderWithContext(
<BillingHistory/>,
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(
<Provider store={storeNoBillingHistory}>
<BillingHistory/>
</Provider>,
renderWithContext(
<BillingHistory/>,
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(
<Provider store={store}>
<BillingHistory/>
</Provider>,
renderWithContext(
<BillingHistory/>,
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(<NoBillingHistorySection selfHosted={false}/>, state);
renderWithContext(
<NoBillingHistorySection selfHosted={false}/>,
state,
);
expect((screen.getByRole('link') as HTMLAnchorElement).href).toContain(CloudLinks.BILLING_DOCS);
});
test('goes to self-hosted docs on self-hosted', () => {
renderWithIntlAndStore(<NoBillingHistorySection selfHosted={true}/>, state);
renderWithContext(
<NoBillingHistorySection selfHosted={true}/>,
state,
);
expect((screen.getByRole('link') as HTMLAnchorElement).href).toContain(HostedCustomerLinks.SELF_HOSTED_BILLING);
});
});

Просмотреть файл

@@ -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(<LimitReachedBanner product={enterprise}/>, state);
renderWithContext(<LimitReachedBanner product={enterprise}/>, 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(<LimitReachedBanner product={enterprise}/>, myState);
renderWithContext(<LimitReachedBanner product={enterprise}/>, 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(<LimitReachedBanner product={free}/>, state);
renderWithContext(<LimitReachedBanner product={free}/>, 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(<LimitReachedBanner product={free}/>, state);
renderWithContext(<LimitReachedBanner product={free}/>, 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(<LimitReachedBanner product={free}/>, state);
renderWithContext(<LimitReachedBanner product={free}/>, state);
screen.getByText(titleFree);
expect(screen.queryByText(titleProfessional)).not.toBeInTheDocument();

Просмотреть файл

@@ -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<GlobalState> {
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(<Provider store={store}><Limits/></Provider>);
renderWithContext(<Limits/>, state);
screen.getByText('Message History');
screen.getByText(/of 10K/);
});
test('storage limit rendered in GB', () => {
const store = setupStore(defaultOptions);
const state = setupState(defaultOptions);
renderWithIntl(<Provider store={store}><Limits/></Provider>);
renderWithContext(<Limits/>, 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(<Provider store={store}><Limits/></Provider>);
renderWithContext(<Limits/>, 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(<Provider store={store}><Limits/></Provider>);
renderWithContext(<Limits/>, state);
screen.getByTestId('limits-panel-title');
});
});

Просмотреть файл

@@ -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(<ToPaidPlanBannerDismissable/>, state);
renderWithContext(<ToPaidPlanBannerDismissable/>, state, {useMockedStore: true});
screen.getByTestId('cloud-free-deprecation-announcement-bar');
});
@@ -84,7 +84,7 @@ describe('ToPaidPlanBannerDismissable', () => {
},
};
renderWithIntlAndStore(<ToPaidPlanBannerDismissable/>, state);
renderWithContext(<ToPaidPlanBannerDismissable/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-free-deprecation-announcement-bar')).toThrow();
});
@@ -108,7 +108,7 @@ describe('ToPaidPlanBannerDismissable', () => {
},
};
renderWithIntlAndStore(<ToPaidPlanBannerDismissable/>, state);
renderWithContext(<ToPaidPlanBannerDismissable/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-free-deprecation-announcement-bar')).toThrow();
});
@@ -132,7 +132,7 @@ describe('ToPaidPlanBannerDismissable', () => {
},
};
renderWithIntlAndStore(<ToPaidPlanBannerDismissable/>, state);
renderWithContext(<ToPaidPlanBannerDismissable/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-free-deprecation-announcement-bar')).toThrow();
});
@@ -166,7 +166,7 @@ describe('ToPaidPlanBannerDismissable', () => {
},
};
renderWithIntlAndStore(<ToPaidPlanBannerDismissable/>, state);
renderWithContext(<ToPaidPlanBannerDismissable/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-free-deprecation-announcement-bar')).toThrow();
});
@@ -189,7 +189,7 @@ describe('ToPaidNudgeBanner', () => {
},
};
renderWithIntlAndStore(<ToPaidNudgeBanner/>, state);
renderWithContext(<ToPaidNudgeBanner/>, state, {useMockedStore: true});
screen.getByTestId('cloud-free-deprecation-alert-banner');
});
@@ -210,7 +210,7 @@ describe('ToPaidNudgeBanner', () => {
},
};
renderWithIntlAndStore(<ToPaidNudgeBanner/>, state);
renderWithContext(<ToPaidNudgeBanner/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-free-deprecation-alert-banner')).toThrow();
});
@@ -231,7 +231,7 @@ describe('ToPaidNudgeBanner', () => {
},
};
renderWithIntlAndStore(<ToPaidNudgeBanner/>, state);
renderWithContext(<ToPaidNudgeBanner/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-free-deprecation-alert-banner')).toThrow();
});

Просмотреть файл

@@ -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(<ToYearlyNudgeBannerDismissable/>, state);
renderWithContext(<ToYearlyNudgeBannerDismissable/>, state, {useMockedStore: true});
screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar');
});
@@ -85,7 +85,7 @@ describe('ToYearlyNudgeBannerDismissable', () => {
},
};
renderWithIntlAndStore(<ToYearlyNudgeBannerDismissable/>, state);
renderWithContext(<ToYearlyNudgeBannerDismissable/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow();
});
@@ -110,7 +110,7 @@ describe('ToYearlyNudgeBannerDismissable', () => {
},
};
renderWithIntlAndStore(<ToYearlyNudgeBannerDismissable/>, state);
renderWithContext(<ToYearlyNudgeBannerDismissable/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow();
});
@@ -135,7 +135,7 @@ describe('ToYearlyNudgeBannerDismissable', () => {
},
};
renderWithIntlAndStore(<ToYearlyNudgeBannerDismissable/>, state);
renderWithContext(<ToYearlyNudgeBannerDismissable/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow();
});
@@ -159,12 +159,12 @@ describe('ToYearlyNudgeBannerDismissable', () => {
},
},
};
renderWithIntlAndStore(<ToYearlyNudgeBannerDismissable/>, state);
renderWithContext(<ToYearlyNudgeBannerDismissable/>, 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(<ToYearlyNudgeBannerDismissable/>, state);
await waitFor(() => {
renderWithContext(<ToYearlyNudgeBannerDismissable/>, state, {useMockedStore: true});
});
expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow();
});
@@ -218,7 +220,7 @@ describe('ToYearlyNudgeBannerDismissable', () => {
},
};
renderWithIntlAndStore(<ToYearlyNudgeBannerDismissable/>, state);
renderWithContext(<ToYearlyNudgeBannerDismissable/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow();
});
@@ -244,7 +246,7 @@ describe('ToYearlyNudgeBannerDismissable', () => {
},
};
renderWithIntlAndStore(<ToYearlyNudgeBannerDismissable/>, state);
renderWithContext(<ToYearlyNudgeBannerDismissable/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow();
});
@@ -268,7 +270,7 @@ describe('ToYearlyNudgeBanner', () => {
},
};
renderWithIntlAndStore(<ToYearlyNudgeBanner/>, state);
renderWithContext(<ToYearlyNudgeBanner/>, state, {useMockedStore: true});
screen.getByTestId('cloud-pro-monthly-deprecation-alert-banner');
});
@@ -290,7 +292,7 @@ describe('ToYearlyNudgeBanner', () => {
},
};
renderWithIntlAndStore(<ToYearlyNudgeBanner/>, state);
renderWithContext(<ToYearlyNudgeBanner/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-alert-banner')).toThrow();
});
@@ -312,7 +314,7 @@ describe('ToYearlyNudgeBanner', () => {
},
};
renderWithIntlAndStore(<ToYearlyNudgeBanner/>, state);
renderWithContext(<ToYearlyNudgeBanner/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-alert-banner')).toThrow();
});
@@ -335,7 +337,7 @@ describe('ToYearlyNudgeBanner', () => {
},
};
renderWithIntlAndStore(<ToYearlyNudgeBanner/>, state);
renderWithContext(<ToYearlyNudgeBanner/>, state, {useMockedStore: true});
expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-alert-banner')).toThrow();
});

Просмотреть файл

@@ -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(
<ColorSetting
id='id'
label='label'
@@ -30,7 +30,7 @@ describe('components/ColorSetting', () => {
test('should match snapshot, no help text', () => {
function emptyFunction() {} //eslint-disable-line no-empty-function
const {container} = renderWithIntl(
const {container} = renderWithContext(
<ColorSetting
id='id'
label='label'
@@ -47,7 +47,7 @@ describe('components/ColorSetting', () => {
test('should match snapshot, disabled', () => {
function emptyFunction() {} //eslint-disable-line no-empty-function
const {container} = renderWithIntl(
const {container} = renderWithContext(
<ColorSetting
id='id'
label='label'
@@ -65,7 +65,7 @@ describe('components/ColorSetting', () => {
test('should match snapshot, clicked on color setting', () => {
function emptyFunction() {} //eslint-disable-line no-empty-function
const {container} = renderWithIntl(
const {container} = renderWithContext(
<ColorSetting
id='id'
label='label'

Просмотреть файл

@@ -2,14 +2,11 @@
// See LICENSE.txt for license information.
import React from 'react';
import {Provider as ReduxProvider} from 'react-redux';
import store from 'stores/redux_store';
import FeatureDiscovery from 'components/admin_console/feature_discovery/feature_discovery';
import {
renderWithIntl,
renderWithContext,
screen,
userEvent,
waitFor,
@@ -25,33 +22,31 @@ describe('components/feature_discovery', () => {
const getCloudSubscription = jest.fn();
const openModal = jest.fn();
renderWithIntl(
<ReduxProvider store={store}>
<FeatureDiscovery
featureName='test'
minimumSKURequiredForFeature={LicenseSkus.Professional}
titleID='translation.test.title'
titleDefault='Foo'
copyID='translation.test.copy'
copyDefault={'Bar'}
learnMoreURL='https://test.mattermost.com/secondary/'
featureDiscoveryImage={<SamlSVG/>}
// 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,
}}
/>
</ReduxProvider>,
renderWithContext(
<FeatureDiscovery
featureName='test'
minimumSKURequiredForFeature={LicenseSkus.Professional}
titleID='translation.test.title'
titleDefault='Foo'
copyID='translation.test.copy'
copyDefault={'Bar'}
learnMoreURL='https://test.mattermost.com/secondary/'
featureDiscoveryImage={<SamlSVG/>}
// 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(
<ReduxProvider store={store}>
<FeatureDiscovery
featureName='test'
minimumSKURequiredForFeature={LicenseSkus.Professional}
titleID='translation.test.title'
titleDefault='Foo'
copyID='translation.test.copy'
copyDefault={'Bar'}
learnMoreURL='https://test.mattermost.com/secondary/'
featureDiscoveryImage={<SamlSVG/>}
// 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,
}}
/>
</ReduxProvider>,
renderWithContext(
<FeatureDiscovery
featureName='test'
minimumSKURequiredForFeature={LicenseSkus.Professional}
titleID='translation.test.title'
titleDefault='Foo'
copyID='translation.test.copy'
copyDefault={'Bar'}
learnMoreURL='https://test.mattermost.com/secondary/'
featureDiscoveryImage={<SamlSVG/>}
// 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(
<ReduxProvider store={store}>
<FeatureDiscovery
featureName='test'
minimumSKURequiredForFeature={LicenseSkus.Professional}
titleID='translation.test.title'
titleDefault='Foo'
copyID='translation.test.copy'
copyDefault={'Bar'}
learnMoreURL='https://test.mattermost.com/secondary/'
featureDiscoveryImage={<SamlSVG/>}
// 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,
}}
/>
</ReduxProvider>,
renderWithContext(
<FeatureDiscovery
featureName='test'
minimumSKURequiredForFeature={LicenseSkus.Professional}
titleID='translation.test.title'
titleDefault='Foo'
copyID='translation.test.copy'
copyDefault={'Bar'}
learnMoreURL='https://test.mattermost.com/secondary/'
featureDiscoveryImage={<SamlSVG/>}
// 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

Просмотреть файл

@@ -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(
<Provider store={store}>
<EnterpriseEditionLeftPanel
{...props}
{...baseProps}
/>
</Provider>,
);
@@ -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(
<Provider store={store}>
<EnterpriseEditionLeftPanel
{...props}
/>
</Provider>,
test('should not add any class if active users is lower than the minimal', () => {
renderWithContext(
<EnterpriseEditionLeftPanel
{...baseProps}
/>,
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(
<Provider store={store}>
<EnterpriseEditionLeftPanel
{...props}
/>
</Provider>,
renderWithContext(
<EnterpriseEditionLeftPanel
{...props}
/>,
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(
<Provider store={store}>
<EnterpriseEditionLeftPanel
{...props}
/>
</Provider>,
const props = {
...baseProps,
statsActiveUsers: exceedHighLimitExtraUsersError,
};
renderWithContext(
<EnterpriseEditionLeftPanel
{...props}
/>,
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(
<Provider store={store}>
<EnterpriseEditionLeftPanel
{...props}
/>
</Provider>,
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(
<EnterpriseEditionLeftPanel
{...props}
/>,
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(
<Provider store={store}>
<EnterpriseEditionLeftPanel
{...props}
/>
</Provider>,
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(
<EnterpriseEditionLeftPanel
{...props}
/>,
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(
<Provider store={store}>
<EnterpriseEditionLeftPanel
{...props}
/>
</Provider>,
renderWithContext(
<EnterpriseEditionLeftPanel
{...props}
/>,
testState,
);
expect(screen.getByText('+ Add seats')).toBeVisible();

Просмотреть файл

@@ -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(
<AdminTextSetting
id='some.id'
label='some label'

Просмотреть файл

@@ -11,11 +11,9 @@ import Permissions from 'mattermost-redux/constants/permissions';
import type {FileUpload} from 'components/file_upload/file_upload';
import type Textbox from 'components/textbox/textbox';
import WebSocketClient from 'client/web_websocket_client';
import mergeObjects from 'packages/mattermost-redux/test/merge_objects';
import {renderWithFullContext, userEvent} from 'tests/react_testing_utils';
import {renderWithContext, userEvent} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import {WebSocketContext} from 'utils/use_websocket';
import type {PostDraft} from 'types/store/draft';
@@ -152,14 +150,13 @@ describe('components/avanced_text_editor/advanced_text_editor', () => {
describe('keyDown behavior', () => {
it('Enter should call postMsgKeyPress', () => {
const postMsgKeyPress = jest.fn();
renderWithFullContext(
<WebSocketContext.Provider value={WebSocketClient}>
<AdavancedTextEditor
{...baseProps}
postMsgKeyPress={postMsgKeyPress}
message={'test'}
/>
</WebSocketContext.Provider>, mergeObjects(initialState, {
renderWithContext(
<AdavancedTextEditor
{...baseProps}
postMsgKeyPress={postMsgKeyPress}
message={'test'}
/>,
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(
<WebSocketContext.Provider value={WebSocketClient}>
<AdavancedTextEditor
{...baseProps}
loadPrevMessage={loadPrevMessage}
/>
</WebSocketContext.Provider>, mergeObjects(initialState, {
renderWithContext(
<AdavancedTextEditor
{...baseProps}
loadPrevMessage={loadPrevMessage}
/>,
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(
<WebSocketContext.Provider value={WebSocketClient}>
<AdavancedTextEditor
{...baseProps}
onEditLatestPost={onEditLatestPost}
/>
</WebSocketContext.Provider>, mergeObjects(initialState, {
renderWithContext(
<AdavancedTextEditor
{...baseProps}
onEditLatestPost={onEditLatestPost}
/>,
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(
<WebSocketContext.Provider value={WebSocketClient}>
<AdavancedTextEditor
{...baseProps}
/>
</WebSocketContext.Provider>, mergeObjects(initialState, {
renderWithContext(
<AdavancedTextEditor
{...baseProps}
/>,
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(
<WebSocketContext.Provider value={WebSocketClient}>
<AdavancedTextEditor
{...baseProps}
applyMarkdown={applyMarkdown}
message={'Some markdown text'}
/>
</WebSocketContext.Provider>, mergeObjects(initialState, {
renderWithContext(
<AdavancedTextEditor
{...baseProps}
applyMarkdown={applyMarkdown}
message={'Some markdown text'}
/>,
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({

Просмотреть файл

@@ -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<GlobalState> = {
const showsTrueUpReviewState: DeepPartial<GlobalState> = {
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(<TrueUpReview/>, showsTrueUpReviewStore);
renderWithContext(<TrueUpReview/>, 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(<TrueUpReview/>, store);
renderWithContext(<TrueUpReview/>, store);
expect(screen.queryByText('Share to Mattermost')).not.toBeInTheDocument();
});
});

Просмотреть файл

@@ -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<ComponentProps<typeof NotifyAdminDowngradeDeliquencyBar>>;
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(
<reactRedux.Provider store={configureStore(store)}>
<NotifyAdminDowngradeDeliquencyBar/>
</reactRedux.Provider>,
);
};
beforeEach(() => {
jest.clearAllMocks();
});
@@ -113,7 +97,7 @@ describe('components/announcement_bar/notify_admin_downgrade_delinquency_bar', (
is_free_trial: 'false',
};
renderComponent({store: state});
renderWithContext(<NotifyAdminDowngradeDeliquencyBar/>, 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(<NotifyAdminDowngradeDeliquencyBar/>, 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(<NotifyAdminDowngradeDeliquencyBar/>, 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(<NotifyAdminDowngradeDeliquencyBar/>, 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(<NotifyAdminDowngradeDeliquencyBar/>, 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(<NotifyAdminDowngradeDeliquencyBar/>, 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(<NotifyAdminDowngradeDeliquencyBar/>, 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(<NotifyAdminDowngradeDeliquencyBar/>, 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(<NotifyAdminDowngradeDeliquencyBar/>, initialState);
fireEvent.click(screen.getByText('Notify admin'));

Просмотреть файл

@@ -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<typeof OverageUsersBanner>;
type RenderComponentArgs = {
props?: Partial<ComponentProps>;
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(
<OverageUsersBanner/>, store);
};
it('should not render the banner because we are not on overage state', () => {
renderComponent();
renderWithContext(<OverageUsersBanner/>);
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(<OverageUsersBanner/>, 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(<OverageUsersBanner/>, 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(<OverageUsersBanner/>, 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(<OverageUsersBanner/>, 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(<OverageUsersBanner/>, 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(<OverageUsersBanner/>, 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(<OverageUsersBanner/>, 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(<OverageUsersBanner/>, 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(<OverageUsersBanner/>, 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(<OverageUsersBanner/>, 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(<OverageUsersBanner/>, 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(<OverageUsersBanner/>, 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(<OverageUsersBanner/>, store);
fireEvent.click(screen.getByText(expandSeatsTextLink));
expect(windowSpy).toBeCalledTimes(1);

Просмотреть файл

@@ -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(<PaymentAnnouncementBar/>, happyPathStore);
renderWithContext(<PaymentAnnouncementBar/>, 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(<PaymentAnnouncementBar/>, store);
renderWithContext(<PaymentAnnouncementBar/>, 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(<PaymentAnnouncementBar/>, store);
renderWithContext(<PaymentAnnouncementBar/>, 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(<PaymentAnnouncementBar/>, store);
renderWithContext(<PaymentAnnouncementBar/>, store);
expect(cloudActions.getCloudCustomer).not.toHaveBeenCalled();
});
});

Просмотреть файл

@@ -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(
<Provider store={testConfigureStore(initialState)}>
<CenterMessageLock channelId={'channelId'}/>
</Provider>,
renderWithContext(
<CenterMessageLock channelId={'channelId'}/>,
initialState,
);
expect(screen.queryByText('Notify Admin')).not.toBeInTheDocument();
expect(screen.queryByText('Upgrade now')).not.toBeInTheDocument();
});
it('Admins have a call to upgrade', () => {
renderWithIntl(
<Provider store={testConfigureStore(exceededLimitsState)}>
<CenterMessageLock channelId={'channelId'}/>
</Provider>,
renderWithContext(
<CenterMessageLock channelId={'channelId'}/>,
exceededLimitsState,
);
screen.getByText('Upgrade now');
});
it('End users have a call to notify admin', () => {
renderWithIntl(
<Provider store={testConfigureStore(endUserLimitExceeded)}>
<CenterMessageLock channelId={'channelId'}/>
</Provider>,
renderWithContext(
<CenterMessageLock channelId={'channelId'}/>,
endUserLimitExceeded,
);
screen.getByText('Notify Admin');
});
it('Filtered messages over one year old display year', () => {
renderWithIntl(
<Provider store={testConfigureStore(exceededLimitsState)}>
<CenterMessageLock channelId={'channelId'}/>
</Provider>,
renderWithContext(
<CenterMessageLock channelId={'channelId'}/>,
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(
<Provider store={testConfigureStore(state)}>
<CenterMessageLock channelId={'channelId'}/>
</Provider>,
renderWithContext(
<CenterMessageLock channelId={'channelId'}/>,
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(
<Provider store={testConfigureStore(exceededLimitsStateNoAccessiblePosts)}>
<CenterMessageLock
channelId={'channelId'}
firstInaccessiblePostTime={now}
/>
</Provider>,
renderWithContext(
<CenterMessageLock
channelId={'channelId'}
firstInaccessiblePostTime={now}
/>,
exceededLimitsStateNoAccessiblePosts,
);
screen.getByText(expectedDate, {exact: false});
});

Просмотреть файл

@@ -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<GlobalState> = {
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(
<Provider store={store}>
<AboutAreaChannel
{...defaultProps}
/>
</Provider>,
test('should display channel purpose', () => {
renderWithContext(
<AboutAreaChannel
{...defaultProps}
/>,
initialState,
);
expect(screen.getByText('my channel purpose')).toBeInTheDocument();
});
test('should display channel header', async () => {
const store = await mockStore(initialState);
renderWithIntl(
<Provider store={store}>
<AboutAreaChannel
{...defaultProps}
/>
</Provider>,
test('should display channel header', () => {
renderWithContext(
<AboutAreaChannel
{...defaultProps}
/>,
initialState,
);
expect(screen.getByText('my channel header')).toBeInTheDocument();

Просмотреть файл

@@ -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<GlobalState> = {
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(
<Provider store={store}>
<AboutAreaDM
{...defaultProps}
/>
</Provider>,
test('should display user avatar', () => {
renderWithContext(
<AboutAreaDM
{...defaultProps}
/>,
initialState,
);
expect(screen.getByAltText('my_username profile image')).toBeInTheDocument();
});
test('should display user name', async () => {
const store = await mockStore(initialState);
renderWithIntl(
<Provider store={store}>
<AboutAreaDM
{...defaultProps}
/>
</Provider>,
test('should display user name', () => {
renderWithContext(
<AboutAreaDM
{...defaultProps}
/>,
initialState,
);
expect(screen.getByText('my_username')).toBeInTheDocument();
});
test('should display user position', async () => {
const store = await mockStore(initialState);
renderWithIntl(
<Provider store={store}>
<AboutAreaDM
{...defaultProps}
/>
</Provider>,
test('should display user position', () => {
renderWithContext(
<AboutAreaDM
{...defaultProps}
/>,
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(
<Provider store={store}>
<AboutAreaDM
{...props}
/>
</Provider>,
const {container} = renderWithContext(
<AboutAreaDM
{...props}
/>,
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(
<Provider store={store}>
<AboutAreaDM
{...props}
/>
</Provider>,
const {container} = renderWithContext(
<AboutAreaDM
{...props}
/>,
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(
<Provider store={store}>
<AboutAreaDM
{...props}
/>
</Provider>,
renderWithContext(
<AboutAreaDM
{...props}
/>,
initialState,
);
expect(screen.getByText('my bot description')).toBeInTheDocument();
});
test('should display channel header', async () => {
const store = await mockStore(initialState);
renderWithIntl(
<Provider store={store}>
<AboutAreaDM
{...defaultProps}
/>
</Provider>,
test('should display channel header', () => {
renderWithContext(
<AboutAreaDM
{...defaultProps}
/>,
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(
<Provider store={store}>
<AboutAreaDM
{...props}
/>
</Provider>,
renderWithContext(
<AboutAreaDM
{...props}
/>,
initialState,
);
expect(screen.queryByText('my channel header')).not.toBeInTheDocument();

Просмотреть файл

@@ -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<GlobalState> = {
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(
<Provider store={store}>
<AboutAreaGM
{...defaultProps}
/>
</Provider>,
test('should display users avatar', () => {
renderWithContext(
<AboutAreaGM
{...defaultProps}
/>,
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(
<Provider store={store}>
<AboutAreaGM
{...defaultProps}
/>
</Provider>,
test('should display user names', () => {
renderWithContext(
<AboutAreaGM
{...defaultProps}
/>,
initialState,
);
expect(screen.getByLabelText('my username')).toBeInTheDocument();
});
test('should display channel header', async () => {
const store = await mockStore(initialState);
renderWithIntl(
<Provider store={store}>
<AboutAreaGM
{...defaultProps}
/>
</Provider>,
test('should display channel header', () => {
renderWithContext(
<AboutAreaGM
{...defaultProps}
/>,
initialState,
);
expect(screen.getByText('my channel header')).toBeInTheDocument();

Просмотреть файл

@@ -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(
<ChannelInfoRHS
{...props}
/>,
@@ -71,7 +71,7 @@ describe('channel_info_rhs', () => {
test('should not be editable in archived channel', async () => {
props.isArchived = true;
renderWithIntl(
renderWithContext(
<ChannelInfoRHS
{...props}
/>,

Просмотреть файл

@@ -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(
<EditableArea
content='test content'
editable={true}
@@ -23,7 +23,7 @@ describe('channel_info_rhs/components/editable_area', () => {
test('should be able to edit content', async () => {
const mockOnEdit = jest.fn();
renderWithIntl(
renderWithContext(
<EditableArea
content='test content'
editable={true}
@@ -38,7 +38,7 @@ describe('channel_info_rhs/components/editable_area', () => {
});
test('should be able prevent edition', async () => {
renderWithIntl(
renderWithContext(
<EditableArea
content='test content'
editable={false}
@@ -52,7 +52,7 @@ describe('channel_info_rhs/components/editable_area', () => {
test('should show the empty label when there\'s no content', async () => {
const mockOnEdit = jest.fn();
renderWithIntl(
renderWithContext(
<EditableArea
content=''
editable={true}

Просмотреть файл

@@ -5,13 +5,13 @@ import React from 'react';
import type {Channel} from '@mattermost/types/channels';
import {fireEvent, renderWithIntl, screen} from 'tests/react_testing_utils';
import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils';
import Header from './header';
describe('channel_info_rhs/header', () => {
test('should the current channel name', () => {
renderWithIntl(
renderWithContext(
<Header
channel={{display_name: 'my channel title'} as Channel}
isMobile={false}
@@ -25,7 +25,7 @@ describe('channel_info_rhs/header', () => {
test('should call onClose when clicking on the close icon', () => {
const onClose = jest.fn();
renderWithIntl(
renderWithContext(
<Header
channel={{display_name: 'my channel title'} as Channel}
isMobile={false}
@@ -41,7 +41,7 @@ describe('channel_info_rhs/header', () => {
test('should call onClose when clicking on the back icon', () => {
const onClose = jest.fn();
renderWithIntl(
renderWithContext(
<Header
channel={{display_name: 'my channel title'} as Channel}
isMobile={true}
@@ -55,7 +55,7 @@ describe('channel_info_rhs/header', () => {
expect(onClose).toHaveBeenCalled();
});
test('should have archived icon when channel is archived', () => {
const {container} = renderWithIntl(
const {container} = renderWithContext(
<Header
channel={{display_name: 'my channel title'} as Channel}
isMobile={false}
@@ -67,7 +67,7 @@ describe('channel_info_rhs/header', () => {
expect(container.querySelector('i.icon-archive-outline')).toBeInTheDocument();
});
test('should not have archived icon when channel is archived', () => {
const {container} = renderWithIntl(
const {container} = renderWithContext(
<Header
channel={{display_name: 'my channel title'} as Channel}
isMobile={false}

Просмотреть файл

@@ -8,7 +8,7 @@ import type {Channel, ChannelStats} from '@mattermost/types/channels';
import {
act,
fireEvent,
renderWithIntl,
renderWithContext,
screen,
} from 'tests/react_testing_utils';
import Constants from 'utils/constants';
@@ -43,7 +43,7 @@ describe('channel_info_rhs/menu', () => {
const props = {...defaultProps};
props.actions.openNotificationSettings = jest.fn();
renderWithIntl(
renderWithContext(
<Menu
{...props}
/>,
@@ -65,7 +65,7 @@ describe('channel_info_rhs/menu', () => {
channel: {type: Constants.DM_CHANNEL} as Channel,
};
renderWithIntl(
renderWithContext(
<Menu
{...props}
/>,
@@ -84,7 +84,7 @@ describe('channel_info_rhs/menu', () => {
isArchived: true,
};
renderWithIntl(
renderWithContext(
<Menu
{...props}
/>,
@@ -101,7 +101,7 @@ describe('channel_info_rhs/menu', () => {
const props = {...defaultProps};
props.actions.showChannelFiles = jest.fn();
renderWithIntl(
renderWithContext(
<Menu
{...props}
/>,
@@ -123,7 +123,7 @@ describe('channel_info_rhs/menu', () => {
const props = {...defaultProps};
props.actions.showPinnedPosts = jest.fn();
renderWithIntl(
renderWithContext(
<Menu
{...props}
/>,
@@ -145,7 +145,7 @@ describe('channel_info_rhs/menu', () => {
const props = {...defaultProps};
props.actions.showChannelMembers = jest.fn();
renderWithIntl(
renderWithContext(
<Menu
{...props}
/>,
@@ -169,7 +169,7 @@ describe('channel_info_rhs/menu', () => {
channel: {type: Constants.DM_CHANNEL} as Channel,
};
renderWithIntl(
renderWithContext(
<Menu
{...props}
/>,

Просмотреть файл

@@ -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(
<TopButtons
{...testProps}
/>,
@@ -60,7 +60,7 @@ describe('channel_info_rhs/top_buttons', () => {
// Favorited to Favorite
toggleFavorite.mockReset();
testProps.isFavorite = true;
renderWithIntl(
renderWithContext(
<TopButtons
{...testProps}
/>,
@@ -83,7 +83,7 @@ describe('channel_info_rhs/top_buttons', () => {
},
};
renderWithIntl(
renderWithContext(
<TopButtons
{...testProps}
/>,
@@ -96,7 +96,7 @@ describe('channel_info_rhs/top_buttons', () => {
// Muted to Mute
toggleMute.mockReset();
testProps.isMuted = true;
renderWithIntl(
renderWithContext(
<TopButtons
{...testProps}
/>,
@@ -118,7 +118,7 @@ describe('channel_info_rhs/top_buttons', () => {
},
};
renderWithIntl(
renderWithContext(
<TopButtons
{...testProps}
/>,
@@ -134,7 +134,7 @@ describe('channel_info_rhs/top_buttons', () => {
channelType: Constants.DM_CHANNEL,
};
renderWithIntl(
renderWithContext(
<TopButtons
{...testProps}
/>,
@@ -149,7 +149,7 @@ describe('channel_info_rhs/top_buttons', () => {
canAddPeople: false,
};
renderWithIntl(
renderWithContext(
<TopButtons
{...testProps}
/>,
@@ -159,7 +159,7 @@ describe('channel_info_rhs/top_buttons', () => {
});
test('can copy link', () => {
renderWithIntl(
renderWithContext(
<TopButtons
{...topButtonDefaultProps}
/>,
@@ -179,7 +179,7 @@ describe('channel_info_rhs/top_buttons', () => {
...topButtonDefaultProps,
channelType,
};
renderWithIntl(
renderWithContext(
<TopButtons
{...localProps}
/>,

Просмотреть файл

@@ -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(
<ActionBar
{...testProps}
/>,
@@ -45,7 +45,7 @@ describe('channel_members_rhs/action_bar', () => {
test('should display Add button', () => {
const testProps: Props = {...actionBarDefaultProps};
renderWithIntl(
renderWithContext(
<ActionBar
{...testProps}
/>,
@@ -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(
<ActionBar
{...testProps}
/>,
@@ -71,7 +71,7 @@ describe('channel_members_rhs/action_bar', () => {
test('should display Manage', () => {
const testProps: Props = {...actionBarDefaultProps};
renderWithIntl(
renderWithContext(
<ActionBar
{...testProps}
/>,
@@ -88,7 +88,7 @@ describe('channel_members_rhs/action_bar', () => {
editing: true,
};
renderWithIntl(
renderWithContext(
<ActionBar
{...testProps}
/>,
@@ -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(
<ActionBar
{...testProps}
/>,

Просмотреть файл

@@ -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<GlobalState> = {
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(
<Provider store={store}>
<CloudUsageModal
{...props}
/>
</Provider>,
renderWithContext(
<CloudUsageModal
{...props}
/>,
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(
<Provider store={store}>
<CloudUsageModal
{...props}
/>
</Provider>,
renderWithContext(
<CloudUsageModal
{...props}
/>,
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(
<Provider store={store}>
<CloudUsageModal
{...props}
/>
</Provider>,
renderWithContext(
<CloudUsageModal
{...props}
/>,
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(
<Provider store={store}>
<CloudUsageModal
{...props}
/>
</Provider>,
renderWithContext(
<CloudUsageModal
{...props}
/>,
state,
);
expect(screen.queryByTestId('limits-modal-footer')).not.toBeInTheDocument();
});

Просмотреть файл

@@ -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(
<Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<TestComponent/>
</Provider>,
</>,
state,
);
screen.getByText(modalRegex);
});
@@ -125,13 +122,13 @@ describe('useShowAdminLimitReached', () => {
],
'admin',
);
const store = configureStore(state);
renderWithIntl(
<Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<TestComponent/>
</Provider>,
</>,
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(
<Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<TestComponent/>
</Provider>,
</>,
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(
<Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<TestComponent/>
</Provider>,
</>,
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(
<Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<TestComponent/>
</Provider>,
</>,
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(
<Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<TestComponent/>
</Provider>,
</>,
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(
<Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<TestComponent/>
</Provider>,
</>,
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(
<Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<TestComponent/>
</Provider>,
</>,
state,
);
expect(screen.queryByText(modalRegex)).not.toBeInTheDocument();
});

Просмотреть файл

@@ -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(
<ConvertGmToChannelModal {...baseProps}/>,
baseState,
);
@@ -87,7 +87,7 @@ describe('component/ConvertGmToChannelModal', () => {
{id: 'team_id_1', display_name: 'Team 1', name: 'team_1'},
]);
renderWithFullContext(
renderWithContext(
<ConvertGmToChannelModal {...baseProps}/>,
baseState,
);
@@ -110,7 +110,7 @@ describe('component/ConvertGmToChannelModal', () => {
get('/channels/channel_id_1/common_teams').
reply(200, []);
renderWithFullContext(
renderWithContext(
<ConvertGmToChannelModal {...baseProps}/>,
baseState,
);
@@ -138,7 +138,7 @@ describe('component/ConvertGmToChannelModal', () => {
baseProps.actions.convertGroupMessageToPrivateChannel.mockResolvedValueOnce({});
renderWithFullContext(
renderWithContext(
<ConvertGmToChannelModal {...baseProps}/>,
baseState,
);
@@ -191,7 +191,7 @@ describe('component/ConvertGmToChannelModal', () => {
},
});
renderWithFullContext(
renderWithContext(
<ConvertGmToChannelModal {...baseProps}/>,
baseState,
);

Просмотреть файл

@@ -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<ComponentProps<typeof DeliquencyModal>>;
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<typeof DeliquencyModal> = {
closeModal: jest.fn(),
onExited: jest.fn(),
planName: 'planName',
isAdminConsole: false,
};
return renderWithIntl(
<reactRedux.Provider store={store}>
<DeliquencyModal
{...defaultProps}
{...props}
/>
</reactRedux.Provider>,
);
const baseProps: ComponentProps<typeof DelinquencyModal> = {
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(<DelinquencyModal {...baseProps}/>, 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(<DelinquencyModal {...baseProps}/>, 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',
}]);

Просмотреть файл

@@ -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<GlobalState> = {
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
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(
<reactRedux.Provider store={store}>
renderWithContext(
<>
<div id='root-portal'/>
<ModalController/>
<DelinquencyModalController/>
</reactRedux.Provider>,
</>,
newState,
);
expect(getCloudProds).toHaveBeenCalledTimes(0);

Просмотреть файл

@@ -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<ComponentProps<typeof FreemiumModal>>;
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<GlobalState> = {
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<typeof FreemiumModal> = {
onClose: jest.fn(),
planName: 'planName',
isAdminConsole: false,
onExited: jest.fn(),
};
return renderWithIntl(
<reactRedux.Provider store={store}>
<FreemiumModal
{...defaultProps}
{...props}
/>
</reactRedux.Provider>,
);
const planName = 'Testing';
const baseProps: ComponentProps<typeof FreemiumModal> = {
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(
<FreemiumModal {...baseProps}/>,
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(
<FreemiumModal {...baseProps}/>,
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(
<FreemiumModal {...baseProps}/>,
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(
<FreemiumModal {...baseProps}/>,
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(
<FreemiumModal {...baseProps}/>,
initialState,
);
expect(screen.queryByText(`Re-activate ${planName}`)).toBeInTheDocument();
expect(screen.getByText('Your workspace has reached free plan limits. Upgrade to a paid plan.')).toBeInTheDocument();

Просмотреть файл

@@ -102,8 +102,10 @@ Object {
"queryByTestId": [Function],
"queryByText": [Function],
"queryByTitle": [Function],
"replaceStoreState": [Function],
"rerender": [Function],
"unmount": [Function],
"updateStoreState": [Function],
}
`;

Просмотреть файл

@@ -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(
<DotMenu {...props}/>,
initialState,
);
@@ -185,7 +185,7 @@ describe('components/dot_menu/DotMenu', () => {
...baseProps,
location: Locations.CENTER,
};
renderWithIntlAndStore(
renderWithContext(
<DotMenu {...props}/>,
initialState,
);
@@ -200,7 +200,7 @@ describe('components/dot_menu/DotMenu', () => {
...baseProps,
channelIsArchived: true,
};
renderWithIntlAndStore(
renderWithContext(
<DotMenu {...props}/>,
initialState,
);
@@ -215,7 +215,7 @@ describe('components/dot_menu/DotMenu', () => {
...baseProps,
location: Locations.SEARCH,
};
renderWithIntlAndStore(
renderWithContext(
<DotMenu {...props}/>,
initialState,
);
@@ -235,7 +235,7 @@ describe('components/dot_menu/DotMenu', () => {
...baseProps,
...caseProps,
};
renderWithIntlAndStore(
renderWithContext(
<DotMenu {...props}/>,
initialState,
);
@@ -256,7 +256,7 @@ describe('components/dot_menu/DotMenu', () => {
...baseProps,
...caseProps,
};
renderWithIntlAndStore(
renderWithContext(
<DotMenu {...props}/>,
initialState,
);
@@ -277,7 +277,7 @@ describe('components/dot_menu/DotMenu', () => {
...caseProps,
location: Locations.RHS_ROOT,
};
renderWithIntlAndStore(
renderWithContext(
<DotMenu {...props}/>,
initialState,
);

Просмотреть файл

@@ -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(
(
<BrowserRouter>
<ErrorPage
location={{
search: `?type=${ErrorPageTypes.CLOUD_ARCHIVED}`,
}}
/>
</BrowserRouter>
<ErrorPage
location={{
search: `?type=${ErrorPageTypes.CLOUD_ARCHIVED}`,
}}
/>
),
{
entities: {

Просмотреть файл

@@ -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(
<ExternalLink href='https://mattermost.com'>
{'Click Me'}
</ExternalLink>,
@@ -81,7 +81,7 @@ describe('components/external_link', () => {
},
},
};
renderWithIntlAndStore(
renderWithContext(
<ExternalLink href='https://mattermost.com?test=true'>
{'Click Me'}
</ExternalLink>,
@@ -107,7 +107,7 @@ describe('components/external_link', () => {
},
},
};
renderWithIntlAndStore(
renderWithContext(
<ExternalLink href='https://google.com'>
{'Click Me'}
</ExternalLink>,
@@ -133,7 +133,7 @@ describe('components/external_link', () => {
},
},
};
renderWithIntlAndStore(
renderWithContext(
<ExternalLink
target='test'
rel='test'
@@ -167,7 +167,7 @@ describe('components/external_link', () => {
},
},
};
renderWithIntlAndStore(
renderWithContext(
<ExternalLink
href='https://mattermost.com#desktop'
>

Просмотреть файл

@@ -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<GlobalState> = {
entities: {
general: {
config: {},
@@ -78,15 +79,15 @@ describe('FileAttachment', () => {
currentUserId: 'currentUserId',
},
},
} as GlobalState;
renderWithIntlAndStore(<FileAttachment {...baseProps}/>, reduxState);
};
renderWithContext(<FileAttachment {...baseProps}/>, 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(<FileAttachment {...{...baseProps, compactDisplay: true}}/>);
renderWithContext(<FileAttachment {...{...baseProps, compactDisplay: true}}/>);
expect(screen.queryByTestId('archived-file-icon')).not.toBeInTheDocument();
expect(screen.queryByText(/archived/)).not.toBeInTheDocument();
@@ -188,7 +189,7 @@ describe('FileAttachment', () => {
},
compactDisplay: true,
};
renderWithIntl(<FileAttachment {...props}/>);
renderWithContext(<FileAttachment {...props}/>);
screen.getByTestId('archived-file-icon');
screen.getByText(baseProps.fileInfo.name);
screen.getByText(/archived/);
@@ -203,7 +204,7 @@ describe('FileAttachment', () => {
},
compactDisplay: false,
};
renderWithIntl(<FileAttachment {...props}/>);
renderWithContext(<FileAttachment {...props}/>);
screen.getByTestId('archived-file-icon');
screen.getByText(baseProps.fileInfo.name);
screen.getByText(/This file is archived/);

Просмотреть файл

@@ -1,10 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`components/HeaderFooterTemplate should match snapshot with about link 1`] = `
<div
data-testid="root-testid"
id="root"
>
<div>
<div
class="inner-wrap"
>
@@ -59,10 +56,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with about link 1
`;
exports[`components/HeaderFooterTemplate should match snapshot with all links 1`] = `
<div
data-testid="root-testid"
id="root"
>
<div>
<div
class="inner-wrap"
>
@@ -147,10 +141,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with all links 1`
`;
exports[`components/HeaderFooterTemplate should match snapshot with children 1`] = `
<div
data-testid="root-testid"
id="root"
>
<div>
<div
class="inner-wrap"
>
@@ -198,10 +189,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with children 1`]
`;
exports[`components/HeaderFooterTemplate should match snapshot with help link 1`] = `
<div
data-testid="root-testid"
id="root"
>
<div>
<div
class="inner-wrap"
>
@@ -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`] = `
<div
data-testid="root-testid"
id="root"
>
<div>
<div
class="inner-wrap"
>
@@ -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`] = `
<div
data-testid="root-testid"
id="root"
>
<div>
<div
class="inner-wrap"
>
@@ -372,10 +354,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with term of serv
`;
exports[`components/HeaderFooterTemplate should match snapshot without children 1`] = `
<div
data-testid="root-testid"
id="root"
>
<div>
<div
class="inner-wrap"
>
@@ -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`] = `
<div
data-testid="root-testid"
id="root"
>
<div>
<div
class="inner-wrap"
>
@@ -506,9 +482,4 @@ exports[`components/HeaderFooterTemplate should set classes on body and #root on
</div>
`;
exports[`components/HeaderFooterTemplate should set classes on body and #root on mount and unset on unmount 2`] = `
<div
data-testid="root-testid"
id="root"
/>
`;
exports[`components/HeaderFooterTemplate should set classes on body and #root on mount and unset on unmount 2`] = `<div />`;

Просмотреть файл

@@ -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<GlobalState> = {
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<GlobalState>) => {
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(<HeaderFooterNotLoggedIn/>, state as DeepPartial<GlobalState>);
const {container} = renderWithContext(<HeaderFooterNotLoggedIn/>, initialState);
expect(container).toMatchSnapshot();
});
test('should match snapshot with children', () => {
const {container} = renderComponent(
const {container} = renderWithContext(
<HeaderFooterNotLoggedIn>
<p>{'test'}</p>
</HeaderFooterNotLoggedIn>,
state as DeepPartial<GlobalState>,
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(<HeaderFooterNotLoggedIn/>, state as DeepPartial<GlobalState>);
const {container} = renderWithContext(<HeaderFooterNotLoggedIn/>, 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(<HeaderFooterNotLoggedIn/>, state as DeepPartial<GlobalState>);
const {container} = renderWithContext(<HeaderFooterNotLoggedIn/>, 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(<HeaderFooterNotLoggedIn/>, state as DeepPartial<GlobalState>);
const {container} = renderWithContext(<HeaderFooterNotLoggedIn/>, 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(<HeaderFooterNotLoggedIn/>, state as DeepPartial<GlobalState>);
const {container} = renderWithContext(<HeaderFooterNotLoggedIn/>, 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(<HeaderFooterNotLoggedIn/>, state as DeepPartial<GlobalState>);
const {container} = renderWithContext(<HeaderFooterNotLoggedIn/>, 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(<HeaderFooterNotLoggedIn/>, state as DeepPartial<GlobalState>);
const {container, unmount} = renderWithContext(<HeaderFooterNotLoggedIn/>, state);
expect(container).toMatchSnapshot();
expect(document.body.classList.contains('sticky')).toBe(true);

Просмотреть файл

@@ -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(
<Router history={getHistory()}>
<ConfirmIntegration {...props}/>
</Router>,
const {container} = renderWithContext(
<ConfirmIntegration {...props}/>,
initialState,
);

Просмотреть файл

@@ -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(<AddToChannels {...props}/>);
const props = {...baseProps, currentChannel: undefined};
renderWithContext(<AddToChannels {...props}/>);
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(<AddToChannels {...props}/>);
const props = {...baseProps, currentChannel: {type: 'D', display_name: ''} as Channel};
renderWithContext(<AddToChannels {...props}/>);
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(<AddToChannels {...props}/>);
const props = {...baseProps, currentChannel: {type: 'O', display_name: 'My Awesome Channel'} as Channel};
renderWithContext(<AddToChannels {...props}/>);
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(<AddToChannels {...props}/>);
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,
},
};

Просмотреть файл

@@ -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(
<OverageUsersBannerNotice/>, store);
};
it('should not render the banner because we are not on overage state', () => {
renderComponent();
renderWithContext(<OverageUsersBannerNotice/>);
expect(screen.queryByText(notifyText, {exact: false})).not.toBeInTheDocument();
});
@@ -153,9 +143,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => {
},
};
renderComponent({
renderWithContext(
<OverageUsersBannerNotice/>,
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(
<OverageUsersBannerNotice/>,
store,
});
);
expect(screen.queryByText(notifyText, {exact: false})).not.toBeInTheDocument();
});
@@ -195,9 +187,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => {
},
};
renderComponent({
renderWithContext(
<OverageUsersBannerNotice/>,
store,
});
);
expect(screen.queryByText(text5PercentageState)).not.toBeInTheDocument();
});
@@ -212,9 +205,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => {
},
};
renderComponent({
renderWithContext(
<OverageUsersBannerNotice/>,
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(
<OverageUsersBannerNotice/>,
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(
<OverageUsersBannerNotice/>,
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(
<OverageUsersBannerNotice/>,
store,
});
);
fireEvent.click(screen.getByRole('button'));
@@ -318,9 +315,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => {
},
};
renderComponent({
renderWithContext(
<OverageUsersBannerNotice/>,
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(
<OverageUsersBannerNotice/>,
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(
<OverageUsersBannerNotice/>,
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(
<OverageUsersBannerNotice/>,
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(
<OverageUsersBannerNotice/>,
store,
});
);
fireEvent.click(screen.getByRole('button'));
@@ -460,9 +462,10 @@ describe('components/invitation_modal/overage_users_banner_notice', () => {
},
};
renderComponent({
renderWithContext(
<OverageUsersBannerNotice/>,
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(
<OverageUsersBannerNotice/>,
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(
<OverageUsersBannerNotice/>,
store,
);
screen.getByText(text10PercentageState);
expect(screen.queryByText(notifyText)).not.toBeInTheDocument();

Просмотреть файл

@@ -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(
<MenuWithModal/>,
);
@@ -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(
<MenuWithModal/>,
);
@@ -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(
<MenuWithSubMenuModal/>,
);
@@ -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(
<MenuWithSubMenuModal/>,
);

Просмотреть файл

@@ -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(
<NewChannelModal/>,
);

Просмотреть файл

@@ -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(
<GatherIntent
modalComponent={DummyModal}
gatherIntentText={gatherIntentText}
typeGatherIntent='monthlySubscription'
/>,
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(
<GatherIntent {...baseProps}/>,
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(
<GatherIntent {...baseProps}/>,
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(
<GatherIntent {...baseProps}/>,
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(
<GatherIntent {...baseProps}/>,
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(
<GatherIntent {...baseProps}/>,
newState,
);
fireEvent.click(screen.getByText(gatherIntentText));

Просмотреть файл

@@ -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<GatherIntentModalProps>;

Просмотреть файл

@@ -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<GatherIntentModalProps> | undefined = {}) => {
const defaultProps: GatherIntentModalProps = {
onClose: jest.fn(),
onSave: jest.fn(),
isSubmitting: false,
showError: false,
};
return renderWithIntl(
<GatherIntentModal
{...defaultProps}
{...props}
/>,
);
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(<GatherIntentModal {...baseProps}/>);
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(<GatherIntentModal {...baseProps}/>);
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(<GatherIntentModal {...baseProps}/>);
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(<GatherIntentModal {...baseProps}/>);
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(<GatherIntentModal {...baseProps}/>);
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(<GatherIntentModal {...baseProps}/>);
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(<GatherIntentModal {...baseProps}/>);
fireEvent.click(screen.getByText('Other'));
fireEvent.change(screen.getByPlaceholderText('Enter payment option here'), {target: {value: 'Test'}});

Просмотреть файл

@@ -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(<PostComponent {...baseProps}/>, baseState);
renderWithContext(<PostComponent {...baseProps}/>, baseState);
expect(screen.getByLabelText('reactions')).toBeInTheDocument();
});
@@ -83,7 +83,7 @@ describe('PostComponent', () => {
...baseProps,
location: Locations.RHS_ROOT,
};
const {rerender} = renderWithFullContext(<PostComponent {...props}/>, state);
const {rerender} = renderWithContext(<PostComponent {...props}/>, state);
expect(screen.getByLabelText('reactions')).toBeInTheDocument();
@@ -101,7 +101,7 @@ describe('PostComponent', () => {
...baseProps,
location: Locations.SEARCH,
};
const {rerender} = renderWithFullContext(<PostComponent {...props}/>, baseState);
const {rerender} = renderWithContext(<PostComponent {...props}/>, 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(<PostComponent {...props}/>);
const {rerender} = renderWithContext(<PostComponent {...props}/>);
expect(screen.queryByText(/Follow|Following/)).not.toBeInTheDocument();
@@ -164,7 +164,7 @@ describe('PostComponent', () => {
post: rootPost,
replyCount: 1,
};
const {rerender} = renderWithFullContext(<PostComponent {...props}/>, state);
const {rerender} = renderWithContext(<PostComponent {...props}/>, state);
expect(screen.queryByText(/Follow|Following/)).toBeInTheDocument();
@@ -194,7 +194,7 @@ describe('PostComponent', () => {
root_id: 'some_other_post_id',
},
};
const {rerender} = renderWithFullContext(<PostComponent {...props}/>);
const {rerender} = renderWithContext(<PostComponent {...props}/>);
expect(screen.queryByText(/Follow|Following/)).not.toBeInTheDocument();
@@ -238,7 +238,7 @@ describe('PostComponent', () => {
post: rootPost,
replyCount: 1,
};
const {rerender} = renderWithFullContext(<PostComponent {...props}/>, state);
const {rerender} = renderWithContext(<PostComponent {...props}/>, 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(<PostComponent {...propsForRootPost}/>, state);
renderWithContext(<PostComponent {...propsForRootPost}/>, state);
userEvent.click(screen.getByText('1 reply'));
@@ -288,7 +288,7 @@ describe('PostComponent', () => {
...propsForRootPost,
team: undefined,
};
renderWithFullContext(<PostComponent {...props}/>, state);
renderWithContext(<PostComponent {...props}/>, state);
userEvent.click(screen.getByText('1 reply'));
@@ -302,7 +302,7 @@ describe('PostComponent', () => {
...propsForRootPost,
location: Locations.SEARCH,
};
renderWithFullContext(<PostComponent {...props}/>, state);
renderWithContext(<PostComponent {...props}/>, state);
userEvent.click(screen.getByText('1 reply'));
@@ -316,7 +316,7 @@ describe('PostComponent', () => {
location: Locations.SEARCH,
team: TestHelper.getTeamMock({id: 'another_team'}),
};
renderWithFullContext(<PostComponent {...props}/>, state);
renderWithContext(<PostComponent {...props}/>, state);
userEvent.click(screen.getByText('1 reply'));

Просмотреть файл

@@ -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(<PostEditHistory {...baseProps}/>);
});
await act(async () => {
const {container} = renderWithIntlAndStore(<PostEditHistory {...baseProps}/>, {});
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(<PostEditHistory {...baseProps}/>);
});
await act(async () => {
const {container} = renderWithIntlAndStore(<PostEditHistory {...baseProps}/>, {});
wrapper = container;
});
await act(async () => {
expect(wrapper).toMatchSnapshot();
expect(mock).toBeCalledWith(baseProps.originalPost.id);
});
expect(wrapper.container).toMatchSnapshot();
expect(mock).toBeCalledWith(baseProps.originalPost.id);
});
});

Просмотреть файл

@@ -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(<PostMarkdown {...props}/>, state);
renderWithContext(<PostMarkdown {...props}/>, state);
expect(screen.getByText('message')).toBeInTheDocument();
});
test('should render properly with an empty post', () => {
renderWithIntlAndStore(
renderWithContext(
<PostMarkdown
{...baseProps}
post={{} as any}
@@ -86,7 +86,7 @@ describe('components/PostMarkdown', () => {
},
}),
};
renderWithIntlAndStore(<PostMarkdown {...props}/>, state);
renderWithContext(<PostMarkdown {...props}/>, state);
const link = screen.getByRole('link');
@@ -115,7 +115,7 @@ describe('components/PostMarkdown', () => {
},
}),
};
renderWithIntlAndStore(<PostMarkdown {...props}/>, state);
renderWithContext(<PostMarkdown {...props}/>, state);
expect(screen.getByText('No highlight')).toBeInTheDocument();
expect(screen.queryByRole('link')).not.toBeInTheDocument();
@@ -132,7 +132,7 @@ describe('components/PostMarkdown', () => {
},
}),
};
renderWithIntlAndStore(<PostMarkdown {...props}/>, state);
renderWithContext(<PostMarkdown {...props}/>, state);
const groupMention = screen.getByText('@group');
@@ -152,7 +152,7 @@ describe('components/PostMarkdown', () => {
id: 'post_id',
}),
};
renderWithIntlAndStore(<PostMarkdown {...props}/>, state);
renderWithContext(<PostMarkdown {...props}/>, state);
expect(screen.getByText('message')).toBeInTheDocument();
});
@@ -176,7 +176,7 @@ describe('components/PostMarkdown', () => {
}),
};
renderWithIntlAndStore(<PostMarkdown {...props}/>, state);
renderWithContext(<PostMarkdown {...props}/>, 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(<PostMarkdown {...props}/>, state);
renderWithContext(<PostMarkdown {...props}/>, state);
expect(screen.queryByText('world', {exact: true})).not.toBeInTheDocument();
// hook message
@@ -260,7 +260,7 @@ describe('components/PostMarkdown', () => {
},
],
};
renderWithIntlAndStore(<PostMarkdown {...props}/>, state);
renderWithContext(<PostMarkdown {...props}/>, state);
expect(screen.queryByText('world', {exact: true})).not.toBeInTheDocument();
expect(screen.queryByText('world!', {exact: true})).toBeInTheDocument();
});

Просмотреть файл

@@ -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(
<ChannelIntroMessage{...baseProps}/>, initialState,
);
@@ -110,7 +110,7 @@ describe('components/post_view/ChannelIntroMessages', () => {
};
test('should match component state, no profiles', () => {
renderWithIntlAndStore(
renderWithContext(
<ChannelIntroMessage
{...props}
/>, initialState,
@@ -126,7 +126,7 @@ describe('components/post_view/ChannelIntroMessages', () => {
});
test('should match component state, with profiles', () => {
renderWithIntlAndStore(
renderWithContext(
<ChannelIntroMessage
{...props}
channelProfiles={users}
@@ -171,7 +171,7 @@ describe('components/post_view/ChannelIntroMessages', () => {
};
test('should match component state, without teammate', () => {
renderWithIntlAndStore(
renderWithContext(
<ChannelIntroMessage
{...props}
/>, initialState,
@@ -183,7 +183,7 @@ describe('components/post_view/ChannelIntroMessages', () => {
});
test('should match component state, with teammate', () => {
renderWithIntlAndStore(
renderWithContext(
<ChannelIntroMessage
{...props}
teammate={user1 as UserProfile}
@@ -229,7 +229,7 @@ describe('components/post_view/ChannelIntroMessages', () => {
};
test('should match component state, readonly', () => {
renderWithIntlAndStore(
renderWithContext(
<ChannelIntroMessage
{...props}
isReadOnly={true}
@@ -246,7 +246,7 @@ describe('components/post_view/ChannelIntroMessages', () => {
});
test('should match component state without any permission', () => {
renderWithIntlAndStore(
renderWithContext(
<ChannelIntroMessage
{...props}
teamIsGroupConstrained={true}
@@ -278,7 +278,7 @@ describe('components/post_view/ChannelIntroMessages', () => {
};
test('should match component state', () => {
renderWithIntlAndStore(
renderWithContext(
<ChannelIntroMessage
{...props}
/>, initialState,

Просмотреть файл

@@ -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(
<LastUsers {...baseProps}/>, initialState,
);
@@ -66,7 +66,7 @@ describe('components/post_view/combined_system_message/LastUsers', () => {
});
test('should match component state, expanded', () => {
renderWithIntlAndStore(
renderWithContext(
<LastUsers {...baseProps}/>, initialState,
);

Просмотреть файл

@@ -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(
<CommentedOnFilesMessage {...props}/>,
);

Просмотреть файл

@@ -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(
<DateSeparator
date={value}
/>, initialState,

Просмотреть файл

@@ -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(<ButtonBinding {...baseProps}/>, initialState);
renderWithContext(<ButtonBinding {...baseProps}/>, initialState);
screen.getByText('some_label');
});
test('should call doAppSubmit on click', async () => {
const props = {
...baseProps,
intl,
};
renderWithIntlAndStore(<ButtonBindingUnwrapped {...props}/>, initialState);
renderWithContext(<ButtonBinding {...baseProps}/>, 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(<ButtonBindingUnwrapped {...props}/>, initialState);
renderWithContext(<ButtonBinding {...props}/>, initialState);
screen.getByText('some_label');

Просмотреть файл

@@ -35,7 +35,7 @@ type State = {
executing: boolean;
}
export class ButtonBinding extends React.PureComponent<Props, State> {
class ButtonBinding extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {

Просмотреть файл

@@ -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(<FailedPostOptions {...baseProps}/>);
renderWithContext(<FailedPostOptions {...baseProps}/>);
const retryLink = screen.getByText('Retry');
const cancelLink = screen.getByText('Cancel');
@@ -43,7 +43,7 @@ describe('components/post_view/FailedPostOptions', () => {
},
};
renderWithIntl(<FailedPostOptions {...props}/>);
renderWithContext(<FailedPostOptions {...props}/>);
const retryLink = screen.getByText('Retry');
@@ -65,7 +65,7 @@ describe('components/post_view/FailedPostOptions', () => {
},
};
renderWithIntl(<FailedPostOptions {...props}/>);
renderWithContext(<FailedPostOptions {...props}/>);
const cancelLink = screen.getByText('Cancel');

Просмотреть файл

@@ -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(<FloatingTimestamp {...baseProps}/>, initialState);
renderWithContext(<FloatingTimestamp {...baseProps}/>, initialState);
const floatingTimeStamp = screen.getByTestId('floatingTimestamp');
const time = screen.getByText('January 01, 1970');

Просмотреть файл

@@ -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(<ActionButton {...baseProps}/>);
renderWithContext(<ActionButton {...baseProps}/>);
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(<ActionButton {...baseProps}/>);
renderWithContext(<ActionButton {...baseProps}/>);
const button = screen.getByRole('button');
@@ -45,7 +45,7 @@ describe('components/post_view/message_attachments/action_button.jsx', () => {
action: {...baseProps.action, style: 'onlineIndicator'},
};
renderWithIntl(<ActionButton {...props}/>);
renderWithContext(<ActionButton {...props}/>);
const button = screen.getByRole('button');
@@ -60,7 +60,7 @@ describe('components/post_view/message_attachments/action_button.jsx', () => {
action: {...baseProps.action, style: 'danger'},
};
renderWithIntl(<ActionButton {...props}/>);
renderWithContext(<ActionButton {...props}/>);
const button = screen.getByRole('button');
@@ -74,7 +74,7 @@ describe('components/post_view/message_attachments/action_button.jsx', () => {
action: {...baseProps.action, style: 'success'},
};
renderWithIntl(<ActionButton {...props}/>);
renderWithContext(<ActionButton {...props}/>);
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(<ActionButton {...props}/>);
renderWithContext(<ActionButton {...props}/>);
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(<ActionButton {...props}/>);
renderWithContext(<ActionButton {...props}/>);
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(<ActionButton {...props}/>);
renderWithContext(<ActionButton {...props}/>);
const button = screen.getByRole('button');
expect(button.style.length).toBe(0);

Просмотреть файл

@@ -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(<ActionMenu {...baseProps}/>, {});
renderWithContext(<ActionMenu {...baseProps}/>);
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(<ActionMenu {...props}/>, {});
renderWithContext(<ActionMenu {...props}/>);
const input = screen.getByPlaceholderText('action');

Просмотреть файл

@@ -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(
<NewMessageSeparator
separatorId='1234'
newMessagesSeparatorActions={[]}

Просмотреть файл

@@ -6,7 +6,7 @@ import React from 'react';
import type {GlobalState} from '@mattermost/types/store';
import type {DeepPartial} from '@mattermost/types/utilities';
import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils';
import {renderWithContext, screen} from 'tests/react_testing_utils';
import PostAttachmentContainer from './post_attachment_container';
import type {Props} from './post_attachment_container';
@@ -37,7 +37,7 @@ describe('PostAttachmentContainer', () => {
};
test('should render correctly', () => {
renderWithIntlAndStore(
renderWithContext(
<PostAttachmentContainer {...baseProps}/>, initialState,
);

Просмотреть файл

@@ -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(
<Provider store={store.store}>
<LatestPostReader {...baseProps}/>
</Provider>,
const {rerender} = renderWithContext(
<LatestPostReader {...baseProps}/>,
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(<Provider store={store.store}> <LatestPostReader {...baseProps}/></Provider>);
rerender(<LatestPostReader {...baseProps}/>);
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(<LatestPostReader {...props}/>, baseState);
renderWithContext(<LatestPostReader {...props}/>, baseState);
// body should be empty
const message = screen.queryByText('This is a test');

Просмотреть файл

@@ -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<GlobalState> = JSON.parse(JSON.stringify(initialState));
stateOverride.entities!.users!.currentUserId = 'otherUserId';
renderWithIntlAndStore(
renderWithContext(
<div id='root-portal'>
<PurchaseInProgressModal
purchaserEmail={'admin@example.com'}
@@ -72,7 +72,7 @@ describe('PurchaseInProgressModal', () => {
});
it('when purchaser and user emails are same, allows user to reset purchase flow', () => {
renderWithIntlAndStore(
renderWithContext(
<div id='root-portal'>
<PurchaseInProgressModal
purchaserEmail={'admin@example.com'}

Просмотреть файл

@@ -5,13 +5,13 @@ import React from 'react';
import * as controlModalHooks from 'components/common/hooks/useControlModal';
import {renderWithIntlAndStore, screen} from 'tests/react_testing_utils';
import {renderWithContext, screen} from 'tests/react_testing_utils';
import ScreeningInProgressModal from './';
describe('ScreeningInProgressModal', () => {
it('informs customer that the subscription is under review', () => {
renderWithIntlAndStore(<ScreeningInProgressModal/>, {});
renderWithContext(<ScreeningInProgressModal/>);
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(<ScreeningInProgressModal/>, {});
renderWithContext(<ScreeningInProgressModal/>);
screen.getAllByText('Close')[1].click();
expect(mockClose).toHaveBeenCalled();
});

Просмотреть файл

@@ -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) => (
<IntlProvider
locale={'en'}
messages={en}
>
{component}
</IntlProvider>
);
describe('components/search_bar/SearchBar', () => {
const store = mockStore({});
const wrapStore = (component: JSX.Element) => (
<Provider store={store}>
{component}
</Provider>
);
const baseProps: ComponentProps<typeof SearchBar> = {
suggestionProviders,
searchTerms: '',
@@ -61,54 +40,46 @@ describe('components/search_bar/SearchBar', () => {
};
it('should match snapshot without search', () => {
const {container} = render(
wrapStore(wrapIntl(<SearchBar {...baseProps}/>)),
const {container} = renderWithContext(
<SearchBar {...baseProps}/>,
);
expect(container).toMatchSnapshot();
});
it('should match snapshot without search, without searchType', () => {
const {container} = render(
wrapStore(wrapIntl((
<SearchBar {...baseProps}/>
))),
const {container} = renderWithContext(
<SearchBar {...baseProps}/>,
);
expect(container).toMatchSnapshot();
});
it('should match snapshot without search, with searchType', () => {
const {container} = render(
wrapStore(wrapIntl((
<SearchBar
{...baseProps}
searchType='files'
/>
))),
const {container} = renderWithContext(
<SearchBar
{...baseProps}
searchType='files'
/>,
);
expect(container).toMatchSnapshot();
});
it('should match snapshot with search, with searchType', () => {
const {container} = render(
wrapStore(wrapIntl((
<SearchBar
{...baseProps}
searchTerms={'test'}
searchType='files'
/>
))),
const {container} = renderWithContext(
<SearchBar
{...baseProps}
searchTerms={'test'}
searchType='files'
/>,
);
expect(container).toMatchSnapshot();
});
it('should match snapshot with search', () => {
const {container} = render(
wrapStore(wrapIntl((
<SearchBar
{...baseProps}
searchTerms={'test'}
/>
))),
const {container} = renderWithContext(
<SearchBar
{...baseProps}
searchTerms={'test'}
/>,
);
expect(container).toMatchSnapshot();
});

Просмотреть файл

@@ -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(
<Header
previousRhsState={RHSStates.CHANNEL_INFO as RhsState}
canGoBack={true}
@@ -30,7 +30,7 @@ describe('search_results_header', () => {
expect(screen.getByLabelText('Back Icon')).toBeInTheDocument();
});
test('should NOT diplay expand when the parent is channel info', () => {
renderWithIntl(
renderWithContext(
<Header
previousRhsState={RHSStates.CHANNEL_INFO as RhsState}
canGoBack={true}
@@ -48,7 +48,7 @@ describe('search_results_header', () => {
expect(screen.queryByLabelText('Expand Sidebar Icon')).not.toBeInTheDocument();
});
test('should diplay expand when the parent is NOT channel info', () => {
renderWithIntl(
renderWithContext(
<Header
previousRhsState={RHSStates.FLAG as RhsState}
canGoBack={true}

Просмотреть файл

@@ -11,7 +11,7 @@ import type {DeepPartial} from '@mattermost/types/utilities';
import mergeObjects from 'packages/mattermost-redux/test/merge_objects';
import {
fireEvent,
renderWithIntlAndStore,
renderWithContext,
screen,
waitFor,
} from 'tests/react_testing_utils';
@@ -270,7 +270,7 @@ function fillForm(form: PurchaseForm) {
describe('SelfHostedExpansionModal Open', () => {
it('renders the form', () => {
renderWithIntlAndStore(<div id='root-portal'><SelfHostedExpansionModal/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedExpansionModal/></div>, 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(<div id='root-portal'><SelfHostedExpansionModal/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedExpansionModal/></div>, initialState);
expect(screen.getByText('Complete purchase')).toBeDisabled();
fillForm(defaultSuccessForm);
});
it('happy path submit shows success screen when confirmation succeeds', async () => {
renderWithIntlAndStore(<div id='root-portal'><SelfHostedExpansionModal/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedExpansionModal/></div>, 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(<div id='root-portal'><SelfHostedExpansionModal/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedExpansionModal/></div>, 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(<div id='root-portal'><SelfHostedExpansionModal/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedExpansionModal/></div>, 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(<div id='root-portal'><SelfHostedExpansionModal/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedExpansionModal/></div>, 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(<div id='root-portal'><SelfHostedExpansionModal/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedExpansionModal/></div>, initialState);
fillForm(defaultSuccessForm);
// The seat input should already have the expected value.
@@ -362,7 +362,7 @@ describe('SelfHostedExpansionModal RHS Card', () => {
const expectedAddNewSeats = '1';
renderWithIntlAndStore(<div id='root-portal'><SelfHostedExpansionModal/></div>, state);
renderWithContext(<div id='root-portal'><SelfHostedExpansionModal/></div>, 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(<div id='root-portal'><SelfHostedExpansionModal/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedExpansionModal/></div>, 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(<div id='root-portal'><SelfHostedExpansionModal/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedExpansionModal/></div>, initialState);
const seatsInputValue = 100;
changeByTestId('seatsInput', seatsInputValue.toString());

Просмотреть файл

@@ -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(<div id='root-portal'><SelfHostedPurchaseModal productId={'prod_professional'}/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedPurchaseModal productId={'prod_professional'}/></div>, 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(<div id='root-portal'><SelfHostedPurchaseModal productId={'prod_professional'}/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedPurchaseModal productId={'prod_professional'}/></div>, initialState);
expect(screen.getByText('Upgrade')).toBeDisabled();
fillForm(defaultSuccessForm);
});
it('disables signup if too few seats chosen', () => {
renderWithIntlAndStore(<div id='root-portal'><SelfHostedPurchaseModal productId={'prod_professional'}/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedPurchaseModal productId={'prod_professional'}/></div>, initialState);
fillForm(defaultSuccessForm);
const tooFewSeats = existingUsers - 1;
@@ -283,7 +283,7 @@ describe('SelfHostedPurchaseModal', () => {
});
it('Minimum of 10 seats is required for sign up', () => {
renderWithIntlAndStore(<div id='root-portal'><SelfHostedPurchaseModal productId={'prod_professional'}/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedPurchaseModal productId={'prod_professional'}/></div>, initialState);
fillForm(defaultSuccessForm);
const tooFewSeats = 9;
@@ -293,7 +293,7 @@ describe('SelfHostedPurchaseModal', () => {
});
it('happy path submit shows success screen', async () => {
renderWithIntlAndStore(<div id='root-portal'><SelfHostedPurchaseModal productId={'prod_professional'}/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedPurchaseModal productId={'prod_professional'}/></div>, 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(<div id='root-portal'><SelfHostedPurchaseModal productId={'prod_professional'}/></div>, initialState);
renderWithContext(<div id='root-portal'><SelfHostedPurchaseModal productId={'prod_professional'}/></div>, initialState);
expect(screen.getByText('Upgrade')).toBeDisabled();
fillForm(defaultSuccessForm);
changeByPlaceholder('Organization Name', failOrg);

Просмотреть файл

@@ -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(
<Sidebar {...baseProps}/>,
mergeObjects(baseState, testState),
);
@@ -204,7 +204,7 @@ describe('components/sidebar', () => {
},
};
renderWithFullContext(
renderWithContext(
<Sidebar {...baseProps}/>,
mergeObjects(baseState, testState),
);
@@ -223,7 +223,7 @@ describe('components/sidebar', () => {
},
};
renderWithFullContext(
renderWithContext(
<Sidebar {...baseProps}/>,
mergeObjects(baseState, testState),
);
@@ -242,12 +242,12 @@ describe('components/sidebar', () => {
},
views: {
channel: {
lastUnreadChannel: {id: channel1.id},
lastUnreadChannel: {id: channel1.id} as any,
},
},
};
renderWithFullContext(
renderWithContext(
<Sidebar {...baseProps}/>,
mergeObjects(baseState, testState),
);

Просмотреть файл

@@ -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(
<BrowserRouter>
<Signup/>
</BrowserRouter>, {});
const {container: signupContainer} = renderWithContext(
<Signup/>,
);
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(
<BrowserRouter>
<Signup/>
</BrowserRouter>, {});
const {container: signupContainer} = renderWithContext(
<Signup/>,
);
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(
<BrowserRouter>
<Signup/>
</BrowserRouter>, {});
const {container: signupContainer} = renderWithContext(
<Signup/>,
);
screen.getByTestId('signup-body-card-form-check-newsletter');
const checkInput = screen.getByTestId('signup-body-card-form-check-newsletter');

Просмотреть файл

@@ -389,7 +389,9 @@ Object {
"queryByTestId": [Function],
"queryByText": [Function],
"queryByTitle": [Function],
"replaceStoreState": [Function],
"rerender": [Function],
"unmount": [Function],
"updateStoreState": [Function],
}
`;

Просмотреть файл

@@ -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<GlobalState> = {
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(
<Provider store={store}>
<BrowserRouter>
<StartTrialFormModal {...props}/>
</BrowserRouter>
</Provider>);
const wrapper = await waitFor(() => {
return renderWithContext(
<BrowserRouter>
<StartTrialFormModal {...props}/>
</BrowserRouter>,
state,
);
});
expect(wrapper!).toMatchSnapshot();
});
test('should pre-fill email, fire trackEvent', async () => {
const store = await mockStore(state);
await act(async () => {
await renderWithIntl(
<Provider store={store}>
<BrowserRouter>
<StartTrialFormModal {...props}/>
</BrowserRouter>
</Provider>);
test('should pre-fill email, fire trackEvent', () => {
waitFor(() => {
renderWithContext(
<BrowserRouter>
<StartTrialFormModal {...props}/>
</BrowserRouter>,
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(
<Provider store={store}>
<BrowserRouter>
<StartTrialFormModal {...props}/>
</BrowserRouter>
</Provider>);
test('Start trial button should be disabled on load', () => {
waitFor(() => {
renderWithContext(
<BrowserRouter>
<StartTrialFormModal {...props}/>
</BrowserRouter>,
state,
);
});
expect(screen.getByRole('button', {name: 'Start trial'})).toBeDisabled();
});

Просмотреть файл

@@ -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(<ToastWrapper {...props}/>);
renderWithContext(<ToastWrapper {...props}/>);
const scrollToBottomToast = screen.queryByTestId(SCROLL_TO_BOTTOM_TOAST_TESTID);
expect(scrollToBottomToast).not.toBeInTheDocument();
});
@@ -644,7 +644,7 @@ describe('components/ToastWrapper', () => {
showScrollToBottomToast: true,
};
renderWithIntlAndStore(<ToastWrapper {...props}/>);
renderWithContext(<ToastWrapper {...props}/>);
const scrollToBottomToast = screen.queryByTestId(SCROLL_TO_BOTTOM_TOAST_TESTID);
expect(scrollToBottomToast).not.toBeInTheDocument();
@@ -656,7 +656,7 @@ describe('components/ToastWrapper', () => {
showScrollToBottomToast: false,
};
renderWithIntlAndStore(<ToastWrapper {...props}/>);
renderWithContext(<ToastWrapper {...props}/>);
const scrollToBottomToast = screen.queryByTestId(SCROLL_TO_BOTTOM_TOAST_TESTID);
expect(scrollToBottomToast).not.toBeInTheDocument();
@@ -669,7 +669,7 @@ describe('components/ToastWrapper', () => {
showScrollToBottomToast: true,
};
renderWithIntlAndStore(<ToastWrapper {...props}/>);
renderWithContext(<ToastWrapper {...props}/>);
const scrollToBottomToast = screen.queryByTestId(SCROLL_TO_BOTTOM_TOAST_TESTID);
expect(scrollToBottomToast).toBeInTheDocument();
@@ -682,7 +682,7 @@ describe('components/ToastWrapper', () => {
showScrollToBottomToast: true,
};
renderWithIntlAndStore(<ToastWrapper {...props}/>);
renderWithContext(<ToastWrapper {...props}/>);
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(<ToastWrapper {...props}/>);
renderWithContext(<ToastWrapper {...props}/>);
const scrollToBottomToast = screen.getByTestId(SCROLL_TO_BOTTOM_TOAST_TESTID);
fireEvent.click(scrollToBottomToast);
@@ -715,7 +715,7 @@ describe('components/ToastWrapper', () => {
showScrollToBottomToast: true,
};
renderWithIntlAndStore(<ToastWrapper {...props}/>);
renderWithContext(<ToastWrapper {...props}/>);
const scrollToBottomToastDismiss = screen.getByTestId(SCROLL_TO_BOTTOM_DISMISS_BUTTON_TESTID);
fireEvent.click(scrollToBottomToastDismiss);

Просмотреть файл

@@ -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<typeof UserSettingsTheme> = {
theme: Preferences.THEMES.denim,
@@ -105,12 +101,9 @@ describe('components/user_settings/display/user_settings_theme/user_settings_the
selected: true,
};
render(
<IntlProvider locale={'en'}>
<Provider store={store}>
<UserSettingsTheme {...props}/>
</Provider>
</IntlProvider>,
renderWithContext(
<UserSettingsTheme {...props}/>,
initialState,
);
// Click the Slack Import button

Просмотреть файл

@@ -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(
<UserSettingsNotifications {...defaultProps}/>,
);
@@ -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(<UserSettingsNotifications {...props}/>);
renderWithContext(<UserSettingsNotifications {...props}/>);
expect(screen.getByText('Reply notifications')).toBeInTheDocument();
});

Просмотреть файл

@@ -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(
<Provider store={store}>
<TestEl {...t.props}/>
</Provider>,
renderWithContext(
<TestEl {...t.props}/>,
initialState,
);
if (t.expects.empty) {
screen.getByText(emptyText);

Просмотреть файл

@@ -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(<GuestTag className={'test'}/>);
renderWithContext(<GuestTag className={'test'}/>);
screen.getByText('GUEST');
});
test('should not render when hideTags is true', () => {
renderWithIntlAndStore(<GuestTag className={'test'}/>, {entities: {general: {config: {HideGuestTags: 'true'}}}});
renderWithContext(<GuestTag className={'test'}/>, {entities: {general: {config: {HideGuestTags: 'true'}}}});
expect(() => screen.getByText('GUEST')).toThrow();
});
});

Просмотреть файл

@@ -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 <div>{'Anything'}</div>;
};
renderWithFullContext(
renderWithContext(
<TestComponent/>,
{},
);
@@ -39,7 +51,7 @@ describe('renderWithFullContext', () => {
);
};
renderWithFullContext(
renderWithContext(
<TestComponent/>,
);
@@ -53,7 +65,7 @@ describe('renderWithFullContext', () => {
return <div>{intl.formatMessage({id: 'about.hash', defaultMessage: 'Build Hash:'})}</div>;
};
renderWithFullContext(
renderWithContext(
<TestComponent/>,
);
@@ -76,7 +88,7 @@ describe('renderWithFullContext', () => {
);
};
renderWithFullContext(
renderWithContext(
<TestComponent/>,
);
@@ -92,7 +104,7 @@ describe('renderWithFullContext', () => {
numProfiles: Object.keys(state.entities.users.profiles).length,
}))(UnconnectedTestComponent);
renderWithFullContext(
renderWithContext(
<TestComponent/>,
);
@@ -105,7 +117,7 @@ describe('renderWithFullContext', () => {
return <div>{`There are ${numProfiles} users loaded`}</div>;
};
renderWithFullContext(
renderWithContext(
<TestComponent/>,
);
@@ -125,7 +137,7 @@ describe('renderWithFullContext', () => {
);
};
const {rerender} = renderWithFullContext(
const {rerender} = renderWithContext(
<TestComponent appTitle='Mattermost'/>,
);
@@ -157,7 +169,7 @@ describe('renderWithFullContext', () => {
return <div>{`User1 is ${user1.username} and User2 is ${user2.username}!`}</div>;
};
const {replaceStoreState} = renderWithFullContext(
const {replaceStoreState} = renderWithContext(
<TestComponent/>,
initialState,
);
@@ -209,7 +221,7 @@ describe('renderWithFullContext', () => {
return <div>{`User1 is ${user1.username} and User2 is ${user2.username}!`}</div>;
};
const {updateStoreState} = renderWithFullContext(
const {updateStoreState} = renderWithContext(
<TestComponent/>,
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 <div>{`${props.greeting}, ${user1.username}!`}</div>;
};
const {rerender, updateStoreState} = renderWithContext(
<TestComponent greeting='Hello'/>,
initialState,
);
expect(screen.getByText('Hello, India!')).toBeInTheDocument();
updateStoreState({
entities: {
users: {
profiles: {
user1: {username: 'Juliet'},
},
},
},
});
expect(screen.getByText('Hello, Juliet!')).toBeInTheDocument();
rerender(<TestComponent greeting='Salutations'/>);
expect(screen.getByText('Salutations, Juliet!')).toBeInTheDocument();
updateStoreState({
entities: {
users: {
profiles: {
user1: {username: 'Kilo'},
},
},
},
});
expect(screen.getByText('Salutations, Kilo!')).toBeInTheDocument();
rerender(<TestComponent greeting='Bonjour'/>);
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 (
<div>
<span>{`User1 is ${username}!`}</span>
<button onClick={loadUser}>{'Load User'}</button>
</div>
);
};
renderWithContext(<TestComponent/>);
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 (
<div>
<button onClick={openTestModal}>{'Open Modal'}</button>
</div>
);
};
const TestModal = (props: {onExited: () => void}) => {
return (
<GenericModal onExited={props.onExited}>
<p>{'This is a modal!'}</p>
</GenericModal>
);
};
renderWithContext(
<>
<TestComponent/>
<ModalController/>
</>,
);
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();
});
});
});

Просмотреть файл

@@ -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(<IntlProvider locale={locale}>{component}</IntlProvider>);
};
export type FullContextOptions = {
locale?: string;
useMockedStore?: boolean;
}
export const renderWithIntlAndStore = (component: React.ReactNode | React.ReactNodeArray, initialState: DeepPartial<GlobalState> = {}, 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<GlobalState> = {},
partialOptions?: FullContextOptions,
) => {
const options = {
locale: partialOptions?.locale ?? 'en',
useMockedStore: partialOptions?.useMockedStore ?? false,
};
const store = mockStore(realStore.getState());
return render(
<IntlProvider locale={locale}>
<Provider store={store}>
{component}
</Provider>
</IntlProvider>,
{container: divContainer},
);
};
export const renderWithFullContext = (component: React.ReactNode | React.ReactNodeArray, initialState: DeepPartial<GlobalState> = {}, 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 (
<Provider store={renderState.store}>
<Router history={renderState.history}>
<IntlProvider
locale={renderState.locale}
locale={renderState.options.locale}
>
<WebSocketContext.Provider value={WebSocketClient}>
{renderState.component}
{props.children}
</WebSocketContext.Provider>
</IntlProvider>
</Router>
@@ -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<GlobalState>) => {
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<GlobalState>) => {
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<T>(initialState: DeepPartial<T>, useMockedStore: boolean) {
let testStore = configureStore(initialState);
if (useMockedStore) {
testStore = mockStore(testStore.getState());
}
return testStore;
}

Просмотреть файл

@@ -14,7 +14,14 @@ export type RelationOneToManyUnique<E1 extends {id: string}, E2 extends {id: str
export type IDMappedObjects<E extends {id: string}> = RelationOneToOne<E, E>;
export type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>;
// 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<T[K]> :
// Else if that field is an optional object, make that a deep partial object
T[K] extends object | undefined ? DeepPartial<T[K]> :
// Else leave it as an optional primitive
T[K];
}
export type ValueOf<T> = T[keyof T];
@@ -26,4 +33,4 @@ export type RequireOnlyOne<T, Keys extends keyof T = keyof T> =
Pick<T, Exclude<keyof T, Keys>> & {[K in Keys]-?: Required<Pick<T, K>> & Partial<Record<Exclude<Keys, K>, undefined>>}[Keys];
export type Intersection<T1, T2> =
Omit<Omit<T1&T2, keyof(Omit<T1, keyof(T2)>)>, keyof(Omit<T2, keyof(T1)>)>;
Omit<Omit<T1&T2, keyof(Omit<T1, keyof(T2)>)>, keyof(Omit<T2, keyof(T1)>)>;