Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: Unable to use with Vue Final Modal due to teleport #2165

Closed
doutatsu opened this issue Aug 21, 2023 · 9 comments
Closed

Bug: Unable to use with Vue Final Modal due to teleport #2165

doutatsu opened this issue Aug 21, 2023 · 9 comments
Labels
bug Something isn't working

Comments

@doutatsu
Copy link

doutatsu commented Aug 21, 2023

Describe the bug
After updating Vue Final Modal from 3.x to 4.x, it is now impossible to have tests pass for the modal, due to the weird behaviour of teleporting to the body, I presume. Basically it's impossible to test contents of the base modal, as even when stubbing teleport,

To Reproduce
https://stackblitz.com/edit/vue-test-utils-repro-1234?file=src%2Fcomponents%2F__tests__%2FHelloWorld.spec.ts

Expected behavior
Tests would pass as normal, without Vue Test Utils throwing an error

Related information:

Error: Cannot call element on an empty DOMWrapper.
  Object.get node_modules/@vue/test-utils/dist/vue-test-utils.esm-bundler.mjs:1550:27
    1548|     return (element.nodeName !== '#comment' &&
    1549|         isStyleVisible(element) &&
    1550|         isAttributeVisible(element) &&
       |                           ^
    1551|         (!element.parentElement || isElementVisible(element.parentElement)));
    1552| }
  eval src/components/__tests__/HelloWorld.spec.ts:46:26

Here what running html() on the modal returns now:

<teleport-stub data-v-e17ea971="" to="body" disabled="false">
  <!---->
</teleport-stub>

Here what it was before (aka it is fully rendered:

<div data-v-2836fdb5="" data-v-90ea3908="" style="z-index: 1000; display: none;" class="vfm vfm--inset vfm--fixed">
  <transition-stub data-v-2836fdb5="" enteractiveclass="ease-out duration-300" enterfromclass="opacity-0" entertoclass="opacity-100" leaveactiveclass="ease-in duration-200" leavefromclass="opacity-100" leavetoclass="opacity-0" appear="false" persisted="false" css="true">
    <!--v-if-->
  </transition-stub>
  <transition-stub data-v-2836fdb5="" enteractiveclass="ease-out duration-300" enterfromclass="opacity-0 translate-y-4 sm_translate-y-0 sm_scale-95" entertoclass="opacity-100 translate-y-0 sm_scale-100" leaveactiveclass="ease-in duration-200" leavefromclass="opacity-100 translate-y-0 sm_scale-100" leavetoclass="opacity-0 translate-y-4 sm_translate-y-0 sm_scale-95" appear="false" persisted="false" css="true">
    <div data-v-2836fdb5="" class="vfm__container vfm--absolute vfm--inset vfm--outline-none flex items-end justify-center min-h-screen p-4 text-center sm_items-center sm_p-0" aria-expanded="false" role="dialog" aria-modal="true" tabindex="-1" style="display: none;">
      <div data-v-2836fdb5="" class="vfm__content sm_max-w-md w-full">
        <div data-v-90ea3908="" data-v-2836fdb5-s="" class="modal-body bg-white dark_bg-gray-800">
          <transition-stub data-v-c6300b7f="" data-v-90ea3908="" data-v-2836fdb5-s="" name="loader-fade" appear="false" persisted="false" css="true" tabindex="-1">
            <div tabindex="0" class="vl-overlay vl-active" aria-busy="false" aria-label="Loading" style="display: none;">
              <div class="vl-background" style="opacity: 0.95;"></div>
              <div class="vl-icon"><svg data-v-c6300b7f="" class="animate-spin h-8 w-8 text-blue-600 dark_text-moon-yellow-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
                  <circle data-v-c6300b7f="" class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                  <path data-v-c6300b7f="" class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                </svg></div>
            </div>
          </transition-stub>
          <div data-v-90ea3908="" data-v-2836fdb5-s="" class="px-4 pt-5 pb-4 sm_p-6 sm_pb-4 rounded-lg bg-white dark_bg-gray-800">
            <div data-v-90ea3908="" data-v-2836fdb5-s="" class="sm_flex sm_items-start"></div>
          </div>
          <!--v-if-->
        </div>
        <!--v-if-->
      </div>
    </div>
  </transition-stub>
</div>

Additional context
I am under the impression that this issue falls under Vue Test Utils, as it should be able to handle teleports better, hence why I am opening this report here instead of the Vue Final Modal repo. Do let me know if you feel like it's out of scope of test utils

@doutatsu doutatsu added the bug Something isn't working label Aug 21, 2023
@cexbrayat
Copy link
Member

Hi @doutatsu
I'm getting a 404 on your repro

Anyway, it looks like you have a teleport stub. If you want to test something that uses Teleport, check out the guide in the documentation
https://test-utils.vuejs.org/guide/advanced/teleport.html

@doutatsu
Copy link
Author

@cexbrayat Apologies for the broken link, I've updated it to make sure it's working now. The issue is that neither stubbing teleporting and not stubbing it doesn't work.

I've read documentation countless times and tried a lot of things, and nothing works I am afraid. I have other teleports in my test suite, which works - it's only specifically the modal associated with this library that started breaking since it's major upgrade.

@doutatsu
Copy link
Author

I know there has been some issues related to teleporting - e.g. this issue (#1781) has been closed, even though one of the latest teleport fixes (#2065) have not fixed it, as mentioned by the PR owner

@cexbrayat
Copy link
Member

I took a look at the repro, and if I remove the teleport stub in mount and then log what is in the body element, then I see the empty comment that Vue adds. So the teleportation is working, but maybe you need to do something to display the modal (like calling useModal() or something like that)?

    beforeEach(() => {
      const vfm = createVfm();
      console.log(window.document.body.outerHTML); // displays <body></body>
      baseModal = mount(HelloWorld, {
        global: { plugins: [vfm] },
      });
      console.log(window.document.body.outerHTML); // displays <body><!-----></body>
    });

I think Teleport is working fine and I don't see an issue with VTU. You probably need to trigger the display of the modal, and you'll be able to test whatever you want.

@doutatsu
Copy link
Author

doutatsu commented Aug 22, 2023

@cexbrayat I see, that actually makes a ton of sense. Previously due to teleport not being present, modal content was always present, hence why tests were working just fine. But now I need to make sure to actually "open" modal - in my case modelValue needs to be true - which is what happens in regular usage, which is why even though library was working as is, but not in tests.

I am still having trouble with fixing tests, as passing through props, as before, seems to not actually trigger visibility, unless I mount the modal with modelValue as true, but I imagine it's not a Vue Test Utils issue at this point. I got something to work with now, thanks and sorry for the false positive bug report 🙏🏻

@cexbrayat
Copy link
Member

No worries, thanks for letting us know 👍

@adholland
Copy link

@doutatsu would you mind helping me out please? I'm seeing the same issue attempting to test Vue Final Modal. Would you be able to show how you enabled the modal, within jest/vitest, using either vfm or useModal()?

Would be really helpful. Thanks.

@adholland
Copy link

@doutatsu I read you're post again and think I can do it via modelValue = true. However that means me ditching vfm / useModal(). This is likely to be a large change, but cant work out how to include vfm / useModal() in my tests, so I have no option I think,

@meddle1
Copy link

meddle1 commented Dec 29, 2023

@doutatsu @adholland, hey!
You should add @update:model-value="emit('update:modelValue', $event)" to the VueFinalModal tag.
See https://github.com/vue-final/vue-final-modal/blob/master/examples/vue3/src/components/MyModal.vue
(vue-final-modal-master/examples/vue3/src/components/MyModal.vue)
Now you can use useModal(...).open() to open the modal window:

import { ModalsContainer, useModal } from 'vue-final-modal'
import { DefineComponent } from 'vue'

const modal = useModal({
  component: MyComponent as DefineComponent<any>,
  attrs: {
    onClose() {
      console.log('Now it works!')
    },
  },
})

await modal.open()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants