Skip to content

fix: stub directives registered with a camelCase or kebab-case name - #2982

Merged
cexbrayat merged 1 commit into
vuejs:mainfrom
MaxFreedomPollard:fix/directive-stub-registered-name
Oct 28, 2026
Merged

cexbrayat merged 1 commit into
vuejs:mainfrom
MaxFreedomPollard:fix/directive-stub-registered-name

Conversation

@MaxFreedomPollard

Copy link
Copy Markdown
Contributor

Summary

global.stubs only replaces a directive when the component registers it under exactly the name in the stub key minus the v. If the directive is registered as myDirective or my-directive, vMyDirective is ignored and the real directive keeps running, even though Vue resolves v-my-directive to those registrations too:

const Component = {
  template: '<div v-my-directive>text</div>',
  directives: { myDirective: MyDirective }
}

mount(Component, { global: { stubs: { vMyDirective: true } } })
// MyDirective still runs

Lowercase keys are the common Options API style. The Vue docs register their example as directives: { highlight } for v-highlight, which vHighlight cannot stub today. A stub key is only treated as a directive when it is v followed by an uppercase letter, so no stub key can match such a registration.

Root cause

createStubDirectivesTransformer (src/vnodeTransformers/stubDirectivesTransformer.ts) picks the directives to replace with Object.keys(type.directives).filter(key => key in directives). getDirectivesFromStubs strips the leading v from the stub key (vMyDirective becomes MyDirective), so only a registration named exactly MyDirective matches. Vue's resolveAsset looks a template directive up by its name, the camelized name and the capitalized name, so myDirective and my-directive are equally valid registrations for v-my-directive.

Fix

Compare the registered name with the stub names using matchName, the helper the component stubs already use. The directive is still replaced under the key it is registered with. PascalCase registrations behave as before, and vMyDirective: false still opts out.

Validation

I added two regression tests to tests/mountingOptions/global.stubs.spec.ts. One stubs a camelCase registration with a stub directive. The other replaces a kebab-case registration with the true noop.

I could not install the project's dependencies in my environment, so I have not run vitest, lint, format-check or the type checks locally. Instead I loaded Vue 3.5.44's runtime-core and compiler-dom from source, using the DOM-free @vue/runtime-test renderer. I then ran this repository's stub transformers on the same templates as the directives tests. On main, both new cases render the real directive's class. With this change they render the stub, and the existing directive cases give the same output as before.

🤖 Generated with Claude Code

`stubs: { vMyDirective: ... }` only replaced a directive registered as
`MyDirective`. A component registering it as `myDirective` or
`my-directive`, which Vue resolves for `v-my-directive` just the same,
kept running the real directive. Stub keys must be `v` followed by an
uppercase letter to be treated as directives, so no stub key could
match those registrations.

The directive transformer looked the registered name up verbatim among
the stub names. Match it with `matchName` instead, as component stubs
already do, and keep replacing the directive under its registered key.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@netlify

netlify Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for vue-test-utils-docs ready!

Name Link
🔨 Latest commit bf21801
🔍 Latest deploy log https://app.netlify.com/projects/vue-test-utils-docs/deploys/6adaf24f9ff5c1a980c03bf1
😎 Deploy Preview https://deploy-preview-2982--vue-test-utils-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@pkg-pr-new

pkg-pr-new Bot commented Oct 23, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vue/test-utils@2982

commit: bf21801

@cexbrayat cexbrayat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

@cexbrayat
cexbrayat merged commit 7a741b5 into vuejs:main Oct 28, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants