-
Notifications
You must be signed in to change notification settings - Fork 668
Mock $refs #271
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
Comments
@charliekassel could you provide an example where you would want to use this functionality? |
Perhaps it's actually stubbing rather than mocking. |
I have a component
And my test
This throws the following error and fails the test:
Stubbing |
Wouldn't that be solvable by stubbing the component that's being referenced? messing with $refs means messing with the implementation of the component under test, which is not a good idea in my opinion. |
@LinusBorg |
@ddykhoff can you post a code example of $refs not being populated correctly in vue-test-utils? |
@eddyerburgh My original comment in the issue has the example I am facing the issue with (#271 (comment)). Let me know if there is more info I can provide. |
@eddyerburgh I was trying to create a JSFiddle to show the issue but I'm not sure its possible to transpile within JSFiddle, or at least I don't know how. Thus vue-test-utils cannot be loaded properly. https://jsfiddle.net/7kgkfrbu/1/
Should I open another issue for this? Being able to provide JSFiddles is useful for bug reproduction. |
@ddykhoff There's an iife build that runs in browsers—https://github.com/vuejs/vue-test-utils/blob/dev/dist/vue-test-utils.iife.js. Once we've released we could add it to CDNJS. At the moment, your best bet is to copy the code from the iife into JSFiddle. You also need to include vueTemplateCompiler (https://cdn.jsdelivr.net/npm/vue-template-compiler@2.5.13/browser.js). |
@eddyerburgh I got it working in JSFiddle. You can use rawgit.com as a "CDN" for the iife build. Here is the bug repro you requested (child components methods not available in https://jsfiddle.net/7kgkfrbu/6/ As you can see from the console output in the |
Hi @ddykhoff, thanks for the fiddle. The reason you can't call the method on the ref is because shallow stubs all the child components. The $refs object is still populated, but the toast component doesn't have any methods (because it's been stubbed). You can use const VueToastStub = {
render: () => {},
methods: {
setOptions: () => {}
}
}
const wrapper = shallow(Approvals, {
stubs: {
'vue-toast': VueToastStub
}
}) |
So if that use case isn't one after all, I posit again: we don't have to mock refs, we can stub the components. And we shouldn't either, because we create situations that are not possible in a real app. |
@eddyerburgh I can confirm that the above technique worked for me and allowed me to test the parent method without error. |
@eddyerburgh Is there an issue with referencing the |
@ddykhoff That is an issue with using an HTML template instead of a template property. If you refactor your example to use a vue-test-utils doesn't support HTML templates at the moment, if you'd like to see it as a feautre, please make a new feature request issue. |
I'm going to close this issue as there are solutions to mock refs by stubbing components without a method that could potentially cause bugs. |
How can I mock Because of this I need a way to mock |
Well, if If you want to test the computed property (which smells a lot like testing implementation details), just test that function on its own, providing a simple componentInstance mock with // your computed property
function isTooTall() {
return this.someData - this$refs.ref.clientHeight < 100
} // your test
const mock = {
someValue: 1000,
$refs: {
ref: {
clientHeight: 910
}
}
}
const result YourComponent.computed.isTooTall.call(mock)
expect(result).toBe(true) Generally, stuff involving dimensions should probably be tested in an end-to-end test where you can verify the correctness of the resulting behaviour (breakpoints, change of dimensions etc), not a unit test that tests implementation details. That computed prop could calculate correctly and a dozen other things only appearant in a real e2e test could make the behaviour relying on this property break. |
@LinusBorg I'm primarily trying to just get the component to complete the render cycle without throwing an error. I guess I could just check if |
Im also having the same issue. I need to mock the clientWidth of an element that I'm using a $ref to retrieve. My functionality involves dynamically translating an object based on the width of the container. It's unfortunate that the $ref doesn't get updated when I modify the elements in the same way the event.target gets updated https://vue-test-utils.vuejs.org/api/wrapper/#trigger-eventtype-options |
same question about test $refs from
Here is my part code of test:
I want to test if
still not familar with |
@xiayuying I have the same problem with element-ui, any ideas? |
@krskibin I had same problem with element-ui.. Example workarounds might be:
if (!this.$refs.filter.validate) {
return false
} Option 2 is how bad testing practices can destroy codebase... |
Weird syntax, no? As this is creating an object, not a Vue component: const VueToastStub = {
render: () => {},
methods: {
setOptions: () => {}
}
}
const wrapper = shallow(Approvals, {
stubs: {
'vue-toast': VueToastStub
}
}) Might work in standard JS, but TS is very unhappy with that. I had to do this in my code: // @ts-ignore
const StubbedCropper = Vue.extend({
methods: {
getCroppedCanvas: () => 'placeholder',
},
render: () => ({}),
}); |
@xyyVee You can try this import { shallowMount } from '@vue/test-utils';
import { Form } from 'element-ui';
import component from '.@/components/index';
describe('index.vue', () => {
beforeEach(() => {
wrapper = shallowMount(component, {
stubs: {
'el-form': Form,
},
});
});
});
|
For me helped the way of changing
Hope this may be useful for someone. |
I have the same question about the element UI validate not a function error, do you fix this problem? waiting~~ |
This is awkward. In my case, the tests pass when ran through WebStorm, but don't pass running on terminal. Basically because something I'm doing with
Switching from Edit |
It was, thanks! I was trying to put the $refs object in mocks within the mount options but never thought of doing it like this :D |
For those simply wanting to access a child method from a mounted component (similarly to how a parent component would use
|
In ParentComponent.vue file
In Jest spec file
|
thank you! this solved my case. closeHandler(sendFocusBackToButton) {
this.isOpen = false
if (sendFocusBackToButton) {
this.$refs.button.focus()
}
}, in a component like: <div
ref="dropdown"
@click="closeHandler"
/> test: beforeEach(async () => {
wrapper = await mount(MyComponent, {
data() {
return {
isOpen: true
}
},
stubs: {
'test-button': TestButton
}
})
wrapper.vm.$refs.button.focus = jest.fn()
})
it("should close the dropdown menu", async () => {
await wrapper.find('.menu').trigger("click")
expect(wrapper.find(".menu").attributes('hidden')).toBe("hidden")
}) |
Thank you buddy, you saved my time! |
I am not sure about you but I got below error after doing this: wrapper.vm.$refs.childComponent.someMethod = mockedMethod Error: |
It would be useful to be able to mock $refs.
Currently, as far as I understand there is no way to test a method that calls a childs methods via $refs.
The text was updated successfully, but these errors were encountered: