cypress 12.1.0 → 12.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/angular/dist/index.js +1 -1
- package/index.js +2 -11
- package/lib/VerboseRenderer.js +2 -16
- package/lib/cli.js +25 -83
- package/lib/cypress.js +1 -14
- package/lib/errors.js +13 -38
- package/lib/exec/info.js +10 -31
- package/lib/exec/open.js +1 -24
- package/lib/exec/run.js +15 -52
- package/lib/exec/shared.js +6 -15
- package/lib/exec/spawn.js +45 -88
- package/lib/exec/versions.js +0 -9
- package/lib/exec/xvfb.js +5 -18
- package/lib/fs.js +0 -1
- package/lib/logger.js +3 -10
- package/lib/tasks/cache.js +5 -29
- package/lib/tasks/download.js +21 -57
- package/lib/tasks/get-folder-size.js +1 -9
- package/lib/tasks/install.js +20 -66
- package/lib/tasks/state.js +5 -51
- package/lib/tasks/unzip.js +7 -41
- package/lib/tasks/verify.js +11 -65
- package/lib/util.js +41 -128
- package/mount-utils/package.json +2 -2
- package/package.json +3 -3
- package/react/dist/cypress-react.cjs.js +8 -15
- package/react/dist/cypress-react.esm-bundler.js +1 -1
- package/react/package.json +1 -1
- package/react18/dist/cypress-react.cjs.js +7 -13
- package/react18/dist/cypress-react.esm-bundler.js +1 -1
- package/react18/package.json +1 -1
- package/svelte/dist/cypress-svelte.cjs.js +2 -4
- package/svelte/dist/cypress-svelte.esm-bundler.js +2 -2
- package/types/cypress.d.ts +11 -6
- package/types/net-stubbing.d.ts +11 -0
- package/vue/dist/cypress-vue.cjs.js +4 -7
- package/vue/dist/cypress-vue.esm-bundler.js +1 -1
- package/vue/package.json +1 -1
- package/vue2/dist/cypress-vue2.cjs.js +19 -28
- package/vue2/dist/cypress-vue2.esm-bundler.js +1 -4
@@ -1,22 +1,17 @@
|
|
1
1
|
|
2
2
|
/**
|
3
3
|
* @cypress/react18 v0.0.0-development
|
4
|
-
* (c)
|
4
|
+
* (c) 2023 Cypress.io
|
5
5
|
* Released under the MIT License
|
6
6
|
*/
|
7
7
|
|
8
8
|
'use strict';
|
9
9
|
|
10
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
11
|
-
|
12
10
|
var ReactDOM = require('react-dom/client');
|
13
11
|
var React = require('react');
|
14
12
|
require('react-dom');
|
15
13
|
|
16
|
-
function
|
17
|
-
|
18
|
-
function _interopNamespace(e) {
|
19
|
-
if (e && e.__esModule) return e;
|
14
|
+
function _interopNamespaceDefault(e) {
|
20
15
|
var n = Object.create(null);
|
21
16
|
if (e) {
|
22
17
|
Object.keys(e).forEach(function (k) {
|
@@ -29,12 +24,11 @@ function _interopNamespace(e) {
|
|
29
24
|
}
|
30
25
|
});
|
31
26
|
}
|
32
|
-
n
|
27
|
+
n.default = e;
|
33
28
|
return Object.freeze(n);
|
34
29
|
}
|
35
30
|
|
36
|
-
var
|
37
|
-
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
31
|
+
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
38
32
|
|
39
33
|
const ROOT_SELECTOR$1 = '[data-cy-root]';
|
40
34
|
/**
|
@@ -521,17 +515,17 @@ function mount(jsx, options = {}, rerenderKey) {
|
|
521
515
|
// to wipe away any state
|
522
516
|
cleanup();
|
523
517
|
const internalOptions = {
|
524
|
-
reactDom:
|
518
|
+
reactDom: ReactDOM,
|
525
519
|
render: (reactComponent, el) => {
|
526
520
|
if (!root) {
|
527
|
-
root =
|
521
|
+
root = ReactDOM.createRoot(el);
|
528
522
|
}
|
529
523
|
return root.render(reactComponent);
|
530
524
|
},
|
531
525
|
unmount: internalUnmount,
|
532
526
|
cleanup,
|
533
527
|
};
|
534
|
-
return makeMountFn('mount', jsx, Object.assign({ ReactDom:
|
528
|
+
return makeMountFn('mount', jsx, Object.assign({ ReactDom: ReactDOM }, options), rerenderKey, internalOptions);
|
535
529
|
}
|
536
530
|
function internalUnmount(options = { log: true }) {
|
537
531
|
return makeUnmountFn(options);
|
package/react18/package.json
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
|
2
2
|
/**
|
3
3
|
* @cypress/svelte v0.0.0-development
|
4
|
-
* (c)
|
4
|
+
* (c) 2023 Cypress.io
|
5
5
|
* Released under the MIT License
|
6
6
|
*/
|
7
7
|
|
8
8
|
'use strict';
|
9
9
|
|
10
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
11
|
-
|
12
10
|
const ROOT_SELECTOR = '[data-cy-root]';
|
13
11
|
/**
|
14
12
|
* Gets the root element used to mount the component.
|
@@ -66,7 +64,7 @@ const cleanup = () => {
|
|
66
64
|
// Extract the component name from the object passed to mount
|
67
65
|
const getComponentDisplayName = (Component) => {
|
68
66
|
if (Component.name) {
|
69
|
-
const [
|
67
|
+
const [, match] = /Proxy\<(\w+)\>/.exec(Component.name) || [];
|
70
68
|
return match || Component.name;
|
71
69
|
}
|
72
70
|
return DEFAULT_COMP_NAME;
|
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
/**
|
3
3
|
* @cypress/svelte v0.0.0-development
|
4
|
-
* (c)
|
4
|
+
* (c) 2023 Cypress.io
|
5
5
|
* Released under the MIT License
|
6
6
|
*/
|
7
7
|
|
@@ -62,7 +62,7 @@ const cleanup = () => {
|
|
62
62
|
// Extract the component name from the object passed to mount
|
63
63
|
const getComponentDisplayName = (Component) => {
|
64
64
|
if (Component.name) {
|
65
|
-
const [
|
65
|
+
const [, match] = /Proxy\<(\w+)\>/.exec(Component.name) || [];
|
66
66
|
return match || Component.name;
|
67
67
|
}
|
68
68
|
return DEFAULT_COMP_NAME;
|
package/types/cypress.d.ts
CHANGED
@@ -420,6 +420,11 @@ declare namespace Cypress {
|
|
420
420
|
titlePath: string[]
|
421
421
|
}
|
422
422
|
|
423
|
+
/**
|
424
|
+
* Information about current test retry
|
425
|
+
*/
|
426
|
+
currentRetry: number
|
427
|
+
|
423
428
|
/**
|
424
429
|
* Information about the browser currently running the tests
|
425
430
|
*/
|
@@ -1589,19 +1594,19 @@ declare namespace Cypress {
|
|
1589
1594
|
*
|
1590
1595
|
* @see https://on.cypress.io/nextuntil
|
1591
1596
|
*/
|
1592
|
-
nextUntil<K extends keyof HTMLElementTagNameMap>(selector: K, options?: Partial<Loggable & Timeoutable>): Chainable<JQuery<HTMLElementTagNameMap[K]>>
|
1597
|
+
nextUntil<K extends keyof HTMLElementTagNameMap>(selector: K, filter?: string, options?: Partial<Loggable & Timeoutable>): Chainable<JQuery<HTMLElementTagNameMap[K]>>
|
1593
1598
|
/**
|
1594
1599
|
* Get all following siblings of each DOM element in a set of matched DOM elements up to, but not including, the element provided.
|
1595
1600
|
*
|
1596
1601
|
* @see https://on.cypress.io/nextuntil
|
1597
1602
|
*/
|
1598
|
-
nextUntil<E extends
|
1603
|
+
nextUntil<E extends Node = HTMLElement>(selector: string, filter?: string, options?: Partial<Loggable & Timeoutable>): Chainable<JQuery<E>>
|
1599
1604
|
/**
|
1600
1605
|
* Get all following siblings of each DOM element in a set of matched DOM elements up to, but not including, the element provided.
|
1601
1606
|
*
|
1602
1607
|
* @see https://on.cypress.io/nextuntil
|
1603
1608
|
*/
|
1604
|
-
nextUntil<E extends
|
1609
|
+
nextUntil<E extends Node = HTMLElement>(element: E | JQuery<E>, filter?: string, options?: Partial<Loggable & Timeoutable>): Chainable<JQuery<E>>
|
1605
1610
|
|
1606
1611
|
/**
|
1607
1612
|
* Filter DOM element(s) from a set of DOM elements. Opposite of `.filter()`
|
@@ -1774,21 +1779,21 @@ declare namespace Cypress {
|
|
1774
1779
|
* Get all previous siblings of each DOM element in a set of matched DOM elements up to, but not including, the element provided.
|
1775
1780
|
* > The querying behavior of this command matches exactly how [.prevUntil()](http://api.jquery.com/prevUntil) works in jQuery.
|
1776
1781
|
*
|
1777
|
-
* @see https://on.cypress.io/
|
1782
|
+
* @see https://on.cypress.io/prevuntil
|
1778
1783
|
*/
|
1779
1784
|
prevUntil<K extends keyof HTMLElementTagNameMap>(selector: K, filter?: string, options?: Partial<Loggable & Timeoutable>): Chainable<JQuery<HTMLElementTagNameMap[K]>>
|
1780
1785
|
/**
|
1781
1786
|
* Get all previous siblings of each DOM element in a set of matched DOM elements up to, but not including, the element provided.
|
1782
1787
|
* > The querying behavior of this command matches exactly how [.prevUntil()](http://api.jquery.com/prevUntil) works in jQuery.
|
1783
1788
|
*
|
1784
|
-
* @see https://on.cypress.io/
|
1789
|
+
* @see https://on.cypress.io/prevuntil
|
1785
1790
|
*/
|
1786
1791
|
prevUntil<E extends Node = HTMLElement>(selector: string, filter?: string, options?: Partial<Loggable & Timeoutable>): Chainable<JQuery<E>>
|
1787
1792
|
/**
|
1788
1793
|
* Get all previous siblings of each DOM element in a set of matched DOM elements up to, but not including, the element provided.
|
1789
1794
|
* > The querying behavior of this command matches exactly how [.prevUntil()](http://api.jquery.com/prevUntil) works in jQuery.
|
1790
1795
|
*
|
1791
|
-
* @see https://on.cypress.io/
|
1796
|
+
* @see https://on.cypress.io/prevuntil
|
1792
1797
|
*/
|
1793
1798
|
prevUntil<E extends Node = HTMLElement>(element: E | JQuery<E>, filter?: string, options?: Partial<Loggable & Timeoutable>): Chainable<JQuery<E>>
|
1794
1799
|
|
package/types/net-stubbing.d.ts
CHANGED
@@ -68,6 +68,9 @@ type Method =
|
|
68
68
|
| 'unlink'
|
69
69
|
| 'unlock'
|
70
70
|
| 'unsubscribe'
|
71
|
+
|
72
|
+
export type ResourceType = 'document' | 'fetch' | 'xhr' | 'websocket' | 'stylesheet' | 'script' | 'image' | 'font' | 'cspviolationreport' | 'ping' | 'manifest' | 'other'
|
73
|
+
|
71
74
|
export namespace CyHttpMessages {
|
72
75
|
export interface BaseMessage {
|
73
76
|
/**
|
@@ -139,6 +142,10 @@ export namespace CyHttpMessages {
|
|
139
142
|
* The HTTP version used in the request. Read only.
|
140
143
|
*/
|
141
144
|
httpVersion: string
|
145
|
+
/**
|
146
|
+
* The resource type that is being requested, according to the browser.
|
147
|
+
*/
|
148
|
+
resourceType: ResourceType
|
142
149
|
/**
|
143
150
|
* If provided, the number of milliseconds before an upstream response to this request
|
144
151
|
* will time out and cause an error. By default, `responseTimeout` from config is used.
|
@@ -370,6 +377,10 @@ export interface RouteMatcherOptionsGeneric<S> {
|
|
370
377
|
* Match on parsed querystring parameters.
|
371
378
|
*/
|
372
379
|
query?: DictMatcher<S>
|
380
|
+
/**
|
381
|
+
* Match on the request's resource type, according to the browser.
|
382
|
+
*/
|
383
|
+
resourceType?: ResourceType | S
|
373
384
|
/**
|
374
385
|
* If set, this `RouteMatcher` will only match the first `times` requests.
|
375
386
|
*/
|
@@ -1,18 +1,15 @@
|
|
1
1
|
|
2
2
|
/**
|
3
3
|
* @cypress/vue v0.0.0-development
|
4
|
-
* (c)
|
4
|
+
* (c) 2023 Cypress.io
|
5
5
|
* Released under the MIT License
|
6
6
|
*/
|
7
7
|
|
8
8
|
'use strict';
|
9
9
|
|
10
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
11
|
-
|
12
10
|
var Vue = require('vue');
|
13
11
|
|
14
|
-
function
|
15
|
-
if (e && e.__esModule) return e;
|
12
|
+
function _interopNamespaceDefault(e) {
|
16
13
|
var n = Object.create(null);
|
17
14
|
if (e) {
|
18
15
|
Object.keys(e).forEach(function (k) {
|
@@ -25,11 +22,11 @@ function _interopNamespace(e) {
|
|
25
22
|
}
|
26
23
|
});
|
27
24
|
}
|
28
|
-
n
|
25
|
+
n.default = e;
|
29
26
|
return Object.freeze(n);
|
30
27
|
}
|
31
28
|
|
32
|
-
var Vue__namespace = /*#__PURE__*/
|
29
|
+
var Vue__namespace = /*#__PURE__*/_interopNamespaceDefault(Vue);
|
33
30
|
|
34
31
|
/******************************************************************************
|
35
32
|
Copyright (c) Microsoft Corporation.
|
package/vue/package.json
CHANGED
@@ -1,20 +1,14 @@
|
|
1
1
|
|
2
2
|
/**
|
3
3
|
* @cypress/vue2 v0.0.0-development
|
4
|
-
* (c)
|
4
|
+
* (c) 2023 Cypress.io
|
5
5
|
* Released under the MIT License
|
6
6
|
*/
|
7
7
|
|
8
8
|
'use strict';
|
9
9
|
|
10
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
11
|
-
|
12
10
|
var Vue = require('vue');
|
13
11
|
|
14
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
15
|
-
|
16
|
-
var Vue__default = /*#__PURE__*/_interopDefaultLegacy(Vue);
|
17
|
-
|
18
12
|
var commonjsGlobal$1 = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
19
13
|
|
20
14
|
function createCommonjsModule$1(fn) {
|
@@ -1076,9 +1070,6 @@ var isIE = UA$1 && /msie|trident/.test(UA$1);
|
|
1076
1070
|
UA$1 && UA$1.indexOf('msie 9.0') > 0;
|
1077
1071
|
var isEdge$1 = UA$1 && UA$1.indexOf('edge/') > 0;
|
1078
1072
|
(UA$1 && UA$1.indexOf('android') > 0) || (weexPlatform === 'android');
|
1079
|
-
(UA$1 && /iphone|ipad|ipod|ios/.test(UA$1)) || (weexPlatform === 'ios');
|
1080
|
-
UA$1 && /chrome\/\d+/.test(UA$1) && !isEdge$1;
|
1081
|
-
UA$1 && /phantomjs/.test(UA$1);
|
1082
1073
|
UA$1 && UA$1.match(/firefox\/(\d+)/);
|
1083
1074
|
|
1084
1075
|
// Firefox has a "watch" function on Object.prototype...
|
@@ -5737,7 +5728,7 @@ var build = /*#__PURE__*/Object.defineProperty({
|
|
5737
5728
|
}, '__esModule', {value: true});
|
5738
5729
|
|
5739
5730
|
try {
|
5740
|
-
var vueVersion =
|
5731
|
+
var vueVersion = Vue.version;
|
5741
5732
|
} catch (e) {}
|
5742
5733
|
|
5743
5734
|
var vueTemplateCompiler = build;
|
@@ -7413,17 +7404,17 @@ var DOM_SELECTOR = 'DOM_SELECTOR';
|
|
7413
7404
|
var INVALID_SELECTOR = 'INVALID_SELECTOR';
|
7414
7405
|
|
7415
7406
|
var VUE_VERSION = Number(
|
7416
|
-
((
|
7407
|
+
((Vue.version.split('.')[0]) + "." + (Vue.version.split('.')[1]))
|
7417
7408
|
);
|
7418
7409
|
|
7419
7410
|
var FUNCTIONAL_OPTIONS =
|
7420
7411
|
VUE_VERSION >= 2.5 ? 'fnOptions' : 'functionalOptions';
|
7421
7412
|
|
7422
|
-
var BEFORE_RENDER_LIFECYCLE_HOOK = semver.gt(
|
7413
|
+
var BEFORE_RENDER_LIFECYCLE_HOOK = semver.gt(Vue.version, '2.1.8')
|
7423
7414
|
? 'beforeCreate'
|
7424
7415
|
: 'beforeMount';
|
7425
7416
|
|
7426
|
-
var CREATE_ELEMENT_ALIAS = semver.gt(
|
7417
|
+
var CREATE_ELEMENT_ALIAS = semver.gt(Vue.version, '2.1.5')
|
7427
7418
|
? '_c'
|
7428
7419
|
: '_h';
|
7429
7420
|
|
@@ -7497,7 +7488,7 @@ var isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge;
|
|
7497
7488
|
|
7498
7489
|
// get the event used to trigger v-model handler that updates bound data
|
7499
7490
|
function getCheckedEvent() {
|
7500
|
-
var version =
|
7491
|
+
var version = Vue.version;
|
7501
7492
|
|
7502
7493
|
if (semver.satisfies(version, '2.1.9 - 2.1.10')) {
|
7503
7494
|
return 'click'
|
@@ -7517,9 +7508,9 @@ function getCheckedEvent() {
|
|
7517
7508
|
* @return {Promise<R>}
|
7518
7509
|
*/
|
7519
7510
|
function nextTick() {
|
7520
|
-
if (VUE_VERSION > 2) { return
|
7511
|
+
if (VUE_VERSION > 2) { return Vue.nextTick() }
|
7521
7512
|
return new Promise(function (resolve) {
|
7522
|
-
|
7513
|
+
Vue.nextTick(resolve);
|
7523
7514
|
})
|
7524
7515
|
}
|
7525
7516
|
|
@@ -7563,7 +7554,7 @@ function addMocks(
|
|
7563
7554
|
);
|
7564
7555
|
}
|
7565
7556
|
// $FlowIgnore
|
7566
|
-
|
7557
|
+
Vue.util.defineReactive(_Vue, key, mockedProperties[key]);
|
7567
7558
|
});
|
7568
7559
|
}
|
7569
7560
|
|
@@ -8064,8 +8055,8 @@ function createStubFromComponent(
|
|
8064
8055
|
var tagName = (name || 'anonymous') + "-stub";
|
8065
8056
|
|
8066
8057
|
// ignoreElements does not exist in Vue 2.0.x
|
8067
|
-
if (
|
8068
|
-
|
8058
|
+
if (Vue.config.ignoredElements) {
|
8059
|
+
Vue.config.ignoredElements.push(tagName);
|
8069
8060
|
}
|
8070
8061
|
|
8071
8062
|
return Object.assign({}, getCoreProperties(componentOptions),
|
@@ -17080,7 +17071,7 @@ function createWrapper(
|
|
17080
17071
|
return wrapper$1
|
17081
17072
|
}
|
17082
17073
|
var wrapper =
|
17083
|
-
node instanceof
|
17074
|
+
node instanceof Vue
|
17084
17075
|
? new VueWrapper(node, options)
|
17085
17076
|
: new Wrapper(node, options);
|
17086
17077
|
return wrapper
|
@@ -19581,7 +19572,7 @@ function _createLocalVue(
|
|
19581
19572
|
_Vue,
|
19582
19573
|
config
|
19583
19574
|
) {
|
19584
|
-
if ( _Vue === void 0 ) _Vue =
|
19575
|
+
if ( _Vue === void 0 ) _Vue = Vue;
|
19585
19576
|
if ( config === void 0 ) config = {};
|
19586
19577
|
|
19587
19578
|
var instance = _Vue.extend();
|
@@ -19603,14 +19594,14 @@ function _createLocalVue(
|
|
19603
19594
|
});
|
19604
19595
|
|
19605
19596
|
// config is not enumerable
|
19606
|
-
instance.config = cloneDeep_1(
|
19597
|
+
instance.config = cloneDeep_1(Vue.config);
|
19607
19598
|
|
19608
19599
|
// if a user defined errorHandler is defined by a localVue instance via createLocalVue, register it
|
19609
19600
|
instance.config.errorHandler = config.errorHandler;
|
19610
19601
|
|
19611
19602
|
// option merge strategies need to be exposed by reference
|
19612
19603
|
// so that merge strats registered by plugins can work properly
|
19613
|
-
instance.config.optionMergeStrategies =
|
19604
|
+
instance.config.optionMergeStrategies = Vue.config.optionMergeStrategies;
|
19614
19605
|
|
19615
19606
|
// make sure all extends are based on this instance.
|
19616
19607
|
// this is important so that global components registered by plugins,
|
@@ -19731,8 +19722,8 @@ function validateOptions(options, component) {
|
|
19731
19722
|
}
|
19732
19723
|
}
|
19733
19724
|
|
19734
|
-
|
19735
|
-
|
19725
|
+
Vue.config.productionTip = false;
|
19726
|
+
Vue.config.devtools = false;
|
19736
19727
|
|
19737
19728
|
function mount$1(component, options) {
|
19738
19729
|
if ( options === void 0 ) options = {};
|
@@ -19741,7 +19732,7 @@ function mount$1(component, options) {
|
|
19741
19732
|
|
19742
19733
|
polyfill();
|
19743
19734
|
|
19744
|
-
addGlobalErrorHandler(
|
19735
|
+
addGlobalErrorHandler(Vue);
|
19745
19736
|
|
19746
19737
|
var _Vue = _createLocalVue(
|
19747
19738
|
options.localVue,
|
@@ -20016,7 +20007,7 @@ const mount = (component, optionsOrProps = {}) => {
|
|
20016
20007
|
})
|
20017
20008
|
.then(() => {
|
20018
20009
|
if (optionsOrProps.log !== false) {
|
20019
|
-
return
|
20010
|
+
return Vue.nextTick(() => {
|
20020
20011
|
Cypress.log({
|
20021
20012
|
name: 'mount',
|
20022
20013
|
message: [message],
|
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
/**
|
3
3
|
* @cypress/vue2 v0.0.0-development
|
4
|
-
* (c)
|
4
|
+
* (c) 2023 Cypress.io
|
5
5
|
* Released under the MIT License
|
6
6
|
*/
|
7
7
|
|
@@ -1068,9 +1068,6 @@ var isIE = UA$1 && /msie|trident/.test(UA$1);
|
|
1068
1068
|
UA$1 && UA$1.indexOf('msie 9.0') > 0;
|
1069
1069
|
var isEdge$1 = UA$1 && UA$1.indexOf('edge/') > 0;
|
1070
1070
|
(UA$1 && UA$1.indexOf('android') > 0) || (weexPlatform === 'android');
|
1071
|
-
(UA$1 && /iphone|ipad|ipod|ios/.test(UA$1)) || (weexPlatform === 'ios');
|
1072
|
-
UA$1 && /chrome\/\d+/.test(UA$1) && !isEdge$1;
|
1073
|
-
UA$1 && /phantomjs/.test(UA$1);
|
1074
1071
|
UA$1 && UA$1.match(/firefox\/(\d+)/);
|
1075
1072
|
|
1076
1073
|
// Firefox has a "watch" function on Object.prototype...
|