Draft: Make component stubs carry the real component's emits

What does this MR do and why?

GitLab runs its Jest suite on Vue 2, and in a separate CI job with VUE_VERSION=3, on Vue 3 via @vue/compat. When a component declares an emits option and emits an event not listed there, Vue logs the warning Component emitted event "x" but it is neither declared in the emits option nor as an "onX" prop, and the Jest console watcher fails the test. This makes the Vue 3 job a completeness check for emits.

The problem is that stubs created by stubComponent() (spec/frontend/__helpers__/stub_component.js) and by the shallowMount auto-stub factory in spec/frontend/vue_compat_test_setup.js declared no emits. Vue skips the check for components without emits, so a spec could call vm.$emit('anything') on a stub and nothing would notice, even if the real component never emits that event.

This MR adds a collectEmits(component) helper that gathers event names from the component's emits, plus those declared by its mixins and extends chain (unwrapping legacy Vue.extend constructors). Both stub kinds now set emits to that list. Only keys are copied, so object-form emits validators never run against spec-provided arguments. When nothing in the chain declares emits, the helper returns undefined and the stub stays exactly as before.

As a result, a spec that emits an event on a stub which the real component does not declare now fails under VUE_VERSION=3 with the warning above. This surfaces specs testing code paths that cannot happen, dead event listeners in parent components, and forwarded events that a wrapper component relays via v-on="glListeners()" without declaring them.

This MR is expected to fail the Vue 3 Jest job right now. A full local run on master found 28 failing spec files, all caused by this new check. They are being cleaned up in separate merge requests that reference this one; this MR should merge after they land. The failures fall into three groups: forwarded events not declared by wrapper components, parent components listening for events the child never emits, and specs emitting events nobody emits or listens for.

References

Cleanup merge requests that fix the failures this change surfaces:

  • Parent components listening for events the child never emits: !253503 (merged)
  • Specs emitting events nobody emits or listens for: !253504 (closed)
  • Double-fired action tracking in the frequent items wrappers, found by this check: !253514 (merged)
  • Forwarded events not declared by wrapper components: not opened yet

Screenshots or screen recordings

Not applicable, this is a test-helper change.

How to set up and validate locally

To confirm stubs still work as before for components without emits:

VUE_VERSION=3 yarn jest spec/frontend/ci/artifacts

To see an example of a spec that now fails because of this check, author_filter_spec.js emits shown on a FilterDropdown stub whose component declares other events only:

VUE_VERSION=3 yarn jest spec/frontend/search/sidebar/components/author_filter_spec.js

Vue 2 is unaffected, since Vue 2 ignores emits at runtime:

yarn jest

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Illya Klymov

Merge request reports

Loading
Loading