UI test
UI and snapshot testing App UI.
Running this example
To run this example locally:
-
If you haven't already, create a new app in the Developer Portal(opens in a new tab or window). For more information, refer to our Quickstart guide.
-
In your app's configuration on the Developer Portal(opens in a new tab or window), ensure the "Development URL" is set to
http://localhost:8080. -
Clone the starter kit:
git clone https://github.com/canva-sdks/canva-apps-sdk-starter-kit.gitcd canva-apps-sdk-starter-kitSHELL -
Install dependencies:
npm installSHELL -
Run the example:
npm run start:example ui_testSHELL -
Click the Preview URL link shown in the terminal to open the example in the Canva editor.
Example app source code
// For usage information, see the README.md file.import { Button, Rows, Text } from "@canva/app-ui-kit";import * as styles from "styles/components.css";export const App = (props: { onClick(): void }) => {return (<div className={styles.scrollContainer}><Rows spacing="2u"><Text>This example demonstrates how to test your app's UI.</Text><Text>Check out <code>examples/testing/ui_test/__tests__/app.test.tsx</code>{" "}to learn how to start testing.</Text><Button variant="primary" onClick={props.onClick}>Do something cool</Button></Rows></div>);};
TYPESCRIPT
// For usage information, see the README.md file.import { createRoot } from "react-dom/client";import { App } from "./app";import "@canva/app-ui-kit/styles.css";import { AppUiProvider } from "@canva/app-ui-kit";import { addElementAtPoint } from "@canva/design";import type { DesignEditorIntent } from "@canva/intents/design";import { prepareDesignEditor } from "@canva/intents/design";async function render() {const root = createRoot(document.getElementById("root") as Element);root.render(<AppUiProvider>{/* Any Apps SDK method needs to be injected to the component, to avoid the need to mock it in tests */}<ApponClick={() =>addElementAtPoint({type: "text",children: ["Hello world!"],})}/></AppUiProvider>,);}const designEditor: DesignEditorIntent = { render };prepareDesignEditor(designEditor);// Hot Module Replacement for development (automatically reloads the app when changes are made)if (module.hot) {module.hot.accept("./app", render);}
TYPESCRIPT
// For usage information, see the README.md file.// Import Canva SDK testing utilitiesimport * as asset from "@canva/asset/test";import * as design from "@canva/design/test";import * as error from "@canva/error/test";import * as intents from "@canva/intents/test";import * as platform from "@canva/platform/test";import * as user from "@canva/user/test";/*Initialize test environments for each Canva SDK packageThis sets up the necessary test infrastructure before mocking the actual SDK methods*/asset.initTestEnvironment();design.initTestEnvironment();error.initTestEnvironment();intents.initTestEnvironment();platform.initTestEnvironment();user.initTestEnvironment();/*Mock all Canva SDK packages except @canva/errorThis allows tests to run without making real API calls to Canva's services*/jest.mock("@canva/asset");jest.mock("@canva/design");jest.mock("@canva/intents");jest.mock("@canva/platform");jest.mock("@canva/user");/*Important: @canva/error should not be mockedUse it to simulate API error responses from other mocks by throwing CanvaError instancesThis allows testing of error handling scenarios*/
TYPESCRIPT
// For usage information, see the README.md file.import { fireEvent, render } from "@testing-library/react";import { TestAppUiProvider } from "@canva/app-ui-kit";import { App } from "../app";describe("app", () => {let addElementAtPoint: jest.Mock;beforeEach(() => {// Create a fresh mock for each test to avoid test interdependencyaddElementAtPoint = jest.fn();});it("calls addElementAtPoint onClick", async () => {const result = render(/*TestAppUiProvider is used instead of AppUiProvider in testsIt provides the same theming and context without browser-specific featuresThe theme prop allows testing both light and dark mode appearances*/<TestAppUiProvider theme="dark"><App onClick={addElementAtPoint} /></TestAppUiProvider>,);// Get reference to the button using accessible role selectorconst button = result.getByRole("button");// Verify button text content matches expected valueexpect(button.textContent).toEqual("Do something cool");// Verify the Canva SDK method hasn't been called yetexpect(addElementAtPoint).not.toHaveBeenCalled();// Simulate user clicking the buttonfireEvent.click(button);// Verify the Canva SDK method was called exactly onceexpect(addElementAtPoint).toHaveBeenCalledTimes(1);});it("Renders 🎉", () => {const result = render(/*Snapshot testing ensures UI doesn't change unexpectedlyTestAppUiProvider ensures consistent rendering across test environments*/<TestAppUiProvider theme="dark"><App onClick={addElementAtPoint} /></TestAppUiProvider>,);// Compare rendered output against saved snapshotexpect(result.container).toMatchSnapshot();});});
TYPESCRIPT
# UI testingDemonstrates how to set up and write tests for app UI components using standard testing frameworks. Shows basic component testing patterns and provides a foundation for testing user interactions.For API reference docs and instructions on running this example, see: <https://www.canva.dev/docs/apps/examples/ui-test/>.Related example: See testing/unit_test for testing app logic and business functions separately from UI.NOTE: This example differs from what is expected for public apps to pass a Canva review:- Error handling is simplified for demonstration. Production apps must implement comprehensive error handling with clear user feedback and graceful failure modes- Internationalization is not implemented. Production apps must support multiple languages using the `@canva/app-i18n-kit` package to pass Canva review requirements- The code structure is simplified: Production apps using [intents](https://www.canva.dev/docs/apps/intents/) are recommended to call the prepareDesignEditor function from src/intents/design_editor/index.tsx
MARKDOWN
API reference
Need help?
- Join our Community Forum(opens in a new tab or window)
- Report issues with this example on GitHub(opens in a new tab or window)