An interactive visualization project for software testing — 43 explorers across 7 sections: foundations, coverage criteria, execution & test generation, black-box design, group-theory testing, AI-assisted research methods (based on the Meta ACH paper at FSE 2025, arXiv 2501.12862), and system / E2E / acceptance testing.
Live demo: https://skhuang.github.io/stvisual/
Every explorer ships with bilingual UI (English / 繁體中文), a self-test quiz, Lab Reflect / Lab Metric modes, and shareable result URLs. Class results stream to Firestore and surface in a Teacher Dashboard. Every Explorer is also tagged across five dimensions (level / technique / series / difficulty / source) so the Overview supports tag-chip filtering, course-pack presets, and per-Explorer deeplinks (e.g. ?explorer=PairwiseExplorer).
| Overview | Graph Coverage |
|---|---|
![]() |
![]() |
| Logic Coverage | Syntax-Based Testing |
|---|---|
![]() |
![]() |
| Symbolic Execution | Concolic Execution |
|---|---|
![]() |
![]() |
Screenshots above are from the original Foundations + Coverage sections; newer explorers (Group Theory, Risk-Based, Advanced Testing / AI-Assisted) are best seen on the live demo.
- Visualizes testing method categories: black-box, white-box, gray-box, and their sub-techniques
- Animates the testing workflow from requirements analysis to defect reporting
- Shows common testing levels: unit, integration, system, and acceptance testing
- Node Coverage, Edge Coverage, Prime Path Coverage, Edge-Pair Coverage, Complete Path Coverage
- Data Flow Graph (DFG) derived from source; DU-pair and all-uses coverage criteria
- Automatically generates test requirements and test path sets
- Greedy set-cover approximation to reduce the selected test path set
- Displays before/after optimization metrics and saved path count
- Lets users edit the graph structure live or upload JSON graph specs / source code
- Supports multiple languages (JavaScript, Python, C, Java)
- Self-test (quiz) mode: select a minimal covering path set and check your answer
- Predicate Coverage (PC), Clause Coverage (CC), Combinatorial Coverage (CoC)
- Active Clause Coverage: GACC / CACC / RACC
- Inactive Clause Coverage: GICC / RICC
- Syntactic (DNF-based) criteria: IC / UTPC / MUTPC / NFPC / MNFPC / CUTPNFP
- Renders truth tables, identifies major / minor clauses, and marks duplicate test rows
- Computes minimized DNF via Quine–McCluskey and renders Karnaugh maps for
fand¬f(n = 1–4) - Per-implicant coloring, UTP / NFP badges, and paired UTP↔NFP for CUTPNFP
- Supports textbook predicate notation: adjacency for AND (
ab) and+for OR (a+b) - Built-in predicates: triangle classifier, leap year, calendar days, GCD, binary search
- 6 mutation operators (AOR / ROR / LOR / COR / UOI / ABS) over JavaScript expressions
- Editable program body, parameters, and test set; built-in examples (
max,isLeapYear,triangle) - Mutation score progress bar, killed / live / equivalent badges, and per-operator mutant grouping
- Grammar-based testing and specification mutation (SMV) sub-tabs
- Symbolic execution: explores all feasible paths; displays path conditions and variable bindings
- Concolic execution: DART/CUTE-style; starts from concrete input, negates branches to explore new paths
- Both map executed paths onto the CFG with zoomable SVG rendering
- Mutation-based fuzzing: seed corpus, configurable mutation budget, coverage-guided iteration
- Automated test generation from symbolic paths with download-as-JS export
Nine techniques live under a single tabbed section:
| Tab | What it covers |
|---|---|
| Boundary Value Analysis | 5-point BVA and Robustness BVA; multi-parameter; self-test quiz |
| Equivalence Classes | Weak (WECT) and Strong (SECT) ECP; partition editor; self-test quiz |
| Decision Table | Condition/action matrix; T/F/– cells; coverage badge; duplicate detection |
| State Transition | SVG state diagram; transition coverage and sequence coverage (BFS paths) |
| Pairwise | IPO greedy algorithm; covering matrix; vs full Cartesian product reduction |
| Cause-Effect Graph | SVG cause-effect graph; AND/OR/NOT connectors; auto-derived decision table |
| Metamorphic Testing | 5 built-in programs × 2–3 relations; generates 8 test pairs; pass/fail table |
| Exploratory Testing | Session charter; SFDIPOT heuristics checklist; HICCUPPS oracle reference; countdown timer; observation log with Markdown export |
| Test Doubles | Dummy / Stub / Fake / Mock / Spy; 2 runnable scenarios per type; live call-log + assertion results |
- Statement / Branch / Condition / MC-DC coverage on small JavaScript programs
- Per-line highlighting; subsumption hint (
MC-DC ⊇ Condition ⊇ Branch ⊇ Statement) - Built-in programs:
absVal,discount(age, isMember),classify,maxOf3 - Self-test: identify the strongest criterion satisfied by the current suite
- Symbolic execution explores all feasible paths and renders path conditions
- Concolic execution (DART/CUTE-style) starts from concrete input and negates branches
- Fuzz testing with mutation-based corpus, CFG coverage heat-map
- Test generation from coverage with download-as-JS export
- Integration testing strategies — Big Bang / Top-down / Bottom-up / Sandwich with step-by-step stub/driver visualization
- Property-based testing — QuickCheck-style random input generation, automatic shrinking, counterexample visualization
- Risk matrix (Likelihood × Impact) with heat-map view
- Module ranking by risk score; filter to high-only / high+medium / all
- Lab Metric: complete the ranked test order under a budget constraint
- Three tabs sharing one Boolean formula:
- Orbit Explorer — automorphism group, orbit partition of truth table, MR copy-button
- CACC Bridge — determination pairs from logic predicates, with “must test” vs “derivable by symmetry” classification
- Covering Array — OA(p, k, t) generator over GF(p), full orbit coverage check
- Cross-explorer bridges: Group Theory ↔ Logic Coverage ↔ Metamorphic Testing
- Per-tab self-test and Lab Reflect questions
Five explorers tabbed under a single Advanced Testing section, all backed by the Meta ACH paper (arXiv 2501.12862, FSE 2025):
| Tab | What it teaches |
|---|---|
| Equivalent Mutants | Three-stage pipeline (syntactic identity → strip-comments → LLM-as-judge); precision 0.79 → 0.95 and recall 0.47 → 0.96 once comments are stripped |
| Mutation Score vs Coverage | Dual line-coverage / mutation-score meters; demonstrates the 49% of ACH tests that kill mutants without adding a single covered line |
| LLM Test Generation Pipeline | Three-agent ACH flow (Mutation → Equivalence → Test); prompt templates, sample I/O, failure modes; rule-based vs LLM-guided kill-rate comparison (2.4% → 15%) |
| Test Quality Review | Five engineer-acceptance dimensions (Buildable / Non-flaky / Hardening / Relevant / Style) across six annotated scenarios |
| Fault-Directed Testing | Blind coverage-driven vs fault-directed mutation across four issue scenarios (null leak, off-by-one, missing cleanup, unchecked exception) |
Every Advanced Testing tab shares the same paper-citation banner (arXiv 2501.12862 · FSE 2025) and ends with a quiz plus a reflection prompt.
Eight explorers tabbed under a single Acceptance & E2E section, filling the upper testing-pyramid (system / E2E / acceptance / non-functional) gap:
| Tab | What it teaches |
|---|---|
| BDD / Gherkin | Feature → Scenario → Step parsing with bound/unbound step highlighting; Scenario Outline + Examples table auto-expands to N parameterized cases; bridges to Decision Table |
| Use Case Derivation | Jacobson's classic main + alternate + exception flow derivation; coverage meter; bridges exception flows to Risk-Based prioritization |
| E2E User Journey | Multi-step journeys tagged per step with one of 5 flakiness sources; deterministic Monte-Carlo simulation of "run 100×" and per-step pass-rate fall-off |
| Contract Testing (Pact) | Consumer/Broker/Provider triad with three breakage kinds (missing-required-request, missing-response-field, status-mismatch); consumer × provider verification matrix |
| Performance Load Profile | Load / Stress / Spike / Soak sparklines × 3 system presets (gateway / DB-bound / CPU-bound); live Little's Law (L = λ × W); knee-of-the-curve marker |
| Chaos Engineering | Steady-state hypothesis vs injected fault on a service-dependency graph; BFS blast-radius propagation; hypothesis-holds verdict box |
| ATDD Cycle | Discuss → Distill → Develop → Demo with PO-involvement badges; TDD red-green-refactor inner loop visible inside Develop |
| Flaky Diagnosis | 8 sample failure logs across 6 flaky categories; per-source mistake bars expose what the student keeps mis-classifying |
Every tab is K1-tagged for filter/search and K4-routable as ?explorer=<ComponentName>.
- Lab Reflect — open-ended reflection prompts on every explorer; freeform text capture
- Lab Metric — pass/fail thresholds (e.g. Mutation Score ≥ 80%, full pairwise coverage)
- Share Results button copies a self-contained URL containing the quiz/lab outcome (no server signature, honor system)
- Result Viewer renders shared URLs side-by-side with the original explorer
Every Explorer carries multi-dimensional metadata in src/data/explorerTags.js:
| Dimension | Controlled vocabulary |
|---|---|
level |
unit · integration · system · e2e · acceptance · nonfunctional · meta |
technique |
22 values, e.g. coverage, mutation, fuzzing, symbolic, metamorphic, group-theory, llm-guided, bdd, chaos, risk, process |
series |
foundations · coverage-criteria · execution · blackbox · mutation-spec · group-theory · ai-assisted · acceptance-e2e |
difficulty |
intro · intermediate · advanced · research |
source |
textbook, paper:<id>, standard:<id> |
The Overview page renders this in two layers:
- Course packs (7 presets — Foundations, Coverage Criteria, Black-Box Design, Execution & Test Generation, Mutation Track, Group Theory, AI-Assisted Research). Clicking a pack chip applies its filter and reveals an ⬇ Export Markdown button that downloads a teaching handout with one row per Explorer, each containing a per-Explorer deeplink.
- Tag-chip filter (level / series / difficulty / technique chip rows). AND across dimensions, OR within a dimension; "Showing N of M sections" counter; "Clear all" resets.
Application state is fully encoded in the URL via src/utils/urlRouter.js so every view is bookmarkable / shareable:
| URL parameter | Effect |
|---|---|
?section=<id> |
Open that section on load |
?section=<id>&tab=<id> |
Plus pick the inner tab (for syntax / blackbox / advanced / flow / types) |
?explorer=<ComponentName> |
Single-param deeplink — resolves to section + tab via EXPLORER_TO_LOCATION. Example: ?explorer=PairwiseExplorer |
?pack=<id> |
Restore course-pack chip + its filter. Example: ?pack=ai-assisted |
?level= ?technique= ?series= ?difficulty= |
Tag-chip filter dims (comma-separated multi-values) |
?lang=zh (planned) |
URL-level locale lock — currently locale lives in localStorage |
URL writes use history.replaceState, so chip toggles don't pollute the back button. The K3 Markdown exporter emits a **Open:** <baseUrl>?explorer=<ComponentName> line per Explorer; baseUrl is injectable for self-hosting.
- Google sign-in via Firebase Authentication
- Firestore sync for predicates, test sets, and mutation data
- Google Drive upload for graph specs and source code
- Class results: students enter a class code; every quiz/lab submission is auto-uploaded to
courses/{classCode}/results/ - Teacher Dashboard: load results by class code, filter by explorer, drill into individual student submissions
flowchart LR
A[index.html] --> B[bootstrap.js]
B -->|http/https| C[main.js]
B -->|file://| D[standalone.js]
C --> E[app.js]
E --> F[UI components]
E --> G[testingData.js]
E --> H[utils/]
I[Vitest + jsdom] --> E
J[Playwright] --> A
K[GitHub Actions] --> I
K --> J
K -->|inject-env + build| L[GitHub Pages]
npm installnpm run devOpens http://localhost:4173 with Vite HMR. Cloud features require a .env.local file — see Environment Variables below.
open index.htmlThe app detects file:// and switches to a pre-built src/standalone.js bundle that avoids ES-module CORS restrictions.
npm run test:run656 tests across 57 files — covering every explorer, coverage algorithms, mutation engine, concolic/symbolic execution, group-theory utilities, the five Advanced Testing explorers, the URL router, the tag/course-pack metadata layer, and the eight Acceptance & E2E explorers.
npm run test:browser # headless
npm run test:browser:headed # with browser windowCloud features (Firebase Auth, Firestore, Google Drive) require credentials that are never committed to the repository. They live in src/config/cloudConfig.js as __PLACEHOLDER__ tokens and are replaced at build time by scripts/inject-env.mjs.
| Variable | Description |
|---|---|
FIREBASE_API_KEY |
Firebase Web API key |
FIREBASE_AUTH_DOMAIN |
Firebase Auth domain (<project>.firebaseapp.com) |
FIREBASE_PROJECT_ID |
Firestore project ID |
FIREBASE_STORAGE_BUCKET |
Firebase Storage bucket (<project>.appspot.com) |
FIREBASE_MESSAGING_SENDER_ID |
FCM sender ID |
FIREBASE_APP_ID |
Firebase App ID |
FIREBASE_MEASUREMENT_ID |
Google Analytics measurement ID (optional) |
DRIVE_UPLOAD_FOLDER_ID |
Google Drive folder ID for file uploads |
Option A — Vite dev server (recommended)
-
Copy the example file and fill in your values:
cp .env.example .env.local # edit .env.local -
Start the dev server — Vite reads
.env.localautomatically viavite.config.js:npm run dev
.env.localis gitignored. Never commit it.
Option B — Legacy static server
-
Copy and fill in
.env(used byinject-env.mjs):cp .env.example .env # edit .env -
Inject credentials and serve:
npm run inject-env # replaces __PLACEHOLDER__ tokens in cloudConfig.js npm run serve # Python http.server on :4173
After testing, restore the placeholder file so it is not accidentally committed:
git checkout src/config/cloudConfig.js
The live site is built and deployed automatically on every push to main via the Deploy GitHub Pages workflow (.github/workflows/deploy-pages.yml).
push to main
└─ test job (ubuntu-latest, Node 20)
├─ npm ci --legacy-peer-deps
├─ npm run test:run ← 656 unit tests must pass
├─ inject-env ← reads GitHub Secrets, writes cloudConfig.js
├─ build:standalone ← esbuild bundles src/ → standalone.js
└─ prepare-pages ← copies src tree → site/
└─ deploy job
└─ actions/deploy-pages@v4 ← uploads site/ to GitHub Pages
npm run pages:prepare runs three scripts in sequence:
| Step | Script | What it does |
|---|---|---|
| 1 | inject-env.mjs |
Reads env vars (CI Secrets or .env), replaces __PLACEHOLDER__ tokens in cloudConfig.js |
| 2 | build-standalone.mjs |
Uses esbuild to bundle the full app into src/standalone.js |
| 3 | prepare-pages.mjs |
Copies src/ tree, index.html, and writes site/.nojekyll |
The resulting site/ directory:
site/
├── index.html
├── .nojekyll
└── src/
├── bootstrap.js ← detects http vs file:// and picks entry point
├── main.js ← ES-module entry (used over http/https)
├── standalone.js ← esbuild bundle (used from file://)
├── app.js
├── styles.css
├── App.css
├── components/ ← all explorer JS + CSS files
├── data/
├── config/ ← cloudConfig.js with real credentials injected
├── utils/
└── i18n/
-
Enable GitHub Pages: go to Settings → Pages, set source to GitHub Actions.
-
Create secrets: go to Settings → Environments, create an environment named
github-pages, and add these Environment secrets:Secret Value FIREBASE_API_KEYFirebase API key FIREBASE_AUTH_DOMAIN<project>.firebaseapp.comFIREBASE_PROJECT_IDFirestore project ID FIREBASE_STORAGE_BUCKET<project>.appspot.comFIREBASE_MESSAGING_SENDER_IDFCM sender ID FIREBASE_APP_IDFirebase App ID FIREBASE_MEASUREMENT_IDAnalytics measurement ID DRIVE_UPLOAD_FOLDER_IDGoogle Drive folder ID Scoping secrets to the
github-pagesenvironment means they are only exposed to the deploy workflow — not to pull requests from forks. -
Push to
main— the workflow triggers automatically.
gh workflow run deploy-pages.ymlOr go to Actions → Deploy GitHub Pages → Run workflow in the GitHub UI.
The site/ directory is a plain static site with no server-side requirements. It can be served from Nginx, Caddy, S3, Netlify, or any CDN:
# build locally
cp .env.example .env && vim .env
npm run pages:prepare # → site/
rsync -av site/ user@host:/var/www/stvisual/If the app is served under a non-root path (e.g. https://example.com/stvisual/), set GITHUB_PAGES_BASE_PATH=/stvisual in .env before running pages:prepare.
| Workflow | File | Triggers | Jobs |
|---|---|---|---|
| Test | test.yml |
push / PR to main |
unit-test (Vitest), browser-test (Playwright/Chromium) |
| Deploy GitHub Pages | deploy-pages.yml |
push to main, manual |
test → inject-env → build → deploy |
Both workflows use Node.js 24 and npm ci --legacy-peer-deps.
.
├── index.html
├── package.json
├── vite.config.js # Vite dev server; reads .env.local for credentials
├── vitest.config.js
├── playwright.config.js
├── .env.example # credential template (safe to commit)
├── scripts/
│ ├── inject-env.mjs # replace __PLACEHOLDER__ tokens in cloudConfig.js
│ ├── build-standalone.mjs # esbuild → src/standalone.js
│ └── prepare-pages.mjs # assemble site/ for GitHub Pages
├── src/
│ ├── app.js # application shell + section/tab wiring
│ ├── bootstrap.js # http vs file:// entry switch
│ ├── main.js # ES-module entry (http/https)
│ ├── standalone.js # esbuild bundle (file://)
│ ├── styles.css # @import aggregator for all component CSS
│ ├── components/
│ │ ├── TestingMethodTree # method taxonomy tree
│ │ ├── TestingFlow # animated testing workflow
│ │ ├── TestingTypesTable # unit/integration/system/acceptance
│ │ ├── DefectCostExplorer # cost-of-defect curve by phase
│ │ ├── VModelExplorer # V-model with dev/test phase mapping
│ │ ├── PyramidAdjusterExplorer # interactive test-pyramid trade-offs
│ │ ├── GraphCoverageExplorer # graph + DFG coverage + self-test quiz
│ │ ├── LogicCoverageExplorer # predicate/clause coverage + K-maps
│ │ ├── CodeCoverageExplorer # statement/branch/condition/MC-DC
│ │ ├── SyntaxCoverageExplorer # program mutation (AOR/ROR/LOR/COR/UOI/ABS)
│ │ ├── GrammarCoverageExplorer # grammar-based testing
│ │ ├── SpecMutationExplorer # specification mutation (SMV)
│ │ ├── SymbolicExecutionExplorer
│ │ ├── ConcolicExecutionExplorer
│ │ ├── FuzzTestingExplorer # mutation-based fuzzing
│ │ ├── TestGenerationExplorer # path-driven test gen + JS export
│ │ ├── IntegrationTestingExplorer # Big Bang / Top-down / Bottom-up / Sandwich
│ │ ├── PropertyBasedTestingExplorer # QuickCheck-style shrinking
│ │ ├── RiskBasedTestingExplorer # risk matrix + heat-map + lab metric
│ │ ├── BoundaryValueExplorer # BVA + Robustness BVA + quiz
│ │ ├── EquivalenceClassExplorer # WECT / SECT + quiz
│ │ ├── DecisionTableExplorer # condition/action decision tables
│ │ ├── StateTransitionExplorer # SVG diagram + transition/sequence coverage
│ │ ├── PairwiseExplorer # IPO greedy covering set
│ │ ├── CauseEffectExplorer # cause-effect graph + decision-table derivation
│ │ ├── MetamorphicTestingExplorer # MR test-pair generation
│ │ ├── ExploratoryTestingExplorer # charter + SFDIPOT + timer + log
│ │ ├── TestDoublesExplorer # Dummy/Stub/Fake/Mock/Spy + live runner
│ │ ├── GroupTheoryExplorer # Orbit / CACC Bridge / Covering Array
│ │ ├── EquivalentMutantExplorer # I1 — 3-stage equivalence pipeline
│ │ ├── MutationScoreExplorer # I2 — mutation score vs line coverage
│ │ ├── LLMPipelineExplorer # I3 — 3-agent ACH flow
│ │ ├── TestQualityExplorer # I4 — 5-dimension quality review
│ │ ├── FaultDirectedTestingExplorer # I5 — blind vs fault-directed mutation
│ │ ├── BDDGherkinExplorer # J1 — Feature → Scenario → Step + Outline expansion
│ │ ├── UseCaseDerivationExplorer # J2 — Jacobson use-case flow derivation
│ │ ├── E2EUserJourneyExplorer # J3 — multi-step journey + flakiness Monte-Carlo
│ │ ├── ContractTestingExplorer # J4 — Pact-style consumer/broker/provider triad
│ │ ├── PerformanceLoadProfileExplorer # J5 — Load/Stress/Spike/Soak + Little's Law
│ │ ├── ChaosEngineeringExplorer # J6 — fault injection + blast radius propagation
│ │ ├── ATDDCycleExplorer # J7 — 4-D outer loop + TDD inner loop
│ │ ├── FlakyDiagnosisExplorer # J8 — 6-category flakiness log classification
│ │ ├── CloudStoragePanel # Firebase Auth + Firestore + Drive + class code
│ │ ├── TeacherDashboard # class-results dashboard (Firestore-backed)
│ │ ├── ResultViewer # render shared self-reported result URLs
│ │ ├── TagFilterBar # K2 — multi-dim chip filter on Overview
│ │ ├── CoursePackBar # K3 — course-pack chips + Markdown export
│ │ └── quiz.css # shared self-test quiz styles
│ ├── config/
│ │ └── cloudConfig.js # __PLACEHOLDER__ tokens (replaced at build time)
│ ├── data/
│ │ ├── testingData.js # technique metadata + predicate examples
│ │ ├── explorerTags.js # K1 — Explorer × 5-dim tag metadata + helpers
│ │ └── courseSeries.js # K3 — named course packs (filter-driven)
│ ├── i18n/
│ │ ├── index.js # t(), getLocale(), setLocale(), onLocaleChange()
│ │ └── dict.js # EN + ZH flat-key dictionary
│ ├── utils/
│ │ ├── graphCoverage.js # graph coverage algorithms
│ │ ├── programToGraph.js # source code → CFG + DFG
│ │ ├── dataFlow.js # def/use analysis + DU-paths
│ │ ├── logicCoverage.js # predicate/clause coverage engine
│ │ ├── logicBinding.js # analytic interval solver for clause binding
│ │ ├── karnaughMap.js # Quine–McCluskey + K-map rendering
│ │ ├── codeCoverage.js # statement / branch / condition / MC-DC engine
│ │ ├── mutation.js # mutation operator engine
│ │ ├── grammar.js # BNF grammar coverage + mutation
│ │ ├── specMutation.js # specification (boolean) mutation
│ │ ├── specFsm.js # safety-monitor FSM for SMV-style specs
│ │ ├── symbolicExecution.js
│ │ ├── concolicExecution.js
│ │ ├── fuzzTesting.js # mutation-based fuzzing engine
│ │ ├── testGeneration.js # path-driven test generator + JS export
│ │ ├── pathToCfg.js # branch trace → CFG SVG overlay
│ │ ├── blackboxTesting.js # BVA / ECP / DT / ST test generators
│ │ ├── pairwise.js # IPO greedy pairwise covering set
│ │ ├── causeEffect.js # cause-effect formula → decision table
│ │ ├── metamorphicTesting.js # MR test-pair generation engine
│ │ ├── propertyTesting.js # QuickCheck-style runner + shrinking
│ │ ├── groupTheory.js # automorphism / orbit / OA(p,k,t) over GF(p)
│ │ ├── resultExporter.js # base64 share-URL encoder / decoder
│ │ ├── urlRouter.js # K4 — ?section / ?tab / ?explorer / ?pack parsing
│ │ ├── coursePackExporter.js # K3+K5 — Markdown handout w/ per-row deeplinks
│ │ └── cloudIntegration.js # Firebase Auth + Firestore + Drive + class results
│ └── tests/ # 57 test files, 656 tests (Vitest + jsdom)
├── e2e/ # Playwright browser tests
├── site/ # generated GitHub Pages output (gitignored)
└── .github/workflows/
├── test.yml # PR/push: unit tests + browser tests
└── deploy-pages.yml # production: test → inject-env → build → deploy
New modules should be written in TypeScript (.ts) for type safety.
- Existing
.jsfiles: leave as-is; no migration needed - New files: create as
.tsinsrc/; Vite compiles them automatically tsconfig.jsonis present for editor support
This project is licensed under the MIT License.





