Files
huangzd1997 837fc9bcc0 task-40(会话/菜单/权限): 真实登录态 smoke 收口本模块
用真实 admin 凭据打本地后端完成登录/cookie 会话/current-user/菜单树/401/
权限路由 smoke(8 场景全过)。smoke 暴露前端登出 URL 错误:session.ts 走
/api/admin/logout(后端无此映射,500),改为 auth 模块根端点 POST /logout;
同步修正 task-25/36 断言。注:当前本地后端 POST /logout 亦返回 500,属
Java 侧缺陷,待后端模块修复后补登出 E2E。
2026-09-05 14:43:59 +08:00

76 lines
4.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import test from 'node:test'
import assert from 'node:assert/strict'
import { readSource } from './helpers.ts'
import { loginRedirectTarget } from '../src/api/envelope.ts'
const httpSrc = readSource('src/api/http.ts')
const sessionSrc = readSource('src/api/session.ts')
test('test_task_025_cookie_session_config_normal_primary_path', () => {
// 正常主路径:共享传输开启同源 Cookie/SessionAxios withCredentials 必须开启)。
assert.match(httpSrc, /withCredentials:\s*true/, 'Cookie 规则:Axios withCredentials 必须开启')
assert.match(httpSrc, /baseURL:\s*'\/'/, '请求使用同源 Cookie/Session')
})
test('test_task_025_cookie_session_config_normal_variant_input', () => {
// 正常变体:current-user / menus / logout 三类会话调用全部复用同一共享 http 实例。
assert.match(sessionSrc, /import \{ http \} from '\.\/http'/)
const getCalls = (sessionSrc.match(/\bhttp\.get\b/g) || []).length
assert.equal(getCalls, 2, 'current-user 与 menus 两个 GET 均走共享 http')
assert.equal((sessionSrc.match(/\bhttp\.post\b/g) || []).length, 1, 'logout 走共享 http')
assert.match(sessionSrc, /current-user/)
assert.match(sessionSrc, /current-user\/menus/)
})
test('test_task_025_cookie_session_config_normal_repeated_operation_is_idempotent', () => {
// 正常重复:传输模块只创建一次 axios 实例,会话模块不另建客户端、不污染状态。
assert.equal((httpSrc.match(/axios\.create/g) || []).length, 1, '共享实例只创建一次')
assert.equal((sessionSrc.match(/axios\.create/g) || []).length, 0, '会话模块不自行创建新客户端')
assert.equal((sessionSrc.match(/import \{ http \}/g) || []).length, 1)
})
test('test_task_025_cookie_session_config_boundary_empty_input', () => {
// 边界空值:无登录态时请求层不把凭证写入本地/会话存储(前端不保存 JWT/密码)。
for (const rel of ['src/api/http.ts', 'src/api/session.ts']) {
const src = readSource(rel)
assert.equal((src.match(/localStorage/g) || []).length, 0, `${rel} 不得使用 localStorage`)
assert.equal((src.match(/sessionStorage/g) || []).length, 0, `${rel} 不得使用 sessionStorage`)
assert.equal(/document\.cookie\s*=/.test(src), false, `${rel} 不得直接写 document.cookie`)
}
})
test('test_task_025_cookie_session_config_boundary_single_item', () => {
// 边界单元素:登出是单次 POST,以 AJAX 标识发到共享实例,后端据此返回 JSON 而非页面。
assert.match(sessionSrc, /X-Requested-With/, '登出走 AJAX 标识以便后端识别为 JSON 请求')
assert.match(sessionSrc, /http\.post/)
assert.match(sessionSrc, /\/logout/, '登出走 auth 模块根端点 POST /logout')
assert.equal(sessionSrc.includes('/api/admin/logout'), false, '不应指向不存在的 /api/admin/logout')
})
test('test_task_025_cookie_session_config_boundary_limit_or_missing_field', () => {
// 边界上限/缺字段:即便会话在身,传输层也不注入 token/Authorization 头——
// 凭证只由同源 Cookie 携带,前端禁止保存并在后续请求回填。
for (const rel of ['src/api/http.ts', 'src/api/session.ts', 'src/api/session-model.ts']) {
const src = readSource(rel)
assert.equal(/\bAuthorization\b/.test(src), false, `${rel} 不应注入 Authorization 头`)
assert.equal(/\bBearer\b/.test(src), false, `${rel} 不应出现 Bearer token`)
}
})
test('test_task_025_cookie_session_config_invalid_input_rejected', () => {
// 异常输入:Cookie 规则要求 withCredentials 必须开启、同源根路径、有界超时。
assert.match(httpSrc, /withCredentials:\s*true/, '传输配置必须字面量开启 withCredentials')
assert.match(httpSrc, /baseURL:\s*'\/'/, '传输配置必须使用同源根路径')
assert.match(httpSrc, /timeout:\s*\d+/, '传输配置必须声明数值型有界超时')
})
test('test_task_025_cookie_session_config_dependency_failure_returns_actionable_message', () => {
// 依赖失败:会话失效/网络异常走同一拦截与解包兜底,且登录跳转携带当前目标路径。
assert.match(httpSrc, /interceptors\.response/, '存在 401/异常统一响应拦截')
assert.match(httpSrc, /unwrap/)
assert.match(httpSrc, /isUnauthorized/)
assert.match(httpSrc, /login\?redirect=/)
const target = loginRedirectTarget({ pathname: '/admin-vue/account/users', search: '?x=1' })
assert.equal(target, encodeURIComponent('/admin-vue/account/users?x=1'), 'redirect 需携带当前目标路径')
})