Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: need to click next twice and verification error #2670

Merged
merged 6 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions app/__tests__/components/GenericPlatform.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,52 @@ describe("when user has previously verified with EnsProvider", () => {
expect(fetchVerifiableCredential).toHaveBeenCalled();
});
});
it("should remove expired stamps if the no longer qualify", async () => {
(fetchVerifiableCredential as jest.Mock).mockResolvedValue({
credentials: [UN_SUCCESSFUL_ENS_RESULT],
});
const drawer = () => (
<ChakraProvider>
<GenericPlatform
isOpen={true}
platform={new Ens.EnsPlatform()}
platFormGroupSpec={[
{
...Ens.ProviderConfig[0],
providers: [...Ens.ProviderConfig[0].providers],
},
]}
platformScoreSpec={EnsScoreSpec}
onClose={() => {}}
/>
</ChakraProvider>
);

const handlePatchStampsMock = jest.fn();
renderWithContext(
{
...mockCeramicContext,
verifiedProviderIds: ["Ens"],
expiredProviders: ["Ens"],
handlePatchStamps: handlePatchStampsMock,
},
drawer()
);
const initialVerifyButton = screen.queryByTestId("button-verify-Ens");
fireEvent.click(initialVerifyButton as HTMLElement);

// Wait to see the done toast
await waitFor(() => {
// extraProvider should be empty but ens should be there to delete expired stamp you no longer qualify for
expect(handlePatchStampsMock).toHaveBeenCalledWith([
{
provider: "Ens",
},
]);

expect(fetchVerifiableCredential).toHaveBeenCalled();
});
});
});

describe("Mulitple EVM plaftorms", () => {
Expand Down
32 changes: 29 additions & 3 deletions app/__tests__/context/stampClaimingContext.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CeramicContext } from "../../context/ceramicContext";
import { StampClaimingContext, StampClaimingContextProvider } from "../../context/stampClaimingContext";
import { fetchVerifiableCredential } from "@gitcoin/passport-identity";

import { PLATFORM_ID } from "@gitcoin/passport-types";
import { PLATFORM_ID, ValidResponseBody } from "@gitcoin/passport-types";
import { PlatformProps } from "../../components/GenericPlatform";
import { AppContext, PlatformClass } from "@gitcoin/passport-platforms";
import { DatastoreConnectionContext, DbAuthTokenStatus } from "../../context/datastoreConnectionContext";
Expand Down Expand Up @@ -51,6 +51,7 @@ jest.mock("../../context/ceramicContext", () => {
});

const handleClaimStep = jest.fn();
const indicateError = jest.fn();

const TestingComponent = () => {
const { claimCredentials } = useContext(StampClaimingContext);
Expand All @@ -60,7 +61,7 @@ const TestingComponent = () => {
<button
data-testid="claim-button"
onClick={() => {
claimCredentials(handleClaimStep, [
claimCredentials(handleClaimStep, indicateError, [
{
platformId: "Google",
selectedProviders: ["Google"],
Expand All @@ -86,7 +87,7 @@ const TestingComponentWithEvmStamp = () => {
<button
data-testid="claim-button"
onClick={() => {
claimCredentials(handleClaimStep, [
claimCredentials(handleClaimStep, indicateError, [
{
platformId: "Google",
selectedProviders: ["Google"],
Expand Down Expand Up @@ -180,6 +181,31 @@ describe("<StampClaimingContext>", () => {

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

it("should not indicate error if verification was successful", async () => {
(fetchVerifiableCredential as jest.Mock).mockImplementation(() => {
return {
credentials: [
{
record: {
type: "Google",
},
} as ValidResponseBody,
],
};
});

renderTestComponent();

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

expect(indicateError).not.toHaveBeenCalled();
});

it("should fetch all credentials specified when calling claimCredentials (evm credentials included)", async () => {
Expand Down
18 changes: 13 additions & 5 deletions app/components/GenericPlatform.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,16 @@ export const GenericPlatform = ({
// If the stamp was not selected, return {provider} to delete the stamp
// If the stamp was selected but cannot be claimed, return null to do nothing and
// therefore keep any existing valid stamp if it exists
const stampPatches: StampPatch[] = platformProviderIds
const stampPatches = platformProviderIds
.map((provider: PROVIDER_ID) => {
const cred = verifiedCredentials.find((cred: any) => cred.record?.type === provider);
if (cred) return { provider, credential: cred.credential };
else if (!selectedProviders.includes(provider)) return { provider };
else return null;
if (cred) {
return { provider, credential: cred.credential };
} else if (expiredProviders.includes(provider)) {
return { provider };
} else {
return null;
}
})
.filter((patch): patch is StampPatch => Boolean(patch));

Expand All @@ -242,7 +246,11 @@ export const GenericPlatform = ({
// can no longer claim the credential, but they still have a valid credential that
// was previously verified, AND they had selected it, we want to keep it
verifiedProviders.forEach((provider) => {
if (!actualVerifiedProviders.includes(provider) && selectedProviders.includes(provider)) {
if (
!actualVerifiedProviders.includes(provider) &&
selectedProviders.includes(provider) &&
!expiredProviders.includes(provider)
) {
actualVerifiedProviders.push(provider);
}
});
Expand Down
21 changes: 19 additions & 2 deletions app/components/InitiateReverifyStampsButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,27 @@ export const ReverifyStampsModal = ({ isOpen, onClose }: ExpiredStampModalProps)
});
};

const errorToast = (platform: string) => {
toast({
duration: 9000,
isClosable: true,
render: (result: any) => (
<DoneToastContent
title="Error"
message={`Failed to reverify stamps for ${platform}. Please double check eligibility and try again.`}
icon="../assets/verification-failed-bright.svg"
result={result}
/>
),
});
};

const expiredPlatforms = Object.keys(STAMP_PROVIDERS).filter((provider) => {
const possibleProviders = getProviderIdsFromPlatformId(provider as PLATFORM_ID);
return possibleProviders.filter((provider) => expiredProviders.includes(provider)).length > 0;
});

const handleClaimStep = async (step: number, platformId?: PLATFORM_ID | "EVMBulkVerify"): Promise<void> => {
const handleClaimStep = async (step: number): Promise<void> => {
if (status === "in_progress") {
setCurrentStepInProgress(true);
} else {
Expand All @@ -75,6 +90,8 @@ export const ReverifyStampsModal = ({ isOpen, onClose }: ExpiredStampModalProps)
}
};

const indicateError = (platform: PLATFORM_ID | "EVMBulkVerify") => errorToast(platform);

const reverifyStamps = async () => {
setIsReverifyingStamps(true);

Expand All @@ -100,7 +117,7 @@ export const ReverifyStampsModal = ({ isOpen, onClose }: ExpiredStampModalProps)
}
});

await claimCredentials(handleClaimStep, [evmStampClaim, ...stampClaims]);
await claimCredentials(handleClaimStep, indicateError, [evmStampClaim, ...stampClaims]);

digitalmnt marked this conversation as resolved.
Show resolved Hide resolved
setIsReverifyingStamps(false);
onClose();
Expand Down
6 changes: 5 additions & 1 deletion app/components/Notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ const ExpiryAction = ({

const message = useMemo(() => {
const refreshStamp = async (stamp: StampClaimForPlatform) => {
await claimCredentials(async () => await Promise.resolve(), [stamp]);
await claimCredentials(
async () => await Promise.resolve(),
() => {},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we not need to provide an error handler here? Fine if not, just wanted to call this out in case it was an oversight!

[stamp]
);
deleteMutation.mutate();
};
const claim: StampClaimForPlatform = {
Expand Down
19 changes: 13 additions & 6 deletions app/context/stampClaimingContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export enum StampClaimProgressStatus {
InProgress = "in_progress",
}

export type VerificationStatuses = { success: string[]; errors: string[] };

export const waitForRedirect = (platform: Platform, timeout?: number): Promise<ProviderPayload> => {
const channel = new BroadcastChannel(`${platform.path}_oauth_channel`);
const waitForRedirect = new Promise<ProviderPayload>((resolve, reject) => {
Expand Down Expand Up @@ -69,15 +71,17 @@ export type StampClaimForPlatform = {

export interface StampClaimingContextState {
claimCredentials: (
handleClaimStep: (step: number, platformId?: PLATFORM_ID | "EVMBulkVerify") => Promise<void>,
handleClaimStep: (step: number) => Promise<void>,
indicateError: (platform: PLATFORM_ID | "EVMBulkVerify") => void,
platformGroups: StampClaimForPlatform[]
) => Promise<void>;
status: StampClaimProgressStatus;
}

const startingState: StampClaimingContextState = {
claimCredentials: async (
handleClaimStep: (step: number, platformId?: PLATFORM_ID | "EVMBulkVerify") => Promise<void>,
handleClaimStep: (step: number) => Promise<void>,
indicateError: (platform: PLATFORM_ID | "EVMBulkVerify") => void,
platformGroups: StampClaimForPlatform[]
) => {},
status: StampClaimProgressStatus.Idle,
Expand Down Expand Up @@ -138,7 +142,8 @@ export const StampClaimingContextProvider = ({ children }: { children: any }) =>

// fetch VCs from IAM server
const claimCredentials = async (
handleClaimStep: (step: number, platformId?: PLATFORM_ID | "EVMBulkVerify") => Promise<void>,
handleClaimStep: (step: number) => Promise<void>,
indicateError: (platform: PLATFORM_ID | "EVMBulkVerify") => void,
platformGroups: StampClaimForPlatform[]
): Promise<any> => {
if (!did) throw new Error("No DID found");
Expand All @@ -156,9 +161,8 @@ export const StampClaimingContextProvider = ({ children }: { children: any }) =>

if ((platform || platformId === "EVMBulkVerify") && selectedProviders.length > 0) {
step++;
await handleClaimStep(step, platformId);
await handleClaimStep(step);
datadogLogs.logger.info("Saving Stamp", { platform: platformId });
await handleClaimStep(step, platformId);
setStatus(StampClaimProgressStatus.InProgress);

// We set the providerPayload to be {} by default
Expand Down Expand Up @@ -208,6 +212,10 @@ export const StampClaimingContextProvider = ({ children }: { children: any }) =>
[]
: [];

if (verifiedCredentials.length === 0) {
indicateError(platformId);
}

const stampPatches: StampPatch[] = selectedProviders.map((provider: PROVIDER_ID) => {
const cred = verifiedCredentials.find((cred: any) => cred.record?.type === provider);
if (cred) return { provider, credential: cred.credential as VerifiableCredential };
Expand All @@ -223,7 +231,6 @@ export const StampClaimingContextProvider = ({ children }: { children: any }) =>
}
}
setStatus(StampClaimProgressStatus.Idle);
await handleClaimStep(-1);
};

const providerProps = {
Expand Down
Loading