This is the new documentation of Custom Applications. You can still visit the legacy documentation during the migration from Project-level Custom Applications.
@/application-shell
React component that ties together all the main functionalities of the Custom Applications.
Installation
yarn add @commercetools-frontend/application-shell# ornpm --save install @commercetools-frontend/application-shell
Additionally install the peer dependencies (if not present)
yarn add @apollo/client react react-dom react-intl react-redux react-router-dom redux @testing-library/react @testing-library/react-hooks# ornpm --save install @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.
The ApplicationShell
component is expected to be rendered as the top-level component of your application.
Usage
We recommend to render the application content as children
of <ApplicationShell>
instead of the render
prop.
This allows the <ApplicationShell>
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.
import { ApplicationShell } from '@commercetools-frontend/application-shell';const loadMessages = async (locale) => {// ...}const AsyncApplicationRoutes = React.lazy(() => import('../../routes' /* webpackChunkName: "avengers" */));const EntryPoint = () => (<ApplicationShellenvironment={window.app}applicationMessages={loadMessages}><AsyncApplicationRoutes /></ApplicationShell>);export default EntryPoint;
Properties
Props | Type | Required | Default | Description |
---|---|---|---|---|
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 Importing translations. |
environment | object | ✅ | - | The application runtime environment, which is exposed in window.app . See Runtime configuration. |
children | node | ✅ (*) | - | Instead of using the render prop, render your application component as children of <ApplicationShell> . By doing so, the <ApplicationShell> 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 | (*) | - | The render function is called when the <ApplicationShell> 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 | - | An optional instance of ApolloClient to be used instead of the default one. This is usually the case when you need to configure the Apollo cache. See createApolloClient . |
Hooks
useMcQuery
A React hook that wraps the useQuery
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.
useMcLazyQuery
A React hook that wraps the 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.
useMcMutation
A React hook that wraps the useMutation
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.
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.
import {setupGlobalErrorListener,ApplicationShell,} from '@commercetools-frontend/application-shell';const EntryPoint = () => {return (<ApplicationShellapolloClient={apolloClient}// ...other props/>);};
createApolloClient
Creates a new instance of the Apollo Client. Use this if you need to configure the Apollo cache.
createApolloClient({cache: {// ...},})
The new Apollo Client instance must be explicitly passed to the <ApplicationShell>
.
import {createApolloClient,ApplicationShell,} from '@commercetools-frontend/application-shell';const apolloClient = createApolloClient({cache: {// Your custom configuration, according to the Apollo cache documentation.// https://www.apollographql.com/docs/react/caching/cache-configuration/},});const EntryPoint = () => {return (<ApplicationShellapolloClient={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.
import { createApolloClient } from '@commercetools-frontend/application-shell';import { renderAppWithRedux } from '@commercetools-frontend/application-shell/test-utils';renderAppWithRedux({apolloClient: createApolloClient(),// ...});
createApolloContextForProxyForwardTo
Creates the Apollo context
object with all the required options for using the /forward-to
endpoint. See Integrate with your own API.
import {createApolloContextForProxyForwardTo,useMcQuery,} from '@commercetools-frontend/application-shell';import { useApplicationContext } from '@commercetools-frontend/application-shell-connectors';const useExternalApiFetcher = () => {// Assuming that the `custom-application-config.json` 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 APIuri: externalApiUrl,// Optionally pass custom HTTP headersheaders: {'x-foo': 'bar',},}),});return {loading,data,error,}};
Test utils
The package provides a separate entry point with utilities for testing Custom Applications.
import { /**/ } from '@commercetools-frontend/application-shell/test-utils';
Most of the utility functions related to React Testing Library, as the recommended testing approach. See Testing for more information.
In general the test-utils
simulate the components-under-test as if it was rendered by the <ApplicationShell>
and provide the necessary setup to fully test a Custom Application. This includes things like Apollo, React Intl, React Router, etc.
renderApp
A wrapper around the render
method of React Testing Library. All the basic setup for testing is included here.
Usage
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
Argument | Type | Concern | Description |
---|---|---|---|
locale | String | Localization | 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, although the Merchant Center is currently only available in a limited set of languages. |
dataLocale | String | Localization | Sets the locale which is used to display LocalizedString s. |
mocks | Array | Apollo | Allows mocking requests made with Apollo. mocks is forwarded as the mocks argument to MockedProvider . 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. |
apolloClient | ApolloClient | Apollo | 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 | Routing | The route the user is on, like /test-project/products . Defaults to / . |
disableAutomaticEntryPointRoutes | Boolean | Routing | Pass true if you are using the render prop for the <ApplicationShell> instead of the children prop. |
history | Object | Routing | 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 | Feature Toggles | The FlopFlip adapter to use when configuring flopflip . Defaults to memoryAdapter . |
flags | Object | Feature Toggles | 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 | Runtime configuration | 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 | Application Context | 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 | Application Context | 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 object of React Testing Library, with the addition of the following fields:
Field | Type | Description |
---|---|---|
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
A wrapper around the 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
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
.
Argument | Type | Concern | Description |
---|---|---|---|
store | Object | Redux | A custom redux store. |
storeState | Object | Redux | Pass an initial state to the default Redux store. |
sdkMocks | Array | Redux | Allows mocking requests made with @commercetools-frontend/sdk (Redux). The sdkMocks is forwarded as mocks to the SDK test-utils . |
mapNotificationToComponent | Function | Redux | 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. See Testing user permissions for more information.
{project: {allAppliedPermissions: mapResourceAccessToAppliedPermissions([PERMISSIONS.ViewAvengers,]),},}
denormalizePermissions
Helper function to map user permissions defined as objects to a list of applied resource permissions.
{project: {allAppliedPermissions: denormalizePermissions({canViewAvengers: true,}),},}