While attempting to handle a situation where an update failed and I wanted to reset a button back to its original state, I discovered then(fn1,fn2) and then(fn1).catch(fn2) were giving different results after a rejected promise, despite the fact that they are supposed to be equivalent.
test('Reproduce error', () => {
//setup jsdom
document.body = document.createElement('body');
let button = document.createElement('button');
button.id = 'id';
document.body.appendChild(button);
//setup functions used
let promiseReject;
const updaterMock = function () {
return new Promise((resolve,reject)=>{promiseReject = reject});
};
const markButtonOn = () => {};
const markButtonOff = function () {
console.log("I'm marking off");
button.textContent = 'off';
button.onclick = () => {
button.textContent = 'updating';
console.log("I'm updating");
updaterMock()
//using only then(): test passes
.then(markButtonOn,markButtonOff);
//using both then() and catch(): test fails on last expect()
//.then(markButtonOn).catch(markButtonOff);
};
}
//initial state
markButtonOff();
//always passes
expect(button.textContent).toBe('off');
//try to turn on
button.click();
//always passes
expect(button.textContent).toBe('updating');
//trigger the update to fail
promiseReject();
//force test to wait for the mock's returned promise to resolve
return Promise.resolve().then(() => {
//passes with .then(markButtonOn,markButtonOff)
//fails with .then(markButtonOn).catch(markButtonOff), received 'updating'
expect(button.textContent).toBe('off');
});
});
I reduced the situation as much as I could, stripping out any unnecessary items. (At least, as best as I can tell. I'm still quite new to Javascript/Typescript. Sidenote: I got the promiseReject technique from here.)
If you change which line is commented out following the updaterMock() call in the button.onclick section in the middle, then the test result changes.
If I use just then(fn1,fn2), the test passes.
If I use then(fn1).catch(fn2) the test fails, saying the textContent is still in the 'updating' state.
In both cases, Jest reports that all 3 calls to console.log() go off:
I'm marking off
I'm updating
I'm marking off
Which tells me the 2nd call to markButtonOff is executing, but Jest isn't seeing the element's change.
Why are
then(fn1,fn2)andthen(fn1).catch(fn2)behaving differently?How can I change things in my test to fix this (ideally, just doing something to the test code, not to the
markButtonOffproduction code, which I wrote straight into the test to make it easy for others to reproduce.)