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

FILE-13 - Add more test coverage #57

Closed
wants to merge 1 commit into from
Closed
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
2,956 changes: 2,779 additions & 177 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"eslint": "eslint src/ test/",
"test": "npm run build && vitest",
"test:unit": "npm run build && vitest test/unit",
"test:coverage": " npm run build && vitest test/unit --coverage",
"test:e2e": "npm run build && vitest test/e2e",
"test:webui-e2e": "npm run build:webui && vitest test/webui-e2e",
"typecheck": "tsc --noEmit",
Expand All @@ -38,13 +39,16 @@
"swr": "^2.0.0"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^14.0.0",
"@types/bytes": "^3.1.1",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9",
"@types/react-router-dom": "^5.3.3",
"@typescript-eslint/eslint-plugin": "^5.46.1",
"@typescript-eslint/parser": "^5.46.1",
"@vitejs/plugin-react-swc": "^3.0.0",
"@vitest/coverage-v8": "^0.34.2",
"autoprefixer": "^10.4.13",
"eslint": "^8.29.0",
"eslint-config-prettier": "^8.5.0",
Expand All @@ -55,6 +59,7 @@
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1",
"husky": "^8.0.2",
"jsdom": "^22.1.0",
"lint-staged": "^13.1.0",
"postcss": "^8.4.20",
"prettier": "^2.8.1",
Expand All @@ -63,7 +68,7 @@
"tailwindcss": "^3.2.4",
"typescript": "^4.9.4",
"vite": "^4.0.1",
"vitest": "^0.25.8"
"vitest": "^0.32.0"
},
"author": "Protocol Labs",
"license": "(Apache-2.0 AND MIT)",
Expand Down
2 changes: 1 addition & 1 deletion src/components/AuthenticateModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
dispatch({ type: "USER_AUTHENTICATED", authorizationToken });

resetForm();
} catch (error: any) {

Check warning on line 33 in src/components/AuthenticateModal.tsx

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
setRequestError(error.message ?? "An unexpected error occurred");
}
},
Expand All @@ -41,7 +41,7 @@
formik.resetForm();
setRequestError("");
}
}, [state.authModalOpen, formik.resetForm, setRequestError]);

Check warning on line 44 in src/components/AuthenticateModal.tsx

View workflow job for this annotation

GitHub Actions / eslint

React Hook useEffect has a missing dependency: 'formik'. Either include it or remove the dependency array

return (
<Transition.Root show={state.authModalOpen} as={Fragment}>
Expand Down Expand Up @@ -72,7 +72,7 @@
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-slate-800 px-4 pt-5 pb-4 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6">
<form className="space-y-6" onSubmit={formik.handleSubmit}>
<div>
<label htmlFor="email" className="block text-sm font-medium">
<label htmlFor="username" className="block text-sm font-medium">
Username
</label>
<div className="mt-1">
Expand Down
3 changes: 2 additions & 1 deletion src/components/FilAddressForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ function FilAddressForm(props: FilAddressFormProps) {
onChange={(e) => setAddress(e.target.value)}
autoFocus={props.autoFocus}
required
data-testid="input-field"
/>
<button onClick={handleAddress}>
<button onClick={handleAddress} data-testid="search-button">
<SearchIcon
className={`absolute right-2 top-0 bottom-0
m-auto cursor-pointer text-slate-100 hover:text-sky-700 ${iconClasses}`}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ export default function Loader(props: { size?: number; className?: string }) {
display: "inline-block",
animation: "rotation 1s linear infinite",
};
return <span style={style} className={className}></span>;
return <span data-testid="loader" style={style} className={className}></span>;
}
2 changes: 1 addition & 1 deletion src/components/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const navigation = [

export default function NavBar() {
return (
<Disclosure as="nav" data-test-id="navbar" className="bg-gray-800">
<Disclosure as="nav" data-testid="navbar" className="bg-gray-800">
{({ open }) => (
<>
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
Expand Down
3 changes: 2 additions & 1 deletion src/components/NodeDetails/NodeDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { DispatchContext, StateContext } from "../../state/Context";

function NodeDetails({ node }: any) {
return (
<div className="mt-5 border-t border-gray-200 px-4 py-5 text-slate-200 sm:px-6">
<div data-testid="node-details" className="mt-5 border-t border-gray-200 px-4 py-5 text-slate-200 sm:px-6">
<dl className="grid grid-cols-1 gap-x-1 gap-y-2 sm:grid-cols-2">
<div className="sm:col-span-1">
<dt className="text-sm text-slate-400">Node details</dt>
Expand Down Expand Up @@ -98,6 +98,7 @@ export default function NodeDetailsPanel() {
type="button"
className="rounded-md text-slate-200 hover:text-gray-500 focus:outline-none"
onClick={() => onClose()}
data-testid="close-panel"
>
<span className="sr-only">Close panel</span>
<SidebarCollapseIcon className="h-6 w-6" aria-hidden="true" />
Expand Down
11 changes: 10 additions & 1 deletion src/components/Spinner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,17 @@ export default function Spinner() {
fill="none"
viewBox="0 0 24 24"
>
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<circle
data-testid="spinner-circle"
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
></circle>
<path
data-testid="spinner-path"
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
Expand Down
3 changes: 2 additions & 1 deletion src/components/StatsGrid/GridButton.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import classNames from "classnames";

export default function GridButton({ children, onClick, className }: any) {
export default function GridButton({ children, onClick, className, testId }: any) {
const [clicked, setClicked] = useState(false);

useEffect(() => {
Expand All @@ -22,6 +22,7 @@ export default function GridButton({ children, onClick, className }: any) {

return (
<button
data-testid={testId}
type="button"
onClick={() => {
setClicked(true);
Expand Down
8 changes: 4 additions & 4 deletions src/components/StatsGrid/StatsGridActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,16 @@ export default function StatsGridActions({ gridApi, columnApi }: any) {

return (
<div className="m-2 mt-0 flex justify-center space-x-2">
<GridButton onClick={handleResetFilters}>
<GridButton testId="reset-filters-button" onClick={handleResetFilters}>
<FilterIcon className="-ml-0.5 mr-2 h-4 w-4" aria-hidden="true" /> Reset filters
</GridButton>

<GridButton onClick={handleShareGrid} className="min-w-[150px]">
<GridButton testId="share-grid-button" onClick={handleShareGrid} className="min-w-[150px]">
<ShareIcon className="-ml-0.5 mr-2 h-4 w-4" aria-hidden="true" />{" "}
{shareCopied ? "Copied to clipboard!" : "Share Current Grid"}
</GridButton>

<GridButton onClick={handleStatsAutoRefreshToggle} className="min-w-[155px]">
<GridButton testId="auto-refresh-toggle" onClick={handleStatsAutoRefreshToggle} className="min-w-[155px]">
<SyncIcon className="-ml-0.5 mr-2 h-4 w-4" aria-hidden="true" />{" "}
{state.statsAutoRefresh ? "Disable Auto Refresh" : "Enable Auto Refresh"}
</GridButton>
Expand All @@ -79,7 +79,7 @@ export default function StatsGridActions({ gridApi, columnApi }: any) {
<UnlockIcon className="-ml-0.5 mr-2 h-4 w-4" aria-hidden="true" /> Admin Authenticated
</GridButton>
) : (
<GridButton onClick={handleAuthentication}>
<GridButton testId="admin-auth" onClick={handleAuthentication}>
<LockIcon className="-ml-0.5 mr-2 h-4 w-4" aria-hidden="true" /> Admin Auth
</GridButton>
)}
Expand Down
4 changes: 2 additions & 2 deletions src/components/StatsGrid/StatsGridConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const columnDefs = [
cellRenderer: (params: any) => {
const action = { type: "OPEN_NODE_DETAILS", id: params.data.id };
return (
<button type="button" onClick={() => params.context.dispatch(action)}>
<button data-testid="node-details-button" type="button" onClick={() => params.context.dispatch(action)}>
<ProjectRoadmapIcon className={classNames("cursor-pointer text-slate-600 hover:text-slate-500")} />
</button>
);
Expand Down Expand Up @@ -126,7 +126,7 @@ export const columnDefs = [
cellRenderer: (params: any) => {
return (
<>
<button type="button" onClick={() => copy(params.data.id)}>
<button data-testid="copy-icon" type="button" onClick={() => copy(params.data.id)}>
<CopyIcon className="cursor-pointer text-slate-600 hover:text-slate-500" />
</button>{" "}
{params.valueFormatted} {params.data.sunrise ? <span>🌅️</span> : null}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/dashboard/components/BandwidthChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default function BandwidthChart(props: BandwidthChartProps) {

return (
<ChartContainer isLoading={isLoading}>
<Line options={options} data={data} />
<Line data-testid="bandwidthChart" options={options} data={data} />
</ChartContainer>
);
}
1 change: 1 addition & 0 deletions src/pages/dashboard/components/ChartContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface ChartContainerProps {
export default function ChartContainer(props: ChartContainerProps) {
return (
<div
data-testid="chart-container"
className={`relative h-[350px] w-[100%] max-w-[600px] rounded bg-slate-900
p-4 pt-2`}
>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/dashboard/components/EarningsChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default function EarningsChart(props: EarningsChartProps) {

return (
<ChartContainer isLoading={isLoading}>
<Line options={options} data={data} />
<Line data-testid="earningsChart" options={options} data={data} />
</ChartContainer>
);
}
2 changes: 1 addition & 1 deletion src/pages/dashboard/components/NodesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default function NodesTable(props: any) {
<button className="w-20"> {params.data.idShort} </button>
{" "}

<button type="button" onClick={() => copy(params.data.nodeId)}>
<button type="button" data-testid="node-table-copy-icon" onClick={() => copy(params.data.nodeId)}>
<CopyIcon className="cursor-pointer text-slate-600 hover:text-slate-500" />
</button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/dashboard/components/RequestsChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default function RequestsChart(props: RequestsChartProps) {

return (
<ChartContainer isLoading={isLoading}>
<Line options={options} data={data} />
<Line data-testid="requestsChart" options={options} data={data} />
</ChartContainer>
);
}
11 changes: 7 additions & 4 deletions src/pages/dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ function SelectTimePeriod(props: { period: TimePeriod; setPeriod: Dispatch<SetSt
value={props.period}
onChange={(e) => props.setPeriod(e.target.value as TimePeriod)}
className="rounded bg-slate-900 p-1"
data-testid="time-period-select"
>
{options.map((o) => (
<option key={o} value={o}>
Expand Down Expand Up @@ -189,17 +190,19 @@ function Overview(props: OverviewProps) {
) : (
<>
<div>Address</div>
<div className="truncate">{props.address}</div>
<div data-testid="address" className="truncate">
{props.address}
</div>
{props.node && nodeIdSection}
{props.node ? nodeStateSection : nodeStatusesSection}
<div>Estimated Earnings</div>
<div>{totalEarnings.toLocaleString()} FIL</div>
<div data-testid="earnings">{totalEarnings.toLocaleString()} FIL</div>
{props.node && nodePayoutSection}
{props.node && uptimeCompletionSection}
<div>Bandwidth</div>
<div>{bytes(totalBandwidth, { unitSeparator: " " })}</div>
<div data-testid="bandwidth">{bytes(totalBandwidth, { unitSeparator: " " })}</div>
<div>Retrievals</div>
<div>{totalRetrievals.toLocaleString()}</div>
<div data-testid="requests">{totalRetrievals.toLocaleString()}</div>
</>
)}
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/stats/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ export default function Stats() {
}

return (
<>
<div data-testid="stats-grid" className="h-full">
juliangruber marked this conversation as resolved.
Show resolved Hide resolved
<StatsGrid />
<NodeDetails />
</>
</div>
);
}
94 changes: 91 additions & 3 deletions test/e2e/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ describe("website mode", async () => {
beforeAll(async () => {
server = await preview();
browser = await puppeteer.launch();
const context = browser.defaultBrowserContext();
context.overridePermissions(server.resolvedUrls.local[0], ["clipboard-read", "clipboard-write"]);
page = await browser.newPage();
});

Expand All @@ -24,9 +26,95 @@ describe("website mode", async () => {
});
});

test("navbar should be visible", async () => {
await page.goto(`${server.resolvedUrls.local[0]}/address/${TEST_FIL_ADDRESS}`);
const navbar = (await page.$("[data-test-id=navbar]"))!;
test("navbar should be visible in address page when the webui mode isn`t runing", async () => {
await page.goto(`${server.resolvedUrls.local[0]}address/${TEST_FIL_ADDRESS}`);
const navbar = (await page.$("[data-testid=navbar]"))!;
expect(navbar).not.toBe(null);
}, 60_000);

test("navbar should be visible", async () => {
await page.goto(`${server.resolvedUrls.local[0]}stats`);
const navbar = await page.$("[data-testid=navbar]");
expect(navbar).toBeTruthy();
}, 60_000);

test("stats grid should be present", async () => {
await page.goto(`${server.resolvedUrls.local[0]}stats`);
const statsGrid = await page.waitForSelector("[data-testid=stats-grid]");
expect(statsGrid).toBeTruthy();
}, 60_0000);

test("Share Grid button should copy URL with encoded state to clipboard", async () => {
await page.goto(`${server.resolvedUrls.local[0]}stats`);
const shareButton = await page.waitForSelector("[data-testid=share-grid-button]");
await shareButton?.click();

const mockClipboardText = "Mocked clipboard text";
await page.evaluate((mockText) => {
const mockClipboard = {
readText: async () => mockText,
};
Object.defineProperty(window.navigator, "clipboard", {
value: mockClipboard,
configurable: true,
});
}, mockClipboardText);

const clipboardText = await page.evaluate(() => window.navigator.clipboard.readText());
expect(clipboardText).toBe(mockClipboardText);
}, 60_000);

test("Auto Refresh toggle should change state when clicked", async () => {
await page.goto(`${server.resolvedUrls.local[0]}stats`);
const autoRefreshButton = await page.waitForSelector("[data-testid=auto-refresh-toggle]");
const initialButtonText = await page.evaluate((el) => el?.textContent, autoRefreshButton);
await autoRefreshButton?.click();

const updatedButtonText = await autoRefreshButton?.evaluate((el) => el.textContent, autoRefreshButton);
expect(initialButtonText).not.toBe(updatedButtonText);
}, 60_000);

test("Node details panel should be visible when clicked", async () => {
await page.goto(`${server.resolvedUrls.local[0]}stats`);
const firstNode = await page.waitForSelector("[data-testid=node-details-button]");
await firstNode?.click();

const nodeDetails = await page.waitForSelector("[data-testid=node-details]");
expect(nodeDetails).toBeTruthy();
expect(nodeDetails).not.toBe(null);
}, 60_000);

test("Admin Auth button should trigger admin authentication model", async () => {
await page.goto(`${server.resolvedUrls.local[0]}stats`);
const AdminAuthButton = await page.waitForSelector("[data-testid=admin-auth]");

expect(AdminAuthButton).toBeTruthy();
}, 60_000);

test("Copy Id icon button should trigger the data", async () => {
await page.goto(`${server.resolvedUrls.local[0]}stats`);
const CopyId = await page.waitForSelector("[data-testid=copy-icon]");
await CopyId?.click();

const mockClipboardText = "db884bbb-33db-4071-9206-12c616339e3e";
await page.evaluate((mockText) => {
const mockClipboard = {
readText: async () => mockText,
};
Object.defineProperty(window.navigator, "clipboard", {
value: mockClipboard,
configurable: true,
});
}, mockClipboardText);

const clipboardText = await page.evaluate(() => window.navigator.clipboard.readText());
expect(clipboardText).toBe(mockClipboardText);
}, 60_000);

test("Reset Filters button should reset filters", async () => {
await page.goto(`${server.resolvedUrls.local[0]}stats`);
const filterButton = await page.waitForSelector("[data-testid=reset-filters-button]");
await filterButton?.click();
expect(filterButton).toBeTruthy();
}, 60_000);
});
1 change: 1 addition & 0 deletions test/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "@testing-library/jest-dom";
Loading
Loading