Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

fix(patch): fix #746, check desc get is null and only patch window.resize additionally #747

Merged
merged 7 commits into from
Apr 25, 2017
13 changes: 8 additions & 5 deletions lib/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,20 +126,23 @@ export function patchProperty(obj: any, prop: string) {
}
if (target.hasOwnProperty(_prop)) {
return target[_prop];
} else {
} else if (originalDescGet) {
// result will be null when use inline event attribute,
// such as <button onclick="func();">OK</button>
// because the onclick function is internal raw uncompiled handler
// the onclick will be evaluated when first time event was triggered or
// the property is accessed, https://github.com/angular/zone.js/issues/525
// so we should use original native get to retrieve the handler
let value = originalDescGet.apply(this);
value = desc.set.apply(this, [value]);
if (typeof target['removeAttribute'] === 'function') {
target.removeAttribute(prop);
if (value) {
desc.set.apply(this, [value]);
if (typeof target['removeAttribute'] === 'function') {
target.removeAttribute(prop);
}
return value;
}
return value;
}
return null;
};

Object.defineProperty(obj, prop, desc);
Expand Down
182 changes: 94 additions & 88 deletions test/browser/browser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,94 +84,100 @@ describe('Zone', function() {
expect(confirmSpy).toHaveBeenCalledWith('confirmMsg');
});

describe('DOM onProperty hooks', ifEnvSupports(canPatchOnProperty, function() {
let mouseEvent = document.createEvent('Event');
let hookSpy: Spy, eventListenerSpy: Spy;
const zone = rootZone.fork({
name: 'spy',
onScheduleTask: (parentZoneDelegate: ZoneDelegate, currentZone: Zone,
targetZone: Zone, task: Task): any => {
hookSpy();
return parentZoneDelegate.scheduleTask(targetZone, task);
}
});

beforeEach(function() {
mouseEvent.initEvent('mousedown', true, true);
hookSpy = jasmine.createSpy('hook');
eventListenerSpy = jasmine.createSpy('eventListener');
});

it('window onclick should be in zone',
ifEnvSupports(
() => {
return canPatchOnProperty(window, 'onmousedown');
},
function() {
zone.run(function() {
window.onmousedown = eventListenerSpy;
});

window.dispatchEvent(mouseEvent);

expect(hookSpy).toHaveBeenCalled();
expect(eventListenerSpy).toHaveBeenCalled();
window.removeEventListener('mousedown', eventListenerSpy);
}));

it('document onclick should be in zone',
ifEnvSupports(
() => {
return canPatchOnProperty(Document.prototype, 'onmousedown');
},
function() {
zone.run(function() {
document.onmousedown = eventListenerSpy;
});

document.dispatchEvent(mouseEvent);

expect(hookSpy).toHaveBeenCalled();
expect(eventListenerSpy).toHaveBeenCalled();
document.removeEventListener('mousedown', eventListenerSpy);
}));

it('SVGElement onclick should be in zone',
ifEnvSupports(
() => {
return typeof SVGElement !== 'undefined' &&
canPatchOnProperty(SVGElement.prototype, 'onmousedown');
},
function() {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
document.body.appendChild(svg);
zone.run(function() {
svg.onmousedown = eventListenerSpy;
});

svg.dispatchEvent(mouseEvent);

expect(hookSpy).toHaveBeenCalled();
expect(eventListenerSpy).toHaveBeenCalled();
svg.removeEventListener('mouse', eventListenerSpy);
document.body.removeChild(svg);
}));

it('get window onerror should not throw error',
ifEnvSupports(
() => {
return canPatchOnProperty(window, 'onerror');
},
function() {
const testFn = function() {
let onerror = window.onerror;
window.onerror = function() {};
onerror = window.onerror;
};
expect(testFn()).not.toThrow();
}));

}));
describe(
'DOM onProperty hooks',
ifEnvSupports(
() => {
return canPatchOnProperty(HTMLElement.prototype, 'onclick');
},
function() {
let mouseEvent = document.createEvent('Event');
let hookSpy: Spy, eventListenerSpy: Spy;
const zone = rootZone.fork({
name: 'spy',
onScheduleTask: (parentZoneDelegate: ZoneDelegate, currentZone: Zone,
targetZone: Zone, task: Task): any => {
hookSpy();
return parentZoneDelegate.scheduleTask(targetZone, task);
}
});

beforeEach(function() {
mouseEvent.initEvent('mousedown', true, true);
hookSpy = jasmine.createSpy('hook');
eventListenerSpy = jasmine.createSpy('eventListener');
});

it('window onclick should be in zone',
ifEnvSupports(
() => {
return canPatchOnProperty(window, 'onmousedown');
},
function() {
zone.run(function() {
window.onmousedown = eventListenerSpy;
});

window.dispatchEvent(mouseEvent);

expect(hookSpy).toHaveBeenCalled();
expect(eventListenerSpy).toHaveBeenCalled();
window.removeEventListener('mousedown', eventListenerSpy);
}));

it('document onclick should be in zone',
ifEnvSupports(
() => {
return canPatchOnProperty(Document.prototype, 'onmousedown');
},
function() {
zone.run(function() {
document.onmousedown = eventListenerSpy;
});

document.dispatchEvent(mouseEvent);

expect(hookSpy).toHaveBeenCalled();
expect(eventListenerSpy).toHaveBeenCalled();
document.removeEventListener('mousedown', eventListenerSpy);
}));

it('SVGElement onclick should be in zone',
ifEnvSupports(
() => {
return typeof SVGElement !== 'undefined' &&
canPatchOnProperty(SVGElement.prototype, 'onmousedown');
},
function() {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
document.body.appendChild(svg);
zone.run(function() {
svg.onmousedown = eventListenerSpy;
});

svg.dispatchEvent(mouseEvent);

expect(hookSpy).toHaveBeenCalled();
expect(eventListenerSpy).toHaveBeenCalled();
svg.removeEventListener('mouse', eventListenerSpy);
document.body.removeChild(svg);
}));

it('get window onerror should not throw error',
ifEnvSupports(
() => {
return canPatchOnProperty(window, 'onerror');
},
function() {
const testFn = function() {
let onerror = window.onerror;
window.onerror = function() {};
onerror = window.onerror;
};
expect(testFn).not.toThrow();
}));

}));

describe('eventListener hooks', function() {
let button: HTMLButtonElement;
Expand Down