Resolve the base Vue constructor for tooltip and popover helpers

What does this MR do?

Fixes TypeError: n.show is not a function, thrown by GlTooltip and GlPopover under @vue/compat (Sentry issue GITLABCOM-CLIENTSIDE-2M1VG, 53 users affected in the first 24 hours).

Root cause

  • The vendored bootstrap-vue code builds the tooltip helper (BVTooltip / BVPopover) with new Ctor({...helperOptions, ...config}), where Ctor is parent.$.appContext.config.globalProperties.constructor.
  • When the app root is created with new (Vue.extend(Component))(...), that constructor is the Vue.extend() subclass, not the base Vue. Under @vue/compat, new SubVue(options) merges SubVue.options into options.
  • So the helper inherited Component's props, data and lifecycle hooks. A show prop shadowed the helper's show() method. Vue warns Methods property "show" is already defined in Props, then $toolpop.show() throws.
  • BVTransporter read Teleport from the same constructor. The subclass has no Teleport, so the tooltip content was not rendered either.

GitLab hits this in the issuable reference popover, which mounts new (Vue.extend(PopoverComponent))({ propsData: { show: true, ... } }).$mount() on every page with issue or MR links. That explains the Sentry feature_category spread across source_code_management, groups_and_projects and team_planning.

Fix

  • Add getVue3Constructor(instance) to the vendored Vue shim. It walks the super chain to the base constructor.
  • Use it in createNewChildComponent and in BVTransporter.
  • Add specs for both. Each fails without the fix under VUE_VERSION=3.

Verification

  • VUE_VERSION=3 NODE_ENV=test npx jest and NODE_ENV=test npx jest on the tooltip, popover, transporter and factory specs: 30 passed in each mode.
  • A Vue 3 Jest repro in gitlab-org/gitlab (root from Vue.extend, BPopover with show: true) fails on main with the Vue warning above and passes with these three files copied into node_modules/@gitlab/ui/src.

Also seen in GitLab feature specs

The same error fails four feature spec examples in gitlab-org/gitlab as Uncaught TypeError: $toolpop.show is not a function (the unminified form of the Sentry message):

  • spec/features/work_items/issues/notes_on_issues_spec.rb and ee/spec/features/work_items/epics/referencing_epics_spec.rb, both of which render cross-reference notes and hover the reference links.
  • It fails in both the Vue 2 job (rspec system pg17 19/32) and the Vue 3 job (rspec system pg17 vue3 27/32). In the Vue 2 job the frame is in a .vue3- commons chunk, so the popover already runs under @vue/compat there.
  • Tracked in gitlab-org/gitlab#628901 (section $toolpop.show is not a function).

Why not fix it in GitLab instead

The consumer uses a valid Vue 2 API, and gitlab-ui claims compat support. Any other consumer that roots an app with Vue.extend() hits the same crash for any prop that matches a helper method name (show, hide, enable, disable), and inherits the root's lifecycle hooks into the helper. Resolving the base constructor fixes all of them. Replacing Vue.extend() roots in GitLab is a separate clean-up.

Screenshots or screen recordings

GDK, issue page under @vue/compat (vue3_migrate_work_items enabled), hovering the #38 reference in a note. Same page, same hover, before and after copying the three changed files into node_modules/@gitlab/ui/src.

Before: no popover, Uncaught TypeError: $toolpop.show is not a function
before
After: popover renders in the Vue 3 realm, no console errors
after

Integrations

No API change. GitLab picks the fix up with the next @gitlab/ui bump.

Does this MR meet the acceptance criteria?

  • The “What does this MR do?” section explains the reasons for and scope of the change.
  • Relevant labels are applied.
  • A changeset is added (patch).
  • Tests added for the fixed behaviour under both Vue 2 and Vue 3.

References

🤖 Generated with Claude Code

Edited by Miguel Rincon

Merge request reports

Loading
Loading