From c4b749b837fc9c43951b6f24db43413027e824be Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Tue, 22 Aug 2023 17:38:44 -0500 Subject: [PATCH] feat(clerk-js): Add tests and the mockNativeRuntime helper --- packages/clerk-js/src/core/clerk.test.ts | 39 +++++++++++++++++++++++- packages/clerk-js/src/testUtils.ts | 37 ++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/packages/clerk-js/src/core/clerk.test.ts b/packages/clerk-js/src/core/clerk.test.ts index bdeeece80c..9859461516 100644 --- a/packages/clerk-js/src/core/clerk.test.ts +++ b/packages/clerk-js/src/core/clerk.test.ts @@ -1,6 +1,7 @@ import type { ActiveSessionResource, SignInJSON, SignUpJSON, TokenResource } from '@clerk/types'; import { waitFor } from '@testing-library/dom'; +import { mockNativeRuntime } from '../testUtils'; import Clerk from './clerk'; import { eventBus, events } from './events'; import type { AuthConfig, DisplayConfig, Organization } from './resources/internal'; @@ -91,7 +92,10 @@ describe('Clerk singleton', () => { }; Object.defineProperty(global.window, 'location', { value: mockWindowLocation }); - Object.defineProperty(global.window.document, 'hasFocus', { value: () => true, configurable: true }); + + if (typeof globalThis.document !== 'undefined') { + Object.defineProperty(global.window.document, 'hasFocus', { value: () => true, configurable: true }); + } const mockAddEventListener = (type: string, callback: (e: any) => void) => { if (type === 'message') { @@ -295,6 +299,39 @@ describe('Clerk singleton', () => { expect(sut.session).toMatchObject(mockSession); }); }); + + mockNativeRuntime(() => { + it('calls session.touch in a non-standard browser', async () => { + mockClientFetch.mockReturnValue(Promise.resolve({ activeSessions: [mockSession] })); + + const sut = new Clerk(frontendApi); + await sut.load({ standardBrowser: false }); + + const executionOrder: string[] = []; + mockSession.touch.mockImplementationOnce(() => { + sut.session = mockSession as any; + executionOrder.push('session.touch'); + return Promise.resolve(); + }); + cookieSpy.mockImplementationOnce(() => { + executionOrder.push('set cookie'); + return Promise.resolve(); + }); + const beforeEmitMock = jest.fn().mockImplementationOnce(() => { + executionOrder.push('before emit'); + return Promise.resolve(); + }); + + await sut.setActive({ organization: { id: 'org-id' } as Organization, beforeEmit: beforeEmitMock }); + + expect(executionOrder).toEqual(['session.touch', 'before emit']); + expect(mockSession.touch).toHaveBeenCalled(); + expect((mockSession as any as ActiveSessionResource)?.lastActiveOrganizationId).toEqual('org-id'); + expect(cookieSpy).not.toHaveBeenCalled(); + expect(beforeEmitMock).toBeCalledWith(mockSession); + expect(sut.session).toMatchObject(mockSession); + }); + }); }); describe('.load()', () => { diff --git a/packages/clerk-js/src/testUtils.ts b/packages/clerk-js/src/testUtils.ts index ec3364d181..57d11a28c9 100644 --- a/packages/clerk-js/src/testUtils.ts +++ b/packages/clerk-js/src/testUtils.ts @@ -11,6 +11,43 @@ const render = (ui: React.ReactElement, options?: RenderOptions) => { return { ..._render(ui, { ...options }), userEvent }; }; +/** + * Helper method to mock a native runtime environment for specific test cases, currently targeted at React Native. + * Makes some assumptions about our runtime detection utilities in `packages/clerk-js/src/utils/runtime.ts`. + * + * Usage: + * + * ```js + * mockNativeRuntime(() => { + * // test cases + * it('simulates native', () => { + * expect(typeof document).toBe('undefined'); + * }); + * }); + * ``` + */ +export const mockNativeRuntime = (fn: () => void) => { + describe('native runtime', () => { + let spyDocument: jest.SpyInstance; + let spyNavigator: jest.SpyInstance; + + beforeAll(() => { + spyDocument = jest.spyOn(globalThis, 'document', 'get'); + spyDocument.mockReturnValue(undefined); + + spyNavigator = jest.spyOn(globalThis.navigator, 'product', 'get'); + spyNavigator.mockReturnValue('ReactNative'); + }); + + afterAll(() => { + spyDocument.mockRestore(); + spyNavigator.mockRestore(); + }); + + fn(); + }); +}; + export * from './ui/utils/test/runFakeTimers'; export * from './ui/utils/test/createFixtures'; export * from '@testing-library/react';