fix: c
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled

This commit is contained in:
2025-12-24 14:42:57 +08:00
parent 08e79c60e7
commit 7743cdc29a
49 changed files with 2179 additions and 4575 deletions

View File

@@ -1,189 +0,0 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { FormApi } from '../src/form-api';
describe('formApi', () => {
let formApi: FormApi;
beforeEach(() => {
formApi = new FormApi();
});
it('should initialize with default state', () => {
expect(formApi.state).toEqual(
expect.objectContaining({
actionWrapperClass: '',
collapsed: false,
collapsedRows: 1,
commonConfig: {},
handleReset: undefined,
handleSubmit: undefined,
layout: 'horizontal',
resetButtonOptions: {},
schema: [],
showCollapseButton: false,
showDefaultActions: true,
submitButtonOptions: {},
wrapperClass: 'grid-cols-1',
}),
);
expect(formApi.isMounted).toBe(false);
});
it('should mount form actions', async () => {
const formActions: any = {
meta: {},
resetForm: vi.fn(),
setFieldValue: vi.fn(),
setValues: vi.fn(),
submitForm: vi.fn(),
validate: vi.fn(),
values: { name: 'test' },
};
await formApi.mount(formActions);
expect(formApi.isMounted).toBe(true);
expect(formApi.form).toEqual(formActions);
});
it('should get values from form', async () => {
const formActions: any = {
meta: {},
values: { name: 'test' },
};
await formApi.mount(formActions);
const values = await formApi.getValues();
expect(values).toEqual({ name: 'test' });
});
it('should set field value', async () => {
const setFieldValueMock = vi.fn();
const formActions: any = {
meta: {},
setFieldValue: setFieldValueMock,
values: { name: 'test' },
};
await formApi.mount(formActions);
await formApi.setFieldValue('name', 'new value');
expect(setFieldValueMock).toHaveBeenCalledWith(
'name',
'new value',
undefined,
);
});
it('should reset form', async () => {
const resetFormMock = vi.fn();
const formActions: any = {
meta: {},
resetForm: resetFormMock,
values: { name: 'test' },
};
await formApi.mount(formActions);
await formApi.resetForm();
expect(resetFormMock).toHaveBeenCalled();
});
it('should call handleSubmit on submit', async () => {
const handleSubmitMock = vi.fn();
const formActions: any = {
meta: {},
submitForm: vi.fn().mockResolvedValue(true),
values: { name: 'test' },
};
const state = {
handleSubmit: handleSubmitMock,
};
formApi.setState(state);
await formApi.mount(formActions);
const result = await formApi.submitForm();
expect(formActions.submitForm).toHaveBeenCalled();
expect(handleSubmitMock).toHaveBeenCalledWith({ name: 'test' });
expect(result).toEqual({ name: 'test' });
});
it('should unmount form and reset state', () => {
formApi.unmount();
expect(formApi.isMounted).toBe(false);
});
it('should validate form', async () => {
const validateMock = vi.fn().mockResolvedValue(true);
const formActions: any = {
meta: {},
validate: validateMock,
};
await formApi.mount(formActions);
const isValid = await formApi.validate();
expect(validateMock).toHaveBeenCalled();
expect(isValid).toBe(true);
});
});
describe('updateSchema', () => {
let instance: FormApi;
beforeEach(() => {
instance = new FormApi();
instance.state = {
schema: [
{ component: 'text', fieldName: 'name' },
{ component: 'number', fieldName: 'age', label: 'Age' },
],
};
});
it('should update the schema correctly when fieldName matches', () => {
const newSchema = [
{ component: 'text', fieldName: 'name' },
{ component: 'number', fieldName: 'age', label: 'Age' },
];
instance.updateSchema(newSchema);
expect(instance.state?.schema?.[0]?.component).toBe('text');
expect(instance.state?.schema?.[1]?.label).toBe('Age');
});
it('should log an error if fieldName is missing in some items', () => {
const newSchema: any[] = [
{ component: 'textarea', fieldName: 'name' },
{ component: 'number' },
];
const consoleErrorSpy = vi
.spyOn(console, 'error')
.mockImplementation(() => {});
instance.updateSchema(newSchema);
expect(consoleErrorSpy).toHaveBeenCalledWith(
'All items in the schema array must have a valid `fieldName` property to be updated',
);
});
it('should not update schema if fieldName does not match', () => {
const newSchema = [{ component: 'textarea', fieldName: 'unknown' }];
instance.updateSchema(newSchema);
expect(instance.state?.schema?.[0]?.component).toBe('text');
expect(instance.state?.schema?.[1]?.component).toBe('number');
});
it('should not update schema if updatedMap is empty', () => {
const newSchema: any[] = [{ component: 'textarea' }];
instance.updateSchema(newSchema);
expect(instance.state?.schema?.[0]?.component).toBe('text');
expect(instance.state?.schema?.[1]?.component).toBe('number');
});
});

View File

@@ -1,116 +0,0 @@
import type { DrawerState } from '../drawer';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { DrawerApi } from '../drawer-api';
// 模拟 Store 类
vi.mock('@vben-core/shared/store', () => {
return {
isFunction: (fn: any) => typeof fn === 'function',
Store: class {
get state() {
return this._state;
}
private _state: DrawerState;
private options: any;
constructor(initialState: DrawerState, options: any) {
this._state = initialState;
this.options = options;
}
batch(cb: () => void) {
cb();
}
setState(fn: (prev: DrawerState) => DrawerState) {
this._state = fn(this._state);
this.options.onUpdate();
}
},
};
});
describe('drawerApi', () => {
let drawerApi: DrawerApi;
let drawerState: DrawerState;
beforeEach(() => {
drawerApi = new DrawerApi();
drawerState = drawerApi.store.state;
});
it('should initialize with default state', () => {
expect(drawerState.isOpen).toBe(false);
expect(drawerState.cancelText).toBe(undefined);
expect(drawerState.confirmText).toBe(undefined);
});
it('should open the drawer', () => {
drawerApi.open();
expect(drawerApi.store.state.isOpen).toBe(true);
});
it('should close the drawer if onBeforeClose allows it', () => {
drawerApi.close();
expect(drawerApi.store.state.isOpen).toBe(false);
});
it('should not close the drawer if onBeforeClose returns false', () => {
const onBeforeClose = vi.fn(() => false);
const drawerApiWithHook = new DrawerApi({ onBeforeClose });
drawerApiWithHook.open();
drawerApiWithHook.close();
expect(drawerApiWithHook.store.state.isOpen).toBe(true);
expect(onBeforeClose).toHaveBeenCalled();
});
it('should trigger onCancel and keep drawer open if onCancel is provided', () => {
const onCancel = vi.fn();
const drawerApiWithHook = new DrawerApi({ onCancel });
drawerApiWithHook.open();
drawerApiWithHook.onCancel();
expect(onCancel).toHaveBeenCalled();
expect(drawerApiWithHook.store.state.isOpen).toBe(true); // 关闭逻辑不在 onCancel 内
});
it('should update shared data correctly', () => {
const testData = { key: 'value' };
drawerApi.setData(testData);
expect(drawerApi.getData()).toEqual(testData);
});
it('should set state correctly using an object', () => {
drawerApi.setState({ title: 'New Title' });
expect(drawerApi.store.state.title).toBe('New Title');
});
it('should set state correctly using a function', () => {
drawerApi.setState((prev) => ({ ...prev, confirmText: 'Yes' }));
expect(drawerApi.store.state.confirmText).toBe('Yes');
});
it('should call onOpenChange when state changes', () => {
const onOpenChange = vi.fn();
const drawerApiWithHook = new DrawerApi({ onOpenChange });
drawerApiWithHook.open();
expect(onOpenChange).toHaveBeenCalledWith(true);
});
it('should call onClosed callback when provided', () => {
const onClosed = vi.fn();
const drawerApiWithHook = new DrawerApi({ onClosed });
drawerApiWithHook.onClosed();
expect(onClosed).toHaveBeenCalled();
});
it('should call onOpened callback when provided', () => {
const onOpened = vi.fn();
const drawerApiWithHook = new DrawerApi({ onOpened });
drawerApiWithHook.open();
drawerApiWithHook.onOpened();
expect(onOpened).toHaveBeenCalled();
});
});

View File

@@ -1,117 +0,0 @@
import type { ModalState } from '../modal';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { ModalApi } from '../modal-api';
vi.mock('@vben-core/shared/store', () => {
return {
isFunction: (fn: any) => typeof fn === 'function',
Store: class {
get state() {
return this._state;
}
private _state: ModalState;
private options: any;
constructor(initialState: ModalState, options: any) {
this._state = initialState;
this.options = options;
}
batch(cb: () => void) {
cb();
}
setState(fn: (prev: ModalState) => ModalState) {
this._state = fn(this._state);
this.options.onUpdate();
}
},
};
});
describe('modalApi', () => {
let modalApi: ModalApi;
// 使用 modalState 而不是 state
let modalState: ModalState;
beforeEach(() => {
modalApi = new ModalApi();
// 获取 modalApi 内的 state
modalState = modalApi.store.state;
});
it('should initialize with default state', () => {
expect(modalState.isOpen).toBe(false);
expect(modalState.cancelText).toBe(undefined);
expect(modalState.confirmText).toBe(undefined);
});
it('should open the modal', () => {
modalApi.open();
expect(modalApi.store.state.isOpen).toBe(true);
});
it('should close the modal if onBeforeClose allows it', () => {
modalApi.close();
expect(modalApi.store.state.isOpen).toBe(false);
});
it('should not close the modal if onBeforeClose returns false', () => {
const onBeforeClose = vi.fn(() => false);
const modalApiWithHook = new ModalApi({ onBeforeClose });
modalApiWithHook.open();
modalApiWithHook.close();
expect(modalApiWithHook.store.state.isOpen).toBe(true);
expect(onBeforeClose).toHaveBeenCalled();
});
it('should trigger onCancel and close the modal if no onCancel hook is provided', () => {
const onCancel = vi.fn();
const modalApiWithHook = new ModalApi({ onCancel });
modalApiWithHook.open();
modalApiWithHook.onCancel();
expect(onCancel).toHaveBeenCalled();
expect(modalApiWithHook.store.state.isOpen).toBe(true);
});
it('should update shared data correctly', () => {
const testData = { key: 'value' };
modalApi.setData(testData);
expect(modalApi.getData()).toEqual(testData);
});
it('should set state correctly using an object', () => {
modalApi.setState({ title: 'New Title' });
expect(modalApi.store.state.title).toBe('New Title');
});
it('should set state correctly using a function', () => {
modalApi.setState((prev) => ({ ...prev, confirmText: 'Yes' }));
expect(modalApi.store.state.confirmText).toBe('Yes');
});
it('should call onOpenChange when state changes', () => {
const onOpenChange = vi.fn();
const modalApiWithHook = new ModalApi({ onOpenChange });
modalApiWithHook.open();
expect(onOpenChange).toHaveBeenCalledWith(true);
});
it('should call onClosed callback when provided', () => {
const onClosed = vi.fn();
const modalApiWithHook = new ModalApi({ onClosed });
modalApiWithHook.onClosed();
expect(onClosed).toHaveBeenCalled();
});
it('should call onOpened callback when provided', () => {
const onOpened = vi.fn();
const modalApiWithHook = new ModalApi({ onOpened });
modalApiWithHook.open();
modalApiWithHook.onOpened();
expect(onOpened).toHaveBeenCalled();
});
});