Wrap trigger into nextTick calls
What does this MR do?
This MR adds proper nextTick
to every trigger
call, if any subsequent call asserts against a component template in our Vue tests
Closes #192019 (closed)
Why do we need this one?
We're preparing to upgrade @vue/test-utils
to .beta.30
in &2291 (closed) which will drop sync mode. We want to make sure we're properly handling all the ways of changing component
🤔 ?
How do you found all of them In order to reveal them I've monkey-patched @vue/test-utils
to throw if we're trying to access component template after calling trigger
let poisoned = false;
const poisonMark = (obj, prop, state) => {
const orig = obj[prop];
obj[prop] = function p(...args) {
const result = orig.apply(this, args);
poisoned = state;
return result;
};
};
const ensureNotPoisoned = (obj, prop) => {
const orig = obj[prop];
obj[prop] = function p(...args) {
if (poisoned) {
throw new Error(`:${prop}: Dirty tree operation`);
}
return orig.apply(this, args);
};
};
poisonMark(vtu.Wrapper.prototype, 'trigger', true);
poisonMark(Vue.prototype, '$nextTick', false);
poisonMark(Vue, 'nextTick', false);
poisonMark(Vue.prototype, '$mount', false);
ensureNotPoisoned(vtu.Wrapper.prototype, 'attributes');
ensureNotPoisoned(vtu.Wrapper.prototype, 'classes');
ensureNotPoisoned(vtu.Wrapper.prototype, 'contains');
ensureNotPoisoned(vtu.Wrapper.prototype, 'emitted');
ensureNotPoisoned(vtu.Wrapper.prototype, 'emittedByOrder');
ensureNotPoisoned(vtu.Wrapper.prototype, 'find');
ensureNotPoisoned(vtu.Wrapper.prototype, 'findAll');
ensureNotPoisoned(vtu.Wrapper.prototype, 'html');
ensureNotPoisoned(vtu.Wrapper.prototype, 'isEmpty');
ensureNotPoisoned(vtu.Wrapper.prototype, 'isVisible');
ensureNotPoisoned(vtu.Wrapper.prototype, 'props');
ensureNotPoisoned(vtu.Wrapper.prototype, 'text');
ensureNotPoisoned(vtu.WrapperArray.prototype, 'at');
ensureNotPoisoned(vtu.WrapperArray.prototype, 'filter');
ensureNotPoisoned(vtu.WrapperArray.prototype, 'isEmpty');
expect.extend({
toMatchSnapshot: function m(...args) {
if (poisoned) {
return {
pass: false,
message: () => 'Poisoned tree',
};
}
return toMatchSnapshot.apply(this, args);
},
});
.beta-30
?
Why are you fixing test cases which do not fail on upgrade to Basically, when testing Vue component we do not want to know anything about it's internal structure. "Immediate" reaction to anything - either setData
, setProps
, trigger
, $emit
, whatever - is an implementation detail - for example we can perform some action in event handler, or we can update some state, which will trigger watch
- former do not require nextTick
, latter does. That's why we ensure all such calls are properly wrapped into nextTick