Skip to content

Commit

Permalink
Chore: UT for package bridge (#199)
Browse files Browse the repository at this point in the history
* chore: add UT for package bridge

* chore: add UT for package bridge

Co-authored-by: aelf-lxy <[email protected]>
  • Loading branch information
work-kevin-flynn and aelf-lxy authored Nov 25, 2024
1 parent 606551b commit 93d1285
Show file tree
Hide file tree
Showing 14 changed files with 460 additions and 89 deletions.
12 changes: 12 additions & 0 deletions packages/bridge/babel.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
presets: [
['@babel/preset-env', { modules: 'auto' }],
[
'@babel/preset-react',
{
runtime: 'automatic',
},
],
'@babel/preset-typescript',
],
};
7 changes: 5 additions & 2 deletions packages/bridge/coverage/coverage-summary.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{"total": {"lines":{"total":22,"covered":20,"skipped":0,"pct":90.9},"statements":{"total":27,"covered":22,"skipped":0,"pct":81.48},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"branches":{"total":5,"covered":5,"skipped":0,"pct":100},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":"Unknown"}}
,"/Users/aelf/Documents/Projects/aelf/aelf-web-login/packages/bridge/src/utils.ts": {"lines":{"total":22,"covered":20,"skipped":0,"pct":90.9},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":27,"covered":22,"skipped":0,"pct":81.48},"branches":{"total":5,"covered":5,"skipped":0,"pct":100}}
{"total": {"lines":{"total":56,"covered":54,"skipped":0,"pct":96.42},"statements":{"total":58,"covered":56,"skipped":0,"pct":96.55},"functions":{"total":11,"covered":11,"skipped":0,"pct":100},"branches":{"total":16,"covered":16,"skipped":0,"pct":100},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":"Unknown"}}
,"/Users/liuxiyang/work/code/aelf-web-login/packages/bridge/src/mountApp.tsx": {"lines":{"total":3,"covered":3,"skipped":0,"pct":100},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":3,"covered":3,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}
,"/Users/liuxiyang/work/code/aelf-web-login/packages/bridge/src/useLockCallback.ts": {"lines":{"total":10,"covered":10,"skipped":0,"pct":100},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":11,"covered":11,"skipped":0,"pct":100},"branches":{"total":2,"covered":2,"skipped":0,"pct":100}}
,"/Users/liuxiyang/work/code/aelf-web-login/packages/bridge/src/useVerifier.ts": {"lines":{"total":25,"covered":25,"skipped":0,"pct":100},"functions":{"total":5,"covered":5,"skipped":0,"pct":100},"statements":{"total":26,"covered":26,"skipped":0,"pct":100},"branches":{"total":8,"covered":8,"skipped":0,"pct":100}}
,"/Users/liuxiyang/work/code/aelf-web-login/packages/bridge/src/utils.ts": {"lines":{"total":18,"covered":16,"skipped":0,"pct":88.88},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":18,"covered":16,"skipped":0,"pct":88.88},"branches":{"total":6,"covered":6,"skipped":0,"pct":100}}
}
40 changes: 36 additions & 4 deletions packages/bridge/jest-report.xml
Original file line number Diff line number Diff line change
@@ -1,13 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuites name="jest tests" tests="4" failures="0" errors="0" time="0.919">
<testsuite name="getCaContractBase()" errors="0" failures="0" skipped="0" timestamp="2024-11-25T04:09:22" time="0.576" tests="4">
<testcase classname="getCaContractBase() should throw error about chain is not running" name="getCaContractBase() should throw error about chain is not running" time="0.002">
<testsuites name="jest tests" tests="17" failures="0" errors="0" time="2.076">
<testsuite name="useLockCallback Hook" errors="0" failures="0" skipped="0" timestamp="2024-11-25T10:44:44" time="0.907" tests="4">
<testcase classname="useLockCallback Hook should execute function and lock" name="useLockCallback Hook should execute function and lock" time="0.108">
</testcase>
<testcase classname="getCaContractBase() should get back contract base" name="getCaContractBase() should get back contract base" time="0.001">
<testcase classname="useLockCallback Hook should prevent concurrent execution" name="useLockCallback Hook should prevent concurrent execution" time="0.102">
</testcase>
<testcase classname="useLockCallback Hook should allow another execution after previous is finished" name="useLockCallback Hook should allow another execution after previous is finished" time="0.202">
</testcase>
<testcase classname="useLockCallback Hook should release the lock if the callback throws an error" name="useLockCallback Hook should release the lock if the callback throws an error" time="0.006">
</testcase>
</testsuite>
<testsuite name="useMountSignIn" errors="0" failures="0" skipped="0" timestamp="2024-11-25T10:44:45" time="0.298" tests="2">
<testcase classname="useMountSignIn should render the SignInModal and children wrapped in PortkeyProvider" name="useMountSignIn should render the SignInModal and children wrapped in PortkeyProvider" time="0.039">
</testcase>
<testcase classname="useMountSignIn should memoize the rendered component" name="useMountSignIn should memoize the rendered component" time="0.001">
</testcase>
</testsuite>
<testsuite name="getCaContractBase()" errors="0" failures="0" skipped="0" timestamp="2024-11-25T10:44:46" time="0.263" tests="4">
<testcase classname="getCaContractBase() should throw error about chain is not running" name="getCaContractBase() should throw error about chain is not running" time="0.001">
</testcase>
<testcase classname="getCaContractBase() should get back contract base" name="getCaContractBase() should get back contract base" time="0">
</testcase>
<testcase classname="getIsManagerReadOnly() should throw error about chain is not running" name="getIsManagerReadOnly() should throw error about chain is not running" time="0">
</testcase>
<testcase classname="getIsManagerReadOnly() should return false" name="getIsManagerReadOnly() should return false" time="0.004">
</testcase>
</testsuite>
<testsuite name="useVerifier" errors="0" failures="0" skipped="0" timestamp="2024-11-25T10:44:46" time="0.056" tests="7">
<testcase classname="useVerifier should return getRecommendationVerifier and verifySocialToken functions" name="useVerifier should return getRecommendationVerifier and verifySocialToken functions" time="0.001">
</testcase>
<testcase classname="useVerifier should call getRecommendationVerifier with correct chainId" name="useVerifier should call getRecommendationVerifier with correct chainId" time="0.001">
</testcase>
<testcase classname="useVerifier should handle Apple account type correctly" name="useVerifier should handle Apple account type correctly" time="0">
</testcase>
<testcase classname="useVerifier should handle Google account type correctly" name="useVerifier should handle Google account type correctly" time="0.001">
</testcase>
<testcase classname="useVerifier should handle Telegram account type correctly" name="useVerifier should handle Telegram account type correctly" time="0.001">
</testcase>
<testcase classname="useVerifier should throw error for unsupported account type" name="useVerifier should throw error for unsupported account type" time="0.001">
</testcase>
<testcase classname="useVerifier should throw error if verifier is missing" name="useVerifier should throw error if verifier is missing" time="0.003">
</testcase>
</testsuite>
</testsuites>
5 changes: 2 additions & 3 deletions packages/bridge/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,8 @@ const config = {
// testRunner: "jest-circus/runner",

// A map from regular expressions to paths to transformers
transform: {
'^.+\\.(t|j)sx?$': '@swc/jest',
},
transform: { '^.+\\.(js|jsx|ts|tsx)$': 'babel-jest', '^.+\\.js$': 'babel-jest' },

// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
transformIgnorePatterns: [
'.pnpm/node_modules/(?!((jest-)?react-native(-.*)?|@react-native(-community)?|victory(-.*)?|uuid)|react-navigation|@shopify/react-native-skia|@react-navigation/.*/)',
Expand Down
9 changes: 9 additions & 0 deletions packages/bridge/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,20 @@
"react-dom": "^18.0.0"
},
"devDependencies": {
"babel-jest": "^29.7.0",
"@portkey/did-ui-react": "^2.15.9",
"@portkey/types": "^2.15.9",
"@portkey/utils": "^2.15.9",
"@babel/core": "^7.24.7",
"@babel/preset-env": "^7.24.7",
"@babel/preset-react": "^7.24.7",
"@babel/preset-typescript": "^7.24.7",
"@swc/core": "^1.9.3",
"@swc/jest": "^0.2.37",
"@testing-library/jest-dom": "^6.5.0",
"@testing-library/react": "^16.0.1",
"@testing-library/react-hooks": "^8.0.1",
"@types/jest": "^29.5.14",
"@types/react": "^18.3.1",
"@types/react-dom": "^18.3.0",
"antd": "4.24.14",
Expand Down
57 changes: 57 additions & 0 deletions packages/bridge/src/__tests__/mountApp.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { renderHook } from '@testing-library/react-hooks';
import { render, screen } from '@testing-library/react';
import { useMountSignIn } from '../mountApp';
import { Bridge } from '../bridge';
import { NetworkEnum, WalletAdapter } from '@aelf-web-login/wallet-adapter-base';
import { IBaseConfig } from '../index';
import '@testing-library/jest-dom';

// Mock components and dependencies
jest.mock('../ui', () => jest.fn(() => <div>SignInModal Component</div>));

jest.mock('@portkey/did-ui-react', () => ({
PortkeyProvider: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
}));

describe('useMountSignIn', () => {
let bridgeInstance: Bridge;
let wallets: WalletAdapter[];
let baseConfig: IBaseConfig;
let children: React.ReactNode;

beforeEach(() => {
bridgeInstance = {} as Bridge;
wallets = [{} as WalletAdapter];
baseConfig = {
PortkeyProviderProps: {},
networkType: NetworkEnum.TESTNET,
} as IBaseConfig;
children = <div>Child Component</div>;
});

it('should render the SignInModal and children wrapped in PortkeyProvider', () => {
const { result } = renderHook(() =>
useMountSignIn(bridgeInstance, wallets, baseConfig, children),
);

const SignInNode = result.current;

render(SignInNode);

expect(screen.getByText('Child Component')).toBeInTheDocument();
});

it('should memoize the rendered component', () => {
const { result, rerender } = renderHook(() =>
useMountSignIn(bridgeInstance, wallets, baseConfig, children),
);

const firstRender = result.current;

rerender();

const secondRender = result.current;

expect(firstRender).toBe(secondRender);
});
});
89 changes: 89 additions & 0 deletions packages/bridge/src/__tests__/useLockCallback.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { renderHook, act } from '@testing-library/react-hooks';
import useLockCallback from '../useLockCallback';

describe('useLockCallback Hook', () => {
it('should execute function and lock', async () => {
const mockFn = jest.fn(async () => {
await new Promise((res) => setTimeout(res, 100));
return 'result';
});

const { result } = renderHook(() => useLockCallback(mockFn, []));

// First call should execute
let value;
await act(async () => {
value = await result.current();
});

expect(mockFn).toHaveBeenCalledTimes(1);
expect(value).toBe('result');
});

it('should prevent concurrent execution', async () => {
const mockFn = jest.fn(async () => {
await new Promise((res) => setTimeout(res, 100));
});

const { result } = renderHook(() => useLockCallback(mockFn, []));

// First call will run
let firstCall;
await act(async () => {
firstCall = result.current();
await result.current();
});

expect(mockFn).toHaveBeenCalledTimes(1); // Should only run once

await firstCall; // Resolve first call
});

it('should allow another execution after previous is finished', async () => {
const mockFn = jest.fn(async () => {
await new Promise((res) => setTimeout(res, 100));
return 'success';
});

const { result } = renderHook(() => useLockCallback(mockFn, []));

// First call
let firstResult;
await act(async () => {
firstResult = await result.current();
});

expect(firstResult).toBe('success');

// Second call, after first one has finished
let secondResult;
await act(async () => {
secondResult = await result.current();
});

expect(secondResult).toBe('success');
expect(mockFn).toHaveBeenCalledTimes(2); // Second call should now be allowed
});

it('should release the lock if the callback throws an error', async () => {
const mockFn = jest.fn(async () => {
throw new Error('Test error');
});

const { result } = renderHook(() => useLockCallback(mockFn, []));

const lockedCallback = result.current;

// First call should execute
const firstPromise = lockedCallback();
expect(mockFn).toHaveBeenCalledTimes(1);

// Expect the first call to throw an error
await expect(firstPromise).rejects.toThrow('Test error');

// Second call should now execute
const secondPromise = lockedCallback();
await expect(secondPromise).rejects.toThrow('Test error');
expect(mockFn).toHaveBeenCalledTimes(2);
});
});
Loading

0 comments on commit 93d1285

Please sign in to comment.