Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
kristianpd committed Jul 4, 2023
1 parent d983fa4 commit 0efd1df
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 21 deletions.
20 changes: 9 additions & 11 deletions packages/react/spec/components/SignedInOrRedirect.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
});

Expand All @@ -25,7 +27,7 @@ describe("SignedInOrRedirectOrRedirect", () => {
test("redirects when signed out", () => {
const component = (
<h1>
<SignedInOrRedirect>Hello, Jane!</SignedInOrRedirect>
<SignedInOrRedirect allIn={false}>Hello, Jane!</SignedInOrRedirect>
</h1>
);

Expand All @@ -35,7 +37,7 @@ describe("SignedInOrRedirectOrRedirect", () => {
mockUrqlClient.executeQuery.pushResponse("currentSession", {
data: {
currentSession: {
id: "123",
id: "999",
userId: null,
user: null,
},
Expand All @@ -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 = (
<h1>
<SignedInOrRedirect>Hello, Jane!</SignedInOrRedirect>
<SignedInOrRedirect allIn={true}>Hello, Jane!</SignedInOrRedirect>
</h1>
);

Expand All @@ -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(`"<div><h1>Hello, Jane!</h1></div>"`);
Expand Down
15 changes: 11 additions & 4 deletions packages/react/spec/testWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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")));
});
}
Expand All @@ -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(", ")}`);
}
Expand Down Expand Up @@ -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();
Expand All @@ -134,6 +139,7 @@ beforeEach(() => {
};
});


export const createMockUrqlCient = (assertions?: {
mutationAssertions?: (request: GraphQLRequest) => void;
queryAssertions?: (request: GraphQLRequest) => void;
Expand All @@ -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 (
<Provider api={api}>
<Suspense fallback={<div>Loading...</div>}>{props.children}</Suspense>
<Suspense fallback={<div>Loading...</div>}>
{props.children}
</Suspense>
</Provider>
);
};
35 changes: 35 additions & 0 deletions packages/react/spec/utils.ts
Original file line number Diff line number Diff line change
@@ -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,
});
};
8 changes: 5 additions & 3 deletions packages/react/src/auth/useSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
};

7 changes: 4 additions & 3 deletions packages/react/src/components/SignedInOrRedirect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions packages/react/src/utils.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand Down

0 comments on commit 0efd1df

Please sign in to comment.