mirror of
https://gitee.com/kekingcn/file-online-preview.git
synced 2026-04-30 12:06:46 +00:00
Compare commits
6 Commits
fix/e2e-ph
...
fix/trust-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2abedc34b4 | ||
|
|
a20606bf33 | ||
|
|
5ba88d1243 | ||
|
|
6bcefedd08 | ||
|
|
084bdc9012 | ||
|
|
1aa477bdf8 |
5
.github/ISSUE_TEMPLATE/config.yml
vendored
5
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +0,0 @@
|
|||||||
blank_issues_enabled: false
|
|
||||||
contact_links:
|
|
||||||
- name: "Security Report / 安全漏洞报告"
|
|
||||||
url: "https://github.com/kekingcn/kkFileView/security/advisories/new"
|
|
||||||
about: "For sensitive security issues, please use private security report. / 涉及敏感安全问题请使用私密安全报告。"
|
|
||||||
76
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
76
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@@ -1,76 +0,0 @@
|
|||||||
name: "Feature Request / 功能建议"
|
|
||||||
description: "Propose a new feature with clear use case and acceptance criteria. / 提交功能建议,请明确场景与验收标准。"
|
|
||||||
title: "[FEATURE] "
|
|
||||||
labels: ["type/feature", "priority/p2", "status/needs-info"]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Thanks for your idea! / 感谢你的建议!
|
|
||||||
|
|
||||||
Please provide concrete business scenarios and the expected behavior.
|
|
||||||
请尽量提供明确业务场景和期望行为,便于评估优先级与实现方案。
|
|
||||||
|
|
||||||
For urgent production issues, you can use our Knowledge Planet channel for faster processing:
|
|
||||||
https://wx.zsxq.com/group/48844125114258
|
|
||||||
如为线上紧急问题,可通过知识星球渠道加速处理:
|
|
||||||
https://wx.zsxq.com/group/48844125114258
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: background
|
|
||||||
attributes:
|
|
||||||
label: "Background / 背景"
|
|
||||||
description: "What problem are you trying to solve? / 你要解决什么问题?"
|
|
||||||
placeholder: "Describe current pain points... / 描述当前痛点..."
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: proposal
|
|
||||||
attributes:
|
|
||||||
label: "Proposal / 建议方案"
|
|
||||||
description: "What do you expect kkFileView to support? / 期望 kkFileView 支持什么?"
|
|
||||||
placeholder: "Describe expected feature behavior... / 描述期望功能行为..."
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: use_case
|
|
||||||
attributes:
|
|
||||||
label: "Use Case / 使用场景"
|
|
||||||
description: "Provide 1-3 concrete scenarios. / 提供 1-3 个具体场景"
|
|
||||||
placeholder: |
|
|
||||||
Scenario 1:
|
|
||||||
Scenario 2:
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: alternatives
|
|
||||||
attributes:
|
|
||||||
label: "Alternatives / 备选方案"
|
|
||||||
description: "What alternatives have you considered? / 是否考虑过替代方案?"
|
|
||||||
placeholder: "Existing workaround or alternative... / 当前替代做法..."
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: acceptance
|
|
||||||
attributes:
|
|
||||||
label: "Acceptance Criteria / 验收标准"
|
|
||||||
description: "How do we know this feature is done? / 如何判断该功能完成?"
|
|
||||||
placeholder: |
|
|
||||||
- [ ] Criterion 1
|
|
||||||
- [ ] Criterion 2
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
id: checklist
|
|
||||||
attributes:
|
|
||||||
label: "Checklist / 提交前检查"
|
|
||||||
options:
|
|
||||||
- label: "I have searched existing issues and did not find a duplicate feature request. / 我已搜索现有 issue,未发现重复功能建议"
|
|
||||||
required: true
|
|
||||||
- label: "I provided concrete use cases and expected behavior. / 我已提供具体使用场景和期望行为"
|
|
||||||
required: true
|
|
||||||
121
.github/ISSUE_TEMPLATE/issue-report.yml
vendored
121
.github/ISSUE_TEMPLATE/issue-report.yml
vendored
@@ -1,121 +0,0 @@
|
|||||||
name: "Issue Report / 问题反馈"
|
|
||||||
description: "Please provide complete required information to help us reproduce and follow up. / 请完整填写必填信息,便于复现与跟进。"
|
|
||||||
title: "[ISSUE] "
|
|
||||||
labels: ["status/needs-info"]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Thanks for your report! / 感谢反馈!
|
|
||||||
|
|
||||||
**Please fill in all required fields.**
|
|
||||||
**请完整填写所有必填项。**
|
|
||||||
|
|
||||||
Incomplete issues may be closed and asked to resubmit.
|
|
||||||
信息不完整的问题可能会被关闭并要求重新提交。
|
|
||||||
|
|
||||||
For urgent production issues, you can use our Knowledge Planet channel for faster processing:
|
|
||||||
https://wx.zsxq.com/group/48844125114258
|
|
||||||
如为线上紧急问题,可通过知识星球渠道加速处理:
|
|
||||||
https://wx.zsxq.com/group/48844125114258
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
id: issue_type
|
|
||||||
attributes:
|
|
||||||
label: "Issue Type / 问题类型"
|
|
||||||
description: "Select the closest type. / 请选择最接近的问题类型"
|
|
||||||
options:
|
|
||||||
- "Bug / 缺陷"
|
|
||||||
- "Performance / 性能问题"
|
|
||||||
- "Security / 安全问题"
|
|
||||||
- "Question / 使用咨询"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: kkfileview_version
|
|
||||||
attributes:
|
|
||||||
label: "kkFileView Version / kkFileView 版本"
|
|
||||||
placeholder: "e.g. 4.4.0"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: deploy_mode
|
|
||||||
attributes:
|
|
||||||
label: "Deployment Mode / 部署方式"
|
|
||||||
description: "jar / docker / k8s / source, etc. / jar / docker / k8s / 源码部署等"
|
|
||||||
placeholder: "e.g. docker"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: environment
|
|
||||||
attributes:
|
|
||||||
label: "Environment / 环境信息"
|
|
||||||
description: "OS, JDK, LibreOffice/OpenOffice, browser, reverse proxy, etc. / 操作系统、JDK、Office组件、浏览器、反向代理等"
|
|
||||||
placeholder: |
|
|
||||||
- OS:
|
|
||||||
- JDK:
|
|
||||||
- LibreOffice/OpenOffice:
|
|
||||||
- Browser:
|
|
||||||
- Proxy (Nginx/Ingress):
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: reproduce_steps
|
|
||||||
attributes:
|
|
||||||
label: "Steps to Reproduce / 复现步骤"
|
|
||||||
description: "Provide clear, minimal, reproducible steps. / 提供清晰、最小可复现步骤"
|
|
||||||
placeholder: |
|
|
||||||
1) ...
|
|
||||||
2) ...
|
|
||||||
3) ...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: expected_result
|
|
||||||
attributes:
|
|
||||||
label: "Expected Result / 期望结果"
|
|
||||||
placeholder: "What should happen? / 期望实际应该出现什么结果?"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: actual_result
|
|
||||||
attributes:
|
|
||||||
label: "Actual Result / 实际结果"
|
|
||||||
placeholder: "What happened instead? / 实际发生了什么?"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: logs
|
|
||||||
attributes:
|
|
||||||
label: "Logs & Screenshots / 日志与截图"
|
|
||||||
description: "Paste key logs/error stack and attach screenshots (mask sensitive data). / 粘贴关键日志或异常堆栈,并上传截图(请脱敏)"
|
|
||||||
render: shell
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: sample_file
|
|
||||||
attributes:
|
|
||||||
label: "Sample File / 样例文件(可选)"
|
|
||||||
description: "If possible, provide a minimal sample file or reproducible URL (desensitized). / 如可提供,请附最小样例文件或可复现 URL(脱敏)"
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
id: checklist
|
|
||||||
attributes:
|
|
||||||
label: "Checklist / 提交前检查"
|
|
||||||
options:
|
|
||||||
- label: "I have searched existing issues and did not find a duplicate. / 我已搜索现有 issue,未发现重复问题"
|
|
||||||
required: true
|
|
||||||
- label: "I can reproduce this issue on the stated version/environment. / 我可在上述版本与环境复现该问题"
|
|
||||||
required: true
|
|
||||||
- label: "I have masked sensitive information in logs/screenshots. / 我已对日志与截图中的敏感信息做脱敏处理"
|
|
||||||
required: true
|
|
||||||
78
.github/workflows/auto-close-old-issues.yml
vendored
78
.github/workflows/auto-close-old-issues.yml
vendored
@@ -1,78 +0,0 @@
|
|||||||
name: Auto Close Old Issues (1y)
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
# Daily at 02:20 UTC
|
|
||||||
- cron: '20 2 * * *'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
close_old_issues:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Close issues older than 1 year
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const owner = context.repo.owner;
|
|
||||||
const repo = context.repo.repo;
|
|
||||||
const now = new Date();
|
|
||||||
const cutoff = new Date(now.getTime() - 365 * 24 * 60 * 60 * 1000);
|
|
||||||
|
|
||||||
const closeComment = `该 Issue 已超过 1 年未活跃,为便于维护当前问题队列,先做关闭处理。\n\n如该问题在最新版本仍存在,欢迎直接 **Reopen** 本 Issue(或新建 Issue 并关联本单),并补充:\n1. 版本与部署方式\n2. 最小复现步骤\n3. 关键日志/截图(请脱敏)\n\n我们会优先跟进。`;
|
|
||||||
|
|
||||||
let page = 1;
|
|
||||||
let processed = 0;
|
|
||||||
while (true) {
|
|
||||||
const { data: issues } = await github.rest.issues.listForRepo({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
state: 'open',
|
|
||||||
per_page: 100,
|
|
||||||
page,
|
|
||||||
sort: 'created',
|
|
||||||
direction: 'asc'
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!issues.length) break;
|
|
||||||
|
|
||||||
for (const issue of issues) {
|
|
||||||
// skip pull requests
|
|
||||||
if (issue.pull_request) continue;
|
|
||||||
|
|
||||||
const createdAt = new Date(issue.created_at);
|
|
||||||
if (createdAt > cutoff) {
|
|
||||||
// list is sorted asc by created time; remaining items are newer
|
|
||||||
core.info('Reached issues newer than cutoff, stop scanning.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
issue_number: issue.number,
|
|
||||||
body: closeComment,
|
|
||||||
});
|
|
||||||
|
|
||||||
await github.rest.issues.update({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
issue_number: issue.number,
|
|
||||||
state: 'closed',
|
|
||||||
});
|
|
||||||
|
|
||||||
processed += 1;
|
|
||||||
core.info(`Closed #${issue.number}`);
|
|
||||||
} catch (e) {
|
|
||||||
core.warning(`Failed to close #${issue.number}: ${e.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
page += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
core.info(`Done. Closed ${processed} old issues.`);
|
|
||||||
34
.github/workflows/copilot-issue-auto-comment.yml
vendored
34
.github/workflows/copilot-issue-auto-comment.yml
vendored
@@ -1,34 +0,0 @@
|
|||||||
name: Copilot Issue Auto Comment
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [opened]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
copilot_auto_comment:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Ask Copilot to triage issue automatically
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const issue = context.payload.issue;
|
|
||||||
if (!issue) return;
|
|
||||||
|
|
||||||
const owner = context.repo.owner;
|
|
||||||
const repo = context.repo.repo;
|
|
||||||
|
|
||||||
const body = `@copilot 请自动分诊并直接给出可执行建议(无需人工先介入):\n\n- 先判断类型:Bug / Performance / Security / Question / Feature\n- 检查 Issue 信息是否完整(版本、部署方式、复现步骤、日志)\n- 若信息不完整:请直接按模板列出缺失项并引导补充\n- 若信息较完整:请给出下一步排查建议与最小复现建议\n- 若判断为已知问题或已修复:请给出对应版本/修复方向\n\nIssue #${issue.number}\n标题:${issue.title}\n链接:${issue.html_url}\n\n---\n\n补充说明 / Support Notice:\n- GitHub Issues 会持续跟进处理 / We will continue to follow up through GitHub Issues.\n- 如为线上紧急问题,可通过知识星球渠道加速处理 / For urgent production issues, you can use our Knowledge Planet channel for faster processing:\n https://wx.zsxq.com/group/48844125114258`;
|
|
||||||
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
issue_number: issue.number,
|
|
||||||
body,
|
|
||||||
});
|
|
||||||
|
|
||||||
core.info(`Copilot prompt comment posted to #${issue.number}`);
|
|
||||||
118
.github/workflows/nightly-e2e.yml
vendored
118
.github/workflows/nightly-e2e.yml
vendored
@@ -1,118 +0,0 @@
|
|||||||
name: Nightly E2E Full
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '30 18 * * *' # 02:30 Asia/Shanghai
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
e2e-nightly:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 50
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup JDK 21
|
|
||||||
uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '21'
|
|
||||||
cache: maven
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: tests/e2e/package-lock.json
|
|
||||||
|
|
||||||
- name: Setup Python 3.11
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.11'
|
|
||||||
|
|
||||||
- name: Install LibreOffice + zip
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y libreoffice zip
|
|
||||||
|
|
||||||
- name: Setup Python deps for office fixtures
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install -r tests/e2e/requirements.txt
|
|
||||||
|
|
||||||
- name: Build kkFileView
|
|
||||||
run: mvn -q -pl server -DskipTests package
|
|
||||||
|
|
||||||
- name: Install E2E deps
|
|
||||||
working-directory: tests/e2e
|
|
||||||
run: |
|
|
||||||
npm ci
|
|
||||||
npx playwright install --with-deps chromium
|
|
||||||
|
|
||||||
- name: Start fixture server
|
|
||||||
run: |
|
|
||||||
cd tests/e2e/fixtures
|
|
||||||
python3 -m http.server 18080 > /tmp/fixture-server.log 2>&1 &
|
|
||||||
|
|
||||||
- name: Start kkFileView
|
|
||||||
run: |
|
|
||||||
JAR_PATH=$(ls server/target/kkFileView-*.jar | head -n 1)
|
|
||||||
nohup env KK_TRUST_HOST='*' KK_NOT_TRUST_HOST='10.*,172.16.*,192.168.*' java -jar "$JAR_PATH" > /tmp/kkfileview.log 2>&1 &
|
|
||||||
|
|
||||||
- name: Wait for services
|
|
||||||
run: |
|
|
||||||
fixture_ready=false
|
|
||||||
for i in {1..60}; do
|
|
||||||
if curl -fsS http://127.0.0.1:18080/sample.txt >/dev/null; then
|
|
||||||
fixture_ready=true
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
if [ "$fixture_ready" != "true" ]; then
|
|
||||||
echo "Error: fixture server did not become ready within 60 seconds." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
kkfileview_ready=false
|
|
||||||
for i in {1..120}; do
|
|
||||||
if curl -fsS http://127.0.0.1:8012/ >/dev/null; then
|
|
||||||
kkfileview_ready=true
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
if [ "$kkfileview_ready" != "true" ]; then
|
|
||||||
echo "Error: kkFileView service did not become ready within 120 seconds." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Run nightly E2E suites
|
|
||||||
working-directory: tests/e2e
|
|
||||||
env:
|
|
||||||
KK_BASE_URL: http://127.0.0.1:8012
|
|
||||||
FIXTURE_BASE_URL: http://127.0.0.1:18080
|
|
||||||
E2E_MAX_PREVIEW_MS: 20000
|
|
||||||
run: npm run test:ci
|
|
||||||
|
|
||||||
- name: Upload Playwright report
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: nightly-playwright-report
|
|
||||||
path: tests/e2e/playwright-report
|
|
||||||
|
|
||||||
- name: Upload service logs
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: nightly-e2e-service-logs
|
|
||||||
path: |
|
|
||||||
/tmp/kkfileview.log
|
|
||||||
/tmp/fixture-server.log
|
|
||||||
100
.github/workflows/pr-e2e-mvp.yml
vendored
100
.github/workflows/pr-e2e-mvp.yml
vendored
@@ -1,100 +0,0 @@
|
|||||||
name: PR E2E MVP
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches: [master]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
e2e-mvp:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 40
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup JDK 21
|
|
||||||
uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '21'
|
|
||||||
cache: maven
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: tests/e2e/package-lock.json
|
|
||||||
|
|
||||||
- name: Setup Python 3.11
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.11'
|
|
||||||
|
|
||||||
- name: Install LibreOffice + zip
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y libreoffice zip
|
|
||||||
|
|
||||||
- name: Setup Python deps for office fixtures
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install -r tests/e2e/requirements.txt
|
|
||||||
|
|
||||||
- name: Build kkFileView
|
|
||||||
run: mvn -q -pl server -DskipTests package
|
|
||||||
|
|
||||||
- name: Install E2E deps
|
|
||||||
working-directory: tests/e2e
|
|
||||||
run: |
|
|
||||||
npm install
|
|
||||||
npx playwright install --with-deps chromium
|
|
||||||
|
|
||||||
- name: Start fixture server
|
|
||||||
run: |
|
|
||||||
cd tests/e2e/fixtures
|
|
||||||
python3 -m http.server 18080 > /tmp/fixture-server.log 2>&1 &
|
|
||||||
|
|
||||||
- name: Start kkFileView
|
|
||||||
run: |
|
|
||||||
JAR_PATH=$(ls server/target/kkFileView-*.jar | head -n 1)
|
|
||||||
nohup env KK_TRUST_HOST='*' KK_NOT_TRUST_HOST='10.*,172.16.*,192.168.*' java -jar "$JAR_PATH" > /tmp/kkfileview.log 2>&1 &
|
|
||||||
|
|
||||||
- name: Wait for services
|
|
||||||
run: |
|
|
||||||
for i in {1..60}; do
|
|
||||||
curl -fsS http://127.0.0.1:18080/sample.txt >/dev/null && break
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
for i in {1..120}; do
|
|
||||||
curl -fsS http://127.0.0.1:8012/ >/dev/null && break
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Run E2E
|
|
||||||
working-directory: tests/e2e
|
|
||||||
env:
|
|
||||||
KK_BASE_URL: http://127.0.0.1:8012
|
|
||||||
FIXTURE_BASE_URL: http://127.0.0.1:18080
|
|
||||||
run: npm test
|
|
||||||
|
|
||||||
- name: Upload Playwright report
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: playwright-report
|
|
||||||
path: tests/e2e/playwright-report
|
|
||||||
|
|
||||||
- name: Upload service logs
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: e2e-service-logs
|
|
||||||
path: |
|
|
||||||
/tmp/kkfileview.log
|
|
||||||
/tmp/fixture-server.log
|
|
||||||
9
tests/e2e/.gitignore
vendored
9
tests/e2e/.gitignore
vendored
@@ -1,9 +0,0 @@
|
|||||||
node_modules/
|
|
||||||
playwright-report/
|
|
||||||
test-results/
|
|
||||||
|
|
||||||
__pycache__/
|
|
||||||
fixtures/zip-tmp/
|
|
||||||
fixtures/sample.docx
|
|
||||||
fixtures/sample.xlsx
|
|
||||||
fixtures/sample.pptx
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
# kkFileView E2E MVP
|
|
||||||
|
|
||||||
This folder contains a first MVP of end-to-end automated tests.
|
|
||||||
|
|
||||||
## What is covered
|
|
||||||
|
|
||||||
- Basic preview smoke checks for common file types (txt/md/json/xml/csv/html/png)
|
|
||||||
- Office Phase-2 smoke checks (docx/xlsx/pptx)
|
|
||||||
- Archive smoke check (zip)
|
|
||||||
- Basic endpoint reachability
|
|
||||||
- Security regression checks for blocked internal-network hosts (`10.*`) on:
|
|
||||||
- `/onlinePreview`
|
|
||||||
- `/getCorsFile`
|
|
||||||
- Basic performance smoke checks (configurable threshold): txt/docx/xlsx preview response time
|
|
||||||
- CI combined run command available via `npm run test:ci`
|
|
||||||
|
|
||||||
## Local run
|
|
||||||
|
|
||||||
1. Build server jar:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mvn -q -pl server -DskipTests package
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Install deps + browser:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd tests/e2e
|
|
||||||
npm install
|
|
||||||
npx playwright install --with-deps chromium
|
|
||||||
pip3 install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
> Prerequisite: ensure `zip` command is available in PATH (used for `sample.zip` fixture generation).
|
|
||||||
|
|
||||||
3. Generate fixtures and start fixture server:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /path/to/kkFileView
|
|
||||||
npm run gen:all
|
|
||||||
cd tests/e2e/fixtures && python3 -m http.server 18080
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Start kkFileView in another terminal:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
JAR_PATH=$(ls server/target/kkFileView-*.jar | head -n 1)
|
|
||||||
KK_TRUST_HOST='*' KK_NOT_TRUST_HOST='10.*,172.16.*,192.168.*' java -jar "$JAR_PATH"
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Run tests:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd tests/e2e
|
|
||||||
KK_BASE_URL=http://127.0.0.1:8012 FIXTURE_BASE_URL=http://127.0.0.1:18080 npm test
|
|
||||||
```
|
|
||||||
|
|
||||||
Optional:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# smoke only (self-contained: will auto-generate fixtures)
|
|
||||||
npm run test:smoke
|
|
||||||
|
|
||||||
# perf smoke (self-contained; default threshold 15000ms)
|
|
||||||
E2E_MAX_PREVIEW_MS=15000 npm run test:perf
|
|
||||||
|
|
||||||
# CI-style combined run (single fixture generation)
|
|
||||||
E2E_MAX_PREVIEW_MS=20000 npm run test:ci
|
|
||||||
```
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
name,value
|
|
||||||
kkFileView,1
|
|
||||||
e2e,1
|
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
<!doctype html><html><body><h1>kkFileView fixture</h1></body></html>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"app": "kkFileView",
|
|
||||||
"e2e": true
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# kkFileView
|
|
||||||
|
|
||||||
This is a markdown fixture.
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
%PDF-1.1
|
|
||||||
1 0 obj<< /Type /Catalog /Pages 2 0 R >>endobj
|
|
||||||
2 0 obj<< /Type /Pages /Kids [3 0 R] /Count 1 >>endobj
|
|
||||||
3 0 obj<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] /Contents 4 0 R >>endobj
|
|
||||||
4 0 obj<< /Length 44 >>stream
|
|
||||||
BT /F1 12 Tf 72 120 Td (kkFileView e2e pdf) Tj ET
|
|
||||||
endstream
|
|
||||||
endobj
|
|
||||||
xref
|
|
||||||
0 5
|
|
||||||
0000000000 65535 f
|
|
||||||
0000000010 00000 n
|
|
||||||
0000000060 00000 n
|
|
||||||
0000000117 00000 n
|
|
||||||
0000000212 00000 n
|
|
||||||
trailer<< /Root 1 0 R /Size 5 >>
|
|
||||||
startxref
|
|
||||||
306
|
|
||||||
%%EOF
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 68 B |
@@ -1 +0,0 @@
|
|||||||
kkFileView e2e sample text
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<root><name>kkFileView</name><e2e>true</e2e></root>
|
|
||||||
Binary file not shown.
78
tests/e2e/package-lock.json
generated
78
tests/e2e/package-lock.json
generated
@@ -1,78 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "kkfileview-e2e",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"": {
|
|
||||||
"name": "kkfileview-e2e",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"devDependencies": {
|
|
||||||
"@playwright/test": "^1.55.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@playwright/test": {
|
|
||||||
"version": "1.58.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz",
|
|
||||||
"integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"playwright": "1.58.2"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"playwright": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/fsevents": {
|
|
||||||
"version": "2.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
|
||||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
|
||||||
"dev": true,
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/playwright": {
|
|
||||||
"version": "1.58.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz",
|
|
||||||
"integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"playwright-core": "1.58.2"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"playwright": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"fsevents": "2.3.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/playwright-core": {
|
|
||||||
"version": "1.58.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz",
|
|
||||||
"integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"bin": {
|
|
||||||
"playwright-core": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "kkfileview-e2e",
|
|
||||||
"private": true,
|
|
||||||
"version": "0.1.0",
|
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
|
||||||
"gen:fixtures": "node ./scripts/generate-fixtures.mjs",
|
|
||||||
"gen:office": "python3 ./scripts/generate-office-fixtures.py",
|
|
||||||
"gen:all": "npm run gen:fixtures && npm run gen:office",
|
|
||||||
"pretest": "npm run gen:all",
|
|
||||||
"test": "playwright test",
|
|
||||||
"test:headed": "playwright test --headed",
|
|
||||||
"pretest:smoke": "npm run gen:all",
|
|
||||||
"test:smoke": "playwright test specs/preview-smoke.spec.ts",
|
|
||||||
"pretest:perf": "npm run gen:all",
|
|
||||||
"test:perf": "playwright test specs/perf-smoke.spec.ts",
|
|
||||||
"test:ci": "npm run gen:all && playwright test specs/preview-smoke.spec.ts specs/perf-smoke.spec.ts"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@playwright/test": "^1.55.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { defineConfig } from '@playwright/test';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
testDir: './specs',
|
|
||||||
timeout: 30_000,
|
|
||||||
expect: { timeout: 10_000 },
|
|
||||||
retries: process.env.CI ? 1 : 0,
|
|
||||||
reporter: [['list'], ['html', { outputFolder: 'playwright-report', open: 'never' }]],
|
|
||||||
use: {
|
|
||||||
baseURL: process.env.KK_BASE_URL || 'http://127.0.0.1:8012',
|
|
||||||
trace: 'on-first-retry',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
python-docx==1.1.2
|
|
||||||
openpyxl==3.1.5
|
|
||||||
python-pptx==1.0.2
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
import fs from 'node:fs';
|
|
||||||
import path from 'node:path';
|
|
||||||
import { execFileSync } from 'node:child_process';
|
|
||||||
import { fileURLToPath } from 'node:url';
|
|
||||||
|
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
||||||
const fixturesDir = path.resolve(__dirname, '..', 'fixtures');
|
|
||||||
fs.mkdirSync(fixturesDir, { recursive: true });
|
|
||||||
|
|
||||||
const write = (name, content) => fs.writeFileSync(path.join(fixturesDir, name), content);
|
|
||||||
|
|
||||||
write('sample.txt', 'kkFileView e2e sample text');
|
|
||||||
write('sample.md', '# kkFileView\n\nThis is a markdown fixture.');
|
|
||||||
write('sample.json', JSON.stringify({ app: 'kkFileView', e2e: true }, null, 2));
|
|
||||||
write('sample.xml', '<root><name>kkFileView</name><e2e>true</e2e></root>');
|
|
||||||
write('sample.csv', 'name,value\nkkFileView,1\ne2e,1\n');
|
|
||||||
write('sample.html', '<!doctype html><html><body><h1>kkFileView fixture</h1></body></html>');
|
|
||||||
|
|
||||||
// zip (contains txt) - only generate if missing to avoid noisy local diffs
|
|
||||||
const zipPath = path.join(fixturesDir, 'sample.zip');
|
|
||||||
if (!fs.existsSync(zipPath)) {
|
|
||||||
const zipWork = path.join(fixturesDir, 'zip-tmp');
|
|
||||||
fs.mkdirSync(zipWork, { recursive: true });
|
|
||||||
fs.writeFileSync(path.join(zipWork, 'inner.txt'), 'kkFileView zip inner file');
|
|
||||||
try {
|
|
||||||
execFileSync('zip', ['-X', '-q', '-r', zipPath, 'inner.txt'], { cwd: zipWork });
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Failed to create sample.zip fixture. Ensure "zip" is installed and available in PATH.');
|
|
||||||
throw err instanceof Error ? err : new Error(String(err));
|
|
||||||
} finally {
|
|
||||||
fs.rmSync(zipWork, { recursive: true, force: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1x1 png
|
|
||||||
write(
|
|
||||||
'sample.png',
|
|
||||||
Buffer.from(
|
|
||||||
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO7Zx1sAAAAASUVORK5CYII=',
|
|
||||||
'base64'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// tiny valid pdf
|
|
||||||
write(
|
|
||||||
'sample.pdf',
|
|
||||||
`%PDF-1.1\n1 0 obj<< /Type /Catalog /Pages 2 0 R >>endobj\n2 0 obj<< /Type /Pages /Kids [3 0 R] /Count 1 >>endobj\n3 0 obj<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] /Contents 4 0 R >>endobj\n4 0 obj<< /Length 44 >>stream\nBT /F1 12 Tf 72 120 Td (kkFileView e2e pdf) Tj ET\nendstream\nendobj\nxref\n0 5\n0000000000 65535 f \n0000000010 00000 n \n0000000060 00000 n \n0000000117 00000 n \n0000000212 00000 n \ntrailer<< /Root 1 0 R /Size 5 >>\nstartxref\n306\n%%EOF\n`
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log('fixtures generated in', fixturesDir);
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from docx import Document
|
|
||||||
from openpyxl import Workbook
|
|
||||||
from pptx import Presentation
|
|
||||||
|
|
||||||
fixtures = Path(__file__).resolve().parent.parent / "fixtures"
|
|
||||||
fixtures.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
# DOCX
|
|
||||||
_doc = Document()
|
|
||||||
_doc.add_heading("kkFileView E2E", level=1)
|
|
||||||
_doc.add_paragraph("This is a DOCX fixture for Phase-2 E2E.")
|
|
||||||
_doc.save(fixtures / "sample.docx")
|
|
||||||
|
|
||||||
# XLSX
|
|
||||||
_wb = Workbook()
|
|
||||||
_ws = _wb.active
|
|
||||||
_ws.title = "Sheet1"
|
|
||||||
_ws["A1"] = "name"
|
|
||||||
_ws["B1"] = "value"
|
|
||||||
_ws["A2"] = "kkFileView"
|
|
||||||
_ws["B2"] = 2
|
|
||||||
_wb.save(fixtures / "sample.xlsx")
|
|
||||||
|
|
||||||
# PPTX
|
|
||||||
_prs = Presentation()
|
|
||||||
slide_layout = _prs.slide_layouts[1]
|
|
||||||
slide = _prs.slides.add_slide(slide_layout)
|
|
||||||
slide.shapes.title.text = "kkFileView E2E"
|
|
||||||
slide.placeholders[1].text = "This is a PPTX fixture for Phase-2 E2E."
|
|
||||||
_prs.save(fixtures / "sample.pptx")
|
|
||||||
|
|
||||||
print("office fixtures generated in", fixtures)
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import { test, expect, request as playwrightRequest } from '@playwright/test';
|
|
||||||
import type { APIRequestContext } from '@playwright/test';
|
|
||||||
|
|
||||||
const fixtureBase = process.env.FIXTURE_BASE_URL || 'http://127.0.0.1:18080';
|
|
||||||
const DEFAULT_MAX_MS = 15000;
|
|
||||||
const envMaxMs = Number(process.env.E2E_MAX_PREVIEW_MS);
|
|
||||||
const maxMs = Number.isFinite(envMaxMs) && envMaxMs >= 1 ? Math.floor(envMaxMs) : DEFAULT_MAX_MS;
|
|
||||||
|
|
||||||
function b64(v: string): string {
|
|
||||||
return Buffer.from(v).toString('base64');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function timedPreview(request: APIRequestContext, fileUrl: string) {
|
|
||||||
const started = Date.now();
|
|
||||||
const resp = await request.get(`/onlinePreview?url=${encodeURIComponent(b64(fileUrl))}`);
|
|
||||||
const elapsed = Date.now() - started;
|
|
||||||
return { resp, elapsed };
|
|
||||||
}
|
|
||||||
|
|
||||||
test.beforeAll(async () => {
|
|
||||||
const api = await playwrightRequest.newContext();
|
|
||||||
const required = ['sample.txt', 'sample.docx', 'sample.xlsx'];
|
|
||||||
try {
|
|
||||||
for (const name of required) {
|
|
||||||
const resp = await api.get(`${fixtureBase}/${name}`);
|
|
||||||
expect(resp.ok(), `fixture missing or unavailable: ${name}`).toBeTruthy();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
await api.dispose();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('perf: txt preview response under threshold', async ({ request }) => {
|
|
||||||
const { resp, elapsed } = await timedPreview(request, `${fixtureBase}/sample.txt`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
expect(elapsed).toBeLessThan(maxMs);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('perf: docx preview response under threshold', async ({ request }) => {
|
|
||||||
const { resp, elapsed } = await timedPreview(request, `${fixtureBase}/sample.docx`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
expect(elapsed).toBeLessThan(maxMs);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('perf: xlsx preview response under threshold', async ({ request }) => {
|
|
||||||
const { resp, elapsed } = await timedPreview(request, `${fixtureBase}/sample.xlsx`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
expect(elapsed).toBeLessThan(maxMs);
|
|
||||||
});
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
import { test, expect, request as playwrightRequest } from '@playwright/test';
|
|
||||||
|
|
||||||
const fixtureBase = process.env.FIXTURE_BASE_URL || 'http://127.0.0.1:18080';
|
|
||||||
|
|
||||||
function b64(v: string): string {
|
|
||||||
return Buffer.from(v).toString('base64');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function openPreview(request: any, fileUrl: string) {
|
|
||||||
const encoded = encodeURIComponent(b64(fileUrl));
|
|
||||||
return request.get(`/onlinePreview?url=${encoded}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
test.beforeAll(async () => {
|
|
||||||
const api = await playwrightRequest.newContext();
|
|
||||||
const required = [
|
|
||||||
'sample.txt',
|
|
||||||
'sample.md',
|
|
||||||
'sample.json',
|
|
||||||
'sample.xml',
|
|
||||||
'sample.csv',
|
|
||||||
'sample.html',
|
|
||||||
'sample.png',
|
|
||||||
'sample.docx',
|
|
||||||
'sample.xlsx',
|
|
||||||
'sample.pptx',
|
|
||||||
'sample.zip',
|
|
||||||
];
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (const name of required) {
|
|
||||||
const resp = await api.get(`${fixtureBase}/${name}`);
|
|
||||||
expect(resp.ok(), `fixture missing or unavailable: ${name}`).toBeTruthy();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
await api.dispose();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('01 home/index reachable', async ({ request }) => {
|
|
||||||
const resp = await request.get('/');
|
|
||||||
expect(resp.status()).toBeLessThan(500);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('02 txt preview', async ({ request }) => {
|
|
||||||
const resp = await openPreview(request, `${fixtureBase}/sample.txt`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('03 markdown preview', async ({ request }) => {
|
|
||||||
const resp = await openPreview(request, `${fixtureBase}/sample.md`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('04 json preview', async ({ request }) => {
|
|
||||||
const resp = await openPreview(request, `${fixtureBase}/sample.json`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('05 xml preview', async ({ request }) => {
|
|
||||||
const resp = await openPreview(request, `${fixtureBase}/sample.xml`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('06 csv preview', async ({ request }) => {
|
|
||||||
const resp = await openPreview(request, `${fixtureBase}/sample.csv`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('07 html preview', async ({ request }) => {
|
|
||||||
const resp = await openPreview(request, `${fixtureBase}/sample.html`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('08 png preview', async ({ request }) => {
|
|
||||||
const resp = await openPreview(request, `${fixtureBase}/sample.png`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('09 docx preview', async ({ request }) => {
|
|
||||||
const resp = await openPreview(request, `${fixtureBase}/sample.docx`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('10 xlsx preview', async ({ request }) => {
|
|
||||||
const resp = await openPreview(request, `${fixtureBase}/sample.xlsx`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('11 pptx preview', async ({ request }) => {
|
|
||||||
const resp = await openPreview(request, `${fixtureBase}/sample.pptx`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('12 zip preview', async ({ request }) => {
|
|
||||||
const resp = await openPreview(request, `${fixtureBase}/sample.zip`);
|
|
||||||
expect(resp.status()).toBe(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('13 security: block 10.x host in onlinePreview', async ({ request }) => {
|
|
||||||
const resp = await openPreview(request, `http://10.1.2.3/a.pdf`);
|
|
||||||
const body = await resp.text();
|
|
||||||
expect(body).toContain('不受信任');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('14 security: block 10.x host in getCorsFile', async ({ request }) => {
|
|
||||||
const encoded = b64('http://10.1.2.3/a.pdf');
|
|
||||||
const resp = await request.get(`/getCorsFile?urlPath=${encoded}`);
|
|
||||||
const body = await resp.text();
|
|
||||||
expect(body).toContain('不受信任');
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user