From 4bfe7b64627ec01137bb685b80a6b87955047a7e Mon Sep 17 00:00:00 2001 From: George Desipris Date: Wed, 1 Nov 2023 16:21:31 +0200 Subject: [PATCH] fix(repo): Update tests and playgrounds with new push prop --- integration/templates/react-vite/src/main.tsx | 2 +- packages/chrome-extension/README.md | 2 +- .../clerk-js/src/core/clerk.redirects.test.ts | 16 +- packages/clerk-js/src/core/clerk.test.ts | 319 ++++++++++++++++-- packages/remix/src/client/ClerkApp.tsx | 2 +- playground/vite-react-ts/src/App.tsx | 10 +- 6 files changed, 308 insertions(+), 43 deletions(-) diff --git a/integration/templates/react-vite/src/main.tsx b/integration/templates/react-vite/src/main.tsx index 1615de2a22..4e03094232 100644 --- a/integration/templates/react-vite/src/main.tsx +++ b/integration/templates/react-vite/src/main.tsx @@ -15,7 +15,7 @@ const Root = () => { // @ts-ignore publishableKey={import.meta.env.VITE_CLERK_PUBLISHABLE_KEY as string} clerkJSUrl={import.meta.env.VITE_CLERK_JS as string} - navigate={(to: string) => navigate(to)} + push={(to: string) => navigate(to)} > diff --git a/packages/chrome-extension/README.md b/packages/chrome-extension/README.md index 76a79eebb4..382160d05e 100644 --- a/packages/chrome-extension/README.md +++ b/packages/chrome-extension/README.md @@ -68,7 +68,7 @@ function ClerkProviderWithRoutes() { return ( navigate(to)} + push={to => navigate(to)} > { clerkForProductionInstance = new Clerk(productionPublishableKey); await clerkForProductionInstance.load({ - navigate: mockNavigate, + push: mockNavigate, }); clerkForDevelopmentInstance = new Clerk(developmentPublishableKey); await clerkForDevelopmentInstance.load({ - navigate: mockNavigate, + push: mockNavigate, }); }); @@ -191,12 +191,12 @@ describe('Clerk singleton - Redirects', () => { clerkForProductionInstance = new Clerk(productionPublishableKey); await clerkForProductionInstance.load({ - navigate: mockNavigate, + push: mockNavigate, }); clerkForDevelopmentInstance = new Clerk(developmentPublishableKey); await clerkForDevelopmentInstance.load({ - navigate: mockNavigate, + push: mockNavigate, }); }); @@ -282,12 +282,12 @@ describe('Clerk singleton - Redirects', () => { clerkForProductionInstance = new Clerk(productionPublishableKey); await clerkForProductionInstance.load({ - navigate: mockNavigate, + push: mockNavigate, }); clerkForDevelopmentInstance = new Clerk(developmentPublishableKey); await clerkForDevelopmentInstance.load({ - navigate: mockNavigate, + push: mockNavigate, }); }); @@ -315,12 +315,12 @@ describe('Clerk singleton - Redirects', () => { clerkForProductionInstance = new Clerk(productionPublishableKey); await clerkForProductionInstance.load({ - navigate: mockNavigate, + push: mockNavigate, }); clerkForDevelopmentInstance = new Clerk(developmentPublishableKey); await clerkForDevelopmentInstance.load({ - navigate: mockNavigate, + push: mockNavigate, }); }); diff --git a/packages/clerk-js/src/core/clerk.test.ts b/packages/clerk-js/src/core/clerk.test.ts index 2d9936c0b1..218f49777d 100644 --- a/packages/clerk-js/src/core/clerk.test.ts +++ b/packages/clerk-js/src/core/clerk.test.ts @@ -527,14 +527,14 @@ describe('Clerk singleton', () => { }); it('uses window location if a custom navigate is defined but destination has different origin', async () => { - await sut.load({ navigate: mockNavigate }); + await sut.load({ push: mockNavigate }); const toUrl = 'https://www.origindifferent.com/'; await sut.navigate(toUrl); expect(mockHref).toHaveBeenCalledWith(toUrl); }); it('wraps custom navigate method in a promise if provided and it sync', async () => { - await sut.load({ navigate: mockNavigate }); + await sut.load({ push: mockNavigate }); const toUrl = 'http://test.host/path#hash'; const res = sut.navigate(toUrl); expect(res.then).toBeDefined(); @@ -594,7 +594,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); if (!sut.client) { fail('we should always have a client'); @@ -659,7 +659,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); if (!sut.client) { fail('we should always have a client'); @@ -727,7 +727,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); if (!sut.client) { fail('we should always have a client'); @@ -785,7 +785,7 @@ describe('Clerk singleton', () => { const mockSetActive = jest.fn(); const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); sut.setActive = mockSetActive; @@ -837,7 +837,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); if (!sut.client) { fail('we should always have a client'); @@ -885,7 +885,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); await sut.handleRedirectCallback(); @@ -928,7 +928,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); sut.handleRedirectCallback({ @@ -984,7 +984,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); sut.setActive = mockSetActive as any; @@ -1041,7 +1041,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); sut.setActive = mockSetActive as any; @@ -1095,7 +1095,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); await sut.handleRedirectCallback(); @@ -1145,7 +1145,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); await sut.handleRedirectCallback(); @@ -1189,7 +1189,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); await sut.handleRedirectCallback(); @@ -1238,7 +1238,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); await sut.handleRedirectCallback(); @@ -1272,7 +1272,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); await sut.handleRedirectCallback(); @@ -1318,7 +1318,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); if (!sut.client) { fail('we should always have a client'); @@ -1472,7 +1472,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); if (!sut.client) { fail('we should always have a client'); @@ -1487,6 +1487,271 @@ describe('Clerk singleton', () => { }); }); +<<<<<<< HEAD +======= + // deprecated: Will be replaced by handleEmailLinkVerification + describe('.handleMagicLinkVerification()', () => { + beforeEach(() => { + mockClientFetch.mockReset(); + mockEnvironmentFetch.mockReset(); + }); + + it('completes the sign in flow if a session was created on this client', async () => { + const createdSessionId = 'sess_123'; + setWindowQueryParams([ + ['__clerk_status', 'verified'], + ['__clerk_created_session', createdSessionId], + ]); + mockClientFetch.mockReturnValue( + Promise.resolve({ + activeSessions: [], + sessions: [{ id: createdSessionId }], + signIn: new SignIn({ + status: 'completed', + } as any as SignInJSON), + signUp: new SignUp(null), + }), + ); + const mockSetActive = jest.fn(); + + const sut = new Clerk(frontendApi); + await sut.load({ + push: mockNavigate, + }); + sut.setActive = mockSetActive; + + const redirectUrlComplete = '/redirect-to'; + sut.handleMagicLinkVerification({ redirectUrlComplete }); + + await waitFor(() => { + expect(mockSetActive).toHaveBeenCalledWith({ + session: createdSessionId, + beforeEmit: expect.any(Function), + }); + }); + }); + + it("continues to redirectUrl for sign in that's not completed", async () => { + setWindowQueryParams([['__clerk_status', 'verified']]); + mockClientFetch.mockReturnValue( + Promise.resolve({ + activeSessions: [], + sessions: [], + signIn: new SignIn({ + status: 'needs_second_factor', + } as any as SignInJSON), + signUp: new SignUp(null), + }), + ); + const mockSetActive = jest.fn(); + + const sut = new Clerk(frontendApi); + await sut.load({ + push: mockNavigate, + }); + sut.setActive = mockSetActive; + + const redirectUrl = '/2fa'; + sut.handleMagicLinkVerification({ redirectUrl }); + + await waitFor(() => { + expect(mockSetActive).not.toHaveBeenCalled(); + expect(mockNavigate).toHaveBeenCalledWith(redirectUrl); + }); + }); + + it('completes the sign up flow if a session was created on this client', async () => { + const createdSessionId = 'sess_123'; + setWindowQueryParams([ + ['__clerk_status', 'verified'], + ['__clerk_created_session', createdSessionId], + ]); + mockClientFetch.mockReturnValue( + Promise.resolve({ + activeSessions: [], + sessions: [{ id: createdSessionId }], + signUp: new SignUp({ + status: 'completed', + } as any as SignUpJSON), + signIn: new SignIn(null), + }), + ); + const mockSetActive = jest.fn(); + + const sut = new Clerk(frontendApi); + await sut.load({ + push: mockNavigate, + }); + sut.setActive = mockSetActive; + + const redirectUrlComplete = '/redirect-to'; + sut.handleMagicLinkVerification({ redirectUrlComplete }); + + await waitFor(() => { + expect(mockSetActive).toHaveBeenCalledWith({ + session: createdSessionId, + beforeEmit: expect.any(Function), + }); + }); + }); + + it("continues the sign up flow for a sign up that's not completed", async () => { + setWindowQueryParams([['__clerk_status', 'verified']]); + mockClientFetch.mockReturnValue( + Promise.resolve({ + activeSessions: [], + sessions: [], + signUp: new SignUp({ + status: 'missing_requirements', + } as any as SignUpJSON), + signIn: new SignIn(null), + }), + ); + const mockSetActive = jest.fn(); + + const sut = new Clerk(frontendApi); + await sut.load({ + push: mockNavigate, + }); + sut.setActive = mockSetActive; + + const redirectUrl = '/next-up'; + sut.handleMagicLinkVerification({ redirectUrl }); + + await waitFor(() => { + expect(mockSetActive).not.toHaveBeenCalled(); + expect(mockNavigate).toHaveBeenCalledWith(redirectUrl); + }); + }); + + it('throws an error for expired verification status parameter', async () => { + setWindowQueryParams([['__clerk_status', 'expired']]); + mockClientFetch.mockReturnValue( + Promise.resolve({ + activeSessions: [], + sessions: [], + signUp: new SignUp(null), + signIn: new SignIn(null), + }), + ); + const mockSetActive = jest.fn(); + + const sut = new Clerk(frontendApi); + await sut.load({ + push: mockNavigate, + }); + sut.setActive = mockSetActive; + + await expect(async () => { + await sut.handleMagicLinkVerification({}); + }).rejects.toThrow(MagicLinkErrorCode.Expired); + expect(mockSetActive).not.toHaveBeenCalled(); + }); + + it('throws an error for failed verification status parameter', async () => { + setWindowQueryParams([['__clerk_status', 'failed']]); + mockClientFetch.mockReturnValue( + Promise.resolve({ + activeSessions: [], + sessions: [], + signUp: new SignUp(null), + signIn: new SignIn(null), + }), + ); + const mockSetActive = jest.fn(); + + const sut = new Clerk(frontendApi); + await sut.load({ + push: mockNavigate, + }); + sut.setActive = mockSetActive; + + await expect(async () => { + await sut.handleMagicLinkVerification({}); + }).rejects.toThrow(MagicLinkErrorCode.Failed); + expect(mockSetActive).not.toHaveBeenCalled(); + }); + + it('runs a callback when verified on other device', async () => { + setWindowQueryParams([ + ['__clerk_status', 'verified'], + ['__clerk_created_session', 'sess_123'], + ]); + mockClientFetch.mockReturnValue( + Promise.resolve({ + activeSessions: [], + sessions: [], + signUp: new SignUp(null), + signIn: new SignIn(null), + }), + ); + const mockSetActive = jest.fn(); + const sut = new Clerk(frontendApi); + await sut.load({ + push: mockNavigate, + }); + sut.setActive = mockSetActive; + const res = { ping: 'ping' }; + const cb = () => { + res.ping = 'pong'; + }; + await sut.handleMagicLinkVerification({ onVerifiedOnOtherDevice: cb }); + expect(res.ping).toEqual('pong'); + expect(mockSetActive).not.toHaveBeenCalled(); + }); + + it('throws an error with no status query parameter', async () => { + setWindowQueryParams([['__clerk_created_session', 'sess_123']]); + mockClientFetch.mockReturnValue( + Promise.resolve({ + activeSessions: [], + sessions: [], + signUp: new SignUp(null), + signIn: new SignIn(null), + }), + ); + const mockSetActive = jest.fn(); + const sut = new Clerk(frontendApi); + await sut.load({ + push: mockNavigate, + }); + sut.setActive = mockSetActive; + await expect(async () => { + await sut.handleMagicLinkVerification({}); + }).rejects.toThrow(MagicLinkErrorCode.Failed); + expect(mockSetActive).not.toHaveBeenCalled(); + }); + + it('throws an error for invalid status query parameter', async () => { + setWindowQueryParams([ + ['__clerk_status', 'whatever'], + ['__clerk_created_session', 'sess_123'], + ]); + mockClientFetch.mockReturnValue( + Promise.resolve({ + activeSessions: [], + sessions: [{ id: 'sess_123' }], + signIn: new SignIn({ + status: 'completed', + } as any as SignInJSON), + signUp: new SignUp(null), + }), + ); + const mockSetActive = jest.fn(); + const sut = new Clerk(frontendApi); + await sut.load({ + push: mockNavigate, + }); + sut.setActive = mockSetActive; + + await expect(async () => { + await sut.handleMagicLinkVerification({}); + }).rejects.toThrow(MagicLinkErrorCode.Failed); + expect(mockSetActive).not.toHaveBeenCalled(); + }); + }); + +>>>>>>> 6adc88919 (fix(repo): Update tests and playgrounds with new push prop) describe('.handleEmailLinkVerification()', () => { beforeEach(() => { mockClientFetch.mockReset(); @@ -1513,7 +1778,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); sut.setActive = mockSetActive; @@ -1544,7 +1809,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); sut.setActive = mockSetActive; @@ -1577,7 +1842,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); sut.setActive = mockSetActive; @@ -1608,7 +1873,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); sut.setActive = mockSetActive; @@ -1635,7 +1900,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); sut.setActive = mockSetActive; @@ -1659,7 +1924,7 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); sut.setActive = mockSetActive; @@ -1685,7 +1950,7 @@ describe('Clerk singleton', () => { const mockSetActive = jest.fn(); const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); sut.setActive = mockSetActive; const res = { ping: 'ping' }; @@ -1710,7 +1975,7 @@ describe('Clerk singleton', () => { const mockSetActive = jest.fn(); const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); sut.setActive = mockSetActive; await expect(async () => { @@ -1737,7 +2002,7 @@ describe('Clerk singleton', () => { const mockSetActive = jest.fn(); const sut = new Clerk(productionPublishableKey); await sut.load({ - navigate: mockNavigate, + push: mockNavigate, }); sut.setActive = mockSetActive; diff --git a/packages/remix/src/client/ClerkApp.tsx b/packages/remix/src/client/ClerkApp.tsx index 23dbd5295d..9134b2842a 100644 --- a/packages/remix/src/client/ClerkApp.tsx +++ b/packages/remix/src/client/ClerkApp.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { RemixClerkProviderProps } from './RemixClerkProvider'; import { ClerkProvider } from './RemixClerkProvider'; -type ClerkAppOptions = Partial>; +type ClerkAppOptions = Partial>; export function ClerkApp(App: () => JSX.Element, opts: ClerkAppOptions = {}) { return () => { diff --git a/playground/vite-react-ts/src/App.tsx b/playground/vite-react-ts/src/App.tsx index cdb762abd0..b8d8840eb7 100644 --- a/playground/vite-react-ts/src/App.tsx +++ b/playground/vite-react-ts/src/App.tsx @@ -1,7 +1,3 @@ -import reactLogo from './assets/react.svg'; -import viteLogo from '/vite.svg'; -import clerkLogo from '/clerk.svg'; -import './App.css'; import { ClerkProvider, RedirectToSignIn, @@ -14,6 +10,10 @@ import { useUser, } from '@clerk/clerk-react'; import { BrowserRouter, Route, Routes, useNavigate } from 'react-router-dom'; +import './App.css'; +import reactLogo from './assets/react.svg'; +import clerkLogo from '/clerk.svg'; +import viteLogo from '/vite.svg'; const clerkPubKey = import.meta.env.VITE_REACT_APP_CLERK_PUBLISHABLE_KEY; @@ -67,7 +67,7 @@ function ClerkProviderWithRoutes() { return ( navigate(to)} + push={to => navigate(to)} >