Skip to content

Commit da9abfa

Browse files
committed
test scope
1 parent fa271f6 commit da9abfa

25 files changed

Lines changed: 189 additions & 99 deletions

explorer_frontend/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@
7777
"serve": "^14.2.4",
7878
"solc": "^0.8.29",
7979
"vite-bundle-visualizer": "^1.1.0",
80+
"vite-plugin-circular-dependency": "0.5.0",
8081
"vite-plugin-string": "^1.2.3",
8182
"vitest": "^3.1.1",
83+
"vitest-canvas-mock": "0.3.3",
8284
"wait-on": "^8.0.1"
8385
}
8486
}

explorer_frontend/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { RouterProvider } from "atomic-router-react";
33
import { ErrorBoundary } from "react-error-boundary";
44
import { useStyletron } from "styletron-react";
55
import { router } from "./features/routing";
6-
import { RoutesView } from "./features/routing";
6+
import { RoutesView } from "./features/routing/components/RoutesView";
77
import type { StylesObject } from "./features/shared";
88

99
const styles: StylesObject = {
Lines changed: 71 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,75 @@
11
import { renderWithLayout } from "@test/unit/renderWithLayout";
22
import { screen } from "@testing-library/react";
33
import * as effectorReact from "effector-react";
4-
import { describe, it, vi } from "vitest";
4+
import { describe, it } from "vitest";
55
import { measure } from "../../shared/utils/measure";
66
import { AccountInfo } from "./AccountInfo";
7-
8-
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
9-
const getUseUnitReturnedValue = (args: any = {}): any => {
10-
return [
11-
args.account ?? { address: "0x123", balance: "1000" },
12-
args.accountCometaInfo ?? null,
13-
args.isLoading ?? false,
14-
args.isLoadingCometaInfo ?? false,
15-
args.params ?? { address: "0x123" },
16-
args.cometa ?? null,
17-
];
7+
import { fork, type Scope, type TypeOfSource } from "effector";
8+
import {
9+
$account,
10+
$accountCometaInfo,
11+
loadAccountCometaInfoFx,
12+
loadAccountStateFx,
13+
} from "../model";
14+
import { $cometaClient } from "../../cometa/model";
15+
import "../init.ts";
16+
import { addressRoute } from "../../routing/routes/addressRoute.ts";
17+
18+
const initScope = (args?: {
19+
account?: Partial<TypeOfSource<typeof $account>>;
20+
accountCometaInfo?: Partial<TypeOfSource<typeof $accountCometaInfo>>;
21+
isLoading?: boolean;
22+
isLoadingCometaInfo?: boolean;
23+
params?: Partial<TypeOfSource<typeof addressRoute.$params>>;
24+
cometa?: Partial<TypeOfSource<typeof $cometaClient>>;
25+
}): Scope => {
26+
return fork({
27+
values: [
28+
[$account, args?.account ?? { address: "0x123", balance: "1000" }],
29+
[$accountCometaInfo, args?.accountCometaInfo ?? null],
30+
[loadAccountStateFx.pending, args?.isLoading ?? false],
31+
[loadAccountCometaInfoFx.pending, args?.isLoadingCometaInfo ?? false],
32+
[addressRoute.$params, args?.params ?? { address: "0x123" }],
33+
[addressRoute.$isOpened, true],
34+
[$cometaClient, args?.cometa ?? null],
35+
],
36+
});
1837
};
1938

20-
vi.mock("../../routing", () => ({
21-
addressRoute: {
22-
$params: { getState: () => ({ address: "0x123" }) },
23-
$isOpened: { getState: () => true },
24-
},
25-
}));
26-
27-
vi.mock("effector-react");
28-
const mockUseUnit = vi.mocked(effectorReact.useUnit);
29-
3039
describe("AccountInfo", () => {
31-
afterEach(() => {
32-
vi.clearAllMocks();
33-
});
34-
3540
it("renders without crashing", () => {
36-
mockUseUnit.mockReturnValue(getUseUnitReturnedValue());
37-
38-
renderWithLayout(<AccountInfo />);
41+
const scope = initScope();
42+
renderWithLayout(
43+
<effectorReact.Provider value={scope}>
44+
<AccountInfo />
45+
</effectorReact.Provider>,
46+
);
3947

4048
expect(screen.getByTestId("vitest-unit--account-container")).toBeInTheDocument();
4149
});
4250

4351
it("renders skeleton when loading", () => {
44-
mockUseUnit.mockReturnValue(getUseUnitReturnedValue({ account: null, isLoading: true }));
45-
46-
renderWithLayout(<AccountInfo />);
52+
const scope = initScope({ isLoading: true });
53+
renderWithLayout(
54+
<effectorReact.Provider value={scope}>
55+
<AccountInfo />
56+
</effectorReact.Provider>,
57+
);
4758

4859
expect(screen.getByRole("progressbar")).toBeInTheDocument();
4960
});
5061

5162
it("renders account information when loaded", () => {
52-
mockUseUnit.mockReturnValue(
53-
getUseUnitReturnedValue({
54-
account: { address: "0x123", balance: "1000", tokens: [] },
55-
}),
63+
const scope = initScope({
64+
account: { balance: "1000", tokens: [] },
65+
});
66+
67+
renderWithLayout(
68+
<effectorReact.Provider value={scope}>
69+
<AccountInfo />
70+
</effectorReact.Provider>,
5671
);
5772

58-
renderWithLayout(<AccountInfo />);
59-
6073
expect(screen.getByText("Address")).toBeInTheDocument();
6174
expect(screen.getByText("0x123")).toBeInTheDocument();
6275
expect(screen.getByText("Balance")).toBeInTheDocument();
@@ -67,27 +80,35 @@ describe("AccountInfo", () => {
6780
});
6881

6982
it("renders fallback UI when source code is not available", () => {
70-
mockUseUnit.mockReturnValue(
71-
getUseUnitReturnedValue({
72-
accountCometaInfo: { sourceCode: { Compiled_Contracts: "" } },
73-
}),
83+
const scope = initScope({
84+
accountCometaInfo: {
85+
sourceCode: {
86+
Compiled_Contracts: "",
87+
},
88+
},
89+
});
90+
91+
renderWithLayout(
92+
<effectorReact.Provider value={scope}>
93+
<AccountInfo />
94+
</effectorReact.Provider>,
7495
);
7596

76-
renderWithLayout(<AccountInfo />);
77-
7897
expect(screen.getByText("Source code")).toBeInTheDocument();
7998
expect(screen.getByText("Not available")).toBeInTheDocument();
8099
});
81100

82101
it("shows spinner when cometa info is loading", () => {
83-
mockUseUnit.mockReturnValue(
84-
getUseUnitReturnedValue({
85-
isLoadingCometaInfo: true,
86-
}),
102+
const scope = initScope({
103+
isLoadingCometaInfo: true,
104+
});
105+
106+
renderWithLayout(
107+
<effectorReact.Provider value={scope}>
108+
<AccountInfo />
109+
</effectorReact.Provider>,
87110
);
88111

89-
renderWithLayout(<AccountInfo />);
90-
91112
expect(screen.getByTestId("vitest-unit--loading-cometa-info-spinner")).toBeInTheDocument();
92113
});
93114
});

explorer_frontend/src/features/account/components/AccountInfo.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import { useStyletron } from "baseui";
1111
import { useUnit } from "effector-react";
1212
import { useEffect } from "react";
1313
import { $cometaClient } from "../../cometa/model";
14-
import { addressRoute } from "../../routing";
15-
import { Divider } from "../../shared";
1614
import { Info } from "../../shared/components/Info";
1715
import { InfoBlock } from "../../shared/components/InfoBlock";
1816
import { SolidityCodeField } from "../../shared/components/SolidityCodeField";
@@ -24,6 +22,9 @@ import {
2422
loadAccountCometaInfoFx,
2523
loadAccountStateFx,
2624
} from "../model";
25+
import { isHexString } from "@nilfoundation/niljs";
26+
import { addressRoute } from "../../routing/routes/addressRoute";
27+
import { Divider } from "../../shared/components/Divider";
2728

2829
const AccountLoading = () => {
2930
const [css] = useStyletron();
@@ -50,7 +51,9 @@ export const AccountInfo = () => {
5051

5152
useEffect(() => {
5253
loadAccountStateFx(params.address);
53-
loadAccountCometaInfoFx({ address: params.address, cometaClient: cometa });
54+
if (cometa && isHexString(params.address)) {
55+
loadAccountCometaInfoFx({ address: params.address, cometaClient: cometa });
56+
}
5457
}, [params.address, cometa]);
5558

5659
if (isLoading) return <AccountLoading />;
@@ -67,7 +70,7 @@ export const AccountInfo = () => {
6770
<Info
6871
label="Source code"
6972
value={
70-
sourceCode?.length > 0 ? (
73+
sourceCode?.length ? (
7174
<SolidityCodeField
7275
code={sourceCode}
7376
className={css({ marginTop: "1ch" })}

explorer_frontend/src/features/account/init.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { sample } from "effector";
2-
import { combine } from "effector";
1+
import { sample, combine } from "effector";
32
import { $cometaClient } from "../cometa/model";
4-
import { addressRoute } from "../routing";
3+
import { addressRoute } from "../routing/routes/addressRoute";
54
import { $account, $accountCometaInfo, loadAccountCometaInfoFx, loadAccountStateFx } from "./model";
65

76
sample({
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1+
import type { CometaClient } from "@nilfoundation/niljs";
12
import type { fetchAccountState } from "../../api/account";
23

34
export type AccountState = Awaited<ReturnType<typeof fetchAccountState>>;
45

5-
export type AccountCometaInfo = {
6-
sourceCode?: string;
7-
};
6+
export type AccountCometaInfo = Awaited<ReturnType<CometaClient['getContract']>

explorer_frontend/src/features/code/code-toolbar/CompilerVersionButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import { useStyletron } from "baseui";
1212
import { Button } from "baseui/button";
1313
import type { MenuOverrides } from "baseui/menu";
1414
import { type FC, useState } from "react";
15-
import { StatefulPopover } from "../../shared";
1615
import { $availableSolidityVersions, changeSolidityVersion } from "../model";
16+
import { StatefulPopover } from "../../shared/components/Popover";
1717

1818
type CompilerVersionButtonProps = {
1919
disabled?: boolean;

explorer_frontend/src/features/code/code-toolbar/HyperlinkButton.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,17 @@ import { useUnit } from "effector-react";
1212
import { expandProperty } from "inline-style-expand-shorthand";
1313
import type { FC } from "react";
1414
import { playgroundWithHashRoute } from "../../routing";
15-
import { HyperlinkIcon, Link, OverflowEllipsis, StatefulPopover, useMobile } from "../../shared";
1615
import {
1716
$codeSnippetHash,
1817
$shareCodeSnippetError,
1918
setCodeSnippetEvent,
2019
setCodeSnippetFx,
2120
} from "../model";
21+
import { StatefulPopover } from "../../shared/components/Popover";
22+
import { OverflowEllipsis } from "../../shared/components/OverflowEllipsis";
23+
import { useMobile } from "../../shared/hooks/useMobile";
24+
import { Link } from "../../shared/components/Link";
25+
import { HyperlinkIcon } from "../../shared/components/HyperlinkIcon";
2226

2327
type HyperlinkButtonProps = {
2428
disabled?: boolean;

explorer_frontend/src/features/code/code-toolbar/OpenProjectButton.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ import type { MenuOverrides } from "baseui/menu";
1313
import { useUnit } from "effector-react";
1414
import { type FC, useState } from "react";
1515
import { useStyletron } from "styletron-react";
16-
import { StatefulPopover, useMobile } from "../../shared";
1716
import AsyncCallExample from "../assets/AsyncCallExample.sol";
1817
import AsyncRequestExample from "../assets/AsyncRequestExample.sol";
1918
import HandlingExtTxExample from "../assets/HandlingExtTxExample.sol";
2019
import TokenExample from "../assets/TokenExample.sol";
2120
import { $recentProjects, changeCode, updateRecentProjects } from "../model";
2221
import { compile } from "../model";
22+
import { useMobile } from "../../shared/hooks/useMobile";
23+
import { StatefulPopover } from "../../shared/components/Popover";
2324

2425
type OpenProjectButtonProps = {
2526
disabled?: boolean;

explorer_frontend/src/features/routing/index.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
export { createRoute } from "./utils/createRoute";
2-
export type { ExtendedRoute } from "./utils/createRoute";
3-
export { RoutesView } from "./components/RoutesView";
41
export { router } from "./routes/routes";
52
export * from "./routes/addressRoute";
63
export * from "./routes/explorerRoute";

0 commit comments

Comments
 (0)