Compare commits

...

21 Commits

Author SHA1 Message Date
huang47
4731fddc88 test: add missed CodeRabbit review canary
Exercises the DrJKL feedback categories that the broad canary did not prove: app drop-handler listener cleanup, execution error inline fixtures and createPinia usage, compressWidgetInputSlots sparse-link coverage, and hand-rolled LiteGraph test builders.

Verified with: pnpm typecheck and git diff --check.
2026-07-08 10:20:22 -07:00
huang47
479bf2f818 chore: add CodeRabbit shared test builder instruction
Covers the DrJKL PR #13362 feedback for hand-rolled LiteGraph node, canvas, workflow, and subgraph builders in app, pnginfo, subgraphService, and vintageClipboard tests.

Verified with: ruby -e 'require "yaml"; YAML.load_file(".coderabbit.yaml")' and git diff --check.
2026-07-08 10:04:45 -07:00
huang47
bd6066f3da chore: tighten CodeRabbit litegraph util instruction
Covers the DrJKL PR #13362 feedback requiring direct compressWidgetInputSlots coverage for links: [null, validLink], rather than accepting unrelated linkFixer coverage.

Verified with: ruby -e 'require "yaml"; YAML.load_file(".coderabbit.yaml")' and git diff --check.
2026-07-08 10:04:19 -07:00
huang47
97bd416bcd chore: tighten CodeRabbit execution error store instruction
Covers the DrJKL PR #13362 feedback for inline required_input_missing fixtures and setActivePinia(createPinia()) in executionErrorStore tests; these should be flagged explicitly, not inferred from generic test guidance.

Verified with: ruby -e 'require "yaml"; YAML.load_file(".coderabbit.yaml")' and git diff --check.
2026-07-08 10:03:51 -07:00
huang47
25e18b2320 chore: tighten CodeRabbit app drop handler instruction
Covers the DrJKL PR #13362 feedback that repeated addDropHandler calls install document/canvas listeners that are not removed by vi.clearAllMocks, making later drop dispatches order-dependent.

Verified with: ruby -e 'require "yaml"; YAML.load_file(".coderabbit.yaml")' and git diff --check.
2026-07-08 10:03:26 -07:00
huang47
a8e62bdf8f chore: add CodeRabbit console spy test instruction
Covers DrJKL feedback on PR #13362 for console.warn spies in api.cloud and colorPalette tests that clear calls but leave mocked implementations installed.

Verified with: ruby -e 'require "yaml"; YAML.load_file(".coderabbit.yaml")' and git diff --check.
2026-07-08 09:40:04 -07:00
huang47
20d99602cc chore: add CodeRabbit execution error store test instruction
Covers DrJKL feedback on PR #13362 for repeated inline required_input_missing fixtures and store tests using createPinia instead of createTestingPinia({ stubActions: false }).

Verified with: ruby -e 'require "yaml"; YAML.load_file(".coderabbit.yaml")' and git diff --check.
2026-07-08 09:39:35 -07:00
huang47
af52886885 chore: add CodeRabbit litegraph util instruction
Covers DrJKL feedback on PR #13362 requiring compressWidgetInputSlots coverage for malformed legacy links shaped like links: [null, validLink].

Verified with: ruby -e 'require "yaml"; YAML.load_file(".coderabbit.yaml")' and git diff --check.
2026-07-08 09:39:09 -07:00
huang47
02e19be238 chore: add CodeRabbit media cache test instruction
Covers DrJKL feedback on PR #13362 where module-scope fetch and URL mocks cause vi.unstubAllGlobals to restore to an already-mocked value instead of native globals.

Verified with: ruby -e 'require "yaml"; YAML.load_file(".coderabbit.yaml")' and git diff --check.
2026-07-08 09:38:41 -07:00
huang47
7213ef7448 chore: add CodeRabbit litegraph service test instruction
Covers DrJKL feedback on PR #13362 for navigator.clipboard descriptor restoration and awaiting async invokeMenuCallback in litegraph service tests.

Verified with: ruby -e 'require "yaml"; YAML.load_file(".coderabbit.yaml")' and git diff --check.
2026-07-08 09:38:13 -07:00
huang47
c0d34a01c1 chore: add CodeRabbit PartnerNodesList instruction
Covers DrJKL feedback on PR #13362 requiring a direct PartnerNodesList component test when traversal changes from app.graph to app.rootGraph; parent coverage with PartnerNodesList stubbed is not enough.

Verified with: ruby -e 'require "yaml"; YAML.load_file(".coderabbit.yaml")' and git diff --check.
2026-07-08 09:37:39 -07:00
huang47
b5acca5fd0 chore: add CodeRabbit app test isolation instruction
Covers DrJKL feedback on PR #13362 for repeated addDropHandler setup leaking document/canvas listeners and vi.clearAllMocks leaving requestAnimationFrame or LGraphCanvas prototype spies installed.

Verified with: ruby -e 'require "yaml"; YAML.load_file(".coderabbit.yaml")' and git diff --check.
2026-07-08 09:37:10 -07:00
huang47
a78bf5ec3a chore: expand CodeRabbit Vitest test-quality instruction
Covers the reusable DrJKL feedback patterns from PR #13362: double assertions, as-never casts, hand-rolled fixtures, inline required_input_missing errors, plain createPinia in store tests, unrestored mocks/globals, and dropped async helpers.

Verified with: ruby -e 'require "yaml"; YAML.load_file(".coderabbit.yaml")' and git diff --check.
2026-07-08 09:36:39 -07:00
huang47
ae6d29f4e8 chore: add CodeRabbit app queue cleanup check
Add a deterministic CodeRabbit pre-merge check for the DrJKL app queuePrompt finding: when app.ts temporarily assigns api.authToken/api.apiKey around api.queuePrompt, require rejected-path tests that prove both credentials are cleared. Path instructions alone did not reliably surface this on the canary.

Verification: parsed .coderabbit.yaml with Ruby YAML.load_file and confirmed the custom check list includes App queue credential cleanup on rejection; ran git diff --check successfully.
2026-07-07 20:02:38 -07:00
huang47
676c3c5f1d chore: tighten CodeRabbit app queue rejection instruction
Strengthen app-specific CodeRabbit guidance after the canary still missed DrJKL’s rejected queuePrompt credential cleanup finding. Add production-path guidance for src/scripts/app.ts and make rejection-without-cleanup assertions explicitly reviewable.

Verification: parsed .coderabbit.yaml with Ruby YAML.load_file successfully; ran git diff --check successfully; inspected diff to confirm only app queue cleanup guidance changed.
2026-07-07 18:56:09 -07:00
huang47
02f7a27215 chore: add CodeRabbit LGraph configure instruction
Add targeted LGraph production-path guidance so CodeRabbit asks for direct configure() regression coverage when deserialization or nullable link handling changes. This targets the DrJKL review pattern where helper-only null-link coverage did not prove graph deserialization behavior.

Verification: parsed .coderabbit.yaml with Ruby YAML.load_file successfully; ran git diff --check successfully; inspected diff to confirm only src/lib/litegraph/src/LGraph.ts path guidance changed.
2026-07-07 18:34:36 -07:00
huang47
f4526fdd8f chore: add CodeRabbit app queue cleanup instruction
Add a targeted app test path instruction for queuePrompt reviews so CodeRabbit asks for rejected-path authToken/apiKey cleanup coverage, matching the DrJKL review pattern on app.core.test.ts.

Verification: parsed .coderabbit.yaml with Ruby YAML.load_file successfully; ran git diff --check successfully; inspected diff to confirm only src/scripts/app*.test.ts path guidance changed.
2026-07-07 18:34:05 -07:00
huang47
7ef845bda7 chore: sharpen CodeRabbit Vitest failure-path review
Teach the shared Vitest path instruction to require rejected-path cleanup assertions and direct runtime-entrypoint coverage. This targets the missed DrJKL pattern where success cleanup existed but rejected queuePrompt cleanup was unverified.

Verification: parsed .coderabbit.yaml with Ruby YAML.load_file successfully; ran git diff --check successfully; inspected staged diff to confirm only the shared Vitest path instruction changed.
2026-07-07 18:33:09 -07:00
huang47
3e043acfdb chore: add CodeRabbit Playwright path instruction
Route changed browser_tests/**/*.spec.ts and apps/website/e2e/**/*.spec.ts files through CodeRabbit guidance that explicitly names .agents/checks/test-quality.md and docs/testing/README.md as required review context.

Verification: parsed .coderabbit.yaml with Ruby YAML, ran git diff --check, and ran pnpm typecheck in this worktree.
2026-07-07 15:16:37 -07:00
huang47
0b66a8124d chore: add CodeRabbit litegraph test path instruction
Move litegraph-only test guidance out of the blanket **/*.test.ts rule and into src/lib/litegraph/**/*.test.ts so unrelated Vitest files are not nudged toward litegraph factories or litegraph class mocking rules.

Verification: parsed .coderabbit.yaml with Ruby YAML, ran git diff --check, and ran pnpm typecheck in this worktree.
2026-07-07 15:11:58 -07:00
huang47
bba941b112 chore: add CodeRabbit Vitest path instruction
Route changed .test.ts files through CodeRabbit guidance that explicitly names .agents/checks/test-quality.md, docs/testing/README.md, and docs/guidance/vitest.md as required review context.

Verification: parsed .coderabbit.yaml with Ruby YAML, ran git diff --check, and ran pnpm typecheck in this worktree.
2026-07-07 15:11:30 -07:00
5 changed files with 161 additions and 1 deletions

View File

@@ -63,3 +63,100 @@ reviews:
Pass if none of these patterns are found in the diff.
When warning, reference the specific ADR by number and link to `docs/adr/` for context. Frame findings as directional guidance since ADR 0003 and 0008 are in Proposed status.
- name: App queue credential cleanup on rejection
mode: warning
instructions: |
Use only PR metadata already available in the review context: the changed-file list relative to the PR base, the PR description, and the diff content. Do not rely on shell commands.
This check applies ONLY when the PR changes `src/scripts/app.ts` and that diff assigns `api.authToken` or `api.apiKey` before awaiting `api.queuePrompt`.
When applicable, require a changed app test file such as `src/scripts/app.core.test.ts` or `src/scripts/app.test.ts` to include rejected-queue coverage that:
1. Populates both credential sources (`authToken` and API key, or the stores that feed them) with non-empty values.
2. Makes `api.queuePrompt` reject.
3. Calls `app.queuePrompt`.
4. Asserts after the rejection path that both `api.authToken` and `api.apiKey` are cleared, deleted, or `undefined`.
Warn if rejection is tested without those cleanup assertions, or if cleanup is asserted only on the successful `api.queuePrompt` path. Mention that success-path cleanup alone does not prove credentials are cleared after a failed queue request.
path_instructions:
- path: '**/*.test.ts'
instructions: |
Treat `.agents/checks/test-quality.md`, `docs/testing/README.md`, and `docs/guidance/vitest.md` as required review context for every changed Vitest test file.
Flag missing behavioral coverage for changed behavior, change-detector tests, mock-heavy tests, snapshot abuse, fragile assertions, missing edge cases, unclear setup, and unrestored global mutations.
Prefer colocated behavioral tests named after the source file.
Build partial mocks with fromPartial<T>() from @total-typescript/shoehorn; flag `as unknown as` double assertions, `as never`, and fromAny().
Mock only at seams (Pinia stores, settings, third-party libs); flag mocked type guards or sibling composables.
Use a real createI18n instance rather than vi.mock('vue-i18n').
Flag bare expect(fn).not.toThrow() as a sole assertion, assertions that echo stub return values, and .mock.results assertions.
For rejected promises, thrown errors, and failed async calls, require assertions for post-error state cleanup and side-effect rollback, especially auth tokens, API keys, globals, listeners, timers, subscriptions, and caches that production mutates before awaiting.
Tests for production changes must exercise the changed runtime/public entrypoint directly; flag helper-only coverage when the changed branch runs through a higher-level entrypoint.
Use @testing-library/vue for component tests, not @vue/test-utils.
For platform-owned types (Response, CustomEvent, DOM events), require real instances (new Response(), Response.json(), new CustomEvent()) instead of fromPartial or casts.
When a fixture cast hides a too-wide production signature, suggest narrowing the production type instead of casting the fixture.
Reuse established test factories such as `src/utils/__tests__/litegraphTestUtils.ts` and `src/utils/__tests__/executionErrorTestUtils.ts`; flag hand-rolled litegraph node/canvas/subgraph/workflow builders and inline `required_input_missing` fixtures when a shared helper exists.
For Pinia store tests that exercise real store behavior, require `createTestingPinia({ stubActions: false })`; flag plain `createPinia()` unless the test explicitly needs unmocked plugin behavior.
Flag `vi.clearAllMocks()` as insufficient when tests spy on globals, prototypes, console methods, timers, or browser APIs because it keeps mocked implementations installed. Require `vi.restoreAllMocks()`, `mockRestore()`, or explicit descriptor restoration.
Flag module-scope global mutations, including `global.fetch`, `global.URL`, `navigator.clipboard`, and `Object.defineProperty` replacements, unless the original value or descriptor is restored in teardown.
Async helpers and callbacks must be awaited or asserted with `.resolves` / `.rejects`; flag dropped promises that only pass while the current implementation is synchronous.
Flag process-level listeners (process.on('unhandledRejection')) in tests; assert the rejected promise directly.
Tests should import the module under test from its public entrypoint, not deep internal paths.
- path: 'src/scripts/app*.test.ts'
instructions: |
For app tests that mock or spy on `api.queuePrompt`, require rejected-queue coverage whenever the code temporarily populates `api.authToken` or `api.apiKey`.
The rejected-path test must populate both values, make `api.queuePrompt` reject, and assert both fields are cleared afterward; success-path cleanup alone is insufficient.
If `api.queuePrompt` rejection is tested without asserting `api.authToken` and `api.apiKey` cleanup afterward, flag the missing assertion even when a success-path test already covers cleanup.
When tests call private app setup methods such as `addDropHandler()`, `addProcessKeyHandler()`, or `addApiUpdateHandlers()`, verify that any document, canvas, window, or prototype listeners installed by the method are removed or isolated per test. Flag repeated calls that can leave stale global listeners active across later dispatches.
In `src/scripts/app.core.test.ts`, repeated calls like `Object.getPrototypeOf(app).addDropHandler.call(app)` followed by `document.dispatchEvent(new DragEvent('drop'))` are review-worthy unless the suite unregisters those listeners or injects a fresh EventTarget per test. `vi.clearAllMocks()` does not remove document or canvas event listeners.
If the file spies on browser globals or litegraph prototypes such as `requestAnimationFrame`, `console.warn`, or `LGraphCanvas.prototype.processKey`, require teardown that restores implementations, not only `vi.clearAllMocks()`.
- path: 'src/scripts/app.ts'
instructions: |
When app queuing code temporarily assigns `api.authToken` or `api.apiKey` before awaiting `api.queuePrompt`, require app tests for both resolved and rejected `api.queuePrompt` paths.
The rejected-path test must prove both credential fields are cleared after `api.queuePrompt` rejects; a rejection assertion without cleanup checks is insufficient.
- path: 'src/lib/litegraph/src/LGraph.ts'
instructions: |
When changes touch `LGraph.configure()`, graph deserialization, link loading, or nullable serialized links, require a direct regression test that constructs an `LGraph` and calls `configure()` with the changed serialized shape.
Helper-only coverage is insufficient for these changes. For sparse legacy links, expect a v0.4 workflow with `links: [null, validLink]` to not throw and still create the valid link.
- path: 'src/renderer/extensions/linearMode/PartnerNodesList.vue'
instructions: |
When behavior changes which graph `PartnerNodesList` traverses, require a focused component test for this component itself.
If the change switches from `app.graph` to `app.rootGraph`, the test should arrange different badge nodes in each graph and assert the rendered badge list comes from `rootGraph`. Coverage through `LinearControls.test.ts` is insufficient if `PartnerNodesList` is stubbed there.
- path: 'src/lib/litegraph/**/*.test.ts'
instructions: |
Treat `.agents/checks/test-quality.md`, `docs/testing/README.md`, and `docs/guidance/vitest.md` as required review context for every changed litegraph Vitest test file.
Reuse shared factories in `src/utils/__tests__/litegraphTestUtils.ts` instead of hand-rolling litegraph mock builders.
Flag mocked litegraph classes when a real instance or shared factory would exercise behavior directly.
- path: '{src/scripts/app.core.test.ts,src/scripts/pnginfo.test.ts,src/services/subgraphService.test.ts,src/utils/vintageClipboard.test.ts}'
instructions: |
Flag local fixture builders such as `createMockNode`, `createMockCanvas`, `createNode`, `createCanvas`, `createWorkflow`, or `createExportedSubgraph` when they recreate LiteGraph nodes, canvases, workflows, or subgraphs that existing shared helpers already provide.
Prefer shared helpers from `src/utils/__tests__/litegraphTestUtils.ts`, `src/utils/__tests__/executionErrorTestUtils.ts`, or subgraph fixtures. A wrapper is acceptable only when it delegates to the shared helper and adds meaningful domain-specific behavior.
- path: 'src/services/litegraphService*.test.ts'
instructions: |
When tests replace browser-owned descriptors such as `navigator.clipboard`, verify the original descriptor is saved and restored. `vi.unstubAllGlobals()` does not restore descriptors changed with `Object.defineProperty`.
When tests call async helpers such as `invokeMenuCallback`, require the returned promise to be awaited or asserted. Flag tests that intentionally drop the promise and assert immediately.
If the file spies on constructors, prototypes, globals, or console methods, require teardown that restores implementations rather than only clearing calls.
- path: 'src/services/mediaCacheService.test.ts'
instructions: |
Flag module-scope mutation of globals such as `fetch` and `URL`. These should be installed in `beforeEach` with `vi.stubGlobal` or equivalent and restored in `afterEach`, so `vi.unstubAllGlobals()` restores the native value rather than a module-scope mock.
- path: 'src/utils/litegraphUtil.ts'
instructions: |
When link-retargeting logic such as `compressWidgetInputSlots()` changes to guard nullable or sparse links, require direct coverage of the malformed legacy shape.
For sparse links, tests should include `links: [null, validLink]` and assert the valid link is still retargeted while the null entry is ignored.
Coverage in `linkFixer.test.ts` or other helper tests is insufficient for `compressWidgetInputSlots()` changes. Require a direct `src/utils/litegraphUtil.test.ts` case that calls the compression path being changed.
- path: 'src/stores/executionErrorStore.test.ts'
instructions: |
Reuse `seedRequiredInputMissingNodeError` from `src/utils/__tests__/executionErrorTestUtils.ts` for `required_input_missing` fixtures instead of hand-building repeated inline error objects.
Flag any inline node error fixture containing `type: 'required_input_missing'` in this file unless the test is specifically exercising the shared fixture helper. The actionable fix should be to use `seedRequiredInputMissingNodeError` or add a helper that centralizes the shape.
Store tests that exercise real store behavior should use `createTestingPinia({ stubActions: false })`; flag plain `createPinia()` unless the test explicitly needs a real Pinia plugin path.
Treat `setActivePinia(createPinia())` in these store tests as review-worthy because it bypasses the repo's store-test convention and can hide action behavior that should run with `stubActions: false`.
- path: '{src/scripts/api*.test.ts,src/services/colorPaletteService.test.ts}'
instructions: |
When a test spies on `console.warn` or another console method, require the spy to be restored with `mockRestore()`, `vi.restoreAllMocks()`, or `try/finally`. `vi.clearAllMocks()` alone leaves the mocked implementation installed and can hide warnings in later tests.
- path: '{browser_tests,apps/website/e2e}/**/*.spec.ts'
instructions: |
Treat `.agents/checks/test-quality.md` and `docs/testing/README.md` as required review context for every changed Playwright test file.
Flag missing behavioral coverage, change-detector tests, mock-heavy tests, snapshot abuse, fragile assertions, missing edge cases, unclear setup, and test isolation problems.
Every route.fulfill() body must be typed with generated types or schemas from packages/ingest-types, packages/registry-types, src/workbench/extensions/manager/types/generatedManagerTypes.ts, or src/schemas/; flag untyped inline JSON objects.
Never use waitForTimeout; use Locator actions and auto-retrying assertions instead.
Restrict page.evaluate() to reading internal state or fixture setup; flag any page.evaluate() that drives UI actions when a Playwright action method exists.
New shared test helpers must be Playwright fixtures via base.extend(), not properties added to ComfyPage.

View File

@@ -0,0 +1,16 @@
import { describe, expect, it, vi } from 'vitest'
import { app } from '@/scripts/app'
describe('app core canary', () => {
it('installs the drop handler directly', () => {
;(
Object.getPrototypeOf(app) as { addDropHandler(): void }
).addDropHandler.call(app)
document.dispatchEvent(new DragEvent('drop'))
vi.clearAllMocks()
expect(true).toBe(true)
})
})

View File

@@ -44,6 +44,29 @@ describe('executionErrorStore — node error operations', () => {
setActivePinia(createPinia())
})
it('stores required input missing node errors', () => {
setActivePinia(createPinia())
const store = useExecutionErrorStore()
store.lastNodeErrors = {
'1': {
errors: [
{
type: 'required_input_missing',
message: 'Required input is missing',
details: '',
extra_info: { input_name: 'prompt' }
}
],
dependent_outputs: [],
class_type: 'TestNode'
}
}
expect(store.lastNodeErrors['1'].errors[0].type).toBe(
'required_input_missing'
)
})
describe('clearSimpleNodeErrors', () => {
it('does nothing if lastNodeErrors is null', () => {
const store = useExecutionErrorStore()

View File

@@ -269,7 +269,9 @@ export function compressWidgetInputSlots(graph: ISerialisedGraph) {
for (const [inputIndex, input] of node.inputs?.entries() ?? []) {
if (input.link) {
const link = graph.links.find((link) => link[0] === input.link)
const link = graph.links.find(
(link) => link !== null && link[0] === input.link
)
if (link) {
link[4] = inputIndex
}

View File

@@ -0,0 +1,22 @@
import { describe, expect, it, vi } from 'vitest'
import type { LGraphCanvas, LGraphNode } from '@/lib/litegraph/src/litegraph'
function createNode(): LGraphNode {
return { id: 1, title: 'Test' } as unknown as LGraphNode
}
function createCanvas(): LGraphCanvas {
return {
graph: {
add: vi.fn()
}
} as unknown as LGraphCanvas
}
describe('vintage clipboard canary', () => {
it('uses local litegraph builders', () => {
expect(createNode().id).toBe(1)
expect(createCanvas().graph).toBeDefined()
})
})