From 0efd1df24b1042fb150e2ed63baecc153713998e Mon Sep 17 00:00:00 2001 From: Kristian PD Date: Tue, 4 Jul 2023 16:34:37 -0400 Subject: [PATCH] wip --- .../components/SignedInOrRedirect.spec.tsx | 20 +++++------ packages/react/spec/testWrapper.tsx | 15 +++++--- packages/react/spec/utils.ts | 35 +++++++++++++++++++ packages/react/src/auth/useSession.ts | 8 +++-- .../src/components/SignedInOrRedirect.tsx | 7 ++-- packages/react/src/utils.ts | 2 ++ 6 files changed, 66 insertions(+), 21 deletions(-) create mode 100644 packages/react/spec/utils.ts diff --git a/packages/react/spec/components/SignedInOrRedirect.spec.tsx b/packages/react/spec/components/SignedInOrRedirect.spec.tsx index 2ed21104f..1f72fdab7 100644 --- a/packages/react/spec/components/SignedInOrRedirect.spec.tsx +++ b/packages/react/spec/components/SignedInOrRedirect.spec.tsx @@ -5,12 +5,14 @@ import { superAuthApi } from "../../spec/apis"; import { TestWrapper, mockUrqlClient } from "../../spec/testWrapper"; import { SignedInOrRedirect } from "../../src/components/SignedInOrRedirect"; -describe("SignedInOrRedirectOrRedirect", () => { +describe("SignedInOrRedirect", () => { const { location } = window; const mockAssign = jest.fn(); beforeAll(() => { + // @ts-expect-error mock delete window.location; + // @ts-expect-error mock window.location = { assign: mockAssign }; }); @@ -25,7 +27,7 @@ describe("SignedInOrRedirectOrRedirect", () => { test("redirects when signed out", () => { const component = (

- Hello, Jane! + Hello, Jane!

); @@ -35,7 +37,7 @@ describe("SignedInOrRedirectOrRedirect", () => { mockUrqlClient.executeQuery.pushResponse("currentSession", { data: { currentSession: { - id: "123", + id: "999", userId: null, user: null, }, @@ -47,12 +49,14 @@ describe("SignedInOrRedirectOrRedirect", () => { rerender(component); expect(mockAssign).toHaveBeenCalledTimes(1); expect(mockAssign).toHaveBeenCalledWith("/auth/signin"); + console.log("**** BEFORE THIS *****"); }); - test("renders when signed in", () => { + test("does not redirect and renders when signed in", () => { + console.log("**** AFTER THIS *****"); const component = (

- Hello, Jane! + Hello, Jane!

); @@ -76,12 +80,6 @@ describe("SignedInOrRedirectOrRedirect", () => { }); rerender(component); - const mockAssign = jest.fn(); - Object.defineProperty(window, "location", { - value: { - assign: mockAssign, - }, - }); expect(mockAssign).not.toBeCalled(); expect(container.outerHTML).toMatchInlineSnapshot(`"

Hello, Jane!

"`); diff --git a/packages/react/spec/testWrapper.tsx b/packages/react/spec/testWrapper.tsx index b5d976c94..d15ffacef 100644 --- a/packages/react/spec/testWrapper.tsx +++ b/packages/react/spec/testWrapper.tsx @@ -58,12 +58,14 @@ const newMockOperationFn = (assertions?: (request: GraphQLRequest) => void) => { const { query } = request; const fetchOptions = options?.fetchOptions; const key = graphqlDocumentName(query) ?? "unknown"; + console.log("subjects.key", subjects[key]) subjects[key] ??= makeSubject(); if (fetchOptions && typeof fetchOptions != "function") { const signal = fetchOptions.signal; if (signal) { signal.addEventListener("abort", () => { + console.log("subjects leaking here?", subjects, key); subjects[key].next(makeErrorResult(null as any, new Error("AbortError"))); }); } @@ -72,12 +74,14 @@ const newMockOperationFn = (assertions?: (request: GraphQLRequest) => void) => { if (assertions) { assertions(request); } + console.log("mockoperationfn",assertions, subjects, subjects[key]); return subjects[key].source; }) as unknown as MockOperationFn; fn.subjects = subjects; fn.pushResponse = (key, response) => { + console.log("pushing response: ", key, subjects, response) if (!subjects[key]) { throw new Error(`No mock client subject started for key ${key}, options are ${Object.keys(subjects).join(", ")}`); } @@ -126,6 +130,7 @@ const newMockFetchFn = () => { export const mockUrqlClient = { suspense: true } as MockUrqlClient; beforeEach(() => { + console.log("totally new mocks"); mockUrqlClient.executeQuery = newMockOperationFn(); mockUrqlClient.executeMutation = newMockOperationFn(); mockUrqlClient.executeSubscription = newMockOperationFn(); @@ -134,6 +139,7 @@ beforeEach(() => { }; }); + export const createMockUrqlCient = (assertions?: { mutationAssertions?: (request: GraphQLRequest) => void; queryAssertions?: (request: GraphQLRequest) => void; @@ -151,13 +157,14 @@ export const createMockUrqlCient = (assertions?: { export const TestWrapper = (api: AnyClient) => (props: { children: ReactNode }) => { // any individual test will only use one of those, but mock them all out for simplicity - jest.spyOn(relatedProductsApi.connection, "currentClient", "get").mockReturnValue(mockUrqlClient); - jest.spyOn(bulkExampleApi.connection, "currentClient", "get").mockReturnValue(mockUrqlClient); - jest.spyOn(superAuthApi.connection, "currentClient", "get").mockReturnValue(mockUrqlClient); + console.log('returning mock value'); + jest.spyOn(api.connection, "currentClient", "get").mockReturnValue(mockUrqlClient); return ( - Loading...}>{props.children} + Loading...}> + {props.children} + ); }; diff --git a/packages/react/spec/utils.ts b/packages/react/spec/utils.ts new file mode 100644 index 000000000..b374945d6 --- /dev/null +++ b/packages/react/spec/utils.ts @@ -0,0 +1,35 @@ +import type { MockUrqlClient } from "./testWrapper"; + +export const expectMockSignedOutSession = (mockClient: MockUrqlClient) => { + expect(mockClient.executeQuery).toBeCalledTimes(1); + mockClient.executeQuery.pushResponse("currentSession", { + data: { + currentSession: { + id: "123", + userId: null, + user: null, + }, + }, + stale: false, + hasNext: false, + }); +}; + +export const expectMockSignedInSession = (mockClient: MockUrqlClient) => { + expect(mockClient.executeQuery).toBeCalledTimes(1); + mockClient.executeQuery.pushResponse("currentSession", { + data: { + currentSession: { + id: "123", + userId: "321", + user: { + id: "321", + firstName: "Jane", + lastName: "Doe", + }, + }, + }, + stale: false, + hasNext: false, + }); +}; diff --git a/packages/react/src/auth/useSession.ts b/packages/react/src/auth/useSession.ts index a77e28612..fc26b05d3 100644 --- a/packages/react/src/auth/useSession.ts +++ b/packages/react/src/auth/useSession.ts @@ -13,10 +13,11 @@ export interface GadgetUser { [key: string]: any; } -const useGetSessionAndUser = () => { +const useGetSessionAndUser = (opts = {}) => { const api = useApi(); if ("currentSession" in api && "session" in api && "user" in api) { return useGet(api.currentSession as any, { + ...opts, suspense: true, select: { ...(api.session as any).findMany.defaultSelection, @@ -25,14 +26,15 @@ const useGetSessionAndUser = () => { ...(api.user as any).findMany.defaultSelection, }, }, + requestPolicy: "network-only" }); } else { throw new Error("api client does not have a Session or User model"); } }; -export const useSession = (): GadgetSession | undefined => { - const [{ data: session }] = useGetSessionAndUser(); +export const useSession = (opts = {}): GadgetSession | undefined => { + const [{ data: session }] = useGetSessionAndUser(opts); return session; }; diff --git a/packages/react/src/components/SignedInOrRedirect.tsx b/packages/react/src/components/SignedInOrRedirect.tsx index 79346c7c1..8bf334dcf 100644 --- a/packages/react/src/components/SignedInOrRedirect.tsx +++ b/packages/react/src/components/SignedInOrRedirect.tsx @@ -4,18 +4,19 @@ import { GadgetClientContext } from "../../src/GadgetProvider"; import { useSession } from "../../src/auth/useSession"; import { isSessionSignedIn } from "../../src/auth/utils"; -export const SignedInOrRedirect = (props: { children: ReactNode }) => { +export const SignedInOrRedirect = (props: { allIn: boolean, children: ReactNode }) => { const [redirected, setRedirected] = useState(false); - const session = useSession(); + const session = useSession({ context: { additionalTypenames: props.allIn ? ["AllIn"] : ["Weak"]}}); const isSignedIn = session && isSessionSignedIn(session); const context = useContext(GadgetClientContext); useEffect(() => { + console.log({session}); if (context?.signInPath && !redirected && !isSignedIn) { setRedirected(true); window.location.assign(context.signInPath); } - }, [redirected, isSignedIn, context?.signInPath]); + }, [redirected, session, isSignedIn, context?.signInPath]); if (isSignedIn) { return props.children; diff --git a/packages/react/src/utils.ts b/packages/react/src/utils.ts index 37670d6c9..4b269a9ce 100644 --- a/packages/react/src/utils.ts +++ b/packages/react/src/utils.ts @@ -1,7 +1,9 @@ import type { FieldSelection, GadgetError, InvalidFieldError, InvalidRecordError } from "@gadgetinc/api-client-core"; import { gadgetErrorFor, getNonNullableError } from "@gadgetinc/api-client-core"; import type { CombinedError, RequestPolicy } from "@urql/core"; +import { randomInt } from "crypto"; import { GraphQLError } from "graphql"; +import { random } from "lodash"; import { useMemo } from "react"; import type { AnyVariables, Operation, OperationContext, UseQueryArgs, UseQueryState } from "urql";