Skip to content

Commit

Permalink
feat(app,iam,platforms): WIP - first working version for the new refe… (
Browse files Browse the repository at this point in the history
passportxyz#1721)

* feat(app,iam,platforms): WIP - first working version for the new referify flow

* feat(app): cleanup & bug fixes

- remove console logs
- removing unused code
- bug fixing cleanPassport in CeramicContext

* fix(app): fix failing test due to EIP712 VC configuration

* fix(app): fix failing test case

* feat(app): adding tests for the stamp claiming context

* feat(app): testing ExpiredStampsPanel

- also his the "Reverify" button in the panel when there are no expired stamps

* feat(app,identity): remove try-catch in _issueEd25519Credential, fixing linter complaints

* fix(app): fix typescript errors

* fix(app): fixing build errors

* feat(app): remove unused variables

* fix(app): remove TODOs

* fix(app): adding back code that was commented out for debugging
  • Loading branch information
nutrina authored Oct 2, 2023
1 parent 27ae9da commit 608e885
Show file tree
Hide file tree
Showing 24 changed files with 758 additions and 113 deletions.
34 changes: 33 additions & 1 deletion app/__test-fixtures__/contextTestHelpers.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { UserContext, UserContextState } from "../context/userContext";
import { ScorerContext, ScorerContextState } from "../context/scorerContext";
import { CeramicContext, CeramicContextState, IsLoadingPassportState } from "../context/ceramicContext";
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: {
Expand Down Expand Up @@ -137,6 +138,7 @@ export const makeTestCeramicContext = (initialState?: Partial<CeramicContextStat
handleCreatePassport: jest.fn(),
handleDeleteStamps: jest.fn(),
expiredProviders: [],
expiredPlatforms: {},
passportHasCacaoError: false,
cancelCeramicConnection: jest.fn(),
verifiedProviderIds: [],
Expand All @@ -145,6 +147,36 @@ export const makeTestCeramicContext = (initialState?: Partial<CeramicContextStat
};
};

export const makeTestCeramicContextWithExpiredStamps = (
initialState?: Partial<CeramicContextState>
): CeramicContextState => {
let expiredPlatforms: Partial<Record<PLATFORM_ID, PlatformProps>> = {};

const ethPlatform = platforms.get("ETH");

if (ethPlatform) {
expiredPlatforms["ETH"] = {
platform: ethPlatform.platform,
platFormGroupSpec: ethPlatform.platFormGroupSpec,
};
}

return {
...makeTestCeramicContext(initialState),
expiredPlatforms,
expiredProviders: ["ethPossessionsGte#1"],
};
};

export const makeTestClaimingContext = (
initialState?: Partial<StampClaimingContextState>
): StampClaimingContextState => {
return {
claimCredentials: jest.fn(),
...initialState,
};
};

export const scorerContext = {
scoredPlatforms: [
{
Expand Down
54 changes: 54 additions & 0 deletions app/__tests__/components/ExpiredStampsPanel.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
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(),
},
}));

jest.mock("next/router", () => ({
useRouter: () => ({
query: { filter: "" },
}),
}));

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" />);
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" />
);
expect(screen.queryByText("Expired Stamps")).toBeInTheDocument();
expect(screen.queryByText("Reverify stamps")).toBeInTheDocument();
expect(screen.queryByAltText("Platform Icon")).toBeInTheDocument();
expect(screen.queryByText("You don't have any expired stamps")).not.toBeInTheDocument();
});
});
2 changes: 2 additions & 0 deletions app/__tests__/components/RefreshMyStampsModalContent.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ValidatedPlatform } from "../../signer/utils";
import { fetchVerifiableCredential } from "@gitcoin/passport-identity/dist/commonjs/src/credentials";
import { reduceStampResponse } from "../../utils/helpers";
import { CredentialResponseBody } from "@gitcoin/passport-types";
import { IAM_SIGNATURE_TYPE } from "../../config/stamp_config";

jest.mock("react-router-dom", () => ({
useNavigate: jest.fn(),
Expand Down Expand Up @@ -110,6 +111,7 @@ describe("RefreshMyStampsModalContent", () => {
version: "0.0.0",
address: "0xmyAddress",
proofs: {},
signatureType: IAM_SIGNATURE_TYPE,
},
undefined
)
Expand Down
193 changes: 193 additions & 0 deletions app/__tests__/context/stampClaimingContext.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import { render, waitFor, screen, fireEvent } from "@testing-library/react";
import { useContext } from "react";
import {
makeTestCeramicContext,
makeTestClaimingContext,
makeTestUserContext,
} from "../../__test-fixtures__/contextTestHelpers";

import { UserContext } from "../../context/userContext";
import { CeramicContext, platforms } from "../../context/ceramicContext";
import { StampClaimingContext, StampClaimingContextProvider } from "../../context/stampClaimingContext";
import { fetchVerifiableCredential } from "@gitcoin/passport-identity/dist/commonjs/src/credentials";

import { PLATFORM_ID } from "@gitcoin/passport-types";
import { PlatformProps } from "../../components/GenericPlatform";
import { AppContext, PlatformClass, ProviderPayload } from "@gitcoin/passport-platforms";

jest.mock("../../utils/helpers", () => ({
generateUID: jest.fn((length: number) => "some random string"),
}));

jest.mock("@gitcoin/passport-identity/dist/commonjs/src/credentials", () => ({
fetchVerifiableCredential: jest.fn(),
}));

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

jest.mock("../../context/ceramicContext", () => {
const originalModule = jest.requireActual("../../context/ceramicContext");
let newPlatforms = new Map<PLATFORM_ID, PlatformProps>();

originalModule.platforms.forEach((value: PlatformProps, key: PLATFORM_ID) => {
let platform: PlatformClass = {
...value.platform,
getProviderPayload: jest.fn(async (appContext: AppContext) => {
return {};
}),
getOAuthUrl: jest.fn(async (state, providers) => {
return "";
}),
};
let newValue: PlatformProps = { ...value };

platform.getProviderPayload = jest.fn(async (appContext: AppContext) => {
return {};
});

newValue.platform = platform;
newPlatforms.set(key, newValue);
});

return {
__esModule: true,
...originalModule,
platforms: newPlatforms,
};
});

const TestingComponent = () => {
const { claimCredentials } = useContext(StampClaimingContext);

return (
<div>
<button
data-testid="claim-button"
onClick={() => {
claimCredentials([
{
platformId: "Google",
selectedProviders: ["Google"],
},
{
platformId: "Gitcoin",
selectedProviders: ["GitcoinContributorStatistics#numGrantsContributeToGte#1"],
},
]);
}}
>
Claim
</button>
</div>
);
};

const TestingComponentWithEvmStamp = () => {
const { claimCredentials } = useContext(StampClaimingContext);

return (
<div>
<button
data-testid="claim-button"
onClick={() => {
claimCredentials([
{
platformId: "Google",
selectedProviders: ["Google"],
},
{
platformId: "Gitcoin",
selectedProviders: ["GitcoinContributorStatistics#numGrantsContributeToGte#1"],
},
{
platformId: "EVMBulkVerify",
selectedProviders: ["ethPossessionsGte#32"],
},
]);
}}
>
Claim
</button>
</div>
);
};

const mockCeramicContext = makeTestCeramicContext({
passport: {
issuanceDate: new Date(),
expiryDate: new Date(),
stamps: [],
},
});

const mockStampClaimingContext = makeTestClaimingContext({});

const mockTestUserContext = makeTestUserContext({});

describe("<StampClaimingContext>", () => {
const renderTestComponent = () =>
render(
<UserContext.Provider value={mockTestUserContext}>
<CeramicContext.Provider value={mockCeramicContext}>
<StampClaimingContextProvider>
<TestingComponent />
</StampClaimingContextProvider>
</CeramicContext.Provider>
</UserContext.Provider>
);

const renderTestComponentWithEvmStamp = () =>
render(
<UserContext.Provider value={mockTestUserContext}>
<CeramicContext.Provider value={mockCeramicContext}>
<StampClaimingContextProvider>
<TestingComponentWithEvmStamp />
</StampClaimingContextProvider>
</CeramicContext.Provider>
</UserContext.Provider>
);

beforeEach(() => {
(fetchVerifiableCredential as jest.Mock).mockImplementation(() => {
return { credentials: [] };
});
});

afterEach(() => {
jest.clearAllMocks();
});

it("should fetch all credentials specified when calling claimCredentials (non-EVM only)", async () => {
renderTestComponent();

// Click the claim button, which should call the `claimCredentials` function in the context
await waitFor(async () => {
const claimButton = screen.getByTestId("claim-button");
await fireEvent.click(claimButton);
});

// Verify that the `fetchVerifiableCredential` function has been called
// Expect 1 call for each platform in the array
expect(fetchVerifiableCredential).toHaveBeenCalledTimes(2);

// Verify that the `handlePatchStamps` function has been called for the ceramic context
expect(mockCeramicContext.handlePatchStamps).toHaveBeenCalledTimes(2);
});

it("should fetch all credentials specified when calling claimCredentials (evm credentials included)", async () => {
renderTestComponentWithEvmStamp();

// Click the claim button, which should call the `claimCredentials` function in the context
await waitFor(async () => {
const claimButton = screen.getByTestId("claim-button");
await fireEvent.click(claimButton);
});

// Verify that the `fetchVerifiableCredential` function has been called
// Expect 1 call for each platform in the array
expect(fetchVerifiableCredential).toHaveBeenCalledTimes(3);

// Verify that the `handlePatchStamps` function has been called for the ceramic context
expect(mockCeramicContext.handlePatchStamps).toHaveBeenCalledTimes(3);
});
});
1 change: 1 addition & 0 deletions app/__tests__/pages/Dashboard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ describe.only("dashboard notifications", () => {
</Router>
);

// We are waiting for a notification "One moment while we load your Stamps..."
const databaseLoadingAlert = screen.getByTestId("db-stamps-alert");
expect(databaseLoadingAlert).toBeInTheDocument();
});
Expand Down
3 changes: 1 addition & 2 deletions app/components/AdditionalStampModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { UserContext } from "../context/userContext";
// utils
import { fetchPossibleEVMStamps, ValidatedPlatform, AdditionalSignature } from "../signer/utils";
import { getPlatformSpec } from "../config/platforms";
import { IAM_SIGNATURE_TYPE } from "../config/stamp_config";
import { IAM_SIGNATURE_TYPE, iamUrl } from "../config/stamp_config";

// Components
import { Spinner } from "@chakra-ui/react";
Expand All @@ -23,7 +23,6 @@ import { fetchVerifiableCredential } from "@gitcoin/passport-identity/dist/commo

// --- Datadog
import { datadogLogs } from "@datadog/browser-logs";
const iamUrl = process.env.NEXT_PUBLIC_PASSPORT_IAM_URL || "";

export const AdditionalStampModal = ({
additionalSigner,
Expand Down
2 changes: 1 addition & 1 deletion app/components/DashboardValidStampsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const DashboardValidStampsPanel = ({ className }: { className: string })
className={`flex flex-col items-center rounded border border-foreground-3 bg-gradient-to-b from-background to-background-2 text-xl text-foreground-2 ${className}`}
>
<div className="my-2">Valid Stamps</div>
<div className="h-[2px] w-full bg-gradient-to-r from-background-4 via-foreground-2 to-background" />
<div className="h-[2px] w-full bg-gradient-to-r from-background via-foreground-2 to-background" />
<StampsList className="m-6" onChainPlatformIds={onChainPlatformIds} />
<InitiateOnChainButton className="mb-2" />
<span className={`mb-2 text-sm ${anyOnchain ? "visible" : "invisible"}`}>
Expand Down
Loading

0 comments on commit 608e885

Please sign in to comment.