Skip to content

Commit

Permalink
refactor(app): updating libraries, improving user state management, s…
Browse files Browse the repository at this point in the history
…qaushing bugs (passportxyz#1874)

* feat(app): upgrading libraries, improving user state management

* refactor(app): fix unnecessary rerendering from onchainContext

* fix(app): bug squashing
  • Loading branch information
lucianHymer authored Nov 9, 2023
1 parent d29d81f commit d7eaeee
Show file tree
Hide file tree
Showing 68 changed files with 2,361 additions and 2,395 deletions.
5 changes: 0 additions & 5 deletions app/__mocks__/@web3-onboard/react.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@ const mockUseConnectWallet = () => [{ wallet: {} }, mockConnectFn, mockDisconnec

react.useConnectWallet = mockUseConnectWallet;

const mockSetChain = jest.fn();
const mockUseSetChain = () => [{ chains: [], connectedChain: {}, settingChain: false }, mockSetChain];

react.useSetChain = mockUseSetChain;

react.useWallets = () => [];

module.exports = react;
71 changes: 37 additions & 34 deletions app/__test-fixtures__/contextTestHelpers.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,17 @@
import { UserContext, UserContextState } from "../context/userContext";
import { ScorerContext, ScorerContextState } from "../context/scorerContext";
import { CeramicContext, CeramicContextState, IsLoadingPassportState, platforms } from "../context/ceramicContext";
import { ProviderSpec, STAMP_PROVIDERS } from "../config/providers";
import { mockAddress, mockWallet } from "./onboardHookValues";
import React from "react";
import { render } from "@testing-library/react";
import { PLATFORM_ID } from "@gitcoin/passport-types";
import { PlatformProps } from "../components/GenericPlatform";
import { OnChainContextState } from "../context/onChainContext";
import { StampClaimingContext, StampClaimingContextState } from "../context/stampClaimingContext";

jest.mock("@didtools/cacao", () => ({
Cacao: {
fromBlockBytes: jest.fn(),
},
}));

export const makeTestUserContext = (initialState?: Partial<UserContextState>): UserContextState => {
return {
loggedIn: true,
loggingIn: false,
connect: jest.fn(),
disconnect: jest.fn(),
address: mockAddress,
wallet: mockWallet,
signer: undefined,
walletLabel: mockWallet.label,
dbAccessToken: "token",
dbAccessTokenStatus: "idle",
userWarning: undefined,
setUserWarning: jest.fn(),
setWalletConnectionError: jest.fn(),
...initialState,
};
};
import { StampClaimingContextState } from "../context/stampClaimingContext";
import {
DatastoreConnectionContext,
DatastoreConnectionContextState,
DbAuthTokenStatus,
} from "../context/datastoreConnectionContext";

export const getProviderSpec = (platform: PLATFORM_ID, provider: string): ProviderSpec => {
return STAMP_PROVIDERS[platform]
Expand Down Expand Up @@ -231,17 +209,42 @@ export const scorerContext = {
rawScore: 0,
} as unknown as ScorerContextState;

export const createWalletStoreMock = () => {
const mockConnect = jest.fn();

const mockWalletState = {
address: "0x123",
connect: mockConnect,
};

const walletStoreLibraryMock = {
useWalletStore: (callback: (state: any) => any) => callback(mockWalletState),
};

return {
walletStoreLibraryMock,
mockConnect,
};
};

const datastoreConnectionContext = {
connect: jest.fn(),
disconnect: jest.fn(),
dbAccessToken: "token",
dbAccessTokenStatus: "idle" as DbAuthTokenStatus,
};

export const renderWithContext = (
userContext: UserContextState,
ceramicContext: CeramicContextState,
ui: React.ReactElement<any, string | React.JSXElementConstructor<any>>
ui: React.ReactElement<any, string | React.JSXElementConstructor<any>>,
datastoreContextOverride: Partial<DatastoreConnectionContextState> = {}
) =>
render(
<ScorerContext.Provider value={scorerContext}>
<UserContext.Provider value={userContext}>
<DatastoreConnectionContext.Provider value={{ ...datastoreConnectionContext, ...datastoreContextOverride }}>
<ScorerContext.Provider value={scorerContext}>
<CeramicContext.Provider value={ceramicContext}>{ui}</CeramicContext.Provider>
</UserContext.Provider>
</ScorerContext.Provider>
</ScorerContext.Provider>
</DatastoreConnectionContext.Provider>
);

export const testOnChainContextState = (initialState?: Partial<OnChainContextState>): OnChainContextState => {
Expand Down
4 changes: 2 additions & 2 deletions app/__test-fixtures__/toastTestHelpers.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { screen, waitForElementToBeRemoved } from "@testing-library/react";
import { toast } from "@chakra-ui/react";
import { toastStore } from "@chakra-ui/toast/dist/toast.store";

export const closeAllToasts = async () => {
// close all toasts before each tests and wait for them to be removed
toast.closeAll();
toastStore.closeAll();
const toasts = screen.queryAllByRole("listitem");
await Promise.all(toasts.map((toasts) => waitForElementToBeRemoved(toasts)));
};
10 changes: 1 addition & 9 deletions app/__tests__/components/AttestationProvider.test.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { OnChainStatus } from "../../hooks/useOnChainStatus";
import { OnChainStatus } from "../../utils/onChainStatus";

import { makeTestCeramicContext, makeTestUserContext } from "../../__test-fixtures__/contextTestHelpers";

import { UserContextState } from "../../context/userContext";
import { CeramicContextState, AllProvidersState, ProviderState } from "../../context/ceramicContext";
import { OnChainProviderType } from "../../context/onChainContext";
import { EASAttestationProvider, VeraxAndEASAttestationProvider } from "../../utils/AttestationProvider";

jest.mock("../../utils/onboard.ts");

jest.mock("next/router", () => ({
useRouter: () => ({
query: { filter: "" },
Expand All @@ -32,9 +27,6 @@ const chains = [
},
];

const mockUserContext: UserContextState = makeTestUserContext();
const mockCeramicContext: CeramicContextState = makeTestCeramicContext();

describe("EASAttestationProvider", () => {
const easAttestationProvider = new EASAttestationProvider({
chainId: "12345",
Expand Down
24 changes: 7 additions & 17 deletions app/__tests__/components/CardList.test.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
import React from "react";
import { screen } from "@testing-library/react";

import { UserContextState } from "../../context/userContext";
import { CardList, CardListProps } from "../../components/CardList";
import {
makeTestCeramicContext,
makeTestUserContext,
renderWithContext,
scorerContext,
} from "../../__test-fixtures__/contextTestHelpers";
import { makeTestCeramicContext, renderWithContext, scorerContext } from "../../__test-fixtures__/contextTestHelpers";
import { CeramicContextState } from "../../context/ceramicContext";
import { ScorerContextState } from "../../context/scorerContext";

jest.mock("../../utils/onboard.ts");

jest.mock("@didtools/cacao", () => ({
Cacao: {
Expand All @@ -26,7 +17,6 @@ jest.mock("next/router", () => ({
}),
}));

const mockUserContext: UserContextState = makeTestUserContext();
const mockCeramicContext: CeramicContextState = makeTestCeramicContext();

let cardListProps: CardListProps = {};
Expand All @@ -37,32 +27,32 @@ describe("<CardList />", () => {
});

it("renders provider cards when loading state is not defined", () => {
renderWithContext(mockUserContext, mockCeramicContext, <CardList {...cardListProps} />);
renderWithContext(mockCeramicContext, <CardList {...cardListProps} />);
expect(screen.queryByTestId("loading-card")).not.toBeInTheDocument();
});

it("renders provider cards when not loading", () => {
cardListProps.isLoading = false;
renderWithContext(mockUserContext, mockCeramicContext, <CardList {...cardListProps} />);
renderWithContext(mockCeramicContext, <CardList {...cardListProps} />);

expect(screen.queryByTestId("loading-card")).not.toBeInTheDocument();
});

it("renders LoadingCards when loading the passport", () => {
cardListProps.isLoading = true;

renderWithContext(mockUserContext, mockCeramicContext, <CardList {...cardListProps} />);
renderWithContext(mockCeramicContext, <CardList {...cardListProps} />);

expect(screen.getAllByTestId("loading-card"));
});

it("renders cards by verification status and possible points", () => {
renderWithContext(mockUserContext, mockCeramicContext, <CardList {...cardListProps} />);
renderWithContext(mockCeramicContext, <CardList {...cardListProps} />);
const possiblePoints = screen.getAllByTestId("platform-name").map((el) => el.textContent);
expect(possiblePoints).toEqual(["Gitcoin", "GTC Staking", "Discord", "Google", "Twitter"]);
});
it("should indicate on card whether or not it has been verified", () => {
renderWithContext(mockUserContext, mockCeramicContext, <CardList {...cardListProps} />);
renderWithContext(mockCeramicContext, <CardList {...cardListProps} />);
const verifiedBtnCnt = screen
.getAllByTestId("connect-button")
.map((el) => el.textContent)
Expand All @@ -73,7 +63,7 @@ describe("<CardList />", () => {
);
});
it("should render available points", () => {
renderWithContext(mockUserContext, mockCeramicContext, <CardList {...cardListProps} />);
renderWithContext(mockCeramicContext, <CardList {...cardListProps} />);
const availablePnts = screen.getAllByTestId("available-points").map((el) => el.textContent);
expect(availablePnts).toEqual(["12.93", "7.44", "0.69", "1.25", "0.00"]);
});
Expand Down
19 changes: 8 additions & 11 deletions app/__tests__/components/ExpiredStampModal.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { screen, waitFor } from "@testing-library/react";
import { fireEvent, screen, waitFor } from "@testing-library/react";
import { ExpiredStampModal, getProviderIdsFromPlatformId } from "../../components/ExpiredStampModal";
import { makeTestCeramicContext, renderWithContext } from "../../__test-fixtures__/contextTestHelpers";
import { CeramicContextState } from "../../context/ceramicContext";
import { UserContextState } from "../../context/userContext";

jest.mock("../../utils/onboard.ts");

jest.mock("@didtools/cacao", () => ({
Cacao: {
Expand All @@ -17,19 +14,18 @@ const mockCeramicContext: CeramicContextState = makeTestCeramicContext();
describe("ExpiredStampModal", () => {
it("should render a list of platforms", () => {
renderWithContext(
{} as UserContextState,
{ ...mockCeramicContext, expiredProviders: ["Linkedin", "Ens", "Lens"] },
<ExpiredStampModal isOpen={true} onClose={() => {}} />
);

const exptedProviders = ["Linkedin", "ENS", "Lens"];
exptedProviders.forEach((platform: string) => {
const expectedProviders = ["Linkedin", "ENS", "Lens"];
expectedProviders.forEach((platform: string) => {
expect(screen.getByText(platform)).toBeInTheDocument();
});
});

it("should not render duplicate platforms", () => {
renderWithContext(
{} as UserContextState,
{
...mockCeramicContext,
expiredProviders: ["EthGTEOneTxnProvider"],
Expand All @@ -39,6 +35,7 @@ describe("ExpiredStampModal", () => {

expect(screen.getAllByText("ETH").length).toBe(1);
});

it("should get a list of all PROVIDER_ID for a given platform", () => {
expect(getProviderIdsFromPlatformId("Gitcoin")).toEqual([
"GitcoinContributorStatistics#numGrantsContributeToGte#1",
Expand All @@ -50,10 +47,10 @@ describe("ExpiredStampModal", () => {
"GitcoinContributorStatistics#totalContributionAmountGte#1000",
]);
});

it("should delete all stamps within each expired platform", async () => {
const handleDeleteStamps = jest.fn();
renderWithContext(
{} as UserContextState,
{ ...mockCeramicContext, expiredProviders: ["Ens", "Linkedin", "Facebook"], handleDeleteStamps },
<ExpiredStampModal isOpen={true} onClose={() => {}} />
);
Expand All @@ -62,8 +59,8 @@ describe("ExpiredStampModal", () => {

expect(deleteButton.getAttribute("disabled")).toBeNull();

deleteButton.click();
expect(deleteButton.getAttribute("disabled")).not.toBeNull();
fireEvent.click(deleteButton);
await waitFor(() => expect(deleteButton.getAttribute("disabled")).not.toBeNull());

expect(handleDeleteStamps).toHaveBeenCalledWith(["Facebook", "FacebookProfilePicture", "Linkedin", "Ens"]);
await waitFor(() => expect(deleteButton.getAttribute("disabled")).toBeNull());
Expand Down
16 changes: 2 additions & 14 deletions app/__tests__/components/ExpiredStampsPanel.test.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import React from "react";
import { screen } from "@testing-library/react";

import { UserContextState } from "../../context/userContext";
import { CardList, CardListProps } from "../../components/CardList";
import {
makeTestCeramicContext,
makeTestUserContext,
renderWithContext,
makeTestCeramicContextWithExpiredStamps,
} from "../../__test-fixtures__/contextTestHelpers";
import { CeramicContextState } from "../../context/ceramicContext";
import { ExpiredStampsPanel } from "../../components/ExpiredStampsPanel";

jest.mock("../../utils/onboard.ts");

jest.mock("@didtools/cacao", () => ({
Cacao: {
fromBlockBytes: jest.fn(),
Expand All @@ -26,26 +21,19 @@ jest.mock("next/router", () => ({
}),
}));

const mockUserContext: UserContextState = makeTestUserContext();
const mockCeramicContext: CeramicContextState = makeTestCeramicContext();

describe("<ExpiredStampsPanel />", () => {
it("renders the text informing use he does not have any expired stamps", () => {
console.log("mockCeramicContext", mockCeramicContext);
renderWithContext(mockUserContext, mockCeramicContext, <ExpiredStampsPanel className="col-span-full" />);
renderWithContext(mockCeramicContext, <ExpiredStampsPanel className="col-span-full" />);
expect(screen.queryByText("Expired Stamps")).toBeInTheDocument();
expect(screen.queryByText("Reverify stamps")).not.toBeInTheDocument();
expect(screen.queryByAltText("Platform Icon")).not.toBeInTheDocument();
expect(screen.queryByText("You don't have any expired stamps")).toBeInTheDocument();
});

it("renders the button to re-verify expired stamps, when there are expired stamps", () => {
console.log("mockCeramicContext", mockCeramicContext);
renderWithContext(
mockUserContext,
makeTestCeramicContextWithExpiredStamps(),
<ExpiredStampsPanel className="col-span-full" />
);
renderWithContext(makeTestCeramicContextWithExpiredStamps(), <ExpiredStampsPanel className="col-span-full" />);
expect(screen.queryByText("Expired Stamps")).toBeInTheDocument();
expect(screen.queryByText("Reverify stamps")).toBeInTheDocument();
expect(screen.queryByAltText("Platform Icon")).toBeInTheDocument();
Expand Down
Loading

0 comments on commit d7eaeee

Please sign in to comment.