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",
|
"build": "max build",
|
||||||
"postinstall": "max setup",
|
"postinstall": "max setup",
|
||||||
"lint": "max lint",
|
"lint": "max lint",
|
||||||
"format": "prettier --write ."
|
"format": "prettier --write .",
|
||||||
|
"test": "vitest run",
|
||||||
|
"test:watch": "vitest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^5.6.1",
|
"@ant-design/icons": "^5.6.1",
|
||||||
"@ant-design/pro-components": "^2.8.7",
|
"@ant-design/pro-components": "^2.8.7",
|
||||||
"@umijs/max": "^4.4.8",
|
"@umijs/max": "^4.4.8",
|
||||||
"antd": "^5.24.2",
|
"antd": "^5.24.2",
|
||||||
"axios": "^1.8.4"
|
"axios": "^1.8.4",
|
||||||
|
"react": "18.3.1",
|
||||||
|
"react-dom": "18.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"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": "^18.3.18",
|
||||||
"@types/react-dom": "^18.3.5",
|
"@types/react-dom": "^18.3.5",
|
||||||
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
|
"jsdom": "^25.0.1",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"typescript": "^5.7.3"
|
"typescript": "^5.7.3",
|
||||||
|
"vitest": "^2.1.9"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.12.4+sha512.5ea8b0deed94ed68691c9bad4c955492705c5eeb8a87ef86bc62c74a26b037b08ff9570f108b2e4dbd1dd1a9186fea925e527f141c648e85af45631074680184"
|
"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