task-96(店铺中心): 实现店铺账号字段校验
新增 shop-manage-field-validators.ts:分组/店铺名/商城/账号/密码逐字段校验 与汇总,错误文案与后端 NotBlank/Size 规则一致。 TDD: task-96.test.ts 8 用例先 RED 后 GREEN。
This commit is contained in:
@@ -0,0 +1,54 @@
|
|||||||
|
/** 店铺中心逐字段校验(任务 96):账号/密码等店铺字段可独立校验,错误文案与后端 NotBlank/Size 一致;纯逻辑。 */
|
||||||
|
import type { ShopManageFormErrors, ShopManageFormValues } from './shop-manage-form-model.ts'
|
||||||
|
|
||||||
|
export const SHOP_MANAGE_ZN_USERNAME_MAX_LEN = 128
|
||||||
|
|
||||||
|
function requiredText(value: string): string {
|
||||||
|
return (value || '').trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateGroupId(value: number | null): string | undefined {
|
||||||
|
return typeof value === 'number' && Number.isFinite(value) && value >= 1 ? undefined : '分组不能为空'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateShopNameValue(value: string): string | undefined {
|
||||||
|
return requiredText(value) ? undefined : '店铺名称不能为空'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateMallNameValue(value: string): string | undefined {
|
||||||
|
return requiredText(value) ? undefined : '商城名称不能为空'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateAccount(value: string): string | undefined {
|
||||||
|
return requiredText(value) ? undefined : '账号不能为空'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validatePassword(value: string): string | undefined {
|
||||||
|
return requiredText(value) ? undefined : '密码不能为空'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateZnUsernameLength(value: string): string | undefined {
|
||||||
|
const trimmed = (value || '').trim()
|
||||||
|
if (trimmed.length > SHOP_MANAGE_ZN_USERNAME_MAX_LEN) {
|
||||||
|
return `自动化账号长度不能超过${SHOP_MANAGE_ZN_USERNAME_MAX_LEN}个字符`
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 汇总逐字段错误(供编辑/新增表单即时反馈)。 */
|
||||||
|
export function collectShopManageFieldErrors(form: ShopManageFormValues): ShopManageFormErrors {
|
||||||
|
const errors: ShopManageFormErrors = {}
|
||||||
|
const groupError = validateGroupId(form.groupId)
|
||||||
|
if (groupError) errors.groupId = groupError
|
||||||
|
const nameError = validateShopNameValue(form.shopName)
|
||||||
|
if (nameError) errors.shopName = nameError
|
||||||
|
const mallError = validateMallNameValue(form.mallName)
|
||||||
|
if (mallError) errors.mallName = mallError
|
||||||
|
const accountError = validateAccount(form.account)
|
||||||
|
if (accountError) errors.account = accountError
|
||||||
|
const passwordError = validatePassword(form.password)
|
||||||
|
if (passwordError) errors.password = passwordError
|
||||||
|
const znError = validateZnUsernameLength(form.znUsername)
|
||||||
|
if (znError) errors.znUsername = znError
|
||||||
|
return errors
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import test from 'node:test'
|
||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import { readSource } from './helpers.ts'
|
||||||
|
import {
|
||||||
|
collectShopManageFieldErrors,
|
||||||
|
validateAccount,
|
||||||
|
validateGroupId,
|
||||||
|
validateMallNameValue,
|
||||||
|
validatePassword,
|
||||||
|
validateShopNameValue,
|
||||||
|
validateZnUsernameLength,
|
||||||
|
} from '../src/pages/shop/shop-manage-field-validators.ts'
|
||||||
|
|
||||||
|
test('test_task_096_shop_field_validators_normal_primary_path', () => {
|
||||||
|
// 正常主路径:合法账号/密码字段无错误。
|
||||||
|
assert.equal(validateAccount('sale@a.com'), undefined)
|
||||||
|
assert.equal(validatePassword('p@ss'), undefined)
|
||||||
|
assert.equal(validateShopNameValue('BlueWave'), undefined)
|
||||||
|
assert.equal(validateGroupId(3), undefined)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_096_shop_field_validators_normal_variant_input', () => {
|
||||||
|
// 正常变体:可选自动化账号超长报错,其余字段各自独立。
|
||||||
|
assert.equal(validateZnUsernameLength('x'.repeat(128)), undefined)
|
||||||
|
assert.match(validateZnUsernameLength('y'.repeat(129)) || '', /128/)
|
||||||
|
assert.equal(validateMallNameValue(' '), '商城名称不能为空')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_096_shop_field_validators_repeated_is_idempotent', () => {
|
||||||
|
// 正常重复:逐字段校验结果稳定、不改输入。
|
||||||
|
assert.equal(validateAccount('a@b.c'), validateAccount('a@b.c'))
|
||||||
|
const form = { groupId: 2, shopName: 'S', mallName: 'M', znUsername: '', account: 'x', password: 'y' }
|
||||||
|
assert.deepEqual(collectShopManageFieldErrors(form), collectShopManageFieldErrors(form))
|
||||||
|
assert.deepEqual(form, { groupId: 2, shopName: 'S', mallName: 'M', znUsername: '', account: 'x', password: 'y' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_096_shop_field_validators_boundary_empty_input', () => {
|
||||||
|
// 边界空值:空白账号/密码返回必填错误。
|
||||||
|
assert.equal(validateAccount(' '), '账号不能为空')
|
||||||
|
assert.equal(validatePassword(''), '密码不能为空')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_096_shop_field_validators_boundary_single_item', () => {
|
||||||
|
// 边界单元素:单字段错误可独立定位。
|
||||||
|
const errors = collectShopManageFieldErrors({ groupId: null, shopName: 'S', mallName: 'M', znUsername: '', account: 'a', password: 'p' })
|
||||||
|
assert.equal(errors.groupId, '分组不能为空')
|
||||||
|
assert.equal('shopName' in errors, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_096_shop_field_validators_boundary_limit_or_missing_field', () => {
|
||||||
|
// 边界上限/缺字段:超长自动化账号/空白商城被定位;长度上限边界放行。
|
||||||
|
assert.equal(validateZnUsernameLength(''), undefined)
|
||||||
|
assert.equal(validateZnUsernameLength('a'.repeat(128)), undefined)
|
||||||
|
assert.match(validateZnUsernameLength('b'.repeat(129)) || '', /128/)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_096_shop_field_validators_invalid_input_rejected', () => {
|
||||||
|
// 异常输入:缺分组/空白店铺名均返回可操作错误。
|
||||||
|
assert.equal(validateGroupId(null), '分组不能为空')
|
||||||
|
assert.equal(validateGroupId(-1), '分组不能为空')
|
||||||
|
assert.equal(validateShopNameValue(' '), '店铺名称不能为空')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_096_shop_field_validators_dependency_failure_returns_actionable_message', () => {
|
||||||
|
// 依赖失败/可操作:字段校验纯逻辑,无框架/http;错误文案与后端 NotBlank 一致。
|
||||||
|
const mod = readSource('src/pages/shop/shop-manage-field-validators.ts')
|
||||||
|
assert.equal(/axios|http\.|vue/.test(mod), false, '字段校验保持纯逻辑')
|
||||||
|
assert.match(mod, /不能为空/)
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user