@forge/react
11.8.3-next.0-experimental-0c74a4b11.9.0-next.1
out/hooks/__test__/useTheme.test.jsout/hooks/__test__/useTheme.test.js+97
Index: package/out/hooks/__test__/useTheme.test.js
===================================================================
--- package/out/hooks/__test__/useTheme.test.js
+++ package/out/hooks/__test__/useTheme.test.js
@@ -0,0 +1,97 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+const tslib_1 = require("tslib");
+const jsx_runtime_1 = require("react/jsx-runtime");
+const utils_1 = require("./utils");
+// defining mock function above import so it is initialised before jest.mock runs
+const mockGetContext = jest.fn(async () => null);
+const react_1 = tslib_1.__importStar(require("react"));
+const reconcilerTestRenderer_1 = tslib_1.__importDefault(require("../../__test__/reconcilerTestRenderer"));
+const useTheme_1 = require("../useTheme");
+const testUtils_1 = require("../../__test__/testUtils");
+jest.mock('@forge/bridge', () => ({
+ view: {
+ getContext: mockGetContext
+ },
+ events: utils_1.simpleBridgeEvents
+}));
+const MOCK_THEME = {
+ colorMode: 'dark',
+ colorScheme: 'blue'
+};
+const MOCK_CONTEXT_WITH_THEME = {
+ theme: MOCK_THEME
+};
+const MOCK_CONTEXT_NO_THEME = {
+ extension: {}
+};
+const themeListener = jest.fn();
+// react app fragment to load useTheme hook
+const renderTest = async () => {
+ const Test = () => {
+ const theme = (0, useTheme_1.useTheme)();
+ (0, react_1.useEffect)(() => themeListener(theme), [theme]);
+ return (0, jsx_runtime_1.jsx)(react_1.default.Fragment, {});
+ };
+ const { update } = await reconcilerTestRenderer_1.default.create((0, jsx_runtime_1.jsx)(Test, {}));
+ return {
+ update: async () => {
+ await update((0, jsx_runtime_1.jsx)(Test, {}));
+ }
+ };
+};
+describe('useTheme', () => {
+ beforeAll(() => (0, testUtils_1.setupBridge)());
+ beforeEach(() => {
+ utils_1.simpleBridgeEvents.clearListeners('FORGE_CORE_THEME_CHANGED');
+ themeListener.mockClear();
+ });
+ afterEach(() => jest.clearAllMocks());
+ it('correctly outputs a given theme', async () => {
+ mockGetContext.mockResolvedValue(MOCK_CONTEXT_WITH_THEME);
+ await renderTest();
+ expect(themeListener).toHaveBeenCalledWith(expect.objectContaining(MOCK_THEME));
+ });
+ it('when there is no theme, outputs null', async () => {
+ mockGetContext.mockResolvedValue(MOCK_CONTEXT_NO_THEME);
+ await renderTest();
+ expect(themeListener).toHaveBeenCalledWith(null);
+ });
+ it('when theme is updated via event, outputs new theme', async () => {
+ mockGetContext.mockResolvedValue(MOCK_CONTEXT_WITH_THEME);
+ await renderTest();
+ expect(themeListener).toHaveBeenCalledWith(expect.objectContaining(MOCK_THEME));
+ const newTheme = { colorMode: 'light', colorScheme: 'red' };
+ utils_1.simpleBridgeEvents.emit('FORGE_CORE_THEME_CHANGED', { theme: newTheme });
+ await (0, utils_1.sleep)();
+ expect(themeListener).toHaveBeenCalledWith(expect.objectContaining(newTheme));
+ });
+ it('does not cause re-render when theme content is the same', async () => {
+ mockGetContext.mockResolvedValue(MOCK_CONTEXT_WITH_THEME);
+ await renderTest();
+ expect(themeListener).toHaveBeenCalledTimes(2); // undefined, then theme
+ // Emit same theme content but different object reference
+ utils_1.simpleBridgeEvents.emit('FORGE_CORE_THEME_CHANGED', {
+ theme: { ...MOCK_THEME } // New object, same content
+ });
+ // Should not trigger re-render due to isEqual check
+ expect(themeListener).toHaveBeenCalledTimes(2);
+ });
+ it('handles event firing before getContext completes', async () => {
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
+ let resolveGetContext = () => { };
+ const getContextPromise = new Promise((resolve) => {
+ resolveGetContext = resolve;
+ });
+ mockGetContext.mockReturnValue(getContextPromise);
+ const renderPromise = renderTest();
+ // Fire event before getContext resolves
+ const eventTheme = { colorMode: 'light', colorScheme: 'green' };
+ utils_1.simpleBridgeEvents.emit('FORGE_CORE_THEME_CHANGED', { theme: eventTheme });
+ // Now resolve getContext
+ resolveGetContext?.(MOCK_CONTEXT_WITH_THEME);
+ await renderPromise;
+ // Should have the event theme, not the getContext theme
+ expect(themeListener).toHaveBeenCalledWith(expect.objectContaining(eventTheme));
+ });
+});