@forge/react

11.8.3-next.0-experimental-0c74a4b11.9.0-next.1
out/hooks/__test__/useTheme.test.js
out/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));
+    });
+});