Skip to content

Commit

Permalink
feat(iam, app): adds Bright Id Stamp
Browse files Browse the repository at this point in the history
- adds BrightId verification steps on iam server failure
- adds toast messages
- adds procedures to verify and sponsor a user with BrightId

Closes #1
  • Loading branch information
farque65 committed May 31, 2022
1 parent 1e54adc commit a4f8655
Show file tree
Hide file tree
Showing 32 changed files with 986 additions and 21 deletions.
5 changes: 5 additions & 0 deletions app/__test-fixtures__/databaseStorageFixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ export const facebookStampFixture: Stamp = {
credential,
};

export const brightidStampFixture: Stamp = {
provider: "Brightid",
credential,
};

export const passportFixture: Passport = {
issuanceDate: new Date("2022-01-01"),
expiryDate: new Date("2022-01-02"),
Expand Down
14 changes: 14 additions & 0 deletions app/__test-fixtures__/verifiableCredentialResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,17 @@ export const SUCCESFUL_POH_RESULT: VerifiableCredentialRecord = {
challenge: credential,
credential: credential,
};

export const SUCCESFUL_BRIGHTID_RESULT: VerifiableCredentialRecord = {
record: {
type: "Brightid",
address: "0xcF323CE817E25b4F784bC1e14c9A99A525fDC50f",
version: "0.0.0",
contextId: "somedata",
meets: "true",
},
signature:
"0xbdbac10fdb0921e73df7575e47cbda484be550c36570bc146bed90c5dcb7435e64178cb263864f48af1ad6eeee1ee94c9a0794a3812ae861f8898a973233abea1c",
challenge: credential,
credential: credential,
};
214 changes: 214 additions & 0 deletions app/__tests__/components/ProviderCards/BrightidCard.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
import React from "react";
import { render, screen, fireEvent, waitFor, waitForElementToBeRemoved } from "@testing-library/react";
import { BrightidCard } from "../../../components/ProviderCards";

import { UserContext, UserContextState } from "../../../context/userContext";
import { mockAddress, mockWallet } from "../../../__test-fixtures__/onboardHookValues";
import { STAMP_PROVIDERS } from "../../../config/providers";
import { brightidStampFixture } from "../../../__test-fixtures__/databaseStorageFixtures";
import { SUCCESFUL_BRIGHTID_RESULT } from "../../../__test-fixtures__/verifiableCredentialResults";
import { fetchVerifiableCredential } from "@dpopp/identity/dist/commonjs";

jest.mock("@dpopp/identity/dist/commonjs", () => ({
fetchVerifiableCredential: jest.fn(),
}));
jest.mock("../../../utils/onboard.ts");

const mockHandleConnection = jest.fn();
const mockCreatePassport = jest.fn();
const handleAddStamp = jest.fn();
const mockUserContext: UserContextState = {
userDid: "mockUserDid",
loggedIn: true,
passport: undefined,
isLoadingPassport: false,
allProvidersState: {
Brightid: {
providerSpec: STAMP_PROVIDERS.Brightid,
stamp: undefined,
},
},
handleAddStamp: handleAddStamp,
handleCreatePassport: mockCreatePassport,
handleConnection: mockHandleConnection,
address: mockAddress,
wallet: mockWallet,
signer: undefined,
walletLabel: mockWallet.label,
};

function setupFetchStub(valid: any) {
return function fetchStub(_url: any) {
return new Promise((resolve) => {
resolve({
json: () =>
Promise.resolve({
valid,
}),
});
});
};
}

describe("when user has not verfied with BrightId Provider", () => {
it("should display a verify button", () => {
render(
<UserContext.Provider value={mockUserContext}>
<BrightidCard />
</UserContext.Provider>
);

const initialVerifyButton = screen.queryByTestId("button-verify-brightid");

expect(initialVerifyButton).toBeInTheDocument();
});
});

describe("when user has verified with BrightId Provider", () => {
it("should display that a verified credential was returned", () => {
render(
<UserContext.Provider
value={{
...mockUserContext,
allProvidersState: {
Brightid: {
providerSpec: STAMP_PROVIDERS.Brightid,
stamp: brightidStampFixture,
},
},
}}
>
<BrightidCard />
</UserContext.Provider>
);

const brightidVerified = screen.queryByText(/Verified/);

expect(brightidVerified).toBeInTheDocument();
});
});

describe("when the verify button is clicked", () => {
let originalFetch: any;
beforeEach(() => {
originalFetch = global.fetch;
global.fetch = jest.fn().mockImplementation(setupFetchStub(true));
});

afterEach(() => {
global.fetch = originalFetch;
jest.clearAllMocks();
});

describe("and when a successful BrightId result is returned", () => {
beforeEach(() => {
(fetchVerifiableCredential as jest.Mock).mockResolvedValue(SUCCESFUL_BRIGHTID_RESULT);
});

it("the modal displays the verify button", async () => {
render(
<UserContext.Provider value={mockUserContext}>
<BrightidCard />
</UserContext.Provider>
);

const initialVerifyButton = screen.queryByTestId("button-verify-brightid");

fireEvent.click(initialVerifyButton!);

const verifyModal = await screen.findByRole("dialog");
const verifyModalButton = screen.getByTestId("modal-verify");

expect(verifyModal).toBeInTheDocument();

await waitFor(() => {
expect(verifyModalButton).toBeInTheDocument();
});
});

it("clicking verify adds the stamp", async () => {
render(
<UserContext.Provider value={mockUserContext}>
<BrightidCard />
</UserContext.Provider>
);

const initialVerifyButton = screen.queryByTestId("button-verify-brightid");

// Click verify button on brightid card
fireEvent.click(initialVerifyButton!);

// Wait to see the verify button on the modal
await waitFor(() => {
const verifyModalButton = screen.getByTestId("modal-verify");
expect(verifyModalButton).toBeInTheDocument();
});

const finalVerifyButton = screen.queryByRole("button", {
name: /Verify/,
});

// Click the verify button on modal
fireEvent.click(finalVerifyButton!);

expect(handleAddStamp).toBeCalled();
});

it("clicking cancel closes the modal and a stamp should not be added", async () => {
(fetchVerifiableCredential as jest.Mock).mockResolvedValue(SUCCESFUL_BRIGHTID_RESULT);
render(
<UserContext.Provider value={mockUserContext}>
<BrightidCard />
</UserContext.Provider>
);

const initialVerifyButton = screen.queryByTestId("button-verify-brightid");

fireEvent.click(initialVerifyButton!);

// Wait to see the cancel button on the modal
let modalCancelButton: HTMLElement | null = null;
await waitFor(() => {
modalCancelButton = screen.queryByRole("button", {
name: /Cancel/,
});
expect(modalCancelButton).toBeInTheDocument();
});

fireEvent.click(modalCancelButton!);

expect(handleAddStamp).not.toBeCalled();

await waitForElementToBeRemoved(modalCancelButton);
expect(modalCancelButton).not.toBeInTheDocument();
});
});

describe("and when a failed Bright Id result is returned", () => {
it("modal displays steps to get sponsored", async () => {
global.fetch = jest.fn().mockImplementation(setupFetchStub(false));
(fetchVerifiableCredential as jest.Mock).mockRejectedValue("ERROR");
render(
<UserContext.Provider value={mockUserContext}>
<BrightidCard />
</UserContext.Provider>
);

const initialVerifyButton = screen.queryByTestId("button-verify-brightid");

fireEvent.click(initialVerifyButton!);

const verifyModal = await screen.findByRole("dialog");
const triggerSponsorButton = screen.queryByTestId("button-sponsor-brightid");
const verifyModalText = screen.getByText(
"A verifiable credential was not generated for your address. Follow the steps below to qualify:"
);

expect(verifyModal).toBeInTheDocument();
await waitFor(() => {
expect(verifyModalText).toBeInTheDocument();
});
expect(triggerSponsorButton).toBeInTheDocument();
});
});
});
1 change: 1 addition & 0 deletions app/__tests__/components/ProviderCards/EnsCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const mockHandleConnection = jest.fn();
const mockCreatePassport = jest.fn();
const handleAddStamp = jest.fn();
const mockUserContext: UserContextState = {
userDid: undefined,
loggedIn: true,
passport: undefined,
isLoadingPassport: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const mockHandleConnection = jest.fn();
const mockCreatePassport = jest.fn();
const handleAddStamp = jest.fn();
const mockUserContext: UserContextState = {
userDid: undefined,
loggedIn: true,
passport: undefined,
isLoadingPassport: false,
Expand Down
1 change: 1 addition & 0 deletions app/__tests__/components/ProviderCards/GoogleCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const mockHandleConnection = jest.fn();
const mockCreatePassport = jest.fn();
const handleAddStamp = jest.fn();
const mockUserContext: UserContextState = {
userDid: undefined,
loggedIn: true,
passport: undefined,
isLoadingPassport: false,
Expand Down
1 change: 1 addition & 0 deletions app/__tests__/components/ProviderCards/PoapCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const mockHandleConnection = jest.fn();
const mockCreatePassport = jest.fn();
const handleAddStamp = jest.fn();
const mockUserContext: UserContextState = {
userDid: undefined,
loggedIn: true,
passport: undefined,
isLoadingPassport: false,
Expand Down
3 changes: 2 additions & 1 deletion app/__tests__/components/ProviderCards/PohCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const mockHandleConnection = jest.fn();
const mockCreatePassport = jest.fn();
const handleAddStamp = jest.fn();
const mockUserContext: UserContextState = {
userDid: undefined,
loggedIn: true,
passport: undefined,
isLoadingPassport: false,
Expand Down Expand Up @@ -114,7 +115,7 @@ describe("when the verify button is clicked", () => {

const initialVerifyButton = screen.queryByTestId("button-verify-poh");

// Click verify button on ens card
// Click verify button on poh card
fireEvent.click(initialVerifyButton!);

// Wait to see the verify button on the modal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const mockHandleConnection = jest.fn();
const mockCreatePassport = jest.fn();
const handleAddStamp = jest.fn();
const mockUserContext: UserContextState = {
userDid: undefined,
loggedIn: true,
passport: undefined,
isLoadingPassport: false,
Expand Down
5 changes: 5 additions & 0 deletions app/__tests__/pages/Dashboard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const mockHandleConnection = jest.fn();
const mockCreatePassport = jest.fn();
const handleAddStamp = jest.fn();
const mockUserContext: UserContextState = {
userDid: undefined,
loggedIn: true,
passport: undefined,
isLoadingPassport: false,
Expand Down Expand Up @@ -40,6 +41,10 @@ const mockUserContext: UserContextState = {
providerSpec: STAMP_PROVIDERS.Facebook,
stamp: undefined,
},
Brightid: {
providerSpec: STAMP_PROVIDERS.Brightid,
stamp: undefined,
},
},
handleAddStamp: handleAddStamp,
handleCreatePassport: mockCreatePassport,
Expand Down
5 changes: 5 additions & 0 deletions app/__tests__/pages/Home.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const mockHandleConnection = jest.fn();
const mockCreatePassport = jest.fn();
const handleAddStamp = jest.fn();
const mockUserContext: UserContextState = {
userDid: undefined,
loggedIn: false,
passport: undefined,
isLoadingPassport: false,
Expand Down Expand Up @@ -40,6 +41,10 @@ const mockUserContext: UserContextState = {
providerSpec: STAMP_PROVIDERS.Facebook,
stamp: undefined,
},
Brightid: {
providerSpec: STAMP_PROVIDERS.Brightid,
stamp: undefined,
},
},
handleAddStamp: handleAddStamp,
handleCreatePassport: mockCreatePassport,
Expand Down
5 changes: 5 additions & 0 deletions app/__tests__/pages/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const mockHandleConnection = jest.fn();
const mockCreatePassport = jest.fn();
const handleAddStamp = jest.fn();
const mockUserContext: UserContextState = {
userDid: undefined,
loggedIn: false,
passport: undefined,
isLoadingPassport: false,
Expand Down Expand Up @@ -37,6 +38,10 @@ const mockUserContext: UserContextState = {
providerSpec: STAMP_PROVIDERS.Facebook,
stamp: undefined,
},
Brightid: {
providerSpec: STAMP_PROVIDERS.Brightid,
stamp: undefined,
},
},
handleAddStamp: handleAddStamp,
handleCreatePassport: mockCreatePassport,
Expand Down
9 changes: 5 additions & 4 deletions app/components/CardList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
import React from "react";

// --- Identity Providers
import { GoogleCard, EnsCard, PohCard, TwitterCard, PoapCard, FacebookCard } from "./ProviderCards";
import { GoogleCard, EnsCard, PohCard, TwitterCard, PoapCard, FacebookCard, BrightidCard } from "./ProviderCards";

export const CardList = (): JSX.Element => {
return (
<div className="container mx-auto py-10">
<div className="-m-4 flex flex-wrap">
<FacebookCard />
<GoogleCard />
<EnsCard />
<TwitterCard />
<PohCard />
<BrightidCard />
<PoapCard />
<FacebookCard />
<EnsCard />
<PohCard />
</div>
</div>
);
Expand Down
Loading

0 comments on commit a4f8655

Please sign in to comment.