Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/binance-orderbook-ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- ".github/workflows/binance-orderbook-ui.yml"
- "package.json"
- "package-lock.json"
- ".nvmrc"
- "playwright.config.js"
- "src/binance-orderbook-trade/**"
- "src/binance-strategy29-bollinger/**"
Expand All @@ -29,6 +30,7 @@ on:
- ".github/workflows/binance-orderbook-ui.yml"
- "package.json"
- "package-lock.json"
- ".nvmrc"
- "playwright.config.js"
- "src/binance-orderbook-trade/**"
- "src/binance-strategy29-bollinger/**"
Expand Down Expand Up @@ -57,7 +59,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
node-version-file: .nvmrc
cache: npm
- run: npm ci
- run: npx playwright install --with-deps chromium
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/binance-strategy27-events.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- ".github/workflows/binance-strategy27-events.yml"
- "package.json"
- "package-lock.json"
- ".nvmrc"
- "scripts/build-userscript.mjs"
- "scripts/userscript-release-contract.mjs"
- "src/binance-strategy27-events/**"
Expand All @@ -23,6 +24,7 @@ on:
- ".github/workflows/binance-strategy27-events.yml"
- "package.json"
- "package-lock.json"
- ".nvmrc"
- "scripts/build-userscript.mjs"
- "scripts/userscript-release-contract.mjs"
- "src/binance-strategy27-events/**"
Expand All @@ -45,12 +47,11 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
node-version-file: .nvmrc
cache: npm
- run: npm ci
- run: npm run test:binance-strategy27-events
- run: npm run build:binance-strategy27-events
- run: git diff --exit-code -- scripts/binance-strategy27-events.user.js
- run: npm run check:binance-userscripts
- run: node scripts/userscript-release-contract.mjs scripts/binance-strategy27-events.user.js

78 changes: 78 additions & 0 deletions .github/workflows/userscript-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Userscript Tests

on:
pull_request:
push:
branches: [main]
schedule:
- cron: "0 20 * * 0"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: userscript-tests-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
tests:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm
- run: npm ci
- run: npm run lint:tests
- run: npm run build:userscripts
- run: git diff --exit-code -- 'scripts/*.user.js'
- run: npm run check:binance-userscripts
- run: npm run check:m3u8-downloader
- name: Select affected tests
id: selection
env:
TEST_BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }}
TEST_FULL: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
run: |
mkdir -p test-results
if [ "$TEST_FULL" = "true" ]; then
node scripts/test-selection/run.mjs --full --list > test-results/selection.json
else
node scripts/test-selection/run.mjs --base "$TEST_BASE_SHA" --list > test-results/selection.json
fi
node --input-type=module <<'JS'
import { appendFileSync, readFileSync } from 'node:fs';
const plan = JSON.parse(readFileSync('test-results/selection.json', 'utf8'));
appendFileSync(process.env.GITHUB_OUTPUT, 'browser=' + (plan.browserTests.length > 0) + '\n');
process.stdout.write(JSON.stringify(plan, null, 2) + '\n');
JS
- name: Install browser for selected scenarios
if: steps.selection.outputs.browser == 'true'
run: npx playwright install --with-deps chromium
- name: Run affected tests
if: github.event_name != 'schedule' && github.event_name != 'workflow_dispatch'
env:
TEST_BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }}
run: npm run test:affected -- --base "$TEST_BASE_SHA"
- name: Run complete source coverage
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
run: npm run test:coverage
- name: Upload test selection and reports
if: always()
uses: actions/upload-artifact@v4
with:
name: userscript-test-evidence
path: |
test-results/selection.json
playwright-report/
test-results/coverage/latest.json
test-results/coverage/run-*/report/
test-results/coverage/run-*/node-results.txt
if-no-files-found: ignore
retention-days: 14
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
| Strategy 29 observer or cross-script chart coordination | docs/binance-strategy29-bollinger-development.md |
| Brooks/m3u8 indexing, export state, timing, or captions | docs/brooks-media-sync-workflow.md |
| Trading-data, CoinMarketCap-data, auto-refresh, or cross-script validation | docs/userscript-validation.md |
| Behavioral tests, test lint, affected selection, or source coverage | docs/test-policy.md |
| Read-only review | skills/userscript-review/SKILL.md |
| Release or publish | skills/userscript-release/SKILL.md |
| Codex/browser/proxy/helper/connection timeout | global timeout rule; if available, ~/.dotfiles/knowledge/shared/CODEX_TOOL_TIMEOUT_TRIAGE.md |
Expand Down Expand Up @@ -78,6 +79,9 @@

## Validation

- Changed tests must pass `npm run lint:tests`. The behavioral test policy and
explicit migration inventory are owned by `docs/test-policy.md`; affected
selection and coverage commands do not replace required builds or live checks.
- Run the affected tests, build, syntax/check commands, and git diff --check for
behavior changes. The release skill owns stage-specific validation and reuse
of passing local checks for unchanged inputs.
Expand Down
10 changes: 10 additions & 0 deletions docs/binance-orderbook-trade-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ Include affected shared-contract and integration checks when the change crosses
script boundaries. Full-suite release validation and reuse of passing local
results are defined in `skills/userscript-release/SKILL.md`.

Test work also follows [Behavioral Test Policy](test-policy.md). Prefer executable
entry-to-outcome scenarios over source-text assertions for runtime behavior;
retain metadata, generated-artifact, and module-boundary contracts. Test changes
must pass `npm run lint:tests` in addition to the affected behavior checks.

## Layout

```text
Expand Down Expand Up @@ -283,6 +288,11 @@ Continuous ladder trading is available only for close actions through `Option/Al

Continuous-session feedback stays in the shared ladder status row and uses `连续阶梯平多` / `连续阶梯平空` as the stable action name. The action, phase, and counters are separated with ` · ` instead of concatenating `连续` after the ordinary ladder label. `2/3 轮` means two rounds completed out of three started, `本轮 1/3 笔` reports the active or latest partial plan, and `累计 7 笔` reports all confirmed submissions across the session. Confirmed cancellations are appended only when greater than zero. The active round must combine its live progress with the completed-round aggregate; ordinary single-round status text must never overwrite the continuous-session identity. Round outcomes must expose a detached progress snapshot so a terminal continuous summary cannot be overwritten by the latest single-round message.

A session waiting for readiness, stopping, or failing before its first recorded
round has `lastRound: null`. Its status shows zero rounds and zero confirmed
submissions, with no current-plan segment. Formatting this valid initial state
must not fail or invent a round.

The active continuous-close control keeps a compact direction-specific stop action (`停止平多` / `停止平空`) on one line throughout both execution and inter-round waiting. Before the native submit control is ready, the status places `等待按钮恢复` immediately after the continuous action name. Only after the fixed cooldown actually begins may it show `1s 后继续` in that same priority position; this is a static duration label, not a countdown. `停止中`, `已停止`, `失败`, and `已中止` use the same phase slot. The button must not temporarily revert to a ladder-start action between rounds.

When a continuous close receives the observed Binance private-page response `code=90802025`, `success=false`, and the max-open-orders message, classify it as a confirmed no-submit capacity rejection. Load the complete lazy current-orders list before ranking rows; the first 50 rendered rows are not a complete candidate set. Release up to 50 current-symbol, same-close-direction Basic limit orders farthest from the current trade price, preserving the nearest orders that are most likely to complete the close. Resume the same unsubmitted ladder level so already confirmed levels are not duplicated. Permit this recovery once per round; a second confirmed capacity rejection ends the current round and lets continuous mode resume after its recovery delay. Do not use Cancel All, and do not touch open-direction, opposite-direction, conditional, or protection orders. If a selected row disappears because it fills while recovery is running, treat that slot as already released but count a cancellation only after the script confirms its own row-cancel action.
Expand Down
21 changes: 21 additions & 0 deletions docs/binance-orderbook-trade-ui-automation.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ L0 and L1 remain fast PR gates. L2 owns the full scenario matrix. L3 and L4 are
smaller integration and release gates because extension state, network timing, and
market state are not deterministic enough for the full matrix.

Scenario naming, Given/When/Then structure, assertions, and permitted test
boundaries follow [Behavioral Test Policy](test-policy.md). L2 still executes the
generated install artifact. Its reviewed fake is tested separately in
`test/unit/binance-fixture-contract.test.js`: wrong symbol filtering or the wrong
Basic/conditional tab must produce the corresponding wrong cancellation scope,
so the fake cannot silently repair an unsafe caller. Native confirmation and
delayed clearing retain the initiating scope snapshot.

Use `helpers/scenario-clock.js` for business deadlines, cooldowns, and negative
proofs such as no new submission after Stop. A pending request stays pending
until `releaseSubmitResponse()` explicitly delivers success or rejection. Keep
performance budgets on real `performance` time; advancing a virtual clock is
not a latency or throughput measurement. The ordinary single-round unknown
submission scenario must not be generalized to continuous mode, whose existing
`submit_unconfirmed` policy deliberately permits a later recovery round.

`npm run test:coverage` additionally collects V8 execution and maps it to the
complete production source set. The collector's own browser proof uses virtual
code and remains separate from production coverage. See [Source Coverage](test-coverage.md)
for report completeness and shared-source merge checks.

## Scenario Model

Scenarios are data, not copied test procedures. Each scenario declares these axes:
Expand Down
Loading
Loading