让状态不变量校验先判字段类型再取值
src/features/ui-editor/stateInvariants.ts 在取 path.trim 与 pixel_size.every 前先判 string / Array.isArray,残缺持久化文档此前会在 firstUiDesignInvariantMessage 里抛 TypeError,被保存流程吞成通用失败文案 tests/uiEditorState.test.ts 补三组残缺界面图都回落到 invalid-image 的用例
This commit is contained in:
@@ -14,8 +14,12 @@ export function validateUiDesignState(state: State): UiDesignInvariantIssue[] {
|
|||||||
const issues: UiDesignInvariantIssue[] = [];
|
const issues: UiDesignInvariantIssue[] = [];
|
||||||
const nodeIds = new Set<string>();
|
const nodeIds = new Set<string>();
|
||||||
for (const [id, image] of Object.entries(state.ui_design_images)) {
|
for (const [id, image] of Object.entries(state.ui_design_images)) {
|
||||||
|
// 这个 seam 专门接住可能残缺的持久化 State,取字段前先判类型,别把 TypeError
|
||||||
|
// 漏给调用方,否则保存失败只会退化成通用文案。
|
||||||
if (
|
if (
|
||||||
|
typeof image.path !== 'string' ||
|
||||||
image.path.trim() === '' ||
|
image.path.trim() === '' ||
|
||||||
|
!Array.isArray(image.pixel_size) ||
|
||||||
!image.pixel_size.every((value) => Number.isFinite(value) && value > 0) ||
|
!image.pixel_size.every((value) => Number.isFinite(value) && value > 0) ||
|
||||||
!Number.isFinite(image.pixels_per_unit) ||
|
!Number.isFinite(image.pixels_per_unit) ||
|
||||||
image.pixels_per_unit <= 0
|
image.pixels_per_unit <= 0
|
||||||
|
|||||||
@@ -163,6 +163,22 @@ describe('useUiEditorState', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('reports malformed images instead of throwing', () => {
|
||||||
|
const state = structuredClone(EMPTY_UI_EDITOR_STATE);
|
||||||
|
for (const malformed of [
|
||||||
|
{ pixel_size: [100, 80], pixels_per_unit: 1 },
|
||||||
|
{ path: 'assets/page.png', pixels_per_unit: 1 },
|
||||||
|
{ path: 'assets/page.png', pixel_size: [0, 80], pixels_per_unit: 1 },
|
||||||
|
]) {
|
||||||
|
state.ui_design_images = {
|
||||||
|
page: malformed as unknown as UIDesignImage,
|
||||||
|
};
|
||||||
|
expect(validateUiDesignState(state)).toEqual([
|
||||||
|
expect.objectContaining({ code: 'invalid-image' }),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('moves a subtree between UI trees without changing its transform', () => {
|
it('moves a subtree between UI trees without changing its transform', () => {
|
||||||
const moved = nodeWithSprite('moved');
|
const moved = nodeWithSprite('moved');
|
||||||
const initial: State = {
|
const initial: State = {
|
||||||
|
|||||||
Reference in New Issue
Block a user