Skip to content

Commit

Permalink
feat(app): create cards for stamp providers
Browse files Browse the repository at this point in the history
- add chakra ui
- update LocalStorageDatabase to automatically create a passport
  when adding a stamp without an existing passport
- rename components/providers -> components/providerCards
- rename Google -> GoogleCard
- rename test-fixtures -> __test-fixtures__
- move __tests__ and __test-fixtures__ to app/
- add csstype resolution to package.json to fix chakra dependency
  issue
- gitignore log and editor files in root

[passportxyz#16]
  • Loading branch information
farque65 authored and shavinac committed Apr 18, 2022
1 parent b06bacc commit 72d0697
Show file tree
Hide file tree
Showing 28 changed files with 1,623 additions and 375 deletions.
22 changes: 21 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,22 @@
node_modules
.env
.env

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
41 changes: 41 additions & 0 deletions app/__test-fixtures__/databaseStorageFixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { VerifiableCredential, Stamp, Passport } from "@dpopp/types";

const credential: VerifiableCredential = {
"@context": ["https://www.w3.org/2018/credentials/v1"],
type: ["VerifiableCredential"],
credentialSubject: {
id: "did:ethr:Simple",
"@context": [
{
root: "https://schema.org/Text",
},
],
root: "randomValuesRoot",
},
issuer: "did:key:randomValuesIssuer",
issuanceDate: "2022-04-15T21:04:01.708Z",
proof: {
type: "Ed25519Signature2018",
proofPurpose: "assertionMethod",
verificationMethod: "did:key:randomValues",
created: "2022-04-15T21:04:01.708Z",
jws: "randomValues",
},
expirationDate: "2022-05-15T21:04:01.708Z",
};

export const simpleStampFixture: Stamp = {
provider: "Simple",
credential,
};

export const googleStampFixture: Stamp = {
provider: "Google",
credential,
};

export const passportFixture: Passport = {
issuanceDate: new Date("2022-01-01"),
expiryDate: new Date("2022-01-02"),
stamps: [googleStampFixture],
};
File renamed without changes.
42 changes: 42 additions & 0 deletions app/__tests__/components/Card.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from "react";
import { render, screen } from "@testing-library/react";

import { Card, CardProps } from "../../src/components/Card";

import { VerifiableCredential } from "@dpopp/types";
import { mock } from "jest-mock-extended";

let cardProps: CardProps;

describe("when the user is not verified", () => {
beforeEach(() => {
cardProps = {
providerSpec: { name: "Some", description: "Some desc" },
verifiableCredential: undefined,
issueCredentialWidget: <div data-testid="some-widget" />,
};
});

it("should show verification button", () => {
render(<Card {...cardProps} />);

expect(screen.getByTestId("some-widget")).toBeInTheDocument();
});
});

describe("when the user is verified", () => {
beforeEach(() => {
cardProps = {
providerSpec: { name: "Some", description: "Some desc" },
verifiableCredential: mock<VerifiableCredential>(),
issueCredentialWidget: <div data-testid="some-widget" />,
};
});

it("should show verified status", () => {
render(<Card {...cardProps} />);

expect(screen.getByText(/[Vv]erified/)).toBeInTheDocument();
expect(screen.queryByText("Verify Button")).not.toBeInTheDocument();
});
});
85 changes: 85 additions & 0 deletions app/__tests__/components/providerCards/Google.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import { GoogleCard } from "../../../src/components/providerCards";

import { UserContext, UserContextState } from "../../../src/App";
import { mockAddress, mockWallet } from "../../../__test-fixtures__/onboardHookValues";
import { STAMP_PROVIDERS } from "../../../src/config/providers";
import { googleStampFixture } from "../../../__test-fixtures__/databaseStorageFixtures";

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

const mockHandleConnection = jest.fn();
const mockCreatePassport = jest.fn();
const mockHasStamp = jest.fn(() => false);
const getStampIndex = jest.fn();
const handleSaveStamp = jest.fn();
const handleAddStamp = jest.fn();
const mockUserContext: UserContextState = {
loggedIn: true,
passport: undefined,
allProvidersState: {
Google: {
providerSpec: STAMP_PROVIDERS.Google,
stamp: undefined,
},
Simple: {
providerSpec: STAMP_PROVIDERS.Simple,
stamp: undefined,
},
},
hasStamp: mockHasStamp,
getStampIndex: getStampIndex,
handleSaveStamp: handleSaveStamp,
handleAddStamp: handleAddStamp,
handleCreatePassport: mockCreatePassport,
handleConnection: mockHandleConnection,
address: mockAddress,
connectedWallets: [mockWallet],
signer: undefined,
walletLabel: mockWallet.label,
};

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

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

expect(verifyGoogleButton).toBeInTheDocument();
});
});

describe("when user has verified with GoogleProvider", () => {
it("should display that google is verified", () => {
render(
<UserContext.Provider
value={{
...mockUserContext,
allProvidersState: {
Google: {
providerSpec: STAMP_PROVIDERS.Google,
stamp: googleStampFixture,
},
Simple: {
providerSpec: STAMP_PROVIDERS.Simple,
stamp: undefined,
},
},
}}
>
<GoogleCard />
</UserContext.Provider>
);

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

expect(googleVerified).toBeInTheDocument();
});
});
85 changes: 85 additions & 0 deletions app/__tests__/components/providerCards/Simple.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import { SimpleCard } from "../../../src/components/providerCards";

import { UserContext, UserContextState } from "../../../src/App";
import { mockAddress, mockWallet } from "../../../__test-fixtures__/onboardHookValues";
import { STAMP_PROVIDERS } from "../../../src/config/providers";
import { simpleStampFixture } from "../../../__test-fixtures__/databaseStorageFixtures";

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

const mockHandleConnection = jest.fn();
const mockCreatePassport = jest.fn();
const mockHasStamp = jest.fn(() => false);
const getStampIndex = jest.fn();
const handleSaveStamp = jest.fn();
const handleAddStamp = jest.fn();
const mockUserContext: UserContextState = {
loggedIn: true,
passport: undefined,
allProvidersState: {
Google: {
providerSpec: STAMP_PROVIDERS.Google,
stamp: undefined,
},
Simple: {
providerSpec: STAMP_PROVIDERS.Simple,
stamp: undefined,
},
},
hasStamp: mockHasStamp,
getStampIndex: getStampIndex,
handleSaveStamp: handleSaveStamp,
handleAddStamp: handleAddStamp,
handleCreatePassport: mockCreatePassport,
handleConnection: mockHandleConnection,
address: mockAddress,
connectedWallets: [mockWallet],
signer: undefined,
walletLabel: mockWallet.label,
};

describe("when user has not verified with SimpleProvider", () => {
it("should display a verification button", () => {
render(
<UserContext.Provider value={mockUserContext}>
<SimpleCard />
</UserContext.Provider>
);

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

expect(verifyButton).toBeInTheDocument();
});
});

describe("when user has verified with SimpleProvider", () => {
it("should display that user is verified", () => {
render(
<UserContext.Provider
value={{
...mockUserContext,
allProvidersState: {
Google: {
providerSpec: STAMP_PROVIDERS.Google,
stamp: undefined,
},
Simple: {
providerSpec: STAMP_PROVIDERS.Simple,
stamp: simpleStampFixture,
},
},
}}
>
<SimpleCard />
</UserContext.Provider>
);

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

expect(verified).toBeInTheDocument();
});
});
81 changes: 81 additions & 0 deletions app/__tests__/services/databaseStorage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/unbound-method */
import { Passport } from "@dpopp/types";
import { LocalStorageDatabase } from "../../src/services/databaseStorage";
import "jest-localstorage-mock";
import { passportFixture, simpleStampFixture } from "../../__test-fixtures__/databaseStorageFixtures";

const localStorageDatabase = new LocalStorageDatabase("testaddress");

beforeEach(() => {
localStorage.clear();
// and reset all mocks
jest.clearAllMocks();
});

afterAll(() => {
localStorage.clear();
// and reset all mocks
jest.clearAllMocks();
});

describe("when there is no passport for the given did", () => {
it("createPassport creates a passport in localstorage", () => {
const actualDID = localStorageDatabase.createPassport();

expect(localStorage.setItem).toBeCalled();
expect(actualDID).toEqual(localStorageDatabase.passportKey);
});

it("getPassport returns undefined", () => {
const actualPassport = localStorageDatabase.getPassport(localStorageDatabase.passportKey);

expect(localStorage.getItem).toBeCalled();
expect(actualPassport).toEqual(undefined);
});

it("addStamp creates a passport with a stamp", () => {
const did = localStorageDatabase.passportKey;

localStorageDatabase.addStamp(did, simpleStampFixture);

// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const finalPassport = JSON.parse(localStorage.__STORE__[did] as string) as Passport;
expect(finalPassport.stamps).toHaveLength(1);
expect(finalPassport.stamps).toContainEqual(simpleStampFixture);
expect(localStorage.setItem).toHaveBeenCalled();
});
});

describe("when there is an existing passport for the given did", () => {
beforeEach(() => {
localStorage.__STORE__[localStorageDatabase.passportKey] = JSON.stringify(passportFixture);
});

// what happens if you try to create a passport for the same key?

it("getPassport retrieves the passport from localstorage", () => {
const actualPassport = localStorageDatabase.getPassport(localStorageDatabase.passportKey);

expect(localStorage.getItem).toBeCalledTimes(1);
expect(actualPassport).toEqual(passportFixture);
});

it("addStamp adds a stamp to the passport", () => {
const did = localStorageDatabase.passportKey;

localStorageDatabase.addStamp(did, simpleStampFixture);

// verify passport has new stamp
const expectedPassport: Passport = {
...passportFixture,
stamps: [...passportFixture.stamps, simpleStampFixture],
};

// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const finalPassport = JSON.parse(localStorage.__STORE__[did] as string) as Passport;
expect(finalPassport.stamps).toHaveLength(passportFixture.stamps.length + 1);
expect(finalPassport.stamps).toContainEqual(simpleStampFixture);
expect(localStorage.setItem).toHaveBeenLastCalledWith(did, JSON.stringify(expectedPassport));
});
});
Loading

0 comments on commit 72d0697

Please sign in to comment.