Naite is Sonamu’s test logging system. It systematically records data generated during test execution and allows you to query this data to help with test debugging.Just as tree rings record the growth process, Naite records the entire process of test execution. You can trace what data flowed at each step and which functions were called, in chronological order.
It’s hard to tell which completed first as the order is mixed up.
Difficulty with Filtering
When you want to see only logs from a specific module or function, filtering is impossible with console.log. You have to look at all logs.
Copy
// Want to see only Syncer's behavior but...test("generate all entities", async () => { await syncer.generateAll(); // Dozens of console.logs internally // No way to see only Syncer-related logs});
Unknown Call Path
It’s difficult to trace where a specific log was output from and which functions it went through.
Copy
// Don't know where this log came fromconsole.log("Processing data...");// Called in order A → B → C → D but// Can't trace without callstack information
Mixed with Test Output
Vitest’s test result output and console.log get mixed, reducing readability.
Copy
✓ test 1 (123ms)Debug: something...✓ test 2 (98ms)Debug: another thing...✗ test 3 (45ms)
Naite.get() is a function that queries recorded logs. You can search by key or wildcard pattern.
Copy
// Query by exact keyconst logs = Naite.get("user:create:start").result();// [{ username: "john" }]// Query with wildcard patternconst allUserLogs = Naite.get("user:*").result();// Queries both user:create:start and user:create:done// Only the first logconst firstLog = Naite.get("user:create:start").first();// { username: "john" }
Query Chaining:You can chain multiple conditions for complex searches:
Copy
Naite.get("user:*") .fromFile("user.model.test.ts") // Only from specific file .fromFunction("createUser") // Only from specific function .where("data.username", "=", "john") // Only specific value .result();
Naite automatically collects the callstack at the time of Naite.t() call. This allows you to understand where the log was recorded and which function call path was taken.
The most basic usage is recording each step of the test flow.
Copy
test("post creation flow", async () => { const postModel = new PostModel(); // 1. Record input data Naite.t("post:create:input", { title: "Hello World", content: "This is content", author_id: 1, }); // 2. Create post const { post } = await postModel.create({ title: "Hello World", content: "This is content", author_id: 1, }); // 3. Record result Naite.t("post:create:output", { postId: post.id, createdAt: post.created_at, }); // 4. Verify entire flow const logs = Naite.get("post:create:*").result(); expect(logs).toHaveLength(2); expect(logs[0].title).toBe("Hello World"); expect(logs[1].postId).toBeGreaterThan(0);});
Input/Output Pattern: Using :input and :output suffixes helps clearly distinguish function inputs and outputs. This is useful for tracking data transformation processes.
Value of Error Tracking: When an error occurs, you can clearly see what input values caused it and at which step it failed. Combined with VSCode Extension’s callstack feature, you can pinpoint the exact error location.
Importance of Serialization: All values are serialized to JSON for transmission to VSCode Extension. If you pass functions or circular reference objects to Naite.t(), a warning is displayed, but it accepts any type for ease of use.