Playground Msw Tests
mastra-ai/mastra
REQUIRED and PRIMARY testing approach for packages/playground and packages/playground-ui.
Design, extend, and run ScienceDiscovery E2E user journeys through the browser, public HTTP API, CLI, or local product stack.
$ npx skills add openJiuwen-ai/sciencediscovery --skill e2e-testing -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install openJiuwen-ai/sciencediscovery e2e-testing --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/openJiuwen-ai/sciencediscovery.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/e2e-testing .claude/skills/e2e-testing && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "e2e-testing" agent skill from https://github.com/openJiuwen-ai/sciencediscovery/tree/main/.agents/skills/e2e-testing into .claude/skills/e2e-testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "e2e-testing", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/openJiuwen-ai/sciencediscovery/tree/main/.agents/skills/e2e-testingType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add openJiuwen-ai/sciencediscovery --skill e2e-testing -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install openJiuwen-ai/sciencediscovery e2e-testing --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/openJiuwen-ai/sciencediscovery.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/e2e-testing .agents/skills/e2e-testing && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "e2e-testing" agent skill from https://github.com/openJiuwen-ai/sciencediscovery/tree/main/.agents/skills/e2e-testing into .agents/skills/e2e-testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "e2e-testing", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add openJiuwen-ai/sciencediscovery --skill e2e-testing -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install openJiuwen-ai/sciencediscovery e2e-testing --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/openJiuwen-ai/sciencediscovery.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/e2e-testing .cursor/skills/e2e-testing && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "e2e-testing" agent skill from https://github.com/openJiuwen-ai/sciencediscovery/tree/main/.agents/skills/e2e-testing into .cursor/skills/e2e-testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "e2e-testing", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/openJiuwen-ai/sciencediscovery.git --path .agents/skills/e2e-testing--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add openJiuwen-ai/sciencediscovery --skill e2e-testing -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install openJiuwen-ai/sciencediscovery e2e-testing --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/openJiuwen-ai/sciencediscovery.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/e2e-testing .gemini/skills/e2e-testing && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "e2e-testing" agent skill from https://github.com/openJiuwen-ai/sciencediscovery/tree/main/.agents/skills/e2e-testing into .gemini/skills/e2e-testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "e2e-testing", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install openJiuwen-ai/sciencediscovery e2e-testingInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add openJiuwen-ai/sciencediscovery --skill e2e-testing -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/openJiuwen-ai/sciencediscovery.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/e2e-testing .github/skills/e2e-testing && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "e2e-testing" agent skill from https://github.com/openJiuwen-ai/sciencediscovery/tree/main/.agents/skills/e2e-testing into .github/skills/e2e-testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "e2e-testing", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add openJiuwen-ai/sciencediscovery --skill e2e-testing -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install openJiuwen-ai/sciencediscovery e2e-testing --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/openJiuwen-ai/sciencediscovery.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/e2e-testing .opencode/skills/e2e-testing && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "e2e-testing" agent skill from https://github.com/openJiuwen-ai/sciencediscovery/tree/main/.agents/skills/e2e-testing into .opencode/skills/e2e-testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "e2e-testing", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
e2e-testingDesign, extend, and run ScienceDiscovery E2E user journeys through the browser, public HTTP API, CLI, or local product stack.
E2E Testing is an agent skill from openJiuwen-ai/sciencediscovery. Design, extend, and run ScienceDiscovery E2E user journeys through the browser, public HTTP API, CLI, or local product stack. Use when changing user-observable behavior, selecting mocked/real journeys, isolating a test stack, reporting user outcomes, or attributing an E2E failure. Browser journeys use the pinned Playwright environment in test/.
Its SKILL.md is about 9.1k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Testing & QA, covering End-to-end testing, Browser testing and Customer journey mapping. It works with Playwright. The repository describes itself as: ScienceDiscovery is an all‑in‑one agentic workbench built specifically for scientific research. The licence is Apache-2.0.
6 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 9189206. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
npmpnpmnodeuvgitplaywrightnpxFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use npm, pnpm, uv, git and npx, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
E2E_API_TOKENE2E_LLM_TOKENSCIENCE_AGENT_AUTH_TOKENFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
E2E Testing loads about 9.1k tokens when it runs. Until then it costs about 90 tokens; SKILL.md has 4,192 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
parent directories, so the main repo's `.env` (its ports,`.env`. Explicitly exported variables win over dotenv; alternatively copy atrimmed `.env` into the worktree as the run's baseline.a real model configured in the stack's `.env`.Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from openJiuwen-ai/sciencediscovery at commit 9189206, republished under its Apache-2.0 licence (© openJiuwen-ai). 4,192 words, ~9,131 tokens.
.claude/skills/e2e-testing/SKILL.md (or your agent's skills folder).Project-local skill for ScienceDiscovery. E2E means simulating actual product use from a user's goal to an observable outcome, not selecting a particular test framework. Browser journeys use Playwright; public API, CLI, and local-stack journeys also qualify when they cross the real product entry point. Package tests, type checks, in-process calls to internal functions, or assertions that only prove a request/click occurred are not E2E.
Read the shared target/isolation rules for every journey. For browser work,
follow the pinned Playwright, metadata, fixtures, and report rules below. For
non-browser work, follow API / CLI / local-stack journeys.
pnpm ci:e2e and the CI e2e layer still run the mocked browser subset;
they neither discover nor certify every kind of user-perspective E2E.
The primary unit of coverage is a user journey: one recognizable user goal
from entering the product through its observable outcome. Do not split the
main suite into internal-module specs such as shell.spec.ts, python.spec.ts,
or environment.spec.ts. Shell, Python, managed environments, subagents,
permissions, and artifacts should appear naturally as steps inside journeys.
A journey is written as numbered user steps, and every run writes a step-by-step report a human can read without opening the spec. That contract is mandatory for new work. Browser automation uses Journey steps and automatic reports; API/CLI drivers record equivalent steps and outcomes without requiring page screenshots.
When an implementation changes user-observable behavior, its implementer must add or improve the relevant journey with the feature, unless existing coverage already verifies the changed contract (identify and rerun it). Do not defer journey coverage to PR preparation or another role. This includes Run outcomes, tool execution, queryable versioned state, artifacts, permissions, failure feedback, cancellation, and recovery, even when no page changes. An independent tester, when assigned, designs scenarios from the user requirements rather than copying implementation conclusions.
Choose the interface the user actually uses. API coverage complements but does not replace browser checks for changed UI behavior. Cover success and the relevant failure/repeat/cancel/recovery paths in proportion to risk. Write E2E: not applicable only when there is no user-observable product path affected (for example documentation/comments-only changes), and explain why. Backend-only / no new UI is not an exemption. A missing environment or journey driver is BLOCKED or a coverage gap, not “not applicable.”
Keep the repository's main worktree read-only. Obtain the target ref from the
test or review request, fetch that ref only when it is not available locally,
then resolve and record its immutable commit SHA. Do not automatically merge,
rebase, or replace the requested target with another branch. Only when the
requested target is origin/master, fetch it immediately before resolving and
testing that fetched SHA.
Use the task's assigned worktree by default. Before a formal run, commit the candidate and record its immutable SHA; do not alter tracked files while that SHA is under test. Create a detached, run-specific worktree only when the task worktree is being rebased, fault injection must mutate it, or parallel runs cannot otherwise isolate their ports/data:
git worktree add --detach .worktrees/e2e-<change>-<run-id> <target-sha>Keep the target commit unchanged. Assemble dependencies, services, data, ports, and evidence only in the assigned or explicitly justified E2E worktree, using ignored or run-specific paths. Report the requested target ref, resolved target SHA, worktree, and whether the run used any separate test-only derived commit.
If validation reveals that code, a spec, or this skill must change, stop treating the current run as validation of the target. Create and commit a new candidate under the repository's development rules, then rerun E2E against that new immutable commit.
./scripts/start-stack.sh --mode local,
or a documented equivalent product entry point when testing that
entry itself. Use --no-build only for artifacts built from the target SHA.
Follow Isolated stack per run for ports, data,
service URLs and authentication. Verify the services required by the journey;
check the Web entry only when the journey uses it.createNativeAgent/createAgentRun in-process nor
starting only a test-constructed server substitutes for the product startup
path. /api/health alone is a preflight, not this complete journey.test/api/, named after the user goal,
with their exact root-level invocation and required environment documented.
The existing run_m1_smoke.sh and run_real_smoke.sh directly instantiate
the adapter: they remain smoke/integration checks, not E2E by location or
name. There is currently no generic non-browser E2E command; inspect the
committed driver or add the missing journey. Do not invent a pnpm entry
point or claim ci:e2e ran it. Integrate future drivers into the existing
test catalog when requested, without silently changing CI layer behavior.check-e2e-meta.mjs apply to browser specs; a non-browser
driver must document and enforce its own gates and reporting. Default to a
journey-owned local model stub registered through the product API. Real
models/services require explicit opt-in and documented costs. Browser
network guards do not protect a CLI or backend: keep their configured
endpoints local and audit all external calls as well.report.md for PASS,
FAIL and BLOCKED. Assert product-promised persistent records where relevant;
internal database reads alone do not replace the user's access path. A
driver must fail on a failed outcome and report missing prerequisites as
BLOCKED, never as a successful zero-case run. No fake screenshots required.finally, after
preserving evidence. Keep data and report files in the run's isolated
directories; never publish credentials or commit generated results.Use only the @playwright/test declared by test/e2e.package.json, assembled
into the gitignored .e2e/ environment:
node test/sync-e2e.mjs --write
cd .e2e
npm install
./node_modules/.bin/playwright install chromiumNever use npx playwright, a globally installed Playwright, a throwaway npm
project, or system browser drivers. Every npm test/list command runs the
fail-closed sync-e2e.mjs --check first. If a committed manifest, lockfile, or
config differs from .e2e, synchronize and rerun npm install; never bypass
the check. Each worktree gets its own .e2e/; only the npm download cache and
the Playwright browser cache may be shared.
If Chromium exits at sandbox_host_linux.cc with Operation not permitted
inside an execution sandbox, classify it as test infrastructure and request an
approved run outside that sandbox. Do not work around it with extra unsafe
browser flags or a different browser binary.
Run formal E2E from the task's assigned immutable worktree or the explicitly justified detached worktree described above, never from the main worktree or an unrelated development worktree.
One run owns one worktree + SHA, one set of API/Runner/Gateway processes and ports, one data directory, and one artifact directory. Parallel runs must be fully isolated or serialized. Start the stack from the worktree root:
./scripts/start-stack.sh --mode local # provisions and builds
./scripts/start-stack.sh --mode local --no-build # only if the build matches this SHAIsolation variables (set for start-stack.sh and the API alike):
| Variable | Default | Meaning |
|---|---|---|
SCIENCE_AGENT_PORT | 4410 in the E2E layer (the product itself defaults to 4310) | API/Web port. The layer keeps its own block so a test stack never competes with the instance a person leaves running. |
SCIENCE_AGENT_RUNNER_PORT | 4411 in the E2E layer (product default 4311) | where the runner listens; the layer also moves evolve to 4413 and memory-graph to 17774 |
SCIENCE_AGENT_RUNNER_URL | http://127.0.0.1:<port> | where the API dials — the API does not read SCIENCE_AGENT_RUNNER_PORT, so on a non-default port always set the full URL too |
SCIENCE_DISCOVERY_DATA_DIR | <CI_RUNTIME_DIR>/data, and CI_RUNTIME_DIR itself falls back to the gitignored .e2e-data/ | data root for a test run; also holds envs/ (service venvs). Separate by default from .sciencediscovery-data, which belongs to a person's own instance. (SCIENCE_AGENT_DATA_DIR is the deprecated spelling.) |
SCIENCE_AGENT_AUTH_TOKEN | generated when omitted | Optional server-side override; never assume a literal default |
E2E_API_TOKEN | none | Required browser/API token; use the value printed/generated by this isolated stack |
E2E_BASE_URL | http://127.0.0.1:4410 | must point at the same API the fixtures use. The fallback names the test stack, not the product default, so an unconfigured run fails to connect instead of driving someone's own instance. |
E2E_ALLOW_STACK_RESET | unset | Permission for a journey to delete records it did not create, so a first-run journey can reach an empty instance. .ci/run-e2e.sh sets it for the throwaway stack it starts; never export it for a stack whose data someone would miss. Without it such a journey is reported BLOCKED rather than clearing anything. |
UV_CACHE_DIR | uv default (~/.cache/uv) | Pin inside the run worktree (for example $SCIENCE_AGENT_DATA_DIR/uv-cache). The home cache sits outside the worktree and fails in environments that cannot write $HOME/.cache. |
After starting, verify API/Runner and any other service required by the
journey; verify the web entry for browser journeys. Export the stack's token
as E2E_API_TOKEN; browser global setup fails before the first scenario when
it is absent. Non-browser clients must use the same stack and authentication.
When a required service,
port, or credential is missing, record the run as BLOCKED with the missing
item — never skip silently.
Isolation traps that produce confusing failures:
.sciencediscovery-data/envs between worktrees (no symlinks). The service
venvs are editable installs: their .pth files point back at the source
tree of whichever worktree provisioned them, so a shared venv silently runs
another worktree's code. Provision per worktree; uv sync is fast when
UV_CACHE_DIR points at a worktree-local cache.UV_CACHE_DIR inside the worktree. uv's default cache is
~/.cache/uv. Export UV_CACHE_DIR to a run-owned path (for example
$SCIENCE_AGENT_DATA_DIR/uv-cache) before start-stack.sh / uv sync. A
permission error against the home cache is test infrastructure, not a
product defect. npm and Playwright browser caches may still be shared as
above; do not send uv's cache to $HOME..worktrees/ lives inside the main repository, and the gateway's dotenv
loading searches parent directories, so the main repo's .env (its ports,
data dir, model config) leaks into the gateway even when the worktree has no
.env. Explicitly exported variables win over dotenv; alternatively copy a
trimmed .env into the worktree as the run's baseline.For repository CI scheduling, use the cross-runner catalog from the repository root before assembling a stack:
pnpm ci:tags
pnpm ci:list -- --tag layer:e2e --tag llm:stub --tag arch:amd64
pnpm ci:run -- --case e2e.mockedEvery catalog case declares arch:*, llm:*, npu:*, and sandbox:* plus
layer/container/network tags. Repeated --tag clauses mean AND; comma-separated
tags within one clause mean OR; --exclude removes matches. Keep e2e.mocked,
e2e.real, and e2e.legacy aligned with the Playwright projects below whenever
their requirements change. Never reclassify an unaudited dependency as safe:
use an unreviewed tag or keep the case unsupported until evidence exists.
The catalog chooses a CI-capability group; it no longer decides which journeys
run. That is the shared plan: pnpm ci:e2e freezes category:e2e from the
source tags and requires every planned journey to report a pass. To see the
plan without running anything, pnpm test:list --slice e2e writes it to
.test-runs/e2e/plan.json. Use the pinned .e2e commands below for
file/title-level discovery while writing a spec.
Run from .e2e/ after synchronizing and installing the committed environment:
npm run check:meta # validate metadata, tags, quarantine
npm run test:list # list only @mocked (safe default)
npm test # run only @mocked (same as below)
npm run test:mocked # run only @mocked
npm run test:real:list # discover only @real; makes no live call
npm run test:real # RUN live @real (explicit opt-in)
npm run test:mixed:list # discover @mocked + @real
npm run test:mixed # RUN both groups (explicit opt-in)
npm run test:mocked -- foo.spec.ts # one file, relative to test/
npm run test:mocked -- -g "title" # semantic title filterThe mocked group is credential-free, not stack-free: start the isolated stack before the default suite. Only explicitly self-contained specs such as the network guard may run without it.
Grouping is enforced by the Playwright projects in
test/playwright.config.ts:
mocked — only specs tagged @mocked. It is the sole default project and
uses a journey-owned local stub model to drive deterministic, user-visible
product contracts (for example permission feedback, tool process, artifacts,
and environment state). It must be hermetic, credential-free, stable, and
repeatable. Its custom test fixture installs the HTTP(S)/WebSocket guard
before hooks or pages. The project also blocks service workers so they
cannot bypass routing.real — specs tagged @real. The project is defined only when E2E_REAL=1
is set, so no default command can trigger live LLM calls, network access, or
paid usage. Without the variable, --project=real fails with "Project(s)
'real' not found": that run is BLOCKED, not passed. Keep this group small:
it is a smoke check that a real user can express the goal naturally and
reach the outcome, not a duplicate deterministic matrix. Assert stable user
invariants, never exact model wording or a single incidental tool sequence.legacy — untagged specs listed in LEGACY in
test/check-e2e-meta.mjs. They are quarantined because their external
behavior has not been audited. Use npm run test:legacy:list to inventory;
run npm run test:legacy only with explicit approval and the same caution as
real tests. During initial adoption, only pre-existing unaudited specs from
the base branch may enter LEGACY; never place a newly written journey there.
Migrate the list incrementally without making old specs undiscoverable.test:real and test:mixed are execution opt-ins, not discovery commands.
Before using either, inspect E2E-META, confirm credentials/endpoints/costs and
record authorization. A skipped real test with a BLOCKED: reason remains
BLOCKED in the run report; zero failures does not turn blocked/skipped cases
into PASS.
Each test() carries an E2E-META comment directly above it and a matching
{ tag: "@mocked" } or { tag: "@real" } option. node test/check-e2e-meta.mjs
enforces the fields and tag consistency (legacy files are warned until
migrated; new files must comply). Template:
/**
* E2E-META
* Purpose: <the user-visible behavior this verifies>
* Steps:
* 1. <main step>
* 2. <main step>
* Environment: <stack, base URL, services, ports, data/fixture preconditions>
* Type: mocked | real
* LLM: <none | local stub | provider/model/endpoint and nondeterminism>
* WebSearch: <none | engine/endpoint and expected queries>
* PaperSources: <none | PubMed/arXiv/etc. and expected queries/downloads>
* MCP: <none | server/tools and expected calls>
* OtherExternal: <none | any other network/process/service behavior>
* Credentials: <none | exact env vars or seeded configuration>
* CostSideEffects: <none | fees, rate limits, writes, messages, mutations>
*/Mocked example:
/**
* E2E-META
* Purpose: A hung agent turn times out with a user-visible reason.
* Steps:
* 1. Register a silent local stub model over the API.
* 2. Start a run and wait for the idle timeout.
* 3. Assert the timeout reason in the session view.
* Environment: Running stack at E2E_BASE_URL; isolated data; no models.
* Type: mocked
* LLM: local silent HTTP stub only; no live model.
* WebSearch: none
* PaperSources: none
* MCP: none
* OtherExternal: none — non-local browser requests are aborted.
* Credentials: none
* CostSideEffects: no cost; temporary records are deleted in finally.
*/
test("超时原因可追溯", { tag: "@mocked" }, async ({ page }) => {Real example:
/**
* E2E-META
* Purpose: A live model run produces an anchored plan card.
* Steps:
* 1. Register the real model via env config; create project/session.
* 2. Run a planning prompt; assert the card position.
* Environment: Isolated stack at E2E_BASE_URL; E2E_SCREENSHOTS for output.
* Type: real
* LLM: real chat completions via E2E_LLM_BASE_URL; output varies.
* WebSearch: none
* PaperSources: none
* MCP: none
* OtherExternal: none
* Credentials: E2E_LLM_BASE_URL / E2E_LLM_MODEL / E2E_LLM_TOKEN.
* CostSideEffects: billable tokens and provider rate limits; creates isolated records.
*/
test("plan card anchors", { tag: "@real" }, async ({ page }, testInfo) => {
requireRealEnv(testInfo, "E2E_LLM_BASE_URL", "E2E_LLM_MODEL", "E2E_LLM_TOKEN");
await requireRealStack(testInfo);
// Check any seeded model/connector state here and testInfo.skip(true, "BLOCKED: ...")
// only when that identifiable precondition is absent.
await page.goto("/");
// Product assertions after satisfied gates still FAIL normally.
});Every test/journey-*.spec.ts must be written as user steps through the
journey fixture. This is a requirement, not a suggestion:
node test/check-e2e-meta.mjs fails a journey spec that does not request the
{ journey } fixture, does not call journey.scenario(...), does not call
journey.step(...), or takes its own page.screenshot().
journey.step() = one user step. Use the steps from the journey's
design document. Merge adjacent micro-interactions (fill three fields, then
save) into the step a user would name; never split by internal module and
never make one step per click.page.screenshot("01-...") as primary evidence.journey.scenario({ goal, preconditions }) is required, at the top of
the test. It supplies the report's goal and preconditions; without it the
report falls back to the English E2E-META Purpose/Environment, which is
contract text rather than an explanation for a reader..e2e/journey-reports/<spec>/<test>/ (gitignored) receives:
| File | Content |
|---|---|
report.md | Result, commit SHA under test (and whether the tree was dirty), spec file, group/tags, start/end/duration, scenario goal, preconditions, gate reason when blocked, the step table, and per-step detail |
report.html | The same content, self-contained: inline CSS only, screenshots by relative path, opens from the filesystem with no network |
NN-<step>.png | One screenshot per step, in step order; a step that failed or was blocked is suffixed accordingly |
Per-step "key logs" are browser console errors/warnings, page errors, failed
requests, and any response with status ≥ 400 — recorded as method, URL, and
status. Bodies are never captured. Every recorded string passes through
redaction: known credential variables, Bearer values, token=/api_key=
query parameters, the repository root, and the home directory are replaced. Keep
it that way; reports get published.
Both files are also attached to the Playwright HTML report, so a CI run carries them without a separate copy step.
Set E2E_JOURNEY_REPORTS to redirect the output root. Never commit reports,
screenshots, or .e2e/.
import { expect } from "@playwright/test";
import { test } from "./helpers/e2e.ts";
import { createProjectAndSession, openProjectSession, scriptedModel,
sendUserMessage, waitForRunTerminal, expandToolStep, cleanupJourney } from "./helpers/journeys.ts";
/**
* E2E-META
* ... all eleven fields ...
*/
test("J9 用户可以拿到一次可核对的执行结果", { tag: "@mocked" }, async ({ journey, page }) => {
journey.scenario({
goal: "一位研究员要确认产品真的在本机执行了他要求的计算,而不只是在聊天。",
preconditions: ["隔离栈已启动", "模型由旅程自带的本地 stub 驱动,不访问外部服务"],
});
const marker = `J9-${Date.now()}`;
const stub = await scriptedModel([
{ arguments: { command: `echo ${marker}` }, tool: "run_shell" },
{ text: "The requested check completed." },
]);
const fixture = await createProjectAndSession(page, {
model: { apiToken: stub.apiToken, baseUrl: stub.baseUrl, model: stub.model, name: `J9 ${Date.now()}` },
projectName: `J9 ${Date.now()}`,
sessionTitle: `J9 ${Date.now()}`,
});
try {
await journey.step(
"进入会话并提出请求",
"任务发出后运行走到完成态,主按钮回到可再次运行的状态。",
async () => {
await openProjectSession(page, fixture);
const run = await sendUserMessage(page, fixture.session.id, "Check the workspace and report what you find.");
expect((await waitForRunTerminal(page, fixture.session.id, run.id)).status).toBe("completed");
},
);
await journey.step(
"展开工具步骤核对输出",
"工具步骤展开后能看到这次执行的真实输出,说明命令确实跑过。",
async () => {
await expect(await expandToolStep(page, { contains: marker })).toContainText(marker);
},
);
} finally {
await cleanupJourney(page, fixture);
await stub.stop();
}
});A @real journey follows the same shape; put requireRealEnv(...) and
await requireRealStack(...) inside the first journey.step, so a run
without credentials still produces a report whose first step reads
⛔ 前置未满足 with the gate reason.
Specs quarantined in LEGACY may adopt this incrementally; they are not
blocked on it. A new file has no grace period: any spec added as
journey-*.spec.ts complies on its first commit, and a non-journey spec that
grows into a full user flow should be renamed and converted rather than kept as
an untracked exception.
node:http createServer on
127.0.0.1, registered through /api/models) or a seeded fake such as the
hang/slow models. Never read E2E_LLM_* in a mocked spec, and never rely on
a real model configured in the stack's .env.test from test/helpers/e2e.ts, never directly from
@playwright/test. Its automatic fixture aborts non-local HTTP(S),
policy-closes non-local WebSockets, and forwards localhost/loopback traffic
before any beforeEach, navigation, or request. check-e2e-meta.mjs
enforces this import for every Type: mocked file, including fixme tests
when later enabled.test/e2e-network-guard.spec.ts passing as the request-level proof for
blocked HTTPS/WebSocket and allowed local HTTP/WebSocket behavior.test/support/tagged/MIGRATION.md), which is frozen from source tags before
the run looks at anything, so a skip is a planned journey that did not
execute — the run fails on it rather than reporting green. The layer starts
its own stack on a run-scoped data directory, so a precondition it owns
(empty first-run state, no writable Skill library, a ready managed Python
base) is asserted with expect, and a failure there is an isolation bug in
the layer, not a reason to decline the journey. A precondition the layer
genuinely cannot own belongs to another group: give the spec the tag that
says so (@model:real, @status:legacy, @status:external,
@status:unreviewed) with a comment explaining why, and it leaves the shared
selector instead of skipping inside it. The gates below still apply to
@real journeys, which are outside that plan.E2E_REAL=1), tagged @real, and declare
their external behavior and cost in E2E-META.beforeEach-equivalent
navigation, API setup, LLM, search, paper-source, or MCP actions, call
requireRealEnv(testInfo, "E2E_LLM_BASE_URL", "E2E_LLM_MODEL", "E2E_LLM_TOKEN")
and await requireRealStack(testInfo). Do not put the gate only at file
scope. check-e2e-meta.mjs enforces both calls per real test body and their
order relative to the first external action.allowRealEnvException(testInfo, "specific reviewed reason"); the stack
gate remains mandatory and the exception appears in test annotations.testInfo.skip(true, "BLOCKED: ...") with a specific reason before first use only
when that identifiable precondition is absent. Once gates pass, product
assertion failures must remain FAIL. Report all gate skips as BLOCKED, never
as passes.Keep score collection separate from diagnostics. Use
node .ci/prepare-real-e2e-results.mjs to stage real-e2e-results: only exact
benchmark-metrics.json, team-metrics.json, evolve-metrics.json basenames
and e2e-real/tagged/{plan,summary,preflight}.json are allowed. Preserve their
relative paths. The staging script projects metrics to score/status/duration
fields and removes free-form tagged errors; prompts and raw model output stay
in diagnostic evidence. Never write credentials to either artifact. Keep new
public fields explicitly allowlisted and covered by packaging tests. Upload the full .ci-results separately as real-e2e-evidence, never
as dashboard input. Both uploads run with if: always(), seven-day retention,
if-no-files-found: warn and include-hidden-files: true.
Mocked e2e-results keeps its results and HTML with linked resources so the
dashboard can host the journeys. If that artifact exceeds 80 MiB, split out
only diagnostic traces, not HTML or results. See
CI artifact rules and validate packaging changes with
node --test .ci/ci-contract.test.mjs; no live model run is needed for packaging
fixtures.
Organize files and describe blocks by user goal, not by implementation
module. A journey may use shell, Python, an environment, a subagent, and
artifact versioning in one coherent flow. Small negative/cancel/recovery
cases may sit beside the journey they qualify. Name main-flow files after
the goal (journey-first-run.spec.ts, journey-deliver-result.spec.ts),
never after an internal tool (shell.spec.ts, python.spec.ts).
Use test/helpers/journeys.ts for common user actions: model registration
and selection, Project/Session setup, natural-language submission, Run
terminal-state waiting, permission handling, timeline/tool-process reading,
environment revision lookup, and opening the environment or artifact
surfaces. Use scriptedModel(mainSteps, subagentSteps?) for deterministic
tool/text sequences; it routes general-purpose subagent requests by their
preset system marker. Use expandToolStep(page, { contains }) with a
journey marker instead of making run_shell or run_python the only
locator. artifactTree(page) deliberately exposes the declared catalog,
@ candidates, and the opt-in physical workspace tree as separate views.
The helpers return records, locators, and visible text; the spec still owns
goal-specific assertions.
Use the journey fixture from test/helpers/e2e.ts (implemented in
test/helpers/journey-report.ts) to structure the test as user steps and
produce its report. See Journey steps and automatic
reports for the full
contract and a copyable skeleton.
Prefer semantic locators (getByRole, getByLabel, getByText); when only
a CSS hook works, that is also an accessibility signal worth noting.
Wait on observable conditions (toast visible, button state, request finished); never sleep-and-hope. Assert user-visible outcomes, not merely that a request or click happened.
Create test data with unique names (Date.now() suffix) and clean up in
finally where practical; leftover data must stay in the run's own data
directory.
Long-term regression specs live in test/; throwaway diagnostic specs stay
in the E2E worktree and are never committed.
journey.step() names
them in step order, waits for the page to settle, and files them with the
step they belong to. Add evidence by adding or resplitting a step, never by
calling page.screenshot() — check-e2e-meta.mjs rejects that.screenshots/
relative to the Playwright cwd (i.e. .e2e/screenshots/), or to
E2E_SCREENSHOTS when the spec supports it, named in step order.animations: "disabled" (and
caret: "hide") from journey.step(). Ad-hoc page.screenshot() calls
must set the same animations: "disabled" option; omitting it leaves CSS
transition ghosts in otherwise stable shots. Eyeball every screenshot after
the run; retake any that does not match its caption — a screenshot that
contradicts its step description is a report defect.trace: retain-on-failure); reports land in playwright-report/ and
test-results/ (including results.json) next to the config in use. Journey
reports are additionally attached to each test in the Playwright HTML report..e2e/ (which contains journey-reports/),
test/node_modules, test/playwright-report/, test/test-results/,
screenshots, traces, or logs — all gitignored. Committed files are the specs,
test/e2e.package.json + test/e2e.package-lock.json,
test/playwright.config.ts, test/helpers/ (including
helpers/journey-report.ts), test/sync-e2e.mjs, and
test/check-e2e-meta.mjs.report.md, report.html, and that
directory's .png files out as a unit — the HTML references the images by
relative name, so the folder must stay together.Prefer negative and fault injections that do not modify tracked files. Keep the target worktree read-only. If tracked changes are unavoidable, use a separate worktree derived from the target and create a test-only commit or an exact index/patch snapshot before injection. Restore from that snapshot and report the derived commit when present; never pollute the target candidate.
| Type | Judgment |
|---|---|
| Product defect | UI/API/Gateway/Runner/orchestration breaks the user goal or gives no reasonable feedback |
| External environment | A third-party dependency failed and the product prompted or degraded correctly |
| Test defect | Selector, wait, timeout, fixture, or assertion is wrong; the product behaves |
| Test infrastructure | Worktree/port/data clash, wrong service, build ≠ SHA, dependency assembly or discovery error |
A timeout is a tripwire, not a conclusion: confirm whether the run was issued,
the service responded, and the UI/API/CLI gave feedback. Every verdict needs at least
one piece of evidence (network log, console, service log, product message,
screenshot, trace); timeouts need two points along that chain. An external
failure the product swallows silently is still a product defect. Fix test or
infra problems and rerun; record BLOCKED when the cause cannot be separated.
Archive evidence first, then stop the stack, free the ports, and remove run
data and .e2e/ from the assigned worktree. Do not remove the task worktree;
its lifecycle belongs to the task owner. Remove a separate detached E2E
worktree only when this run created it for one of the justified isolation
reasons above. The main worktree must remain untouched.
© openJiuwen-ai, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/e2e-testing of openJiuwen-ai/sciencediscovery.
Open the folder on GitHubat commit 9189206
E2E Testing next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| E2E Testing this skillopenJiuwen-ai/sciencediscovery | 156 | — | ~9.1k | Automated safety check: Notes | Apache-2.0 | |
| Playground Msw Testsmastra-ai/mastra | 29k | — | ~2.6k | Automated safety check: Pass | Custom licence | |
| Playwright TestAI-Unified-Process/marketplace | 142 | — | ~3.8k | Automated safety check: Warn | Apache-2.0 | |
| Solution Testingkid-sid/claude-spellbook | 190 | — | ~3.9k | Automated safety check: Pass | MIT | |
| Web Application Testinganthropics/skills | 180k | 51 repos | ~966 | Automated safety check: Pass | Apache-2.0 | |
| Write and Verify Playwright Testsappsmithorg/appsmith | 41k | — | ~2.9k | Automated safety check: Notes | Apache-2.0 |
mastra-ai/mastra
REQUIRED and PRIMARY testing approach for packages/playground and packages/playground-ui.
AI-Unified-Process/marketplace
Creates Playwright browser-based tests for Vaadin views using the Drama Finder library for type-safe element wrappers with accessibility-first APIs.
kid-sid/claude-spellbook
A skill your agent uses when writing Playwright E2E tests for critical user journeys, setting up post-deployment smoke tests, debugging flaky browser automation, or implementing BDD feature files…
anthropics/skills
Tests local web applications with Python Playwright scripts, checking frontend behavior, capturing screenshots and reading browser console logs.
appsmithorg/appsmith
Writes a Playwright end-to-end test from a prompt, runs it against a live Appsmith deployment and retries with fixes up to three times until it passes.
github/gh-aw
Drives a real browser from the command line with playwright-cli to open pages, interact, mock requests, save state and work with Playwright tests.
openJiuwen-ai/sciencediscovery
A skill your agent uses when you need to write and execute Python/R code to process, transform, and analyze data, delivering reproducible computational results with complete code-level methodology…
openJiuwen-ai/sciencediscovery
Operate GitCode issues, PRs, wikis, code/MR refs, and cached org templates.
openJiuwen-ai/sciencediscovery
Inspect a local PDB structure, summarize chains and residue composition, and identify protein atoms near a user-specified ligand or pocket center.
openJiuwen-ai/sciencediscovery
Prepare, launch, monitor, and summarize the real RFdiffusion to ProteinMPNN to Protenix antibody pipeline on a local or remote ScienceDiscovery Runner with sandboxed Ascend NPUs.
openJiuwen-ai/sciencediscovery
A skill your agent uses to orchestrate a multi-domain research team for literature/evidence research and data analysis.
openJiuwen-ai/sciencediscovery
A skill your agent uses when a research workflow needs verified academic source retrieval through literature-search MCP interfaces available in the current session before evidence extraction.
Works with
Categories
Design, extend, and run ScienceDiscovery E2E user journeys through the browser, public HTTP API, CLI, or local product stack. E2E Testing is an agent skill from openJiuwen-ai/sciencediscovery. Design, extend, and run ScienceDiscovery E2E user journeys through the browser, public HTTP API, CLI, or local product stack.
E2E Testing fits situations like: changing user-observable behavior; selecting mocked/real journeys; isolating a test stack; reporting user outcomes.
Run `npx skills add openJiuwen-ai/sciencediscovery --skill e2e-testing -a claude-code`. Or copy the skill folder (.agents/skills/e2e-testing in openJiuwen-ai/sciencediscovery) into .claude/skills/e2e-testing in your project. Claude Code loads it when a task matches its description.
Run `npx skills add openJiuwen-ai/sciencediscovery --skill e2e-testing -a codex`. Or copy the skill folder (.agents/skills/e2e-testing in openJiuwen-ai/sciencediscovery) into .agents/skills/e2e-testing in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add openJiuwen-ai/sciencediscovery --skill e2e-testing -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/e2e-testing, .gemini/skills/e2e-testing, .github/skills/e2e-testing and .opencode/skills/e2e-testing in your project.
Going by SKILL.md and its folder, E2E Testing needs the command-line tools its instructions call (npm, pnpm, node, uv, git and playwright) and credentials named E2E_API_TOKEN, E2E_LLM_TOKEN and SCIENCE_AGENT_AUTH_TOKEN. Our summary lists: Node.js; A credential in SCIENCE_AGENT_AUTH_TOKEN; A credential in E2E_API_TOKEN.
SKILL.md contains no URLs. Its commands use npm, uv, git and npx, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.
E2E Testing is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 9.1k tokens (SKILL.md is roughly 37k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with E2E Testing: Playground Msw Tests (mastra-ai/mastra, 29k stars), Playwright Test (AI-Unified-Process/marketplace, 142 stars), Solution Testing (kid-sid/claude-spellbook, 190 stars) and Web Application Testing (anthropics/skills, 180k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
openJiuwen-ai (a GitHub organization) maintains it in openJiuwen-ai/sciencediscovery, which has 156 GitHub stars. The repository holds 22 skills in this directory. The repository was last updated on October 9, 2026.
Source: openJiuwen-ai/sciencediscovery on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.