Skip to content

Commit

Permalink
Merge pull request #6 from chalabi2/main
Browse files Browse the repository at this point in the history
feats: mfx minting | tx indexing
  • Loading branch information
fmorency authored Aug 28, 2024
2 parents ef71e3b + 7569043 commit 278c20d
Show file tree
Hide file tree
Showing 155 changed files with 7,739 additions and 2,539 deletions.
15 changes: 15 additions & 0 deletions .github/workflows/prettier.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Prettier

on: [push, pull_request]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Bun
uses: oven-sh/setup-bun@v1
- name: Install dependencies
run: bun install
- name: Check Prettier
run: bun prettier . --check
22 changes: 22 additions & 0 deletions .github/workflows/test-coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Test and Coverage

on: [push, pull_request]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install
- name: Run tests and generate coverage
run: bun run test:coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage/lcov.info
token: ${{ secrets.CODECOV_TOKEN }}
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ yarn-error.log*
*.tsbuildinfo
next-env.d.ts

.idea/
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Ignore artifacts:
build
coverage
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ This is a web app that allows users to interact with the Manifest Network and it

For more information on the Manifest Network and its modules, please visit the [Manifest Network GitHub](https://github.com/liftedinit/manifest-ledger).

[![codecov](https://codecov.io/gh/chalabi2/manifest-app/branch/main/graph/badge.svg)](https://codecov.io/gh/chalabi2/manifest-app)

## Getting Started

### Installation
Expand All @@ -16,6 +18,21 @@ For more information on the Manifest Network and its modules, please visit the [
2. Install dependencies
- `bun install`

### .env

```
NEXT_PUBLIC_ABLY_API_KEY=
NEXT_PUBLIC_WALLETCONNECT_KEY=
NEXT_PUBLIC_WEB3_CLIENT_ID=
NEXT_PUBLIC_CHAIN=manifest
NEXT_PUBLIC_CHAIN_ID=manifest-1
NEXT_PUBLIC_TESTNET_CHAIN_ID=manifest-ledger-beta
NEXT_PUBLIC_MAINNET_RPC_URL=https://nodes.chandrastation.com/rpc/manifest/
NEXT_PUBLIC_TESTNET_RPC_URL=https://manifest-beta-rpc.liftedinit.tech/
NEXT_PUBLIC_MAINNET_API_URL=https://nodes.chandrastation.com/api/manifest/
NEXT_PUBLIC_TESTNET_API_URL=https://manifest-beta-rest.liftedinit.tech/
```

### Development

1. Start the server
Expand Down
Binary file modified bun.lockb
Binary file not shown.
2 changes: 2 additions & 0 deletions bunfig.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[test]
preload = "./happydom.ts"
62 changes: 62 additions & 0 deletions components/admins/components/__tests__/adminOptions.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { afterEach, describe, expect, test } from "bun:test";
import React from "react";
import { screen, cleanup, within, fireEvent } from "@testing-library/react";
import AdminOptions from "@/components/admins/components/adminOptions";
import matchers from "@testing-library/jest-dom/matchers";
import { renderWithChainProvider } from "@/tests/render";
import { mockPoaParams, mockGroup } from "@/tests/mock";

expect.extend(matchers);

const renderWithProps = (props = {}) => {
const defaultProps = {
poaParams: mockPoaParams,
group: mockGroup,
isLoading: false,
address: "test_address",
admin: "admin1",
};
return renderWithChainProvider(<AdminOptions {...defaultProps} {...props} />);
};

describe("AdminOptions", () => {
afterEach(cleanup);

test("renders loading state correctly", () => {
renderWithProps({ isLoading: true });
expect(screen.getByText("Admin")).toBeInTheDocument();
});

test("renders admin details correctly when not loading", () => {
renderWithProps();
expect(screen.getByText("Admin")).toBeInTheDocument();
expect(screen.getByAltText("Profile Avatar")).toBeInTheDocument();
const titleContainer = screen.getByLabelText("title");
expect(within(titleContainer).getByText("title1")).toBeInTheDocument();
const detailsContainer = screen.getByLabelText("details");
expect(within(detailsContainer).getByText("details1")).toBeInTheDocument();
});

test("opens update modal on button click", () => {
renderWithProps();
const updateAdminButtonContainer = screen.getByLabelText("update admin");
fireEvent.click(
within(updateAdminButtonContainer).getByText("Update Admin"),
);
const modal = document.getElementById(
"update-admin-modal",
) as HTMLDialogElement;
expect(modal).toBeInTheDocument();
expect(modal.open).toBe(true);
});

test("opens description modal on button click", () => {
renderWithProps();
fireEvent.click(screen.getByLabelText("three-dots"));
const modal = document.getElementById(
"description-modal",
) as HTMLDialogElement;
expect(modal).toBeInTheDocument();
expect(modal.open).toBe(true);
});
});
82 changes: 82 additions & 0 deletions components/admins/components/__tests__/stakingParams.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { afterEach, describe, expect, test } from "bun:test";
import React from "react";
import { screen, cleanup, within, fireEvent } from "@testing-library/react";
import StakingParams from "@/components/admins/components/stakingParams";
import matchers from "@testing-library/jest-dom/matchers";
import { mockStakingParams } from "@/tests/mock";
import { renderWithChainProvider } from "@/tests/render";

expect.extend(matchers);

const renderWithProps = (props = {}) => {
const defaultProps = {
stakingParams: mockStakingParams,
isLoading: false,
address: "test_address",
admin: "admin1",
};
return renderWithChainProvider(
<StakingParams {...defaultProps} {...props} />,
);
};

describe("StakingParams", () => {
afterEach(cleanup);

test("renders correctly when not loading", () => {
renderWithProps();
const stakingParamsContainer = screen.getByLabelText("Staking Params");
expect(
within(stakingParamsContainer).getByText("UNBONDING TIME"),
).toBeInTheDocument();
expect(within(stakingParamsContainer).getByText("1")).toBeInTheDocument();
expect(
within(stakingParamsContainer).getByText("MAX VALIDATORS"),
).toBeInTheDocument();
expect(within(stakingParamsContainer).getByText("100")).toBeInTheDocument();
expect(
within(stakingParamsContainer).getByText("BOND DENOM"),
).toBeInTheDocument();
expect(
within(stakingParamsContainer).getByText("upoa"),
).toBeInTheDocument();
expect(
within(stakingParamsContainer).getByText("MINIMUM COMMISSION"),
).toBeInTheDocument();
expect(within(stakingParamsContainer).getByText("5 %")).toBeInTheDocument();
expect(
within(stakingParamsContainer).getByText("MAX ENTRIES"),
).toBeInTheDocument();
expect(within(stakingParamsContainer).getByText("7")).toBeInTheDocument();
expect(
within(stakingParamsContainer).getByText("HISTORICAL ENTRIES"),
).toBeInTheDocument();
expect(within(stakingParamsContainer).getByText("200")).toBeInTheDocument();
});

test("renders loading state correctly", () => {
renderWithProps({ isLoading: true });
const stakingParamsContainer = screen.getByLabelText(
"Skeleton Staking Params",
);
expect(
within(stakingParamsContainer).getByText("Staking Params"),
).toBeInTheDocument();
expect(
within(stakingParamsContainer).getByText("Update"),
).toBeInTheDocument();
});

test("opens update modal on button click", () => {
renderWithProps();
const stakingParamsContainer = screen.getByLabelText(
"Skeleton Staking Params",
);
fireEvent.click(within(stakingParamsContainer).getByText("Update"));
const modal = document.getElementById(
"update-params-modal",
) as HTMLDialogElement;
expect(modal).toBeInTheDocument();
expect(modal.open).toBe(true);
});
});
65 changes: 65 additions & 0 deletions components/admins/components/__tests__/validatorList.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { afterEach, describe, expect, test } from "bun:test";
import React from "react";
import ValidatorList from "@/components/admins/components/validatorList";
import { fireEvent, screen, cleanup, waitFor } from "@testing-library/react";
import matchers from "@testing-library/jest-dom/matchers";
import { mockActiveValidators, mockPendingValidators } from "@/tests/mock";
import { renderWithChainProvider } from "@/tests/render";

expect.extend(matchers);

const renderWithProps = (props = {}) => {
const defaultProps = {
admin: "admin1",
activeValidators: mockActiveValidators,
pendingValidators: mockPendingValidators,
isLoading: false,
};
return renderWithChainProvider(
<ValidatorList {...defaultProps} {...props} />,
);
};

describe("ValidatorList", () => {
afterEach(cleanup);

test("renders correctly", () => {
renderWithProps();
expect(screen.getByText("Active Validators")).toBeInTheDocument();
expect(screen.getByText("Validator One")).toBeInTheDocument();
expect(screen.getByText("Validator Two")).toBeInTheDocument();
});

test("search functionality works", () => {
renderWithProps();
fireEvent.change(screen.getByPlaceholderText("Search for a validator..."), {
target: { value: "Validator One" },
});
expect(screen.getByText("Validator One")).toBeInTheDocument();
expect(screen.queryByText("Validator Two")).not.toBeInTheDocument();
});

test("active/pending toggle works", () => {
renderWithProps();
fireEvent.click(screen.getByText("Pending"));
expect(screen.getByText("Pending Validators")).toBeInTheDocument();
expect(screen.getByText("Validator Three")).toBeInTheDocument();
});

test("clicking on a validator row opens the modal", async () => {
renderWithProps();
fireEvent.click(screen.getByText("Validator One"));
await waitFor(() => expect(screen.getByRole("dialog")).toBeInTheDocument());
});

test("remove button works and shows the warning modal", async () => {
renderWithProps();
const allRemoveButtons = screen.getAllByText("Remove");
fireEvent.click(allRemoveButtons[0]);
await waitFor(() =>
expect(
screen.getByText("Are you sure you want to remove the validator"),
).toBeInTheDocument(),
);
});
});
13 changes: 9 additions & 4 deletions components/admins/components/adminOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ export default function AdminOptions({

const handleOpen = () => {
const modal = document.getElementById(
`update-admin-modal`
`update-admin-modal`,
) as HTMLDialogElement;
modal?.showModal();
};

const handleDescription = () => {
const modal = document.getElementById(
`description-modal`
`description-modal`,
) as HTMLDialogElement;
modal?.showModal();
};
Expand Down Expand Up @@ -97,16 +97,20 @@ export default function AdminOptions({
size={64}
/>
</div>
<a className="lg:text-2xl text-xl leading-6 -mt-2">
<a className="lg:text-2xl text-xl leading-6 -mt-2" aria-label="title">
{group?.ipfsMetadata?.title}
</a>

<a className="text-sm leading-tight flex-wrap text-center text-neutral-content max-h-10 max-w-96 overflow-y-auto -mt-6">
<a
className="text-sm leading-tight flex-wrap text-center text-neutral-content max-h-10 max-w-96 overflow-y-auto -mt-6"
aria-label="details"
>
{group?.ipfsMetadata?.details}
</a>
<button
className="btn btn-sm btn-ghost absolute right-2 bottom-17"
onClick={handleDescription}
aria-label="three-dots"
>
<BsThreeDots />
</button>
Expand All @@ -121,6 +125,7 @@ export default function AdminOptions({
<button
className="btn hidden lg:block btn-primary btn-sm w-2/6"
onClick={handleOpen}
aria-label="update admin"
>
Update Admin
</button>
Expand Down
14 changes: 10 additions & 4 deletions components/admins/components/stakingParams.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ export default function StakingParams({
}: StakingParamsProps) {
const openParamsModal = () => {
const modal = document.getElementById(
`update-params-modal`
`update-params-modal`,
) as HTMLDialogElement;
modal?.showModal();
};

return (
<div className="lg:w-1/2 w-full mx-auto p-4 bg-base-100 rounded-md lg:max-h-[352px] lg:min-h-[352px]">
<div className="px-4 py-2 border-base-content flex items-center flex-row justify-between">
<div
className="px-4 py-2 border-base-content flex items-center flex-row justify-between"
aria-label="Skeleton Staking Params"
>
<h3 className="text-lg font-bold leading-6">Staking Params</h3>

<button
Expand All @@ -37,15 +40,18 @@ export default function StakingParams({
<div className="divider divider-horizon -mt-2 mb-1"></div>
{isLoading && <div className="skeleton w-full h-auto"></div>}
{!isLoading && (
<div className="flex flex-col gap-[1.85rem] justify-center items-center w-full px-1">
<div
className="flex flex-col gap-[1.85rem] justify-center items-center w-full px-1"
aria-label="Staking Params"
>
<div className="flex flex-row gap-4 w-full justify-center items-center">
<div className="flex flex-col gap-2 w-1/2 rounded-md">
<span className="text-sm text-gray-400">UNBONDING TIME</span>
<span className="text-md bg-base-300 py-2 rounded-md">
<span className="p-2">
{Number(
BigInt(stakingParams.unbonding_time?.seconds ?? 1) /
BigInt(86400)
BigInt(86400),
).toString()}
</span>
</span>
Expand Down
Loading

0 comments on commit 278c20d

Please sign in to comment.