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

need export createWrapper #283

Closed
shixin-guo opened this issue Dec 23, 2020 · 12 comments
Closed

need export createWrapper #283

shixin-guo opened this issue Dec 23, 2020 · 12 comments
Labels
discussion question Further information is requested

Comments

@shixin-guo
Copy link
Contributor

shixin-guo commented Dec 23, 2020

vue-test-utils-next we export these:

export {
  mount,
  shallowMount,
  RouterLinkStub,
  VueWrapper,
  DOMWrapper,
  config,
  flushPromises
}

I think 'createWrapper' also needs to be exported to the user... or will we use other opinions?
and in doc I did not find about this,
if need I can create a pull request export createWrapper

@cexbrayat
Copy link
Member

Hi @gzponline

Until now, we did not need to export createWrapper. This is intended as an internal function, that end users don't need to write tests. You can simply use mount or shallowMount.

Do you have a use-case where you need createWrapper?

@lmiller1990 lmiller1990 added discussion question Further information is requested labels Dec 23, 2020
@shixin-guo
Copy link
Contributor Author

shixin-guo commented Dec 24, 2020

if create a new Vue instance in a component such as popper, tooltips, datepick table UI component, their sub-component will use data or methods of their parent component, and some components maybe append their sub-component DOM to , wapper.find can not find them.so I can not trigger some event in it

I will try to make a demo in this repo later, and if you have other suggestions for this, please tell me @cexbrayat

@cexbrayat
Copy link
Member

If I understand correctly, I think you are looking for stubs or shallowMount?

See https://vue-test-utils.vuejs.org/v2/guide/stubs-shallow-mount.html

I usually do something like (if I want to stub the RouterLink component for example):

const wrapper = mount(Bet, {
    global: {
      stubs: {
        RouterLink: true
      }
    }
  });

Then you can still use findComponent or getComponent:

const links = wrapper.findAllComponents(RouterLink);

Does that work for you?

@shixin-guo
Copy link
Contributor Author

shixin-guo commented Dec 28, 2020

@cexbrayat
I know stubs and shallowMount.
my case is one component creates a new VM internal, maybe want to build a dom out of this component, such as tooltip, datepicker.

a demo in ElementUI
image

    <el-tooltip class="item" effect="dark" content="Top Left prompts info" placement="top-start">
      <el-button>top-start</el-button>
    </el-tooltip>

https://element.eleme.io/#/en-US/component/tooltip

in this component will create a VM node and use PopperJS render it.

this.popperVM.node = (
          <transition
            name={this.transition}
            onAfterLeave={this.doDestroy}>
            <div
              role="tooltip"
              aria-label={ariaLabel}
              id={this.tooltipId}
              aria-hidden={(this.disabled || !this.showPopper) ? 'true' : 'false'}
              v-show={!this.disabled && this.showPopper}
              class={
                ['zm-tooltip__popper', 'is-' + this.effect, this.popperClass, this.breakWord ? 'is-break-word' : '']
              }>
              {this.$slots.content || this.content}
            </div>
          </transition>);
 this.popperJS = new PopperJS(reference, popper, options);

this popper is not child dom in our
so If I want to find this content "Top Left prompts info",

before in vue-test-utils (vue.js 2.~), we use createWrapper to get a wrapper then trigger event , but in this next version, I find this function is not export.

image

I do not know if you understand me, there are many other component use this way, especially some complex component in my team, table and picker all render by this way. and it puzzles me a long time

😄 I will try to make a simple demo not depending on myself code, maybe it will be easy to understand,and I think createWrapper is usefull

@cexbrayat
Copy link
Member

@gzponline A simple demo to illustrate your use-case would be awesome 👍

@lmiller1990
Copy link
Member

I think we should just export it - any reason why this should be internal, when createDOMWrapper is public? What does everyone think?

@lmiller1990
Copy link
Member

Going to close this for now - no follow up from OP.

I don't really see a problem exposing this, though. We won't document createWrapper, so it's still technically an internal API.

If someone else has this need just make a PR exporting createWrapper.

@deleugpn
Copy link

deleugpn commented Sep 8, 2023

hey @lmiller1990 I don't know if this has been addressed in any other way by now, but my use-case is that I am mounting a modal component, but the modal itself gets rendered at the root of the document.

console.log(wrapper.html(); // does NOT contain any of the stuff I'm looking for
console.log(wrapper.element.parentElement.outerHTML); // this one contains exactly what I'm looking for!!

Basically what I want is wrapper.vm.$root or wrapper.vm.$parent to become an instance of the same thing that wrapper is. The end result would be something like this:

const wrapper = mount(Modal, {...});

const parent = createWrapper(wrapper.vm.$root) as VueWrapper;

expect(parent.text()).toContain('My Modal Content')

@AntonioDell
Copy link
Contributor

Hi @lmiller1990 ,
I have a use case for providing access to the createWrapper function.

In my current project we have the following code, which is a utility to create a download link from a blob and click it without user interaction to download files.


const createDownloadLinkFromBlobAndClickIt = async (
  fileNameParts: string[],
  fileType: FileType,
  blob?: Blob
): Promise<string> => {
  const downloadedFileType =
    fileNameParts.length > 1 || fileType === "xml" ? "zip" : fileType;
  const blobType = "application/" + downloadedFileType;
  if (!blob || blob.type !== blobType) {
    return "error_msgs.pdfs_corrupt_or_not_present";
  }

  let filename = fileNameParts.join("_");
  // Sanitize filename if more than 1 pdf (truncate to 36 characters)
  if (fileNameParts.length > 1)
    filename =
      filename.length > 36 ? filename.substring(0, 35) + "-" : filename;
  filename += "." + downloadedFileType;

  downloadBlob(blob, filename);
  return "Downloading...";
};

// Create <a> tag and click it to download blob to file system
const downloadBlob = (blob: Blob, filename: string) => {
  const fileURL = URL.createObjectURL(blob);
  const fileLink = document.createElement("a");
  fileLink.href = fileURL;
  fileLink.setAttribute("download", filename);
  fileLink.setAttribute("data-test", "download-link");
  document.body.appendChild(fileLink);
  fileLink.click();
};

export { createDownloadLinkFromBlobAndClickIt, downloadBlob };

It doesn't contain a Vue component, but since we use VTU to test the rest of the app, we used createWrapper to get a wrapper for document.body and assert, that the tag is created with the correct attributes. This is a test which worked in VTU v1 and doesn't anymore, because createWrapper is not exported anymore:

//  ... rest of the tests
  it("creates an <a> link in the document ", async () => {
     global.URL.createObjectURL = vi
       .fn()
       .mockReturnValueOnce("http://someurl/to/a/download");
     const mockBlob = new Blob([], { type: "application/pdf" });

     await createDownloadLinkFromBlobAndClickIt(["test"], "pdf", mockBlob);

     const link = createWrapper(document.body).find(
       "[data-test=download-link]"
     );
     expect(link.exists()).toBeTruthy();
   });

We can work around it in this case and assert on the document.body with normal query selectors and not use VTU, but in other cases the flexibility of VTU utils are very helpful.

Is there maybe a different way of having a Wrapper around the document.body without createWrapper?

@lmiller1990
Copy link
Member

Should we just export createWrapper?

@lmiller1990 lmiller1990 reopened this Nov 7, 2023
@AntonioDell
Copy link
Contributor

I found a workaround actually. Not sure if that is "clean" or a hack tbh.
Instead of createWrapper I now use the DOMWrapper constructor like so:


import { DOMWrapper } from "@vue/test-utils";

...

  it("creates an <a> link in the document ", async () => {
     global.URL.createObjectURL = vi
       .fn()
       .mockReturnValueOnce("http://someurl/to/a/download");
     const mockBlob = new Blob([], { type: "application/pdf" });

     await createDownloadLinkFromBlobAndClickIt(["test"], "pdf", mockBlob);

     const link = new DOMWrapper(document.body).find(
       "[data-test=download-link]"
     );
     expect(link.exists()).toBeTruthy();
   });

So maybe a hint in the documentation would be sufficient for people who have similar use cases as me.

@cexbrayat
Copy link
Member

👍 Nice to hear you found what you were looking for @AntonioDell
Feel free to open a docs PR if you find a good spot to add, we'll gladly review it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion question Further information is requested
Projects
None yet
Development

No branches or pull requests

5 participants