ln-522-manual-tester
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePaths: File paths (,shared/,references/) are relative to skills repo root. If not found at CWD, locate this SKILL.md directory and go up one level for repo root.../ln-*
路径说明: 文件路径(、shared/、references/)均相对于技能仓库根目录。如果在当前工作目录找不到,请定位到该SKILL.md所在目录,再向上一级即为仓库根目录。../ln-*
Manual Tester
手动测试工具
Manually verifies Story AC on running code and reports structured results for the quality gate.
在运行的代码上手动验证Story AC,并向质量门禁上报结构化结果。
Purpose & Scope
目的与适用范围
- Create executable test scripts in folder of target project.
tests/manual/ - Run AC-driven checks via bash/curl (API) or puppeteer (UI).
- Save scripts permanently for regression testing (not temp files).
- Document results in Linear with pass/fail per AC and script path.
- No status changes or task creation.
- 在目标项目的文件夹下创建可执行测试脚本。
tests/manual/ - 通过bash/curl(API场景)或puppeteer(UI场景)执行AC驱动的校验。
- 永久保存脚本用于回归测试(不得使用临时文件)。
- 在Linear中记录测试结果,标注每个AC的通过/失败状态以及脚本路径。
- 不修改状态或创建新任务。
When to Use
适用场景
- Invoked by ln-520-test-planner after ln-521-test-researcher completes
- Research comment "## Test Research:" exists on Story (from ln-521)
- All implementation tasks in Story status = Done
- 在ln-521-test-researcher完成工作后,由ln-520-test-planner调用
- Story上存在来自ln-521的"## Test Research:"调研注释
- Story下所有实现任务的状态均为Done
Test Design Principles
测试设计原则
1. Fail-Fast - No Silent Failures
1. 快速失败 - 无静默故障
CRITICAL: Tests MUST return 1 (fail) immediately when any criterion is not met.
Never use: for validation failures, graceful degradation without explicit flags, silent fallbacks that hide errors.
print_status "WARN" + return 0Exceptions (WARN is OK): Informational warnings that don't affect correctness, optional features (with clear justification in comments), infrastructure issues (e.g., missing Nginx in dev environment).
核心要求: 当任何条件不满足时,测试必须立即返回1(失败)。
禁止使用: 校验失败时使用、无显式标记的优雅降级、隐藏错误的静默降级逻辑。
print_status "WARN" + return 0例外情况(允许WARN): 不影响正确性的提示性警告、可选功能(需在注释中明确说明理由)、基础设施问题(例如开发环境缺少Nginx)。
2. Expected-Based Testing - The Golden Standard
2. 基于预期值测试 - 黄金准则
CRITICAL: Tests MUST compare actual results against expected reference files, not apply heuristics or algorithmic checks.
Directory structure:
tests/manual/NN-feature/
├── samples/ # Input files
├── expected/ # Expected output files (REQUIRED!)
│ └── {base_name}_{source_lang}-{target_lang}.{ext}
└── test-*.shHeuristics acceptable ONLY for: dynamic/non-deterministic data (timestamps, UUIDs, tokens - normalize before comparison; JSON with unordered keys - use ).
jq --sort-keys核心要求: 测试必须将实际结果与预期参考文件对比,不得使用启发式或算法校验。
目录结构:
tests/manual/NN-feature/
├── samples/ # Input files
├── expected/ # Expected output files (REQUIRED!)
│ └── {base_name}_{source_lang}-{target_lang}.{ext}
└── test-*.sh仅以下场景允许使用启发式校验: 动态/非确定性数据(时间戳、UUID、token - 对比前先做标准化;键顺序无序的JSON - 使用处理)。
jq --sort-keys3. Results Storage
3. 结果存储
Test results saved to (persistent, in .gitignore). Named: or . Inspectable after test completion for debugging.
tests/manual/results/result_{ac_name}.{ext}response_{ac_name}.json测试结果保存在目录下(持久化存储,加入.gitignore),命名规则为: 或 ,测试完成后可查看结果用于调试。
tests/manual/results/result_{ac_name}.{ext}response_{ac_name}.json4. Expected File Generation
4. 预期文件生成
To create expected files:
- Run test with current implementation
- Review output in folder
results/ - If correct: copy to folder with proper naming
expected/ - If incorrect: fix implementation first, then copy
IMPORTANT: Never blindly copy results to expected. Always validate correctness first.
创建预期文件的步骤:
- 基于当前实现运行测试
- 检查文件夹下的输出
results/ - 如果结果正确:按照规范命名后复制到文件夹
expected/ - 如果结果错误:先修复实现,再复制
重要提示: 切勿盲目将结果复制到预期文件夹,必须先验证结果的正确性。
Workflow
工作流程
Phase 1: Setup tests/manual structure
阶段1:搭建tests/manual目录结构
- Read — get Docker commands, API base URL, test prerequisites, environment setup
docs/project/runbook.md - Check if folder exists in project root
tests/manual/ - If missing, create structure:
- — shared configuration (BASE_URL, helpers, colors)
tests/manual/config.sh - — folder documentation (see README.md template below)
tests/manual/README.md - — master script to run all test suites (see test-all.sh template below)
tests/manual/test-all.sh - — folder for test outputs (add to
tests/manual/results/).gitignore
- Add to project
tests/manual/results/if not present.gitignore - If exists, read existing to reuse settings (BASE_URL, tokens)
config.sh
- 阅读— 获取Docker命令、API基础地址、测试前置条件、环境配置说明
docs/project/runbook.md - 检查项目根目录下是否存在文件夹
tests/manual/ - 如果不存在,创建以下结构:
- — 共享配置(BASE_URL、工具函数、颜色配置)
tests/manual/config.sh - — 目录说明文档(参考下方的README.md模板)
tests/manual/README.md - — 运行所有测试套件的主脚本(参考下方的test-all.sh模板)
tests/manual/test-all.sh - — 测试输出目录(加入
tests/manual/results/).gitignore
- 如果未加入项目
tests/manual/results/,则添加进去.gitignore - 如果目录已存在,读取现有复用配置(BASE_URL、token)
config.sh
Phase 2: Create Story test script
阶段2:创建Story测试脚本
- Fetch Story, parse AC into Given/When/Then list (3-5 expected)
- Check for research comment (from ln-521-test-researcher) — incorporate findings into test cases
- Detect API vs UI (API → curl, UI → puppeteer)
- Create test folder structure:
- — input files (if needed)
tests/manual/{NN}-{story-slug}/samples/ - — expected output files (REQUIRED for deterministic tests)
tests/manual/{NN}-{story-slug}/expected/
- Generate test script:
tests/manual/{NN}-{story-slug}/test-{story-slug}.sh- Use appropriate template: TEMPLATE-api-endpoint.sh (direct calls) or TEMPLATE-document-format.sh (async jobs)
- Header: Story ID, AC list, prerequisites
- Test function per AC + edge/error cases
- diff-based validation against expected files (PRIMARY)
- Results saved to
tests/manual/results/ - Summary table with timing
- Make script executable ()
chmod +x
- 拉取Story,将AC拆解为Given/When/Then列表(3-5个预期结果)
- 检查调研注释(来自ln-521-test-researcher)— 将调研结论纳入测试用例
- 区分测试类型是API还是UI(API用curl,UI用puppeteer)
- 创建测试目录结构:
- — 输入文件(如需要)
tests/manual/{NN}-{story-slug}/samples/ - — 预期输出文件(确定性测试必填)
tests/manual/{NN}-{story-slug}/expected/
- 生成测试脚本:
tests/manual/{NN}-{story-slug}/test-{story-slug}.sh- 使用对应模板:TEMPLATE-api-endpoint.sh(直接调用场景)或TEMPLATE-document-format.sh(异步任务场景)
- 头部信息:Story ID、AC列表、前置条件
- 每个AC对应一个测试函数 + 边界/错误场景
- 基于diff对比预期文件的校验方式(主要校验方式)
- 结果保存到
tests/manual/results/ - 带耗时统计的汇总表格
- 给脚本添加可执行权限()
chmod +x
Phase 3: Update Documentation
阶段3:更新文档
- Update :
tests/manual/README.md- Add new test to "Available Test Suites" table
- Include Story ID, AC covered, run command
- Update :
tests/manual/test-all.sh- Add call to new script in SUITES array
- Maintain execution order (00-setup first, then numbered suites)
- 更新:
tests/manual/README.md- 在"可用测试套件"表格中新增本次测试
- 包含Story ID、覆盖的AC、运行命令
- 更新:
tests/manual/test-all.sh- 在SUITES数组中添加对新脚本的调用
- 保持执行顺序(00-setup优先,之后按编号顺序执行)
Phase 4: Execute and report
阶段4:执行测试并上报结果
- Rebuild Docker containers (no cache), ensure healthy
- Run generated script, capture output
- Parse results (pass/fail counts)
- Post Linear comment with:
- AC matrix (pass/fail per AC)
- Script path:
tests/manual/{NN}-{story-slug}/test-{story-slug}.sh - Rerun command:
cd tests/manual && ./{NN}-{story-slug}/test-{story-slug}.sh
- 无缓存重建Docker容器,确保容器健康
- 运行生成的脚本,捕获输出
- 解析结果(通过/失败统计)
- 在Linear中发布评论,包含:
- AC矩阵(每个AC的通过/失败状态)
- 脚本路径:
tests/manual/{NN}-{story-slug}/test-{story-slug}.sh - 重跑命令:
cd tests/manual && ./{NN}-{story-slug}/test-{story-slug}.sh
Critical Rules
核心规则
- Scripts saved to project , NOT temp files.
tests/manual/ - Rebuild Docker before testing; fail if rebuild/run unhealthy.
- Keep language of Story (EN/RU) in script comments and Linear comment.
- No fixes or status changes; only evidence and verdict.
- Script must be idempotent (can rerun anytime).
- 脚本保存在项目目录下,不得使用临时文件。
tests/manual/ - 测试前重建Docker;如果重建/运行不健康则测试失败。
- 脚本注释和Linear评论保留Story的原始语言(英文/俄文)。
- 不做代码修复或状态修改,仅提供证据和结论。
- 脚本必须是幂等的(可随时重复运行)。
Definition of Done
完成定义
- structure exists (config.sh, README.md, test-all.sh, results/ created if missing).
tests/manual/ - added to project
tests/manual/results/..gitignore - Test script created at .
tests/manual/{NN}-{story-slug}/test-{story-slug}.sh - folder created with at least 1 expected file per deterministic AC.
expected/ - Script uses diff-based validation against expected files (not heuristics).
- Script saves results to for debugging.
tests/manual/results/ - Script is executable and idempotent.
- README.md updated with new test suite in "Available Test Suites" table.
- test-all.sh updated with call to new script in SUITES array.
- App rebuilt and running; tests executed.
- Verdict and Linear comment posted with script path and rerun command.
- 结构完整(如缺失则创建config.sh、README.md、test-all.sh、results/)。
tests/manual/ - 已加入项目
tests/manual/results/。.gitignore - 测试脚本已创建在路径下。
tests/manual/{NN}-{story-slug}/test-{story-slug}.sh - 文件夹已创建,每个确定性AC至少对应1个预期文件。
expected/ - 脚本使用基于diff对比预期文件的校验方式(非启发式校验)。
- 脚本将结果保存到用于调试。
tests/manual/results/ - 脚本具备可执行权限且是幂等的。
- README.md已更新,在"可用测试套件"表格中新增了本次测试套件。
- test-all.sh已更新,在SUITES数组中添加了对新脚本的调用。
- 应用已重建并运行;测试已执行。
- 已发布Linear评论,包含测试结论、脚本路径和重跑命令。
Script Templates
脚本模板
README.md (created once per project)
README.md(每个项目创建一次)
markdown
undefinedmarkdown
undefinedManual Testing Scripts
Manual Testing Scripts
SCOPE: Bash scripts for manual API testing. Complements automated tests with CLI-based workflows.
SCOPE: Bash scripts for manual API testing. Complements automated tests with CLI-based workflows.
Quick Start
Quick Start
bash
cd tests/manual
./00-setup/create-account.sh # (if auth required)
./test-all.sh # Run ALL test suitesbash
cd tests/manual
./00-setup/create-account.sh # (if auth required)
./test-all.sh # Run ALL test suitesPrerequisites
Prerequisites
- Docker containers running ()
docker compose ps - jq installed (or
apt-get install jq)brew install jq
- Docker containers running ()
docker compose ps - jq installed (or
apt-get install jq)brew install jq
Folder Structure
Folder Structure
tests/manual/
├── config.sh # Shared configuration (BASE_URL, helpers, colors)
├── README.md # This file
├── test-all.sh # Run all test suites
├── 00-setup/ # Account & token setup (if auth required)
│ ├── create-account.sh
│ └── get-token.sh
└── {NN}-{topic}/ # Test suites by Story
└── test-{slug}.shtests/manual/
├── config.sh # Shared configuration (BASE_URL, helpers, colors)
├── README.md # This file
├── test-all.sh # Run all test suites
├── 00-setup/ # Account & token setup (if auth required)
│ ├── create-account.sh
│ └── get-token.sh
└── {NN}-{topic}/ # Test suites by Story
└── test-{slug}.shAvailable Test Suites
Available Test Suites
<!-- Add new test suites here when creating new tests -->
| Suite | Story | AC Covered | Run Command |
|---|---|---|---|
| — | — | — | — |
<!-- Add new test suites here when creating new tests -->
| Suite | Story | AC Covered | Run Command |
|---|---|---|---|
| — | — | — | — |
Adding New Tests
Adding New Tests
- Create script in
{NN}-{topic}/test-{slug}.sh - Update this README (Available Test Suites table)
- Update (add to SUITES array)
test-all.sh
undefined- Create script in
{NN}-{topic}/test-{slug}.sh - Update this README (Available Test Suites table)
- Update (add to SUITES array)
test-all.sh
undefinedtest-all.sh (created once per project)
test-all.sh(每个项目创建一次)
bash
#!/bin/bashbash
#!/bin/bash=============================================================================
=============================================================================
Run all manual test suites
Run all manual test suites
=============================================================================
=============================================================================
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config.sh"
echo "=========================================="
echo "Running ALL Manual Test Suites"
echo "=========================================="
check_jq
check_api
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config.sh"
echo "=========================================="
echo "Running ALL Manual Test Suites"
echo "=========================================="
check_jq
check_api
Setup (if exists)
Setup (if exists)
[ -f "$SCRIPT_DIR/00-setup/create-account.sh" ] && "$SCRIPT_DIR/00-setup/create-account.sh"
[ -f "$SCRIPT_DIR/00-setup/get-token.sh" ] && "$SCRIPT_DIR/00-setup/get-token.sh"
[ -f "$SCRIPT_DIR/00-setup/create-account.sh" ] && "$SCRIPT_DIR/00-setup/create-account.sh"
[ -f "$SCRIPT_DIR/00-setup/get-token.sh" ] && "$SCRIPT_DIR/00-setup/get-token.sh"
Test suites (add new suites here)
Test suites (add new suites here)
SUITES=(
# "01-auth/test-auth-flow.sh"
# "02-translation/test-translation.sh"
)
PASSED=0; FAILED=0
for suite in "${SUITES[@]}"; do
echo ""
echo "=========================================="
echo "Running: $suite"
echo "=========================================="
if "$SCRIPT_DIR/$suite"; then
((++PASSED))
print_status "PASS" "$suite"
else
((++FAILED))
print_status "FAIL" "$suite"
fi
done
echo ""
echo "=========================================="
echo "TOTAL: $PASSED suites passed, $FAILED failed"
echo "=========================================="
[ $FAILED -eq 0 ] && exit 0 || exit 1
undefinedSUITES=(
# "01-auth/test-auth-flow.sh"
# "02-translation/test-translation.sh"
)
PASSED=0; FAILED=0
for suite in "${SUITES[@]}"; do
echo ""
echo "=========================================="
echo "Running: $suite"
echo "=========================================="
if "$SCRIPT_DIR/$suite"; then
((++PASSED))
print_status "PASS" "$suite"
else
((++FAILED))
print_status "FAIL" "$suite"
fi
done
echo ""
echo "=========================================="
echo "TOTAL: $PASSED suites passed, $FAILED failed"
echo "=========================================="
[ $FAILED -eq 0 ] && exit 0 || exit 1
undefinedconfig.sh (created once per project)
config.sh(每个项目创建一次)
bash
#!/bin/bashbash
#!/bin/bashShared configuration for manual testing scripts
Shared configuration for manual testing scripts
export BASE_URL="${BASE_URL:-http://localhost:8080}"
export RED='\033[0;31m'
export GREEN='\033[0;32m'
export YELLOW='\033[1;33m'
export NC='\033[0m'
print_status() {
local status=$1; local message=$2
case $status in
"PASS") echo -e "${GREEN}[PASS]${NC} $message" ;;
"FAIL") echo -e "${RED}[FAIL]${NC} $message" ;;
"WARN") echo -e "${YELLOW}[WARN]${NC} $message" ;;
"INFO") echo -e "[INFO] $message" ;;
esac
}
check_jq() {
command -v jq &> /dev/null || { echo "Error: jq required"; exit 1; }
}
check_api() {
local response=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/health" 2>/dev/null)
if [ "$response" != "200" ]; then
echo "Error: API not reachable at $BASE_URL"
exit 1
fi
print_status "INFO" "API reachable at $BASE_URL"
}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export SCRIPT_DIR
undefinedexport BASE_URL="${BASE_URL:-http://localhost:8080}"
export RED='\033[0;31m'
export GREEN='\033[0;32m'
export YELLOW='\033[1;33m'
export NC='\033[0m'
print_status() {
local status=$1; local message=$2
case $status in
"PASS") echo -e "${GREEN}[PASS]${NC} $message" ;;
"FAIL") echo -e "${RED}[FAIL]${NC} $message" ;;
"WARN") echo -e "${YELLOW}[WARN]${NC} $message" ;;
"INFO") echo -e "[INFO] $message" ;;
esac
}
check_jq() {
command -v jq &> /dev/null || { echo "Error: jq required"; exit 1; }
}
check_api() {
local response=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/health" 2>/dev/null)
if [ "$response" != "200" ]; then
echo "Error: API not reachable at $BASE_URL"
exit 1
fi
print_status "INFO" "API reachable at $BASE_URL"
}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export SCRIPT_DIR
undefinedTest Script Templates
测试脚本模板
See: references/templates/
| Template | Use Case | Location |
|---|---|---|
| template-api-endpoint.sh | API endpoint tests (NO async jobs) | template-api-endpoint.sh |
| template-document-format.sh | Document/file processing (WITH async jobs) | template-document-format.sh |
Quick start:
bash
cp references/templates/template-api-endpoint.sh {NN}-feature/test-{feature}.sh # Endpoint tests
cp references/templates/template-document-format.sh {NN}-feature/test-{format}.sh # Document tests查看: references/templates/
| 模板 | 适用场景 | 位置 |
|---|---|---|
| template-api-endpoint.sh | API端点测试(无异步任务) | template-api-endpoint.sh |
| template-document-format.sh | 文档/文件处理(含异步任务) | template-document-format.sh |
快速开始:
bash
cp references/templates/template-api-endpoint.sh {NN}-feature/test-{feature}.sh # Endpoint tests
cp references/templates/template-document-format.sh {NN}-feature/test-{format}.sh # Document testsReference Files
参考文件
- Script format reference: prompsit-api (production example)
tests/manual/ - AC format: (or local
shared/templates/test_task_template.mdin target project)docs/templates/ - Risk-based context:
shared/references/risk_based_testing_guide.md - Research findings: ln-521-test-researcher creates "## Test Research" comment on Story
Version: 1.0.0
Last Updated: 2026-01-15
- 脚本格式参考:prompsit-api (生产环境示例)
tests/manual/ - AC格式:(或目标项目本地的
shared/templates/test_task_template.md)docs/templates/ - 基于风险的测试上下文:
shared/references/risk_based_testing_guide.md - 调研结论:ln-521-test-researcher在Story上创建的"## Test Research"注释
版本: 1.0.0
最后更新: 2026-01-15