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

Commit 427705f

Browse files
JiaLiPassionmhevery
authored andcommitted
feat(custom-element): patch customElement v1 APIs (#1133)
1 parent 60adc9c commit 427705f

11 files changed

+239
-15
lines changed

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,5 @@ script:
5454
- node_modules/.bin/karma start karma-build-sauce-selenium3-mocha.conf.js --single-run
5555
- node_modules/.bin/gulp test/node
5656
- node_modules/.bin/gulp test/node -no-patch-clock
57+
- cp ./test/browser/custom-element.spec.js ./build/test/browser
58+
- node_modules/.bin/karma start karma-dist-sauce-jasmine.es6.conf.js --single-run

file-size-limit.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{
44
"path": "dist/zone.min.js",
55
"checkTarget": true,
6-
"limit": 42050
6+
"limit": 42500
77
}
88
]
9-
}
9+
}

karma-build-jasmine.es6.conf.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
module.exports = function (config) {
3+
require('./karma-build-jasmine.conf.js')(config);
4+
config.client.entrypoint = 'browser_es6_entry_point';
5+
};

karma-dist-sauce-jasmine.es6.conf.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
module.exports = function (config) {
3+
require('./karma-dist-jasmine.conf.js')(config);
4+
require('./sauce.es6.conf')(config);
5+
config.client.entrypoint = 'browser_es6_entry_point';
6+
};

lib/browser/browser.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {bindArguments, patchClass, patchMacroTask, patchMethod, patchOnPropertie
1717
import {propertyPatch} from './define-property';
1818
import {eventTargetPatch, patchEvent} from './event-target';
1919
import {propertyDescriptorPatch} from './property-descriptor';
20-
import {registerElementPatch} from './register-element';
20+
import {patchCustomElements, registerElementPatch} from './register-element';
2121

2222
Zone.__load_patch('util', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
2323
api.patchOnProperties = patchOnProperties;
@@ -74,7 +74,11 @@ Zone.__load_patch('EventTarget', (global: any, Zone: ZoneType, api: _ZonePrivate
7474
Zone.__load_patch('on_property', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
7575
propertyDescriptorPatch(api, global);
7676
propertyPatch();
77+
});
78+
79+
Zone.__load_patch('customElements', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
7780
registerElementPatch(global);
81+
patchCustomElements(global);
7882
});
7983

8084
Zone.__load_patch('canvas', (global: any) => {

lib/browser/register-element.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,16 @@ import {attachOriginToPatched, isBrowser, isMix, ObjectGetOwnPropertyDescriptor,
1010

1111
import {_redefineProperty} from './define-property';
1212

13-
export function registerElementPatch(_global: any) {
14-
if ((!isBrowser && !isMix) || !('registerElement' in (<any>_global).document)) {
13+
function patchCallbacks(target: any, targetName: string, method: string, callbacks: string[]) {
14+
const symbol = Zone.__symbol__(method);
15+
if (target[symbol]) {
1516
return;
1617
}
17-
18-
const _registerElement = (<any>document).registerElement;
19-
const callbacks =
20-
['createdCallback', 'attachedCallback', 'detachedCallback', 'attributeChangedCallback'];
21-
22-
(<any>document).registerElement = function(name: any, opts: any) {
18+
const nativeDelegate = target[symbol] = target[method];
19+
target[method] = function(name: any, opts: any, options?: any) {
2320
if (opts && opts.prototype) {
2421
callbacks.forEach(function(callback) {
25-
const source = 'Document.registerElement::' + callback;
22+
const source = `${targetName}.${method}::` + callback;
2623
const prototype = opts.prototype;
2724
if (prototype.hasOwnProperty(callback)) {
2825
const descriptor = ObjectGetOwnPropertyDescriptor(prototype, callback);
@@ -38,8 +35,30 @@ export function registerElementPatch(_global: any) {
3835
});
3936
}
4037

41-
return _registerElement.call(document, name, opts);
38+
return nativeDelegate.call(target, name, opts, options);
4239
};
4340

44-
attachOriginToPatched((<any>document).registerElement, _registerElement);
41+
attachOriginToPatched(target[method], nativeDelegate);
42+
}
43+
44+
export function registerElementPatch(_global: any) {
45+
if ((!isBrowser && !isMix) || !('registerElement' in (<any>_global).document)) {
46+
return;
47+
}
48+
49+
const callbacks =
50+
['createdCallback', 'attachedCallback', 'detachedCallback', 'attributeChangedCallback'];
51+
52+
patchCallbacks(document, 'Document', 'registerElement', callbacks);
53+
}
54+
55+
export function patchCustomElements(_global: any) {
56+
if ((!isBrowser && !isMix) || !('customElements' in _global)) {
57+
return;
58+
}
59+
60+
const callbacks =
61+
['connectedCallback', 'disconnectedCallback', 'adoptedCallback', 'attributeChangedCallback'];
62+
63+
patchCallbacks(_global.customElements, 'customElements', 'define', callbacks);
4564
}

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"closure:test": "scripts/closure/closure_compiler.sh",
2121
"format": "gulp format:enforce",
2222
"karma-jasmine": "karma start karma-build-jasmine.conf.js",
23+
"karma-jasmine:es6": "karma start karma-build-jasmine.es6.conf.js",
2324
"karma-jasmine:phantomjs": "karma start karma-build-jasmine-phantomjs.conf.js --single-run",
2425
"karma-jasmine:single": "karma start karma-build-jasmine.conf.js --single-run",
2526
"karma-jasmine:autoclose": "npm run karma-jasmine:single && npm run ws-client",
@@ -38,6 +39,7 @@
3839
"tsc:w": "tsc -w -p .",
3940
"tslint": "tslint -c tslint.json 'lib/**/*.ts'",
4041
"test": "npm run tsc && concurrently \"npm run tsc:w\" \"npm run ws-server\" \"npm run karma-jasmine\"",
42+
"test:es6": "npm run tsc && concurrently \"npm run tsc:w\" \"npm run ws-server\" \"npm run karma-jasmine:es6\"",
4143
"test:phantomjs": "npm run tsc && concurrently \"npm run tsc:w\" \"npm run ws-server\" \"npm run karma-jasmine:phantomjs\"",
4244
"test:phantomjs-single": "npm run tsc && concurrently \"npm run ws-server\" \"npm run karma-jasmine-phantomjs:autoclose\"",
4345
"test:single": "npm run tsc && concurrently \"npm run ws-server\" \"npm run karma-jasmine:autoclose\"",

sauce.es6.conf.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Sauce configuration
2+
3+
module.exports = function(config, ignoredLaunchers) {
4+
// The WS server is not available with Sauce
5+
config.files.unshift('test/saucelabs.js');
6+
7+
var basicLaunchers = {
8+
'SL_CHROME_66': {base: 'SauceLabs', browserName: 'chrome', version: '66'},
9+
};
10+
11+
var customLaunchers = {};
12+
if (!ignoredLaunchers) {
13+
customLaunchers = basicLaunchers;
14+
} else {
15+
Object.keys(basicLaunchers).forEach(function(key) {
16+
if (ignoredLaunchers
17+
.filter(function(ignore) {
18+
return ignore === key;
19+
})
20+
.length === 0) {
21+
customLaunchers[key] = basicLaunchers[key];
22+
}
23+
});
24+
}
25+
26+
config.set({
27+
captureTimeout: 120000,
28+
browserNoActivityTimeout: 240000,
29+
30+
sauceLabs: {
31+
testName: 'Zone.js',
32+
startConnect: false,
33+
recordVideo: false,
34+
recordScreenshots: false,
35+
options: {
36+
'selenium-version': '2.53.0',
37+
'command-timeout': 600,
38+
'idle-timeout': 600,
39+
'max-duration': 5400
40+
}
41+
},
42+
43+
customLaunchers: customLaunchers,
44+
45+
browsers: Object.keys(customLaunchers),
46+
47+
reporters: ['dots', 'saucelabs'],
48+
49+
singleRun: true,
50+
51+
plugins: ['karma-*']
52+
});
53+
54+
if (process.env.TRAVIS) {
55+
config.sauceLabs.build =
56+
'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
57+
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
58+
59+
process.env.SAUCE_ACCESS_KEY = process.env.SAUCE_ACCESS_KEY.split('').reverse().join('');
60+
}
61+
};

test/browser/custom-element.spec.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
/*
10+
* check that document.registerElement(name, { prototype: proto });
11+
* is properly patched
12+
*/
13+
14+
function customElementsSupport() {
15+
return 'registerElement' in document;
16+
}
17+
customElementsSupport.message = 'window.customElements';
18+
19+
describe('customElements', function() {
20+
const testZone = Zone.current.fork({ name: 'test' });
21+
const bridge = {
22+
connectedCallback: () => {},
23+
disconnectedCallback: () => {},
24+
adoptedCallback: () => {},
25+
attributeChangedCallback: () => {}
26+
};
27+
28+
class TestCustomElement extends HTMLElement {
29+
constructor() {
30+
super();
31+
}
32+
33+
static get observedAttributes() {
34+
return ['attr1', 'attr2'];
35+
}
36+
37+
connectedCallback() {
38+
return bridge.connectedCallback();
39+
}
40+
41+
disconnectedCallback() {
42+
return bridge.disconnectedCallback();
43+
}
44+
45+
attributeChangedCallback(attrName, oldVal, newVal) {
46+
return bridge.attributeChangedCallback(attrName, oldVal, newVal);
47+
}
48+
49+
adoptedCallback() {
50+
return bridge.adoptedCallback();
51+
}
52+
}
53+
54+
testZone.run(() => {
55+
customElements.define('x-test', TestCustomElement);
56+
});
57+
58+
let elt;
59+
60+
beforeEach(() => {
61+
bridge.connectedCallback = () => {};
62+
bridge.disconnectedCallback = () => {};
63+
bridge.attributeChangedCallback = () => {};
64+
bridge.adoptedCallback = () => {};
65+
});
66+
67+
afterEach(() => {
68+
if (elt) {
69+
document.body.removeChild(elt);
70+
elt = null;
71+
}
72+
});
73+
74+
it('should work with connectedCallback', function(done) {
75+
bridge.connectedCallback = function() {
76+
expect(Zone.current.name).toBe(testZone.name);
77+
done();
78+
};
79+
80+
elt = document.createElement('x-test');
81+
document.body.appendChild(elt);
82+
});
83+
84+
it('should work with disconnectedCallback', function(done) {
85+
bridge.disconnectedCallback = function() {
86+
expect(Zone.current.name).toBe(testZone.name);
87+
done();
88+
};
89+
90+
elt = document.createElement('x-test');
91+
document.body.appendChild(elt);
92+
document.body.removeChild(elt);
93+
elt = null;
94+
});
95+
96+
it('should work with attributeChanged', function(done) {
97+
bridge.attributeChangedCallback = function(attrName, oldVal, newVal) {
98+
expect(Zone.current.name).toBe(testZone.name);
99+
expect(attrName).toEqual('attr1');
100+
expect(newVal).toEqual('value1');
101+
done();
102+
};
103+
104+
elt = document.createElement('x-test');
105+
document.body.appendChild(elt);
106+
elt.setAttribute('attr1', 'value1');
107+
});
108+
});

test/browser_es6_entry_point.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import './browser/custom-element.spec';

test/main.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,19 @@ declare const __karma__: {
1414

1515
__karma__.loaded = function() {};
1616

17+
let entryPoint = 'browser_entry_point';
18+
1719
if (typeof __karma__ !== 'undefined') {
1820
(window as any)['__Zone_Error_BlacklistedStackFrames_policy'] =
1921
(__karma__ as any).config.errorpolicy;
22+
if ((__karma__ as any).config.entrypoint) {
23+
entryPoint = (__karma__ as any).config.entrypoint;
24+
}
2025
} else if (typeof process !== 'undefined') {
2126
(window as any)['__Zone_Error_BlacklistedStackFrames_policy'] = process.env.errorpolicy;
27+
if (process.env.entrypoint) {
28+
entryPoint = process.env.entrypoint;
29+
}
2230
}
2331

2432
(window as any).global = window;
@@ -54,7 +62,7 @@ browserPatchedPromise.then(() => {
5462
// Setup test environment
5563
System.import(testFrameworkPatch).then(() => {
5664
System.import('/base/build/lib/common/error-rewrite').then(() => {
57-
System.import('/base/build/test/browser_entry_point')
65+
System.import(`/base/build/test/${entryPoint}`)
5866
.then(
5967
() => {
6068
__karma__.start();

0 commit comments

Comments
 (0)