From 8b07321fbbdd788da8c63e9bb26aa78eb79e90ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=87=AA=E8=BE=BE?= <980324341@qq.com> Date: Sat, 5 Sep 2026 14:12:25 +0800 Subject: [PATCH] =?UTF-8?q?task-27(=E4=BC=9A=E8=AF=9D/=E8=8F=9C=E5=8D=95/?= =?UTF-8?q?=E6=9D=83=E9=99=90):=20=E9=94=81=E5=AE=9A=20Pinia=20admin-sessi?= =?UTF-8?q?on=20store=20=E5=88=9D=E5=A7=8B=E7=8A=B6=E6=80=81=E5=A5=91?= =?UTF-8?q?=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit state 工厂返回全新对象含 user/menuTree/initialized/loading/error 五字段, 默认 null/[]/false/''/'',无凭证字段;仅一个 defineStore,守卫与 getter 依赖该初始态。8 用例全过。 --- admin-frontend-vue/tests/task-27.test.ts | 64 ++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 admin-frontend-vue/tests/task-27.test.ts diff --git a/admin-frontend-vue/tests/task-27.test.ts b/admin-frontend-vue/tests/task-27.test.ts new file mode 100644 index 00000000..8ac5eb12 --- /dev/null +++ b/admin-frontend-vue/tests/task-27.test.ts @@ -0,0 +1,64 @@ +import test from 'node:test' +import assert from 'node:assert/strict' +import { readSource } from './helpers.ts' + +const store = readSource('src/stores/admin-session.ts') + +test('test_task_027_store_initial_state_normal_primary_path', () => { + // 正常主路径:state 以函数返回全新对象,含 5 个契约字段。 + assert.match(store, /state:\s*\(\)\s*=>\s*\(\{/, 'state 必须是返回对象字面量的工厂函数') + assert.match(store, /user:\s*null/) + assert.match(store, /menuTree:\s*\[\]/) + assert.match(store, /initialized:\s*false/) + assert.match(store, /loading:\s*false/) + assert.match(store, /error:\s*''/) +}) + +test('test_task_027_store_initial_state_normal_variant_input', () => { + // 正常变体:状态字段与模块契约字段一一对应,供 AdminLayout / guard 消费。 + assert.match(store, /user\b/) + assert.match(store, /menuTree\b/) + assert.match(store, /initialized\b/) + assert.match(store, /loading\b/) + assert.match(store, /error\b/) +}) + +test('test_task_027_store_initial_state_normal_repeated_operation_is_idempotent', () => { + // 正常重复:只声明一个 Pinia store 定义,实例由 useStore 工厂创建,不共享可变单例。 + assert.equal((store.match(/defineStore\(/g) || []).length, 1, '仅定义一个 admin-session store') + assert.match(store, /export const useAdminSessionStore\s*=\s*defineStore/) +}) + +test('test_task_027_store_initial_state_boundary_empty_input', () => { + // 边界空值:未登录时 user 为 null、error 为空串,而不是 undefined 残留。 + assert.match(store, /user:\s*null\s+as\s+AdminUser/) + assert.match(store, /error:\s*''/) +}) + +test('test_task_027_store_initial_state_boundary_single_item', () => { + // 边界单元素:初始时无任何用户/菜单,首次进入路由需触发初始化。 + assert.match(store, /initialized:\s*false/, '未初始化才能触发首次初始化') + const router = readSource('src/router/index.ts') + assert.match(router, /if\s*\(!session\.initialized\)/, '守卫在未初始化时调用 initialize') +}) + +test('test_task_027_store_initial_state_boundary_limit_or_missing_field', () => { + // 边界上限/缺字段:初始状态不携带任何凭证字段,凭证只走同源 Cookie。 + assert.equal(/\btoken\b|\bjwt\b|\bpassword\b/.test(store), false, 'store 初始状态不得保存凭证') +}) + +test('test_task_027_store_initial_state_invalid_input_rejected', () => { + // 异常输入:非法/未知状态字段不应出现(state 形状稳定)。 + assert.equal(/\bnickname\b|\bavatar\b/.test(store), false, 'store 不引入契约外字段') + assert.match(store, /import type \{ AdminMenuNode, AdminUser \}/) +}) + +test('test_task_027_store_initial_state_dependency_failure_returns_actionable_message', () => { + // 依赖失败:store 依赖会话 API 与 pinia,状态字段供 getter/action 消费。 + assert.match(store, /import \{ defineStore \} from 'pinia'/) + assert.match(store, /fetchCurrentUser/) + assert.match(store, /fetchAdminMenuTree/) + assert.match(store, /getters:/) + assert.match(store, /firstVisible:/) + assert.match(store, /isSuperAdmin:/) +})