packages/vue/PARITY.md
@copilotkit/vue)This document is the living parity map for the Vue port.
Keep it updated whenever React parity work lands in packages/vue.
packages/vue/** only.packages/react-core/, packages/react-ui/, packages/react-textarea/.@copilotkit/vue follows the same single-package direction as @copilotkit/react.vue-ui package split.docs/ V2 reference unless the repository adopts an explicit Vue section there.README.md.examples/v2/vue/storybook/**..ts files and re-export from package barrels.Use this decision rule for every React feature:
render* arrays or useRender* hooks):
Translate to Vue composable state plus slot-based rendering at chat/view boundaries.Agents must classify each React feature and its tests before porting.
A React feature/test is near-100% translatable when all of the following are true:
Examples usually include:
If a feature is near-100% translatable, follow these rules strictly:
describe blocks and test case names word-for-word identical to React for the matching cases.CopilotChat flow vs renderer-only unit boundary)partial in the matrix and treated as incomplete parity work.This rule exists to maximize discoverability. Someone reading the React package should be able to find the Vue counterpart immediately in both implementation and tests.
A feature is not near-100% translatable when one or more of these are true:
In those cases:
If an agent is unsure whether a feature belongs in the near-100% bucket, the default action is to discuss it with the user before proceeding.
Vue intentionally keeps slots as the primary customization model. For render bridges, the mirror strategy is deterministic slot translation at chat view boundaries, with a small number of approved secondary programmatic APIs where strict parity requires framework-managed registration semantics.
| React surface | Vue surface |
|---|---|
renderToolCalls / useRenderToolCall specific tool renderer | #tool-call-<toolName> |
renderToolCalls wildcard renderer (name: "*" ) | #tool-call |
renderActivityMessages specific activity renderer | #activity-<activityType> |
renderActivityMessages fallback renderer | #activity-message |
renderCustomMessages (position: "before") | #message-before or provider renderCustomMessages |
renderCustomMessages (position: "after") | #message-after or provider renderCustomMessages |
inProgress -> executing -> complete.mcp-apps, render MCPAppsActivityRenderer.a2ui-surface and the runtime reports a2uiEnabled: true, render A2UISurfaceActivityRenderer.@submit-message, @input-change, @select-suggestion, @edit-message, @switch-to-branch, @thumbs-up, @thumbs-down, @read-aloud, and @regenerate.onCopy, onEdit, goPrev, goNext, and onSubmitMessage for slotted control surfaces.CopilotChatView.onFinishTranscribeWithAudio.h(...) render functions when either can express the same behavior.renderCustomMessages is an approved secondary provider API in Vue because ordered multi-renderer registration and agent-scoped precedence cannot be expressed honestly through a single slot function alone.This is a constraint for future parity work: new React render-hook behavior should be mirrored by extending slot contracts, not by re-introducing provider render props in Vue.
Vue also diverges intentionally from React for render-oriented hooks that mix behavior with a render callback.
This preserves semantic parity with React while avoiding a Vue API that requires userland render functions or TSX for common usage.
useAgent, useAgentContext, useFrontendTool, useHumanInTheLoop, useSuggestions, useConfigureSuggestions, useThreads.useInterrupt.useRenderTool, useDefaultRenderTool, and useComponent are supported in Vue as secondary programmatic APIs; keep slots as the primary customization surface.h(...) render functions or TSX for the primary usage path.WatchSource-based dependencies to mirror React deps behaviorKeep React-to-Vue mapping obvious for both implementation and tests.
*.e2e.test.ts in Vue when React uses *.e2e.test.tsx.describe/it wording exactly for the mirrored cases.CopilotKitCore behavior where practical.CopilotKitProvider, CopilotChatConfigurationProvider)useAgent, useAgentContext, useSuggestions, useConfigureSuggestions, useFrontendTool, useHumanInTheLoop)defineToolCallRenderer)src/__tests__/utils/test-helpers.ts aligned with React helper exports for framework-agnostic factories/scenario helpers.waitForAgentRunSubscription, emitAgentEventAndFlush, completeAgentAndFlush) as explicit additive adapters; do not hide framework flush inside parity event factories.StrictMode identity semantics as framework-specific: Vue parity targets lifecycle behavior invariants under rerender/remount, not same-instance identity across unmount/remount.core, react, angular) unless an intentional repo-wide upgrade occurs.src/components/icons/index.ts and do not import from lucide-vue-next directly in feature components.Before writing or editing Vue parity tests:
matched when wording is mirrored but approach/depth differs materially from the React counterpart.@testing-library/vue query style (screen.getBy*, screen.findBy*, waitFor) so the Vue assertion model mirrors React Testing Library usage closely.wrapper.get(...) as the primary assertion/query style unless there is a documented blocker.h(...) render-function harnesses.describe(...) block labeled as Vue-specific semantics.StrictMode by introducing runtime remount caches in Vue production code; validate Vue rerender/remount lifecycle invariants directly in Vue tests.React slot-system suites need a separate rule from near-100% translatable suites.
For React slot/customization suites, the parity target is:
It is not:
describe/it wording when it remains honest at the Vue slot boundary.matched if the Vue file is broader, shallower, or validates a different feature than the React counterpart, even if the file names align.Use this default recipe for slot-only Vue counterparts:
*.slots.e2e.test.ts).describe(...).Vue package scripts should mirror React command surface for tests:
testtest:watchtest:coveragetest:uiThis phase does not enforce coverage thresholds.
When React parity work is ported:
packages/vue/src/**.For package-level parity work, all items below are required before a ported React feature is considered complete in this package:
packages/vue/src/** and exports are wired through the relevant package barrels.README.md.Out-of-package follow-up, when the repo enters repo-wide parity work:
Status values:
matched: equivalent behavior and tests exist.partial: some behavior/tests exist, but parity depth is incomplete.intentional-divergence: API shape differs by design, behavior parity still required.Current snapshot: mapped React->Vue counterpart rows are either matched or intentional-divergence.
| React surface | Vue counterpart | Status | Notes |
|---|---|---|---|
useAgent, useAgentContext, useSuggestions, useConfigureSuggestions, useFrontendTool, useHumanInTheLoop, useInterrupt, useThreads | Same-named Vue composables in src/hooks | matched | Headless/data-oriented parity model. useAgent delegates subscription, throttle, and subscriber error-guarding to CopilotKitCore.subscribeToAgentWithOptions (shared core API) — matching React: onMessagesChanged and onStateChanged share a single leading+trailing throttle window, and onRunInitialized / onRunFinalized / onRunFailed / onRunErrorEvent always fire immediately. |
renderToolCalls / useRenderToolCall | #tool-call-<toolName> and #tool-call slots | intentional-divergence | Slot translation, behavior parity required. |
renderActivityMessages / useRenderActivityMessage | #activity-<type> and #activity-message slots | intentional-divergence | Slot translation, behavior parity required. |
renderCustomMessages / useRenderCustomMessages | #message-before and #message-after slots, plus provider renderCustomMessages | intentional-divergence | Slots remain primary; provider registration is the approved secondary parity surface for ordered/agent-scoped custom message renderers. |
useRenderTool, useDefaultRenderTool, useComponent | Same-named Vue composables in src/hooks | matched | Secondary programmatic APIs now exist with dedicated parity tests, including SFC/component renderer support and React-matching toolCallId threading through render-tool prop unions and CopilotChatToolCallsView core render props; slots remain the primary customization surface. |
| React test/feature anchor | Vue counterpart | Status | Notes |
|---|---|---|---|
CopilotKitProvider.test.tsx | CopilotKitProvider.test.ts | matched | Core provider behavior. |
CopilotKitProvider.wildcard.test.tsx | CopilotKitProvider.wildcard.test.ts | matched | Wildcard behavior parity. |
CopilotChatConfigurationProvider.test.tsx | CopilotChatConfigurationProvider.test.ts | matched | Configuration provider parity. |
CopilotKitProvider.onError.test.tsx | CopilotKitProvider.onError.test.ts | matched | Dedicated Vue on-error parity suite. |
CopilotKitProvider.stability.test.tsx | CopilotKitProvider.stability.test.ts | matched | Strict counterpart matches provider stability behavior and runtimeUrl setter timing semantics; Vue remount lifecycle invariants are covered explicitly, while literal React StrictMode remount identity is treated as framework-specific. |
CopilotKitProvider.renderCustomMessages.e2e.test.tsx | CopilotKitProvider.renderCustomMessages.e2e.test.ts | matched | Dedicated strict counterpart uses provider renderCustomMessages with React-matching case names and ordering/scoping semantics, with a trailing Vue-specific slot-precedence check. |
React CopilotKitProvider.tsx debug prop | CopilotKitProvider.debug.test.ts | matched | Vue CopilotKitProvider exposes debug?: DebugConfig parity with React. Dedicated Vue suite covers initial constructor threading, runtime setDebug(...) sync on prop changes, core-instance stability, clearing behavior, and regression safety for neighboring runtime-config prop sync. |
CopilotKitProvider.license.test.tsx | CopilotKitProvider.license.test.ts | matched | Dedicated strict counterpart for the P1 license-banner parity package. Mirrors React case wording 1:1 across the five server-driven banner states (none shows "Powered by CopilotKit", expired shows the expired banner, invalid shows the invalid banner, valid shows no banner, missing licenseStatus shows no banner). Vue mocks globalThis.fetch via vi.stubGlobal("fetch", ...) in lockstep with React's globalThis.fetch = assignment style. |
| React test anchor | Vue counterpart | Status | Notes |
|---|---|---|---|
CopilotChat.e2e.test.tsx | CopilotChat.e2e.test.ts + CopilotChat.test.ts | matched | Full strict counterpart exists with React-matching suite/case wording and now passes on Vue chat-flow boundaries. |
CopilotChatPropsRerender.e2e.test.tsx | CopilotChatPropsRerender.e2e.test.ts | matched | Dedicated strict counterpart now covers FOR-75 rerender stability parity through Vue slot analogues (messageView + labels inline-object regressions) with deterministic render-count assertions. |
copilot-chat-throttle.test.tsx | copilot-chat-throttle.test.ts | matched | Dedicated strict counterpart verifies CopilotChat throttle forwarding and CopilotSidebarProps/CopilotPopupProps throttle inheritance parity. |
CopilotChat.attachments.test.tsx | CopilotChat.attachments.test.ts | matched | Dedicated strict counterpart mirrors React onUploadFailed coverage (invalid-type, file-too-large, upload-failed, multi-reject, and valid-file no-failure), validates Vue attachment drop flow through CopilotChat, and now asserts stable attachment action identities across input-only rerenders. Attachment public-surface closure is complete via exported CopilotChatAttachmentQueue / CopilotChatAttachmentRenderer plus Attachment / AttachmentsConfig / AttachmentModality type exports. |
CopilotChat.onError.test.tsx | CopilotChat.onError.test.ts | matched | Dedicated strict counterpart exists with React-matching suite and case wording. |
CopilotChat.slots.e2e.test.tsx | CopilotChat.slots.e2e.test.ts | matched | Dedicated slot forwarding and override suite. |
CopilotChatActivityRendering.e2e.test.tsx | CopilotChatActivityRendering.e2e.test.ts | matched | Suite/case titles and approach now match React, including per-thread clone forwarding to activity renderers (getThreadClone(...) parity assertion), both MockReconnectableAgent durable-compaction restoration cases (a2ui-surface and open-generative-ui), and the IntelligenceAgent /connect gateway-replay restoration case (restores a completed A2UI surface from IntelligenceAgent /connect gateway replay) ported on N3 with colocated Phoenix mock infrastructure (MockPhoenixPush / MockPhoenixChannel / MockPhoenixSocket / mockPhoenixSockets / triggerJoin / serverPush). |
CopilotChatAssistantMessage.slots.e2e.test.tsx | CopilotChatAssistantMessage.slots.e2e.test.ts | matched | Dedicated strict slot counterpart now mirrors React section/case structure (26 cases) using Vue slot translation boundaries. |
CopilotChatAssistantMessage.test.tsx | CopilotChatAssistantMessage.test.ts | matched | Dedicated strict counterpart now mirrors the React unit suite structure/case wording (32 mirrored cases) using Vue slot translation, including a #layout counterpart for children-render-prop coverage; Vue-only checks are isolated in a trailing block. |
CopilotChatAssistantMessage.thumbs.test.tsx | CopilotChatAssistantMessage.thumbs.test.ts | matched | Dedicated strict counterpart for the React #3457 thumbs callback payload fix. Asserts @thumbs-up / @thumbs-down emit the full AssistantMessage payload (id/role/content) and not an event-shaped object (no nativeEvent, target, or currentTarget). |
CopilotChatInput.slots.e2e.test.tsx | CopilotChatInput.slots.e2e.test.ts | matched | Dedicated strict slot counterpart now mirrors the full React matrix (48 cases) with Vue slot-first translation and React-matching section/case wording. |
CopilotChatInput.test.tsx | CopilotChatInput.test.ts | matched | Dedicated strict counterpart mirrors the React suite/case structure and depth, including slash-command behavior plus the trailing container-dimension cache block (resize invalidation, warm-cache keystrokes, and fallback paths). Now also includes an "IME composition parity" block mirroring the React #3318 guard (no-submit on Enter during composition, isComposing: true suppression, keyCode === 229 suppression, and compositionend-then-submit) and the React #3593 controlled-input clear-notification regressions that assert update:modelValue("") is emitted after button-click and Enter-key submits in controlled mode. |
CopilotChatSuggestionView.slots.e2e.test.tsx | CopilotChatSuggestionView.slots.e2e.test.ts | matched | Dedicated strict counterpart mirrors the React section/case structure across container/suggestion slots, children-render-function drill-down, and loading-state scenarios using Vue slot translation. |
CopilotChatToolRendering.e2e.test.tsx | CopilotChatToolRendering.e2e.test.ts | matched | Dedicated tool rendering/status suite. |
CopilotChatToolRerenders.e2e.test.tsx | CopilotChatToolRerenders.e2e.test.ts | matched | Strict chat-flow parity rewrite is complete and now passes with React-matching rerender-prevention semantics. |
MCPAppsActivityRenderer.e2e.test.tsx | MCPAppsActivityRenderer.e2e.test.ts | matched | Strict counterpart now passes with React-matching MCP activity flow coverage (request/loading/error/content and metadata scenarios). |
MCPAppsUiMessage.e2e.test.tsx | MCPAppsUiMessage.e2e.test.ts | matched | Dedicated strict counterpart now mirrors ui/message continuation semantics (followUp default/override behavior plus add-message assertions). |
A2UIMessageRenderer.test.tsx | A2UIMessageRenderer.test.ts | matched | Dedicated strict counterpart mirrors the React A2UI rendering matrix (surface render, same-surface in-place update via updateComponents text flip, multi-surface independence) using the real @copilotkit/a2ui-renderer bridge, and asserts strict default-loading parity with React's DefaultA2UILoading (animated dot + "Generating UI..." label + three shimmer bars at 80% / 60% / 40% widths with staggered cpk-a2ui-pulse opacity animation and inline @keyframes). Custom loadingComponent override contract stays unchanged. |
OpenGenerativeUIRenderer.test.tsx | OpenGenerativeUIRenderer.test.ts | matched | Dedicated strict counterpart mirrors the full React OpenGenerativeUI matrix — placeholder, final/preview sandbox creation, HTML wrapping/joining, jsFunctions and jsExpressions execution, recreation on html/function changes, localApi handler-identity (e.g. localApi.addToCart.toBe(handler)) and multi-handler identity, plus the progressive streaming matrix (chunk-arrival preview, throttled updates, preview→final handoff, cssComplete gating, non-meaningful body suppression, fast-path skip). |
CopilotChatMessageView.slots.e2e.test.tsx | CopilotChatMessageView.slots.e2e.test.ts | matched | Dedicated slot precedence/fallback suite. |
CopilotChatMessageView.test.tsx | CopilotChatMessageView.test.ts | matched | Dedicated strict counterpart mirrors the React file shape and wording, including activity rendering and duplicate-id deduplication behavior. |
CopilotChatUserMessage.slots.e2e.test.tsx | CopilotChatUserMessage.slots.e2e.test.ts | matched | Dedicated strict slot counterpart now mirrors React section/case structure (26 cases) using Vue slot composition for API-shape differences. |
CopilotChatView.onClick.e2e.test.tsx | CopilotChatView.onClick.e2e.test.ts | matched | Dedicated strict counterpart now mirrors React section/case structure and behavior boundaries (29 cases), translated through Vue slots where API shape differs. |
CopilotChatView.slots.e2e.test.tsx | CopilotChatView.slots.e2e.test.ts | matched | Dedicated strict counterpart now mirrors React section/case structure and slot-system matrix (43 cases), with Vue slot-first translation while preserving behavioral assertions. |
CopilotChatView.pinToSend.test.tsx | CopilotChatView.pinToSend.test.ts | matched | Dedicated strict counterpart for the pin-to-send mode parity package (N2). Mirrors React case wording 1:1 across pin-to-send / pin-to-bottom / none / boolean back-compat, validating the data-pin-to-send-spacer element only renders for autoScroll === "pin-to-send". Trailing Vue-specific block proves LastUserMessageContext reactivity (provide(LastUserMessageKey, ref(...))) drives usePinToSend updates the same way <Provider value={...}> rerender does in React. |
CopilotChatView.inputOverlay.test.tsx | CopilotChatView.inputOverlay.test.ts | matched | Dedicated strict counterpart for the N2 input-overlay parity package. Mirrors React case wording 1:1 across overlay positioning, attachment-queue DOM order above the input, welcome-screen exclusion, and the paddingBottom = inputContainerHeight + 32 formula. Vue swaps a few React-only testids (copilot-send-button → copilot-chat-input-send, copilot-attachment-queue → copilot-chat-attachment-queue) where the React testid does not exist on Vue components. |
normalize-auto-scroll.test.ts | normalize-auto-scroll.test.ts | matched | Dedicated strict counterpart for the N2 AutoScrollMode helper. Mirrors React case wording 1:1 across all 7 cases (default, boolean back-compat, string passthrough, unknown-string fallback). |
React CopilotChatInput.tsx bottomAnchored prop + CopilotChatView.tsx main-overlay forwarding | CopilotChatInput.bottomAnchored.test.ts | matched | Dedicated Vue counterpart for the P1 license-banner offset contract (no React test counterpart exists at this granularity, so the file documents the Vue-side contract directly). Verifies padding-bottom: var(--copilotkit-license-banner-offset, 0px) is applied on the [data-testid="copilot-chat-input-container"] when positioning="absolute", when bottomAnchored=true with positioning="static", and is not applied for the welcome-screen static input. Also asserts CopilotChatView's main run-state input forwards bottomAnchored=true. |
React CopilotChat.tsx / CopilotSidebar.tsx / CopilotPopup.tsx inline feature-warning surface | CopilotChat.licenseWarning.test.ts | matched | Dedicated Vue counterpart for the P1 inline license-warning parity surface. Mirrors React's InlineFeatureWarning featureName="Chat" / "Sidebar" / "Popup" rendering and console.warn('[CopilotKit] Warning: "<feature>" feature is not licensed. Visit copilotkit.ai/pricing') semantics. The default permissive createLicenseContextValue(null) path renders no warning; an explicit gated LicenseContextKey provided inside CopilotKitProvider (which itself re-provides the permissive default) renders the inline warning + emits the matching console warning. |
CopilotModalHeader.slots.e2e.test.tsx | CopilotModalHeader.slots.e2e.test.ts | matched | Dedicated strict counterpart now mirrors React section/case structure (24 cases) via Vue slot translation, including layout/drill-down and mixed integration scenarios. |
CopilotPopupView.slots.e2e.test.tsx | CopilotPopupView.slots.e2e.test.ts | matched | Dedicated strict counterpart now mirrors the full React section/case structure (31 cases) across header slots, inherited chat-view slots, popup-specific props, integration, and toggle-button matrix. |
CopilotSidebarView.slots.e2e.test.tsx | CopilotSidebarView.slots.e2e.test.ts | matched | Dedicated strict counterpart now mirrors the full React section/case structure (25 cases) across header slots, inherited chat-view slots, width/mixed customization, integration, and toggle-button matrix. |
| React test anchor | Vue counterpart | Status | Notes |
|---|---|---|---|
use-agent-context.test.tsx | use-agent-context.test.ts | matched | Base parity exists. |
use-agent.e2e.test.tsx | use-agent.e2e.test.ts (+ use-agent.test.ts) | matched | Dedicated strict e2e counterpart exists and passes with React-matching case wording and behavior boundaries. |
use-agent-throttle.test.tsx | use-agent-throttle.test.ts | matched | Dedicated strict counterpart now mirrors the full React throttle/scheduling matrix, including unthrottled immediate message updates, state/run-status microtask batching, trailing-edge timing semantics, cleanup cases, and provider defaultThrottleMs coverage. Post-shared-core alignment it also covers: onStateChanged throttled in the same shared window as onMessagesChanged, OnStateChanged-only subscriptions firing on the leading edge, invalid throttleMs warnings sourced from CopilotKitCore.subscribeToAgentWithOptions, and onRunErrorEvent bypassing the shared window. |
use-agent-context-timing.e2e.test.tsx | use-agent-context-timing.e2e.test.ts | matched | Dedicated strict counterpart exists and now passes with React-matching follow-up context behavior ({"spicy":false} on the second run). |
use-agent-error-state.test.tsx | use-agent-error-state.test.ts | matched | Dedicated strict counterpart now matches React error-state behavior by returning a provisional runtime agent instead of throwing when runtime sync fails. |
use-agent-stability.test.tsx | use-agent-stability.test.ts | matched | Dedicated strict counterpart now matches React provisional-agent caching semantics across Disconnected->Connecting->Connected transitions. |
use-agent-thread-isolation.test.tsx | use-agent-thread-isolation.test.ts | matched | Dedicated strict counterpart now mirrors React thread-clone isolation semantics, cache invalidation on registry replacement, and provisional->real clone transitions. |
use-attachments.test.tsx | use-attachments.test.ts | matched | Dedicated strict counterpart validates stable attachment action identities across rerenders/config identity changes, latest-config reads without stale closures, and empty-queue consumeAttachments() no-op semantics. |
use-configure-suggestions.e2e.test.tsx | use-configure-suggestions.e2e.test.ts (+ use-configure-suggestions.test.ts) | matched | Dedicated strict e2e counterpart exists and now passes the full React-mirrored suite, including deferred reload behavior during in-progress runs. |
use-frontend-tool-available.test.tsx | use-frontend-tool-available.test.ts | matched | Dedicated strict counterpart exists with React-matching suite and case wording. |
use-frontend-tool.e2e.test.tsx | use-frontend-tool.e2e.test.ts (+ use-frontend-tool.test.ts) | matched | Dedicated strict e2e counterpart exists and now passes the full React-mirrored suite, including unmount, override, and error-propagation coverage. |
use-interrupt.test.tsx | use-interrupt.test.ts | matched | Dedicated strict counterpart includes the full React case set and naming, including thenable handler support and latest-interrupt-wins behavior. |
use-render-tool.test.tsx | use-render-tool.test.ts | matched | Dedicated Vue counterpart exists with React-matching suite/case wording and matching Standard Schema/Zod regression coverage via dedicated counterparts. |
use-default-render-tool.test.tsx | use-default-render-tool.test.ts | matched | Dedicated Vue counterpart exists with React-matching suite/case wording. |
use-component.test.tsx | use-component.test.ts | matched | Dedicated Vue counterpart exists with React-matching suite/case wording and matching Standard Schema/Zod regression coverage via dedicated counterparts. |
standard-schema.test.tsx | standard-schema.test.ts | matched | Dedicated Vue counterpart exists with React-matching vendor coverage (zod, valibot, arktype) and matching suite/case wording. |
standard-schema-types.test.tsx | standard-schema-types.test.ts | matched | Dedicated Vue counterpart exists with React-matching vendor type-inference coverage and matching suite/case wording. |
zod-regression.test.tsx | zod-regression.test.ts | matched | Dedicated Vue counterpart exists with React-matching suite/case wording and coverage boundaries. |
use-human-in-the-loop.e2e.test.tsx | use-human-in-the-loop.e2e.test.ts (+ use-human-in-the-loop.test.ts) | matched | Dedicated strict e2e counterpart exists and now passes full React-mirrored HITL status, interaction, registration, and reconnection coverage. |
use-suggestions.e2e.test.tsx | use-suggestions.e2e.test.ts (+ use-suggestions.test.ts) | matched | Dedicated strict e2e counterpart exists and passes the full mirrored React case set, including clear/reload/loading transitions. |
use-threads.test.tsx | use-threads.test.ts | matched | Dedicated strict counterpart preserves the full React case set and wording; Vue now also matches pagination naming (hasMoreThreads, isFetchingMoreThreads, fetchMoreThreads) and filtered public thread shape, with Vue-only reactivity coverage isolated in a trailing Vue-specific reactive semantics block. |
use-keyboard-height.test.tsx | use-keyboard-height.test.ts | matched | Dedicated strict counterpart mirrors the React useKeyboardHeight suite (Visual Viewport unavailable, open/close threshold at 150 px, resize + scroll updates, listener cleanup on unmount); Vue returns readonly refs with matching field names instead of a plain state object, and a chat-view-level integration assertion in CopilotChatView.slots.e2e.test.ts proves the translateY(-keyboardHeight) transform is forwarded through CopilotChatView. |
use-katex-styles.test.tsx | use-katex-styles.test.ts | matched | Dedicated strict counterpart mirrors the React useKatexStyles suite (dynamic-import success path, failure path with no throw, regression guard that CopilotChatAssistantMessage.vue no longer statically imports katex/dist/katex.min.css and now calls useKatexStyles()). |
use-pin-to-send.test.tsx | use-pin-to-send.test.ts | matched | Dedicated strict counterpart for the N2 usePinToSend parity package. Mirrors React case wording 1:1 across spacer height math (viewportHeight - bubbleHeight - topOffset), scrollTo offset (offsetTop - topOffset), shrink-only ResizeObserver semantics, and rAF cleanup on unmount. Vue uses provide(LastUserMessageKey, ref(...)) instead of LastUserMessageContext.Provider, and reuses the same jsdom rAF + height-mock harness as React. |
This backlog captures React tests that are intentionally out of scope or not yet represented by a Vue public surface. It is no longer a list of open strict-port test failures.
Backlog classification:
existing-unmapped: a Vue test file already exists, but the matrix does not yet audit/map it explicitly.missing-parity: no Vue counterpart exists at the React test boundary yet.intentional-divergence: React test targets a render-hook or API pattern that Vue should not port literally.api-gap: Vue does not yet expose an equivalent package surface, so this is not a pure test-port task.| React test anchor | Current Vue state | Classification | Next action |
|---|---|---|---|
CopilotChatCssClasses.test.tsx | No dedicated Vue counterpart; Vue does not currently preserve React's legacy v1/v2 CSS class contract | intentional-divergence | Excluded from current parity scope. Keep Vue focused on behavioral/customization parity unless package-level styling contract parity is later required explicitly. |
No currently open hook/helper items — use-katex-styles and use-keyboard-height are now mapped in the Hooks parity matrix below.