Skip to content

Commit 1c85abe

Browse files
committed
docs: Add Overview and Benchmarking guides (#8879)
1 parent ba4bae1 commit 1c85abe

3 files changed

Lines changed: 83 additions & 0 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Benchmarking and Performance Testing
2+
3+
> **Note:** The official Neo.mjs benchmarking suite and harness are maintained in a separate repository: [neomjs/benchmarks](https://github.com/neomjs/benchmarks).
4+
5+
## Philosophy: Measuring Resilience
6+
7+
Most web benchmarks (like Lighthouse or Core Web Vitals) focus on the "First Impression"—how fast a page loads. Neo.mjs, being an application engine for complex enterprise tools, focuses on the "Lived-In" experience.
8+
9+
Our benchmarking philosophy is not about "Page Load" time. It is about **Resilience**:
10+
* Can the UI handle 1,000 updates per second without freezing?
11+
* Can a grid ingest 100,000 rows while the user is scrolling?
12+
* Does the application remain responsive (60 FPS) during heavy background calculations?
13+
14+
## The Challenges of Benchmarking
15+
16+
Building a reliable benchmark for multi-threaded applications required solving three specific problems that standard test runners (like Playwright out-of-the-box) do not address.
17+
18+
### 1. The Parallelism Trap
19+
**Problem:** Standard test runners execute tests in parallel to save time. This is disastrous for benchmarking because tests compete for CPU resources, causing massive variance in results (up to 50%).
20+
**Solution:** Our harness enforces **Serial Execution** (`--workers=1`). Every test gets the full, undivided attention of the CPU.
21+
22+
### 2. The Latency Chasm
23+
**Problem:** Sending commands from Node.js (Test Runner) to the Browser introduces unpredictable network/process latency (The "Observer Effect").
24+
**Solution:** We use **Atomic Measurement**. The entire test sequence (Action -> Wait -> Measure) is injected into the browser via `page.evaluate()`. The measurement happens entirely within the browser's high-precision context, returning only the final result to Node.js.
25+
26+
### 3. The Polling Fallacy
27+
**Problem:** Standard `waitFor()` functions use polling (checking every ~30ms). You cannot measure a 20ms event with a 30ms ruler.
28+
**Solution:** We reject polling in favor of **MutationObservers**. Our harness attaches a listener that checks the pass condition *synchronously* on every single DOM mutation, allowing us to stop the timer with microsecond precision.
29+
30+
## Running the Benchmarks
31+
32+
To run the benchmarks, you must clone the separate repository:
33+
34+
```bash
35+
git clone https://github.com/neomjs/benchmarks.git
36+
cd benchmarks
37+
npm install
38+
npm run test
39+
```
40+
41+
**Why a separate repository?**
42+
The benchmarking suite provides direct, apples-to-apples comparisons between **Neo.mjs**, **React**, **Angular**, and **AG Grid**. To ensure a fair comparison, we include the full production build environments for these frameworks. Keeping the benchmarks separate ensures that the core `neomjs/neo` repository remains lightweight and free of these heavy third-party dependencies.
43+
44+
For detailed instructions on reproducing results and understanding the methodology, please refer to the documentation within that repository.

learn/guides/testing/Overview.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Testing Neo.mjs Applications
2+
3+
Testing is a critical part of the Neo.mjs ecosystem. Because of the framework's unique multi-threaded architecture, our testing strategy is divided into three distinct pillars, each serving a specific purpose.
4+
5+
## 1. Unit Testing (Logic & State)
6+
**Focus:** Core logic, State Management, VDOM Diffing.
7+
**Environment:** Simulated Single-Thread Node.js (via Playwright).
8+
9+
Unit tests in Neo.mjs are designed for extreme speed and debugging simplicity. We simulate the entire worker architecture (App, VDom, Data) inside a single Node.js thread. This allows you to step through code execution across "workers" without context switching and verify logic without the overhead of a real browser.
10+
11+
[Read the Unit Testing Guide](UnitTesting.md)
12+
13+
## 2. Component Testing (Visual & Interaction)
14+
**Focus:** DOM Events, CSS, Layout, Browser APIs.
15+
**Environment:** Real Browser (Chrome/Firefox/Webkit).
16+
17+
Component tests run your actual application code inside a real browser environment. This is where you verify that your buttons click, your layouts resize correctly, and your CSS renders as expected. We use a specialized "Remote Control" architecture to drive the App Worker from the test runner.
18+
19+
[Read the Component Testing Guide](ComponentTesting.md)
20+
21+
## 3. Benchmarking (Performance & Resilience)
22+
**Focus:** Concurrency, FPS, Memory Leaks, Resilience under Load.
23+
**Environment:** Specialized High-Precision Harness (Separate Repository).
24+
25+
Standard functional tests pass if the UI "eventually" reaches the correct state. Benchmarks measure *how* it gets there. We focus on "Resilience Testing"—measuring if the application can handle high-frequency updates, massive datasets, and background calculations without dropping frames.
26+
27+
**Note:** The benchmarking suite is maintained in a separate repository to ensure a sterile, isolation-focused environment.
28+
29+
[Read the Benchmarking Guide](Benchmarking.md)
30+
31+
## Summary
32+
33+
| Type | Environment | Use Case |
34+
| :--- | :--- | :--- |
35+
| **Unit** | Node.js (Simulated) | "Does the logic work?" (Store filtering, VDOM generation) |
36+
| **Component** | Real Browser | "Does it look right and react to clicks?" (Drag & drop, Focus) |
37+
| **Benchmark** | Specialized Harness | "Is it fast and stable under pressure?" (100k rows, 60 FPS) |

learn/tree.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,10 @@
6767
{"name": "Custom Events", "parentId": "guides/userinteraction/events", "id": "guides/userinteraction/events/CustomEvents"},
6868
{"name": "DOM Events", "parentId": "guides/userinteraction/events", "id": "guides/userinteraction/events/DomEvents"},
6969
{"name": "Testing", "parentId": "guides", "isLeaf": false, "id": "guides/testing", "collapsed": true},
70+
{"name": "Overview", "parentId": "guides/testing", "id": "guides/testing/Overview"},
7071
{"name": "Unit Testing", "parentId": "guides/testing", "id": "guides/testing/UnitTesting"},
7172
{"name": "Component Testing", "parentId": "guides/testing", "id": "guides/testing/ComponentTesting"},
73+
{"name": "Benchmarking", "parentId": "guides/testing", "id": "guides/testing/Benchmarking"},
7274
{"name": "Specific Applications/Features", "parentId": "guides", "isLeaf": false, "id": "guides/specificfeatures", "collapsed": true},
7375
{"name": "Multi-Window Applications", "parentId": "guides/specificfeatures", "id": "guides/specificfeatures/MultiWindow", "hidden": true},
7476
{"name": "Mixins", "parentId": "guides/specificfeatures", "id": "guides/specificfeatures/Mixins", "hidden": true},

0 commit comments

Comments
 (0)