fix onboarding login glitch (#1118)
This commit is contained in:
		
							parent
							
								
									9befd4abb9
								
							
						
					
					
						commit
						df687009bd
					
				
					 4 changed files with 59 additions and 20 deletions
				
			
		
							
								
								
									
										1
									
								
								.github/workflows/e2e.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/e2e.yml
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -9,6 +9,7 @@ jobs:
 | 
				
			||||||
      DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
 | 
					      DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
 | 
				
			||||||
      BASE_URL: http://localhost:3000
 | 
					      BASE_URL: http://localhost:3000
 | 
				
			||||||
      JWT_SECRET: secret
 | 
					      JWT_SECRET: secret
 | 
				
			||||||
 | 
					      GOOGLE_API_CREDENTIALS: "{}"
 | 
				
			||||||
      # GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
 | 
					      # GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
 | 
				
			||||||
      # CRON_API_KEY: xxx
 | 
					      # CRON_API_KEY: xxx
 | 
				
			||||||
      # CALENDSO_ENCRYPTION_KEY: xxx
 | 
					      # CALENDSO_ENCRYPTION_KEY: xxx
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@ import {
 | 
				
			||||||
import { signOut, useSession } from "next-auth/client";
 | 
					import { signOut, useSession } from "next-auth/client";
 | 
				
			||||||
import Link from "next/link";
 | 
					import Link from "next/link";
 | 
				
			||||||
import { useRouter } from "next/router";
 | 
					import { useRouter } from "next/router";
 | 
				
			||||||
import React, { ReactNode, useEffect } from "react";
 | 
					import React, { ReactNode, useEffect, useState } from "react";
 | 
				
			||||||
import { Toaster } from "react-hot-toast";
 | 
					import { Toaster } from "react-hot-toast";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import LicenseBanner from "@ee/components/LicenseBanner";
 | 
					import LicenseBanner from "@ee/components/LicenseBanner";
 | 
				
			||||||
| 
						 | 
					@ -37,7 +37,11 @@ import { useViewerI18n } from "./I18nLanguageHandler";
 | 
				
			||||||
import Logo from "./Logo";
 | 
					import Logo from "./Logo";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function useMeQuery() {
 | 
					function useMeQuery() {
 | 
				
			||||||
  const meQuery = trpc.useQuery(["viewer.me"]);
 | 
					  const meQuery = trpc.useQuery(["viewer.me"], {
 | 
				
			||||||
 | 
					    retry(failureCount) {
 | 
				
			||||||
 | 
					      return failureCount > 3;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return meQuery;
 | 
					  return meQuery;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -45,7 +49,6 @@ function useMeQuery() {
 | 
				
			||||||
function useRedirectToLoginIfUnauthenticated() {
 | 
					function useRedirectToLoginIfUnauthenticated() {
 | 
				
			||||||
  const [session, loading] = useSession();
 | 
					  const [session, loading] = useSession();
 | 
				
			||||||
  const router = useRouter();
 | 
					  const router = useRouter();
 | 
				
			||||||
  const query = useMeQuery();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    if (!loading && !session) {
 | 
					    if (!loading && !session) {
 | 
				
			||||||
| 
						 | 
					@ -56,28 +59,36 @@ function useRedirectToLoginIfUnauthenticated() {
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }, [loading, session, router]);
 | 
					    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
				
			||||||
 | 
					  }, [loading, session]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (query.status !== "loading" && !query.data) {
 | 
					  return {
 | 
				
			||||||
    router.replace("/auth/login");
 | 
					    loading: loading && !session,
 | 
				
			||||||
  }
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function useRedirectToOnboardingIfNeeded() {
 | 
					function useRedirectToOnboardingIfNeeded() {
 | 
				
			||||||
  const [session, loading] = useSession();
 | 
					 | 
				
			||||||
  const router = useRouter();
 | 
					  const router = useRouter();
 | 
				
			||||||
  const query = useMeQuery();
 | 
					  const query = useMeQuery();
 | 
				
			||||||
  const user = query.data;
 | 
					  const user = query.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [isRedirectingToOnboarding, setRedirecting] = useState(false);
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    if (!loading && user) {
 | 
					    if (user && shouldShowOnboarding(user)) {
 | 
				
			||||||
      if (shouldShowOnboarding(user)) {
 | 
					      setRedirecting(true);
 | 
				
			||||||
        router.replace({
 | 
					 | 
				
			||||||
          pathname: "/getting-started",
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }, [loading, session, router, user]);
 | 
					  }, [router, user]);
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (isRedirectingToOnboarding) {
 | 
				
			||||||
 | 
					      router.replace({
 | 
				
			||||||
 | 
					        pathname: "/getting-started",
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
				
			||||||
 | 
					  }, [isRedirectingToOnboarding]);
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    isRedirectingToOnboarding,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function ShellSubHeading(props: {
 | 
					export function ShellSubHeading(props: {
 | 
				
			||||||
| 
						 | 
					@ -109,8 +120,8 @@ export default function Shell(props: {
 | 
				
			||||||
}) {
 | 
					}) {
 | 
				
			||||||
  const { t } = useLocale();
 | 
					  const { t } = useLocale();
 | 
				
			||||||
  const router = useRouter();
 | 
					  const router = useRouter();
 | 
				
			||||||
  useRedirectToLoginIfUnauthenticated();
 | 
					  const { loading } = useRedirectToLoginIfUnauthenticated();
 | 
				
			||||||
  useRedirectToOnboardingIfNeeded();
 | 
					  const { isRedirectingToOnboarding } = useRedirectToOnboardingIfNeeded();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const telemetry = useTelemetry();
 | 
					  const telemetry = useTelemetry();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -157,7 +168,7 @@ export default function Shell(props: {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const i18n = useViewerI18n();
 | 
					  const i18n = useViewerI18n();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (i18n.status === "loading") {
 | 
					  if (i18n.status === "loading" || isRedirectingToOnboarding || loading) {
 | 
				
			||||||
    // show spinner whilst i18n is loading to avoid language flicker
 | 
					    // show spinner whilst i18n is loading to avoid language flicker
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className="z-50 absolute w-full h-screen bg-gray-50 flex items-center">
 | 
					      <div className="z-50 absolute w-full h-screen bg-gray-50 flex items-center">
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,7 +45,7 @@ export function loginProvider(opts: {
 | 
				
			||||||
      if (cachedCookies) {
 | 
					      if (cachedCookies) {
 | 
				
			||||||
        await context.addCookies(cachedCookies);
 | 
					        await context.addCookies(cachedCookies);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        await page.goto("http://localhost:3000/event-types");
 | 
					        await page.goto("http://localhost:3000/auth/login");
 | 
				
			||||||
        // Click input[name="email"]
 | 
					        // Click input[name="email"]
 | 
				
			||||||
        await page.click('input[name="email"]');
 | 
					        await page.click('input[name="email"]');
 | 
				
			||||||
        // Fill input[name="email"]
 | 
					        // Fill input[name="email"]
 | 
				
			||||||
| 
						 | 
					@ -57,7 +57,12 @@ export function loginProvider(opts: {
 | 
				
			||||||
        // Press Enter
 | 
					        // Press Enter
 | 
				
			||||||
        await page.press('input[name="password"]', "Enter");
 | 
					        await page.press('input[name="password"]', "Enter");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await page.waitForSelector("[data-testid=event-types]");
 | 
					        await page.waitForNavigation({
 | 
				
			||||||
 | 
					          url(url) {
 | 
				
			||||||
 | 
					            return !url.pathname.startsWith("/auth");
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const cookies = await context.cookies();
 | 
					        const cookies = await context.cookies();
 | 
				
			||||||
        cookieCache.set(opts.user, cookies);
 | 
					        cookieCache.set(opts.user, cookies);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										22
									
								
								playwright/onboarding.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								playwright/onboarding.test.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					import { kont } from "kont";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { loginProvider } from "./lib/loginProvider";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jest.setTimeout(60e3);
 | 
				
			||||||
 | 
					jest.retryTimes(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ctx = kont()
 | 
				
			||||||
 | 
					  .useBeforeEach(
 | 
				
			||||||
 | 
					    loginProvider({
 | 
				
			||||||
 | 
					      user: "onboarding",
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					  .done();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test("redirects to /getting-started after login", async () => {
 | 
				
			||||||
 | 
					  await ctx.page.waitForNavigation({
 | 
				
			||||||
 | 
					    url(url) {
 | 
				
			||||||
 | 
					      return url.pathname === "/getting-started";
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
		Loading…
	
		Reference in a new issue