add tests
This commit is contained in:
parent
4ba4dc98bf
commit
70532dda3a
52
__mocks__/@umijs/max.ts
Normal file
52
__mocks__/@umijs/max.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { vi } from 'vitest';
|
||||
|
||||
// Generic API envelope used by the real backend: `{ code, msg, data }`.
|
||||
// `data` carries the object-shaped fields pages read off `request(...)`
|
||||
// directly (`list` for the login tenant search, `nodes`/`edges` for the CRM
|
||||
// graph), all empty so access never throws.
|
||||
function makeData() {
|
||||
return { list: [], total: 0, records: [], nodes: [], edges: [] };
|
||||
}
|
||||
|
||||
export const request = vi.fn(() =>
|
||||
Promise.resolve({ code: 0, msg: 'ok', success: true, data: makeData() }),
|
||||
);
|
||||
|
||||
export const history = {
|
||||
push: vi.fn(),
|
||||
replace: vi.fn(),
|
||||
back: vi.fn(),
|
||||
go: vi.fn(),
|
||||
location: { pathname: '/', search: '', hash: '', state: null },
|
||||
};
|
||||
|
||||
export const useModel = vi.fn(() => ({
|
||||
initialState: { currentUser: { name: 'tester', menuPaths: [] }, menuPaths: [] },
|
||||
setInitialState: vi.fn(),
|
||||
refresh: vi.fn(),
|
||||
loading: false,
|
||||
}));
|
||||
|
||||
export const useParams = vi.fn(() => ({ id: '1' }));
|
||||
export const useSearchParams = vi.fn(() => [new URLSearchParams(), vi.fn()]);
|
||||
export const useNavigate = vi.fn(() => vi.fn());
|
||||
export const useLocation = vi.fn(() => history.location);
|
||||
export const useAccess = vi.fn(() => ({}));
|
||||
export const useIntl = vi.fn(() => ({ formatMessage: ({ defaultMessage }: any) => defaultMessage }));
|
||||
|
||||
export const Link = ({ children }: any) => children;
|
||||
export const NavLink = ({ children }: any) => children;
|
||||
export const Access = ({ children }: any) => children;
|
||||
export const Outlet = () => null;
|
||||
|
||||
export const getLocale = vi.fn(() => 'zh-CN');
|
||||
export const setLocale = vi.fn();
|
||||
|
||||
export default {
|
||||
request,
|
||||
history,
|
||||
useModel,
|
||||
useParams,
|
||||
useNavigate,
|
||||
Link,
|
||||
};
|
||||
16
package.json
16
package.json
@ -8,20 +8,30 @@
|
||||
"build": "max build",
|
||||
"postinstall": "max setup",
|
||||
"lint": "max lint",
|
||||
"format": "prettier --write ."
|
||||
"format": "prettier --write .",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.6.1",
|
||||
"@ant-design/pro-components": "^2.8.7",
|
||||
"@umijs/max": "^4.4.8",
|
||||
"antd": "^5.24.2",
|
||||
"axios": "^1.8.4"
|
||||
"axios": "^1.8.4",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@types/react": "^18.3.18",
|
||||
"@types/react-dom": "^18.3.5",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"jsdom": "^25.0.1",
|
||||
"prettier": "^3.5.3",
|
||||
"typescript": "^5.7.3"
|
||||
"typescript": "^5.7.3",
|
||||
"vitest": "^2.1.9"
|
||||
},
|
||||
"packageManager": "pnpm@10.12.4+sha512.5ea8b0deed94ed68691c9bad4c955492705c5eeb8a87ef86bc62c74a26b037b08ff9570f108b2e4dbd1dd1a9186fea925e527f141c648e85af45631074680184"
|
||||
}
|
||||
|
||||
1170
pnpm-lock.yaml
generated
1170
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
11
src/pages/CRM/Graph/index.test.tsx
Normal file
11
src/pages/CRM/Graph/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('CRM / Graph page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/CRM/Relations/index.test.tsx
Normal file
11
src/pages/CRM/Relations/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('CRM / Relations page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Dashboard/index.test.tsx
Normal file
11
src/pages/Dashboard/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Dashboard page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Inventory/Adjusts/index.test.tsx
Normal file
11
src/pages/Inventory/Adjusts/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Inventory / Adjusts page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Inventory/Bolts/index.test.tsx
Normal file
11
src/pages/Inventory/Bolts/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Inventory / Bolts page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Inventory/Checks/index.test.tsx
Normal file
11
src/pages/Inventory/Checks/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Inventory / Checks page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Inventory/Import/index.test.tsx
Normal file
11
src/pages/Inventory/Import/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Inventory / Import page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Inventory/Pans/index.test.tsx
Normal file
11
src/pages/Inventory/Pans/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Inventory / Pans page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Inventory/Products/index.test.tsx
Normal file
11
src/pages/Inventory/Products/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Inventory / Products page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Inventory/Stats/index.test.tsx
Normal file
11
src/pages/Inventory/Stats/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Inventory / Stats page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Inventory/Stocks/index.test.tsx
Normal file
11
src/pages/Inventory/Stocks/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Inventory / Stocks page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Login/index.test.tsx
Normal file
11
src/pages/Login/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Login page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Purchase/Orders/detail.test.tsx
Normal file
11
src/pages/Purchase/Orders/detail.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './detail';
|
||||
|
||||
describe('Purchase / Orders / detail page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Purchase/Orders/index.test.tsx
Normal file
11
src/pages/Purchase/Orders/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Purchase / Orders page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Purchase/Receipts/index.test.tsx
Normal file
11
src/pages/Purchase/Receipts/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Purchase / Receipts page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Purchase/Stats/index.test.tsx
Normal file
11
src/pages/Purchase/Stats/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Purchase / Stats page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/Purchase/Suppliers/index.test.tsx
Normal file
11
src/pages/Purchase/Suppliers/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('Purchase / Suppliers page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/System/Configs/index.test.tsx
Normal file
11
src/pages/System/Configs/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('System / Configs page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/System/Menus/index.test.tsx
Normal file
11
src/pages/System/Menus/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('System / Menus page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/System/Roles/index.test.tsx
Normal file
11
src/pages/System/Roles/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('System / Roles page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
11
src/pages/System/Users/index.test.tsx
Normal file
11
src/pages/System/Users/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { describe, vi } from 'vitest';
|
||||
|
||||
vi.mock('@umijs/max');
|
||||
vi.mock('@/services/api');
|
||||
|
||||
import { smokeTest } from '../../../../test/smoke';
|
||||
import Page from './index';
|
||||
|
||||
describe('System / Users page', () => {
|
||||
smokeTest(Page);
|
||||
});
|
||||
105
src/services/__mocks__/api.ts
Normal file
105
src/services/__mocks__/api.ts
Normal file
@ -0,0 +1,105 @@
|
||||
import { vi } from "vitest";
|
||||
|
||||
// Manual mock for the API layer. Every endpoint resolves with the standard
|
||||
// `{ code: 0, data }` envelope so pages can render without a live backend.
|
||||
// Object envelope covering the shapes pages read: `data.list` for paginated
|
||||
// tables plus the nested arrays detail pages iterate (`details`, etc.). All
|
||||
// default to empty so `.map`/`.length` access never throws.
|
||||
function makeData() {
|
||||
return {
|
||||
list: [],
|
||||
total: 0,
|
||||
records: [],
|
||||
nodes: [],
|
||||
edges: [],
|
||||
details: [],
|
||||
payments: [],
|
||||
receipts: [],
|
||||
items: [],
|
||||
children: [],
|
||||
bolts: [],
|
||||
pans: [],
|
||||
colors: [],
|
||||
};
|
||||
}
|
||||
|
||||
const ok = () => Promise.resolve({ code: 0, msg: "ok", success: true, data: makeData() });
|
||||
|
||||
export const login = vi.fn(() =>
|
||||
Promise.resolve({ code: 0, msg: "ok", data: { token: "test-token", userInfo: { tenantId: "t1", name: "tester" } } }),
|
||||
);
|
||||
export const getUserInfo = vi.fn(() =>
|
||||
Promise.resolve({ code: 0, msg: "ok", data: { name: "tester", menuPaths: [], roles: [] } }),
|
||||
);
|
||||
export const logout = vi.fn(ok);
|
||||
export const changePassword = vi.fn(ok);
|
||||
export const listUsers = vi.fn(ok);
|
||||
export const getUser = vi.fn(ok);
|
||||
export const createUser = vi.fn(ok);
|
||||
export const updateUser = vi.fn(ok);
|
||||
export const deleteUser = vi.fn(ok);
|
||||
export const updateUserStatus = vi.fn(ok);
|
||||
export const listRoles = vi.fn(ok);
|
||||
export const createRole = vi.fn(ok);
|
||||
export const updateRole = vi.fn(ok);
|
||||
export const deleteRole = vi.fn(ok);
|
||||
export const setRolePermissions = vi.fn(ok);
|
||||
export const listMenus = vi.fn(ok);
|
||||
export const createMenu = vi.fn(ok);
|
||||
export const updateMenu = vi.fn(ok);
|
||||
export const deleteMenu = vi.fn(ok);
|
||||
export const listLogs = vi.fn(ok);
|
||||
export const listConfigs = vi.fn(ok);
|
||||
export const updateConfig = vi.fn(ok);
|
||||
export const listProducts = vi.fn(ok);
|
||||
export const getProduct = vi.fn(ok);
|
||||
export const createProduct = vi.fn(ok);
|
||||
export const updateProduct = vi.fn(ok);
|
||||
export const deleteProduct = vi.fn(ok);
|
||||
export const exportProducts = vi.fn(ok);
|
||||
export const getProductSummary = vi.fn(ok);
|
||||
export const getColorDetail = vi.fn(ok);
|
||||
export const getProductTree = vi.fn(ok);
|
||||
export const listPans = vi.fn(ok);
|
||||
export const savePans = vi.fn(ok);
|
||||
export const listBolts = vi.fn(ok);
|
||||
export const saveBolts = vi.fn(ok);
|
||||
export const listPanView = vi.fn(ok);
|
||||
export const listBoltView = vi.fn(ok);
|
||||
export const getStockSummary = vi.fn(ok);
|
||||
export const getStockByColor = vi.fn(ok);
|
||||
export const getStockByLocation = vi.fn(ok);
|
||||
export const listStockChecks = vi.fn(ok);
|
||||
export const getStockCheck = vi.fn(ok);
|
||||
export const createStockCheck = vi.fn(ok);
|
||||
export const confirmStockCheck = vi.fn(ok);
|
||||
export const listStockAdjusts = vi.fn(ok);
|
||||
export const getStockAdjust = vi.fn(ok);
|
||||
export const createStockAdjust = vi.fn(ok);
|
||||
export const approveStockAdjust = vi.fn(ok);
|
||||
export const listUpstream = vi.fn(ok);
|
||||
export const listDownstream = vi.fn(ok);
|
||||
export const createRelation = vi.fn(ok);
|
||||
export const updateRelation = vi.fn(ok);
|
||||
export const listRelationHistory = vi.fn(ok);
|
||||
export const listSuppliers = vi.fn(ok);
|
||||
export const getSupplier = vi.fn(ok);
|
||||
export const createSupplier = vi.fn(ok);
|
||||
export const updateSupplier = vi.fn(ok);
|
||||
export const deleteSupplier = vi.fn(ok);
|
||||
export const listPurchaseOrders = vi.fn(ok);
|
||||
export const getPurchaseOrder = vi.fn(ok);
|
||||
export const createPurchaseOrder = vi.fn(ok);
|
||||
export const updatePurchaseOrder = vi.fn(ok);
|
||||
export const confirmPurchaseOrder = vi.fn(ok);
|
||||
export const cancelPurchaseOrder = vi.fn(ok);
|
||||
export const listPurchaseReceipts = vi.fn(ok);
|
||||
export const getPurchaseReceipt = vi.fn(ok);
|
||||
export const createPurchaseReceipt = vi.fn(ok);
|
||||
export const confirmPurchaseReceipt = vi.fn(ok);
|
||||
export const listPurchasePayments = vi.fn(ok);
|
||||
export const createPurchasePayment = vi.fn(ok);
|
||||
export const getPurchaseStatsSummary = vi.fn(ok);
|
||||
export const getPurchaseStatsBySupplier = vi.fn(ok);
|
||||
export const getPurchaseStatsByProduct = vi.fn(ok);
|
||||
export const listInventoryLogs = vi.fn(ok);
|
||||
80
test/setup.ts
Normal file
80
test/setup.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import '@testing-library/jest-dom/vitest';
|
||||
import { afterEach, vi } from 'vitest';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
|
||||
// jsdom is missing a handful of browser APIs that antd / pro-components touch on
|
||||
// mount. Provide minimal stand-ins so component pages can render in tests.
|
||||
|
||||
if (!window.matchMedia) {
|
||||
window.matchMedia = vi.fn().mockImplementation((query: string) => ({
|
||||
matches: false,
|
||||
media: query,
|
||||
onchange: null,
|
||||
addListener: vi.fn(),
|
||||
removeListener: vi.fn(),
|
||||
addEventListener: vi.fn(),
|
||||
removeEventListener: vi.fn(),
|
||||
dispatchEvent: vi.fn(),
|
||||
}));
|
||||
}
|
||||
|
||||
class ResizeObserverStub {
|
||||
observe() {}
|
||||
unobserve() {}
|
||||
disconnect() {}
|
||||
}
|
||||
// @ts-expect-error -- assigning test stub
|
||||
window.ResizeObserver = window.ResizeObserver || ResizeObserverStub;
|
||||
|
||||
class IntersectionObserverStub {
|
||||
root = null;
|
||||
rootMargin = '';
|
||||
thresholds = [];
|
||||
observe() {}
|
||||
unobserve() {}
|
||||
disconnect() {}
|
||||
takeRecords() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
// @ts-expect-error -- assigning test stub
|
||||
window.IntersectionObserver = window.IntersectionObserver || IntersectionObserverStub;
|
||||
|
||||
if (!window.scrollTo) {
|
||||
// @ts-expect-error -- jsdom does not implement scrollTo
|
||||
window.scrollTo = vi.fn();
|
||||
}
|
||||
|
||||
// Some pages read auth tokens from localStorage during render; ensure a working
|
||||
// Storage implementation is present regardless of the jsdom build.
|
||||
if (typeof window.localStorage?.getItem !== 'function') {
|
||||
const store = new Map<string, string>();
|
||||
const storage: Storage = {
|
||||
get length() {
|
||||
return store.size;
|
||||
},
|
||||
clear: () => store.clear(),
|
||||
getItem: (k: string) => (store.has(k) ? store.get(k)! : null),
|
||||
key: (i: number) => Array.from(store.keys())[i] ?? null,
|
||||
removeItem: (k: string) => void store.delete(k),
|
||||
setItem: (k: string, v: string) => void store.set(k, String(v)),
|
||||
};
|
||||
Object.defineProperty(window, 'localStorage', { value: storage, configurable: true });
|
||||
}
|
||||
|
||||
// jsdom's getContext is unimplemented; the CRM graph page guards against a null
|
||||
// context, so returning null keeps it on its safe path.
|
||||
if (!HTMLCanvasElement.prototype.getContext) {
|
||||
HTMLCanvasElement.prototype.getContext = () => null;
|
||||
}
|
||||
|
||||
// jsdom throws "Not implemented" when getComputedStyle is called with a
|
||||
// pseudo-element (rc-table does this while measuring scrollbars). Drop the
|
||||
// unsupported second argument so the call succeeds quietly.
|
||||
const originalGetComputedStyle = window.getComputedStyle.bind(window);
|
||||
window.getComputedStyle = ((elt: Element) =>
|
||||
originalGetComputedStyle(elt)) as typeof window.getComputedStyle;
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
25
test/smoke.tsx
Normal file
25
test/smoke.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { it, expect } from 'vitest';
|
||||
import { render, act, cleanup } from '@testing-library/react';
|
||||
import type { ComponentType } from 'react';
|
||||
|
||||
/**
|
||||
* Smoke test for a routed page entry: render it with its `@umijs/max` and
|
||||
* `@/services/api` dependencies mocked, flush the async data fetches that
|
||||
* pages kick off on mount, and assert it mounted without throwing. A render
|
||||
* error (or an error thrown from a settled effect) fails the test.
|
||||
*
|
||||
* Each page test file calls this so every frontend entry has its own case.
|
||||
*/
|
||||
export function smokeTest(Page: ComponentType<any>) {
|
||||
it('mounts without crashing', async () => {
|
||||
const { container } = render(<Page />);
|
||||
// Let the mocked API promises resolve and their state updates apply
|
||||
// inside act(), so pages that fetch on mount settle cleanly.
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
});
|
||||
expect(container).toBeInstanceOf(HTMLElement);
|
||||
cleanup();
|
||||
});
|
||||
}
|
||||
22
vitest.config.ts
Normal file
22
vitest.config.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import path from 'path';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, 'src'),
|
||||
'@@': path.resolve(__dirname, 'src/.umi'),
|
||||
},
|
||||
},
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
setupFiles: ['./test/setup.ts'],
|
||||
include: ['src/**/*.test.{ts,tsx}'],
|
||||
css: false,
|
||||
// Pages pull in antd + pro-components; allow a comfortable timeout.
|
||||
testTimeout: 15000,
|
||||
},
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user