# Application Shell Set of components and utilities to serve as the customization framework. ## Installation Install the `@commercetools-frontend/application-shell` package ```npm npm --save install @commercetools-frontend/application-shell ``` ```yarn yarn add @commercetools-frontend/application-shell ``` Additionally, install the peer dependencies (if not present) ```npm npm --save install @apollo/client react react-dom react-intl react-redux react-router-dom redux @testing-library/react @testing-library/react-hooks ``` ```yarn yarn add @apollo/client react react-dom react-intl react-redux react-router-dom redux @testing-library/react @testing-library/react-hooks ``` ## Components ### ApplicationShell This is the main component that contains all the general logic to render a Custom Application. This component applies only to Custom Applications. If you're developing a Custom View, use [CustomViewShell](/merchant-center-customizations/tooling-and-configuration/commercetools-frontend-application-shell.md#customviewshell) instead. The `ApplicationShell` component is expected to be rendered as the top-level component of your application. #### Usage We recommend that you render the application content as `children` of `` instead of the `render` prop. This allows the `` to pre-configure the application entry point routes. In addition to that, the entry point route is protected by the basic `View` permission check. This means that a user without permissions of your Custom Application won't be able to access the Custom Application route. ```jsx title="entry-point.js" import { ApplicationShell } from '@commercetools-frontend/application-shell'; const loadMessages = async (locale) => { // ... }; const AsyncApplicationRoutes = React.lazy(() => import('../../routes' /* webpackChunkName: "channels" */) ); const EntryPoint = () => ( ); export default EntryPoint; ``` #### Properties ##### `applicationMessages` **object** or **func** This is either an object containing all the translated messages, grouped by locale`{ en: { Welcome: "Welcome" }, de: { Welcome: "Wilkommen" } }`or a function that returns a Promise that resolves to such an object.The function is called with a `locale` parameter. See [Import translations](/merchant-center-customizations/development/translations.md#import-translations). ##### `environment` **object** The application runtime environment, which is exposed in `window.app`. See [Runtime configuration](/merchant-center-customizations/tooling-and-configuration/custom-application-config.md#runtime-application-environment). ##### `children` **node** Instead of using the `render` prop, render your application component as children of ``.By doing so, the `` pre-configures the main application routes according to the `entryPointUriPath` defined in the `custom-application-config.json`.This is an opt-int behavior as a replacement of the `render` prop, to simplify the entry point setup. ##### `render` **func** (optional) The render function is called when the `` is ready to render the actual application. This is the case when the required data (user, project) has been fetched and the application context has been initialized.It's **recommended to use** the `children` prop to benefit from a simpler setup. ##### `apolloClient` **ApolloClient** (optional) An optional instance of [ApolloClient](https://www.apollographql.com/docs/react/) to be used instead of the default one. This is usually the case when you need to configure the Apollo cache. See [`createApolloClient`](/merchant-center-customizations/tooling-and-configuration/commercetools-frontend-application-shell.md#createapolloclient). ### CustomViewShell This component applies only to Custom Views. If you're developing a Custom Application, use [ApplicationShell](/merchant-center-customizations/tooling-and-configuration/commercetools-frontend-application-shell.md#applicationshell) instead. This is the main component that contains all the general logic to render a Custom View. The `CustomViewShell` component must be rendered as the top-level component of your Custom View. #### Usage We recommend that you render the Custom View content as `children` of ``. The `` pre-configures the Custom View entry point routes. In addition, the entry point route is protected by the basic View permission check. This means that a user without permission from your Custom View won't be able to access the Custom View route. You aren't required to use routes in your Custom View. You can use them if you need to have different views. For example, a Custom View with a listing page and details page. ```jsx title="entry-point.js" import { CustomViewShell } from '@commercetools-frontend/application-shell'; const loadMessages = async (locale) => { // ... }; const AsyncApplicationRoutes = React.lazy(() => import('../../routes' /* webpackChunkName: "channels" */) ); const EntryPoint = () => ( ); export default EntryPoint; ``` #### Properties ##### `applicationMessages` **object** or **func** This is either an object containing all the translated messages, grouped by locale`{ en: { Welcome: "Welcome" }, de: { Welcome: "Willkommen" } }`or a function that returns a Promise that resolves to such an object.The function is called with a `locale` parameter. See [Import translations](/merchant-center-customizations/development/translations.md#import-translations). ##### `children` **node** Instead of using the `render` prop, render your application component as children of ``.By doing so, the `` pre-configures the main application routes according to the `entryPointUriPath` defined in the `custom-application-config.json`.This is an opt-int behavior as a replacement of the `render` prop, to simplify the entry point setup. ##### `apolloClient` **ApolloClient** (optional) An optional instance of [ApolloClient](https://www.apollographql.com/docs/react/) to be used instead of the default one. This is usually the case when you need to configure the Apollo cache. See [`createApolloClient`](/merchant-center-customizations/tooling-and-configuration/commercetools-frontend-application-shell.md#createapolloclient). ### ApplicationPageTitle This component applies only to Custom Applications and is available from version `21.15.0` onwards. Use this component to overwrite the document's default ``. #### Usage We recommend using this component on pages with a human-readable resource identifier, for example, a Product name on the product details page. ```js import { ApplicationPageTitle } from '@commercetools-frontend/application-shell'; <ApplicationPageTitle additionalParts={['Red shoes']} />; // Red shoes - products - my-shop - Merchant Center ``` When the `<ApplicationPageTitle>` component is used multiple times, the last one rendered will overwrite the previous ones. Refer to the [Mapping guidelines](/merchant-center-customizations/development/page-titles.md#mapping-guidelines) to understand when to overwrite the title and when not. #### Properties ##### `additionalParts` **string\[]** A list of parts to be prepended to the default page title, separated by `-`. ## Hooks ### useMcQuery A React hook that wraps the [useQuery](https://www.apollographql.com/docs/react/data/queries/) hook of Apollo Client. The only difference is that `useMcQuery` properly types the `context` object, which is always used to define the GraphQL `target`. See [Data fetching](/merchant-center-customizations/development/data-fetching.md). ### useMcLazyQuery A React hook that wraps the [useLazyQuery](https://www.apollographql.com/docs/react/data/queries/#manual-execution-with-uselazyquery) hook of Apollo Client. The only difference is that `useMcLazyQuery` properly types the `context` object, which is always used to define the GraphQL `target`. See [Data fetching](/merchant-center-customizations/development/data-fetching.md). ### useMcMutation A React hook that wraps the [useMutation](https://www.apollographql.com/docs/react/data/mutations/) hook of Apollo Client. The only difference is that `useMcMutation` properly types the `context` object, which is always used to define the GraphQL `target`. See [Data fetching](/merchant-center-customizations/development/data-fetching.md). ## Utilities ### setupGlobalErrorListener Configures global event listeners to catch unexpected errors and report them to Sentry. Make sure to render this in the `entry-point` file. ```js title="entry-point.js" highlightLines="6" import { setupGlobalErrorListener, ApplicationShell, } from '@commercetools-frontend/application-shell'; setupGlobalErrorListener(); const EntryPoint = () => { return ( <ApplicationShell apolloClient={apolloClient} // ...other props /> ); }; ``` ```js title="entry-point.js" highlightLines="6" import { setupGlobalErrorListener, CustomViewShell, } from '@commercetools-frontend/application-shell'; setupGlobalErrorListener(); const EntryPoint = () => { return ( <CustomViewShell apolloClient={apolloClient} // ...other props /> ); }; ``` ### createApolloClient Creates a new instance of the Apollo Client. Use this to extend certain functionalities of the preconfigured Apollo Client. ```js import { createApolloClient } from '@commercetools-frontend/application-shell'; createApolloClient({ // ... }); ``` Available options are: - `cache` (optional): Configuration of the [Apollo cache](https://www.apollographql.com/docs/react/caching/cache-configuration) in relation to the data requirements of your customization. - `restLink` (optional): Instance of the [Apollo REST link](https://www.apollographql.com/docs/react/v3/api/link/apollo-link-rest). This feature is available from version `21.10.0` onwards. The `apollo-link-rest` and its related dependencies are not included in the `@commercetools-frontend/application-shell` package and must be installed separately. When configuring the REST link, we recommend setting the `uri` using the [getMcApiUrl()](/merchant-center-customizations/tooling-and-configuration/commercetools-frontend-application-shell.md#getmcapiurl) utility function. To allow reusing the custom Apollo Client instance in different places, we recommend creating a separate file, for example `src/apollo-client.js`, and define the configuration there. ```js title="apollo-client.js" import { createApolloClient } from '@commercetools-frontend/application-shell'; const configureApollo = () => createApolloClient({ cache: { // ... }, }); export default configureApollo; ``` The new Apollo Client instance must be explicitly passed to the either the `<ApplicationShell>` or `<CustomViewShell>`. ```js title="entry-point.js" import { ApplicationShell } from '@commercetools-frontend/application-shell'; import configureApolloClient from '../../apollo-client'; const apolloClient = configureApolloClient(); const EntryPoint = () => { return ( <ApplicationShell apolloClient={apolloClient} // ...other props /> ); }; ``` ```js title="entry-point.js" import { CustomViewShell } from '@commercetools-frontend/application-shell'; import configureApolloClient from '../../apollo-client'; const apolloClient = configureApolloClient(); const EntryPoint = () => { return ( <CustomViewShell apolloClient={apolloClient} // ...other props /> ); }; ``` Furthermore, in your tests you also need to create a new instance of your custom Apollo Client and pass it to the test utils. ```js import { renderAppWithRedux } from '@commercetools-frontend/application-shell/test-utils'; import configureApolloClient from '../../apollo-client'; renderAppWithRedux({ apolloClient: configureApolloClient(), // ... }); ``` ```js import { renderCustomView } from '@commercetools-frontend/application-shell/test-utils'; import configureApolloClient from '../../apollo-client'; renderCustomView({ apolloClient: configureApolloClient(), // ... }); ``` ### createApolloContextForProxyForwardTo Creates the Apollo `context` object with all the required options for using the `/forward-to` endpoint. See [Integrate with your own API](/merchant-center-customizations/concepts/integrate-with-your-own-api.md). ```js highlightLines="2,14-25" import { createApolloContextForProxyForwardTo, useMcQuery, } from '@commercetools-frontend/application-shell'; import { useApplicationContext } from '@commercetools-frontend/application-shell-connectors'; const useExternalApiFetcher = () => { // Assuming that the `custom-application-config` file contains the custom value: // `{ additionalEnv: { externalApiUrl: 'https://my-custom-app.com/graphql'} }` const externalApiUrl = useApplicationContext( (context) => context.environment.externalApiUrl ); const { loading, data, error } = useMcQuery(MyQuery, { context: createApolloContextForProxyForwardTo({ // The URL to your external API uri: externalApiUrl, // Provide custom HTTP headers (optional) headers: { 'x-foo': 'bar', }, // Set `"X-Forward-To-Audience-Policy"` header in the request with provided value (optional) audiencePolicy: 'forward-url-full-path', // Set `"X-Forward-To-Claims": "permissions"` header in the request (optional) includeUserPermissions: true, }), }); return { loading, data, error, }; }; ``` ```js highlightLines="2,14-25" import { createApolloContextForProxyForwardTo, useMcQuery, } from '@commercetools-frontend/application-shell'; import { useCustomViewContext } from '@commercetools-frontend/application-shell-connectors'; const useExternalApiFetcher = () => { // Assuming that the `custom-view-config` file contains the custom value: // `{ additionalEnv: { externalApiUrl: 'https://my-custom-view.com/graphql'} }` const externalApiUrl = useCustomViewContext( (context) => context.environment.externalApiUrl ); const { loading, data, error } = useMcQuery(MyQuery, { context: createApolloContextForProxyForwardTo({ // The URL to your external API uri: externalApiUrl, // Provide custom HTTP headers (optional) headers: { 'x-foo': 'bar', }, // Set `"X-Forward-To-Audience-Policy"` header in the request with provided value (optional) audiencePolicy: 'forward-url-full-path', // Set `"X-Forward-To-Claims": "permissions"` header in the request (optional) includeUserPermissions: true, }), }); return { loading, data, error, }; }; ``` Available options are: - `uri` (**required**): The URL of the external API to forward the request to. - `headers` (optional): Additional HTTP headers to be included in the request to the external API. - `audiencePolicy` (optional): See [configure the audience policy](/merchant-center-customizations/concepts/integrate-with-your-own-api.md#configure-the-audience-policy). - `includeUserPermissions` (optional): See [configure custom claims](/merchant-center-customizations/concepts/integrate-with-your-own-api.md#configure-custom-claims). - `version` (optional): See [versioning](/merchant-center-customizations/concepts/integrate-with-your-own-api.md#versioning). ### executeHttpClientRequest This feature is available from version `21.10.0` onwards. This function should be used for configuring [custom HTTP clients](/merchant-center-customizations/development/data-fetching.md#custom-http-client) to provide all the recommended functionalities such as: - Defining the required/recommended [HTTP headers for the Merchant Center API](/merchant-center-customizations/concepts/merchant-center-api.md#http-headers). - Automatically renewing the token to access a particular API. ```js import { executeHttpClientRequest } from '@commercetools-frontend/application-shell'; ``` The function accepts a callback function `THttpClientFetcher` to execute the request and an optional object `THttpClientConfig` for the HTTP request configuration. The callback function `THttpClientFetcher` is passed one argument with the configured request options `THttpClientOptions` that you would use to configure the HTTP request for your HTTP client. ```ts type THttpClientOptions = { credentials: 'include'; /** * The HTTP headers included by default are: * - Accept * - Authorization (only in development) * - X-Application-Id * - X-Correlation-Id * - X-Project-Key * - X-User-Agent */ headers: THeaders; }; type TFetcherResponse<Data> = { /** * The parsed response from the server. */ data: Data; /** * The HTTP status code from the server response. */ statusCode: number; /** * Implement a function to access the HTTP headers from the server response. */ getHeader: (headerName: string) => string | null; }; type THttpClientFetcher<Data> = ( options: THttpClientOptions ) => Promise<THttpClientFetcherResponse<Data>>; async function executeHttpClientRequest<Data>( fetcher: THttpClientFetcher<Data>, config?: THttpClientConfig ): Promise<Data>; ``` The `THttpClientConfig` object accepts the following options: - `userAgent` (optional): A custom user agent to identify the HTTP client. We recommend to use the `@commercetools/http-user-agent` package. ```js import createHttpUserAgent from '@commercetools/http-user-agent'; const userAgent = createHttpUserAgent({ name: 'fetch-client', version: '2.6.0', libraryName: window.app.applicationName, contactEmail: 'support@my-company.com', }); ``` - `headers` (optional): Additional HTTP headers to be included in the request. The provided recommended headers won't be overwritten. - `forwardToConfig` (optional): Configuration for using the `/proxy/forward-to` endpoint to [connect to an external API](/merchant-center-customizations/concepts/integrate-with-your-own-api.md#usage-for-custom-http-clients). - `uri` (**required**): The URL of the external API to forward the request to. - `headers` (optional): Additional HTTP headers to be included in the request to the external API. - `audiencePolicy` (optional): See [configure the audience policy](/merchant-center-customizations/concepts/integrate-with-your-own-api.md#configure-the-audience-policy). - `includeUserPermissions` (optional): See [configure custom claims](/merchant-center-customizations/concepts/integrate-with-your-own-api.md#configure-custom-claims). - `version` (recommended): See [versioning](/merchant-center-customizations/concepts/integrate-with-your-own-api.md#versioning). You can see some examples of integrating this with different HTTP clients: - [Example using Fetch](/merchant-center-customizations/development/data-fetching.md#example-using-fetch) - [Example using Axios](/merchant-center-customizations/development/data-fetching.md#example-using-axios) - [Example using Stale-While-Revalidate (SWR)](/merchant-center-customizations/development/data-fetching.md#example-using-swr) - [Example using Ky](/merchant-center-customizations/development/data-fetching.md#example-using-ky) ### getMcApiUrl Returns the URL of the [Merchant Center API](/merchant-center-customizations/concepts/merchant-center-api.md). This is useful to configure HTTP clients that should connect to that API. ```js import { getMcApiUrl } from '@commercetools-frontend/application-shell'; const mcApiUrl = getMcApiUrl(); // https://mc-api.<region>.commercetools.com ``` ### buildApiUrl Returns a URL of the [Merchant Center API](/merchant-center-customizations/concepts/merchant-center-api.md) for the given URI path. This is useful to configure the request URL without having to get the URL of the Merchant Center API. ```js import { buildApiUrl } from '@commercetools-frontend/application-shell'; const apiEndpoint = buildApiUrl('/proxy/ctp/channels'); // https://mc-api.<region>.commercetools.com/proxy/ctp/channels ``` ## Test utils The package provides a separate entry point with utilities for testing customizations. ```js import /**/ '@commercetools-frontend/application-shell/test-utils'; ``` Most of the utility functions related to [React Testing Library](https://github.com/testing-library/react-testing-library), as the recommended testing approach. For more information, see [Testing](/merchant-center-customizations/development/testing.md). In general, the `test-utils` simulate the components-under-test as if it was rendered by the `<ApplicationShell>` or `<CustomViewShell>` and provide the necessary setup to fully test a customization. This includes things like Apollo, React Intl, React Router, etc. ### renderApp This component applies only to Custom Applications. If you're developing a Custom View, see [renderCustomView](/merchant-center-customizations/tooling-and-configuration/commercetools-frontend-application-shell.md#rendercustomview). A wrapper around the [`render`](https://testing-library.com/docs/react-testing-library/api/#render) method of React Testing Library. All the basic setup for testing is included here. #### Usage ```js import { renderApp, screen, } from '@commercetools-frontend/application-shell/test-utils'; describe('rendering', () => { it('should render the authenticated users first name', async () => { renderApp(<FirstName />, { user: { firstName: 'Leonard', }, }); await screen.findByText('First name: Leonard'); }); }); ``` #### Options ##### `locale` **string** Determines the UI language and number format. Is used to configure `<IntlProvider>`. Only core messages will be available during tests, no matter the `locale`. The locale can be a full [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag), although the Merchant Center is currently only available in a limited set of languages. ##### `dataLocale` **string** Sets the locale which is used to display [`LocalizedString`](/api/types.md#localizedstring)s. ##### `mocks` **mock\[]** Allows mocking requests made with Apollo. `mocks` is forwarded as the `mocks` argument to [`MockedProvider`](https://www.apollographql.com/docs/react/development-testing/testing/). If `mocks` is not provided or is an empty array, the Apollo `MockedProvider` is not used. This is an opt-in functionality, as the default behavior is to mock requests using [Mock Service Worker](https://mswjs.io/). ##### `apolloClient` **ApolloClient** Pass a custom instance of Apollo client, useful when your Custom Application has some custom cache policies. You can use the exported function `createApolloClient` of `@commercetools-frontend/application-shell`. ##### `route` **string** The route the user is on, like `/test-project/products`. Defaults to `/`. ##### `disableAutomaticEntryPointRoutes` **boolean** Pass `true` if you are using the `render` prop for the `<ApplicationShell>` instead of the `children` prop. ##### `history` **object** By default a memory-history is generated which has the provided `route` set as its initial history entry. It's possible to pass a custom history as well. In that case, we recommend using the factory function `createEnhancedHistory` from the `@commercetools-frontend/browser-history` package, as it contains the enhanced `location` with the parsed `query` object. ##### `adapter` **object** The [FlopFlip](https://github.com/tdeekens/flopflip) adapter to use when configuring `flopflip`. Defaults to [`memoryAdapter`](https://github.com/tdeekens/flopflip/tree/master/packages/memory-adapter). ##### `flags` **object** An object whose keys are feature-toggle keys and whose values are their toggle state. Use this to test your component with different feature toggle combinations. Example: `{ betaUserProfile: true }`. ##### `environment` **object** Allows to set the `applicationContext.environment`. The passed object gets merged with the tests default environment. Pass `null` to completely remove the `environment`, which renders the `ui` as if no `environment` was given. ##### `user` **object** Allows to set the `applicationContext.user`. The passed object gets merged with the test's default user. Pass `null` to completely remove the `user`, which renders the `ui` as if no user was authenticated. ##### `project` **object** Allows to set the `applicationContext.project`. The passed object gets merged with the tests default project. Pass `null` to completely remove the `project` which renders the `ui` outside of a project context. #### Return values Calling `renderApp` returns the same [Result](https://testing-library.com/docs/react-testing-library/api#render-result) object of React Testing Library, with the addition of the following properties: ##### `history` **object** The history created by `renderApp` which is passed to the router. It can be used to simulate location changes and so on. ##### `user` **object** The `user` object used to configure `<ApplicationContextProvider>`, so the result of merging the default user with `options.user`. Note that this is not the same as `applicationContext.user`. Can be `undefined` when no user is authenticated (when `options.user` was `null`). ##### `project` **object** The `project` object used to configure `<ApplicationContextProvider>`, so the result of merging the default project with `options.project`. Note that this is not the same as `applicationContext.project`. Can be `undefined` when no project was set (when `options.project` was `null`). ##### `environment` **object** The `environment` object used to configure `<ApplicationContextProvider>`, so the result of merging the default environment with `options.environment`. Note that this is not the same as `applicationContext.environment`. Can be `undefined` when no environment was set (when `options.environment` was `null`). ### renderAppWithRedux This component applies only to Custom Applications. If you're developing a Custom View, see [renderCustomView](/merchant-center-customizations/tooling-and-configuration/commercetools-frontend-application-shell.md#rendercustomview). A wrapper around the [`renderApp`](/merchant-center-customizations/tooling-and-configuration/commercetools-frontend-application-shell.md#renderapp) method with the additional support of Redux. This is only useful if your components-under-test relies on Redux, for example when dispatching notifications. #### Usage ```js import { renderAppWithRedux, screen, } from '@commercetools-frontend/application-shell/test-utils'; describe('rendering', () => { it('should render the authenticated users first name', async () => { renderAppWithRedux(<FirstName />, { user: { firstName: 'Leonard', }, }); await screen.findByText('First name: Leonard'); }); }); ``` #### Options In addition to the following options, the method accepts all options from `renderApp`. It is not possible to pass either `storeState` or `sdkMocks` together with `store`. ##### `store` **object** A custom redux store. ##### `storeState` **object** Pass an initial state to the default Redux store. ##### `sdkMocks` **mock\[]** Allows mocking requests made with `@commercetools-frontend/sdk` (Redux). The `sdkMocks` is forwarded as `mocks` to the [SDK `test-utils`](https://github.com/commercetools/merchant-center-application-kit/blob/main/packages/sdk/src/test-utils/README.md). ### renderCustomView This component applies only to Custom Views. If you're developing a Custom Application, see [renderApp](/merchant-center-customizations/tooling-and-configuration/commercetools-frontend-application-shell.md#renderapp) or [renderAppWithRedux](/merchant-center-customizations/tooling-and-configuration/commercetools-frontend-application-shell.md#renderappwithredux). A wrapper around the [`render`](https://testing-library.com/docs/react-testing-library/api/#render) method of the React Testing Library. All the basic setup for testing is included here. #### Usage ```js import { renderCustomView, screen, } from '@commercetools-frontend/application-shell/test-utils'; describe('rendering', () => { it('should render the authenticated users first name', async () => { renderCustomView({ user: { firstName: 'Leonard', }, children: <FirstName />, }); await screen.findByText('First name: Leonard'); }); }); ``` #### Options ##### `locale` **string** Determines the UI language and number format. It is used to configure `<IntlProvider>`. Only core messages will be available during tests, no matter the `locale`. The locale can be a full [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag), although the Merchant Center is currently only available in a limited set of languages. ##### `projectKey` **string** Sets the Custom View context `projectKey`. The passed key gets merged with the tests default project. ##### `projectAllAppliedPermissions` **string** Sets the default project `allAppliedPermissions` property. The passed array will replace the default project `allAppliedPermissions`. ##### `customViewHostUrl` **string** Defines the URL the Custom View receives as part of the emulation of it being rendered in a Merchant Center built-in application. ##### `customViewConfig` **string** The configuration object used to configure the `<CustomViewContextProvider>`, so the result of merging the default Custom View configuration with `options.customViewConfig`. ##### `apolloClient` **ApolloClient** Pass a custom instance of Apollo client, useful when your Custom View has some custom cache policies. You can use the exported function `createApolloClient` of `@commercetools-frontend/application-shell`. ##### `environment` **object** Sets the `customViewContext.environment`. The passed object gets merged with the tests default environment. Pass `null` to completely remove the `environment`, which renders the `ui` as if no `environment` was given. ##### `user` **object** Sets the `customViewContext.user`. The passed object gets merged with the test's default user. Pass `null` to completely remove the `user`, which renders the `ui` as if no user was authenticated. #### Return values Calling `renderCustomView` returns the [Result](https://testing-library.com/docs/react-testing-library/api#render-result) object of React Testing Library, with the addition of the following properties: ##### `history` **object** The history created by `renderApp` which is passed to the router. It can be used to simulate location changes and so on. ##### `user` **object** The `user` object used to configure `<CustomViewContextProvider>`, so the result of merging the default user with `options.user`. Note that this is not the same as `customViewContext.user`. Can be `undefined` when no user is authenticated (when `options.user` was `null`). ##### `project` **object** The `project` object used to configure `<CustomViewContextProvider>`, so the result of merging the default project with `options.project`. Note that this is not the same as `customViewContext.project`. Can be `undefined` when no project was set (when `options.project` was `null`). ##### `environment` **object** The `environment` object used to configure `<CustomViewContextProvider>`, so the result of merging the default environment with `options.environment`. Note that this is not the same as `customViewContext.environment`. Can be `undefined` when no environment was set (when `options.environment` was `null`). ##### `mapNotificationToComponent` **func** Pass a function to map a notification to a custom component. ### mapResourceAccessToAppliedPermissions Helper function to map user permissions to applied resource permissions. This is useful in testing when defining user permissions. For more information, see [Test user permissions](/merchant-center-customizations/development/testing.md#test-user-permissions). ```js { project: { allAppliedPermissions: mapResourceAccessToAppliedPermissions([ PERMISSIONS.View, ]), }, } ``` ### denormalizePermissions Helper function to map user permissions defined as objects to a list of applied resource permissions. ```js { project: { allAppliedPermissions: denormalizePermissions({ canViewCustomChannels: true, }), }, } ``` ## Related pages - [Area overview page with navigation](/merchant-center-customizations.md) - [Previous page: Global actions](/merchant-center-customizations/tooling-and-configuration/commercetools-frontend-actions-global.md) - [Next page: Application Shell connectors](/merchant-center-customizations/tooling-and-configuration/commercetools-frontend-application-shell-connectors.md)