-
Notifications
You must be signed in to change notification settings - Fork 668
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
Add ability to add new methods to Wrapper #611
Comments
I can see that this would be useful, but it also encourages adding non-standard methods to the wrapper object. I'm not convinced either way and would like to hear other opinions. |
I read the example of usage which adds an alias of |
I'm not sure I see the use case beyond method extends being aliases to existing methods supported by test-utils as @38elements mentioned. If there are methods that aren't currently supported by test utils, we should add them to the library instead of allowing wrapper to be extended. I also don't think a wrapper extend is more readable or concise, and as @eddyerburgh mentioned it could result in users adding non standard methods to wrapper object, which could result in weird/unexpected bugs. |
I realise my examples were quite brief. Perhaps they don't illustrate the usefulness very well. It's hard to come up with examples that don't rely on code that I cannot share, but I'll try something a little closer to what I'm trying to achieve. Imagine you have a particular interaction that requires a couple of steps. In domain terms, this is 'add a record'. In terms of the component, it requires hovering to show some buttons, then clicking a button. Part of the requirement is that once an interaction like this has taken place (say for example it opens a popup window) the buttons should remain showing (as if hovered) and the row should remain highlighted. Two tests I'd like to write would be:
Example code for the two tests below: test('keeps hover open whilst adding a record', () => {
const component = shallow(MyComponent);
component.trigger('mouseover');
component.find('.add-btn').trigger('click');
component.trigger('mouseout');
expect(component.find('.hidden-buttons').isVisible()).toBe(true);
});
test('keeps row highlighted whilst adding a record', () => {
const component = shallow(MyComponent);
component.trigger('mouseover');
component.find('.add-btn').trigger('click');
component.trigger('mouseout');
expect(component.find('tr').classes()).toContain('highlight');
}); The mechanics of how the 'add record' popup is shown don't really matter to the test; they are at too low a level of abstraction. We wish to be able to say "When I start adding a record, the row should be highlighted" or "When I start adding a record, the buttons should remain showing". If, for example, the component were to change slightly and the interaction now requires also clicking on a menu item that drops down from the button, all the tests that specify these mechanics will need to be updated. Consider the below as an alternative (including custom Jest matchers as before): test('keeps hover open whilst adding a record', () => {
const component = shallow(MyComponent);
component.beginAddingRecord();
expect(component).toHaveVisible('.hidden-buttons');
});
test('keeps row highlighted whilst adding a record', () => {
const component = shallow(MyComponent);
component.beginAddingRecord();
expect(component.find('tr')).toBeHighlighted();
}); In my opinion these are nicer tests since the operate at a higher level of abstraction and are written in terms of the component's desired behaviour, rather than in terms of the mechanics of how that behaviour is triggered. Hopefully these examples show that whilst it is effectively aliasing, it can be used to help abstract away 'details' that may not be important to the test you are writing. |
Thanks for the example! I think I have a better understanding of what you're proposing. I'm still not 100% convinced of having a method alias like |
Let's not get too wrapped up in the fact that I've used mouse events in my examples. You could just as easily add methods that set props, introspect state, do anything that you would/could do with a wrapper normally. The key point is that it allows me to add methods that are applicable to my domain, not general usage. const component = shallow(MyInvoiceComponent);
component.pay(); // This is a method on the component itself
let isBilled = component.isBilled(); // This is a domain-specific test helper on the wrapper
expect(isBilled).toBeTruthy(); const component = shallow(MyEntityComponent);
let isBeingEdited = component.isBeingEdited(); // This is a domain-specific test helper on the wrapper
expect(isBeingEdited).toBeTruthy(); const component = shallow(MyTreeLikeComponent);
let hasOpenParent = component.hasOpenParent(); // This is a domain-specific test helper on the wrapper
expect(hasOpenParent).toBeFalsy(); const component = shallow(MyComponentThatCanBeInvalidated);
// Without helper we are relying on component internals in each test
component.setProps({invalid: true, error_message: 'Testing invalidation'});
// With helper, we can concentrate on behaviour
component.invalidateWithMessage('Testing invalidation');
// We can also abstract more complex operations that are specific to our components
let popupHasClosed = !component.findPopup().visible();
expect(popupHasClosed).toBeTruthy(); Another use case, besides in-house development, would be someone who authors a library of Vue components (think It would be nice if the component library authors could provide another package, I'm happy to keep monkey-patching these sort of helpers in as I do at the moment by wrapping 'shallow()' and just adding the methods to the returned wrapper object, but it would be nice to have an official mechanism to do so, particularly because I can then just 'drop-in' extra methods at the bootstrap stage, rather than having to modify my tests to use my own wrapper functions. |
The next beta will export Wrapper and WrapperArray, so you can add properties to their prototype: import { Wrapper } from '@vue/test-utils'
Wrapper.prototype.someCustomMethod = () => {} I'm going to leave it undocumented for now, because I don't think we should encourage most users to add custom methods. |
For a |
Hi @begueradj! The issue was closed a year and a half ago, so it would be way better if you could open up a new one if you are facing an issue. If you have a general question, it would be better if you could submit it to the forum or the official chat. Thanks! :) |
What problem does this feature solve?
I think it would be nice to be able to extend the
Wrapper
class with new methods (helper methods, effectively) to increase readability / reduce test-specific boilerplate.For example, using Jest, I've added some new matchers to keep things clean whilst testing components. Contrived example below:
It would be nice to be able to add similar helper methods to the
Wrapper
object so that tests could be written at a slightly higher level of abstraction. See a before and after below:Although the above examples are somewhat contrived for the sake of example, I think they lead to test code that more clearly documents the component under test.
What does the proposed API look like?
As for an example of how this might look in terms of the API, I'm not too sure; Wrapper is not exposed for reasons I think I agree with (from other issues on the topic). An exported function that provides this ability might work? I'm not much of a JS expert so please forgive me if I don't understand why the following example is unfeasible.
I'm interested to hear thoughts on this, thanks for taking the time to read.
The text was updated successfully, but these errors were encountered: