test(zone.js): should invoke XHR task even onload handler throw error. ()

Close .

This case related to the issue .

```
Zone.root
  .fork({
    name: 'xhr',
    onHasTask(delegate, currentZone, zone, taskState) {
      console.log('hasMacrotask', taskState.macroTask);
      return delegate.hasTask(zone, taskState);
    },
  })
  .run(() => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', 'https://cdnjs.cloudflare.com/ajax/libs/zone.js/0.11.4/zone.min.js');
    xhr.addEventListener('load', () => {
      throw new Error();
    });
    xhr.send();
  });
```

zone.js invoke all `onload` event handlers before change the XHR task's state from
`scheduled` to `notscheduled`, so if any `onload` listener throw error, the XHR task
wlll be hang to `scheduled`, and leave the macroTask status in the zone wrongly.

This has been fixed in the previous commit, this commit add test to verify the case.

PR Close 
This commit is contained in:
JiaLiPassion 2021-04-11 14:58:00 +08:00 committed by Andrew Kushnir
parent 5c48cd30b5
commit 6910118b0d

@ -103,6 +103,77 @@ describe('XMLHttpRequest', function() {
req!.send();
});
it('should run onload listeners before internal readystatechange', function(done) {
const logs: string[] = [];
const xhrZone = Zone.current.fork({
name: 'xhr',
onInvokeTask: (delegate, curr, target, task, applyThis, applyArgs) => {
logs.push('invokeTask ' + task.source);
return delegate.invokeTask(target, task, applyThis, applyArgs);
}
});
xhrZone.run(function() {
const req = new XMLHttpRequest();
req.onload = function() {
logs.push('onload');
(window as any)[Zone.__symbol__('setTimeout')](() => {
expect(logs).toEqual([
'invokeTask XMLHttpRequest.addEventListener:load', 'onload',
'invokeTask XMLHttpRequest.send'
])
done();
});
};
req.open('get', '/', true);
req.send();
});
});
it('should invoke xhr task even onload listener throw error', function(done) {
const logs: string[] = [];
const xhrZone = Zone.current.fork({
name: 'xhr',
onInvokeTask: (delegate, curr, target, task, applyThis, applyArgs) => {
logs.push('invokeTask ' + task.source);
return delegate.invokeTask(target, task, applyThis, applyArgs);
},
onHasTask: (delegate, curr, target, hasTaskState) => {
if (hasTaskState.change === 'macroTask') {
logs.push('hasTask ' + hasTaskState.macroTask);
}
return delegate.hasTask(target, hasTaskState);
}
});
xhrZone.run(function() {
const req = new XMLHttpRequest();
req.onload = function() {
logs.push('onload');
throw new Error('test');
};
const unhandledRejection = (e: PromiseRejectionEvent) => {
logs.push(e.reason.message);
};
window.addEventListener('unhandledrejection', unhandledRejection);
req.addEventListener('load', () => {
logs.push('onload1');
(window as any)[Zone.__symbol__('setTimeout')](() => {
expect(logs).toEqual([
'hasTask true', 'invokeTask XMLHttpRequest.addEventListener:load', 'onload',
'invokeTask XMLHttpRequest.addEventListener:load', 'onload1',
'invokeTask XMLHttpRequest.send', 'hasTask false',
'invokeTask Window.addEventListener:unhandledrejection', 'test'
]);
window.removeEventListener('unhandledrejection', unhandledRejection);
done();
});
});
req.open('get', '/', true);
req.send();
});
});
it('should return null when access ontimeout first time without error', function() {
let req: XMLHttpRequest = new XMLHttpRequest();
expect(req.ontimeout).toBe(null);