@angular-wave/angular.ts 0.0.1
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/.eslintignore +1 -0
- package/.eslintrc.cjs +29 -0
- package/.github/workflows/playwright.yml +27 -0
- package/CHANGELOG.md +17974 -0
- package/CODE_OF_CONDUCT.md +3 -0
- package/CONTRIBUTING.md +246 -0
- package/DEVELOPERS.md +488 -0
- package/LICENSE +22 -0
- package/Makefile +31 -0
- package/README.md +115 -0
- package/RELEASE.md +98 -0
- package/SECURITY.md +16 -0
- package/TRIAGING.md +135 -0
- package/css/angular.css +22 -0
- package/dist/angular-ts.cjs.js +36843 -0
- package/dist/angular-ts.esm.js +36841 -0
- package/dist/angular-ts.umd.js +36848 -0
- package/dist/build/angular-animate.js +4272 -0
- package/dist/build/angular-aria.js +426 -0
- package/dist/build/angular-message-format.js +1072 -0
- package/dist/build/angular-messages.js +829 -0
- package/dist/build/angular-mocks.js +3757 -0
- package/dist/build/angular-parse-ext.js +1275 -0
- package/dist/build/angular-resource.js +911 -0
- package/dist/build/angular-route.js +1266 -0
- package/dist/build/angular-sanitize.js +891 -0
- package/dist/build/angular-touch.js +368 -0
- package/dist/build/angular.js +36600 -0
- package/e2e/unit.spec.ts +15 -0
- package/images/android-chrome-192x192.png +0 -0
- package/images/android-chrome-512x512.png +0 -0
- package/images/apple-touch-icon.png +0 -0
- package/images/favicon-16x16.png +0 -0
- package/images/favicon-32x32.png +0 -0
- package/images/favicon.ico +0 -0
- package/images/site.webmanifest +1 -0
- package/index.html +104 -0
- package/package.json +47 -0
- package/playwright.config.ts +78 -0
- package/public/circle.html +1 -0
- package/public/my_child_directive.html +1 -0
- package/public/my_directive.html +1 -0
- package/public/my_other_directive.html +1 -0
- package/public/test.html +1 -0
- package/rollup.config.js +31 -0
- package/src/animations/animateCache.js +55 -0
- package/src/animations/animateChildrenDirective.js +105 -0
- package/src/animations/animateCss.js +1139 -0
- package/src/animations/animateCssDriver.js +291 -0
- package/src/animations/animateJs.js +367 -0
- package/src/animations/animateJsDriver.js +67 -0
- package/src/animations/animateQueue.js +851 -0
- package/src/animations/animation.js +506 -0
- package/src/animations/module.js +779 -0
- package/src/animations/ngAnimateSwap.js +119 -0
- package/src/animations/rafScheduler.js +50 -0
- package/src/animations/shared.js +378 -0
- package/src/constants.js +20 -0
- package/src/core/animate.js +845 -0
- package/src/core/animateCss.js +73 -0
- package/src/core/animateRunner.js +195 -0
- package/src/core/attributes.js +199 -0
- package/src/core/cache.js +45 -0
- package/src/core/compile.js +4727 -0
- package/src/core/controller.js +225 -0
- package/src/core/exceptionHandler.js +63 -0
- package/src/core/filter.js +146 -0
- package/src/core/interpolate.js +442 -0
- package/src/core/interval.js +188 -0
- package/src/core/intervalFactory.js +57 -0
- package/src/core/location.js +1086 -0
- package/src/core/parser/parse.js +2562 -0
- package/src/core/parser/parse.md +13 -0
- package/src/core/q.js +746 -0
- package/src/core/rootScope.js +1596 -0
- package/src/core/sanitizeUri.js +85 -0
- package/src/core/sce.js +1161 -0
- package/src/core/taskTrackerFactory.js +125 -0
- package/src/core/timeout.js +121 -0
- package/src/core/urlUtils.js +187 -0
- package/src/core/utils.js +1349 -0
- package/src/directive/a.js +37 -0
- package/src/directive/attrs.js +283 -0
- package/src/directive/bind.js +51 -0
- package/src/directive/bind.md +142 -0
- package/src/directive/change.js +12 -0
- package/src/directive/change.md +25 -0
- package/src/directive/cloak.js +12 -0
- package/src/directive/cloak.md +24 -0
- package/src/directive/events.js +75 -0
- package/src/directive/events.md +166 -0
- package/src/directive/form.js +725 -0
- package/src/directive/init.js +15 -0
- package/src/directive/init.md +41 -0
- package/src/directive/input.js +1783 -0
- package/src/directive/list.js +46 -0
- package/src/directive/list.md +22 -0
- package/src/directive/ngClass.js +249 -0
- package/src/directive/ngController.js +64 -0
- package/src/directive/ngCsp.js +82 -0
- package/src/directive/ngIf.js +134 -0
- package/src/directive/ngInclude.js +217 -0
- package/src/directive/ngModel.js +1356 -0
- package/src/directive/ngModelOptions.js +509 -0
- package/src/directive/ngOptions.js +670 -0
- package/src/directive/ngRef.js +90 -0
- package/src/directive/ngRepeat.js +650 -0
- package/src/directive/ngShowHide.js +255 -0
- package/src/directive/ngSwitch.js +178 -0
- package/src/directive/ngTransclude.js +98 -0
- package/src/directive/non-bindable.js +11 -0
- package/src/directive/non-bindable.md +17 -0
- package/src/directive/script.js +30 -0
- package/src/directive/select.js +624 -0
- package/src/directive/style.js +25 -0
- package/src/directive/style.md +23 -0
- package/src/directive/validators.js +329 -0
- package/src/exts/aria.js +544 -0
- package/src/exts/messages.js +852 -0
- package/src/filters/filter.js +207 -0
- package/src/filters/filter.md +69 -0
- package/src/filters/filters.js +239 -0
- package/src/filters/json.md +16 -0
- package/src/filters/limit-to.js +43 -0
- package/src/filters/limit-to.md +19 -0
- package/src/filters/order-by.js +183 -0
- package/src/filters/order-by.md +83 -0
- package/src/index.js +13 -0
- package/src/injector.js +1034 -0
- package/src/jqLite.js +1117 -0
- package/src/loader.js +1320 -0
- package/src/public.js +215 -0
- package/src/routeToRegExp.js +41 -0
- package/src/services/anchorScroll.js +135 -0
- package/src/services/browser.js +321 -0
- package/src/services/cacheFactory.js +398 -0
- package/src/services/cookieReader.js +72 -0
- package/src/services/document.js +64 -0
- package/src/services/http.js +1537 -0
- package/src/services/httpBackend.js +206 -0
- package/src/services/log.js +160 -0
- package/src/services/templateRequest.js +139 -0
- package/test/angular.spec.js +2153 -0
- package/test/aria/aria.spec.js +1245 -0
- package/test/binding.spec.js +504 -0
- package/test/build-test.html +14 -0
- package/test/injector.spec.js +2327 -0
- package/test/jasmine/jasmine-5.1.2/boot0.js +65 -0
- package/test/jasmine/jasmine-5.1.2/boot1.js +133 -0
- package/test/jasmine/jasmine-5.1.2/jasmine-html.js +963 -0
- package/test/jasmine/jasmine-5.1.2/jasmine.css +320 -0
- package/test/jasmine/jasmine-5.1.2/jasmine.js +10824 -0
- package/test/jasmine/jasmine-5.1.2/jasmine_favicon.png +0 -0
- package/test/jasmine/jasmine-browser.json +17 -0
- package/test/jasmine/jasmine.json +9 -0
- package/test/jqlite.spec.js +2133 -0
- package/test/loader.spec.js +219 -0
- package/test/messages/messages.spec.js +1146 -0
- package/test/min-err.spec.js +174 -0
- package/test/mock-test.html +13 -0
- package/test/module-test.html +15 -0
- package/test/ng/anomate.spec.js +606 -0
- package/test/ng/cache-factor.spec.js +334 -0
- package/test/ng/compile.spec.js +17956 -0
- package/test/ng/controller-provider.spec.js +227 -0
- package/test/ng/cookie-reader.spec.js +98 -0
- package/test/ng/directive/a.spec.js +192 -0
- package/test/ng/directive/bind.spec.js +334 -0
- package/test/ng/directive/boolean.spec.js +136 -0
- package/test/ng/directive/change.spec.js +71 -0
- package/test/ng/directive/class.spec.js +858 -0
- package/test/ng/directive/click.spec.js +38 -0
- package/test/ng/directive/cloak.spec.js +44 -0
- package/test/ng/directive/constoller.spec.js +194 -0
- package/test/ng/directive/element-style.spec.js +92 -0
- package/test/ng/directive/event.spec.js +282 -0
- package/test/ng/directive/form.spec.js +1518 -0
- package/test/ng/directive/href.spec.js +143 -0
- package/test/ng/directive/if.spec.js +402 -0
- package/test/ng/directive/include.spec.js +828 -0
- package/test/ng/directive/init.spec.js +68 -0
- package/test/ng/directive/input.spec.js +3810 -0
- package/test/ng/directive/list.spec.js +170 -0
- package/test/ng/directive/model-options.spec.js +1008 -0
- package/test/ng/directive/model.spec.js +1905 -0
- package/test/ng/directive/non-bindable.spec.js +55 -0
- package/test/ng/directive/options.spec.js +3583 -0
- package/test/ng/directive/ref.spec.js +575 -0
- package/test/ng/directive/repeat.spec.js +1675 -0
- package/test/ng/directive/script.spec.js +52 -0
- package/test/ng/directive/scrset.spec.js +67 -0
- package/test/ng/directive/select.spec.js +2541 -0
- package/test/ng/directive/show-hide.spec.js +253 -0
- package/test/ng/directive/src.spec.js +157 -0
- package/test/ng/directive/style.spec.js +178 -0
- package/test/ng/directive/switch.spec.js +647 -0
- package/test/ng/directive/validators.spec.js +717 -0
- package/test/ng/document.spec.js +52 -0
- package/test/ng/filter/filter.spec.js +714 -0
- package/test/ng/filter/filters.spec.js +35 -0
- package/test/ng/filter/limit-to.spec.js +251 -0
- package/test/ng/filter/order-by.spec.js +891 -0
- package/test/ng/filter.spec.js +149 -0
- package/test/ng/http-backend.spec.js +398 -0
- package/test/ng/http.spec.js +4071 -0
- package/test/ng/interpolate.spec.js +642 -0
- package/test/ng/interval.spec.js +343 -0
- package/test/ng/location.spec.js +3488 -0
- package/test/ng/on.spec.js +229 -0
- package/test/ng/parse.spec.js +4655 -0
- package/test/ng/prop.spec.js +805 -0
- package/test/ng/q.spec.js +2904 -0
- package/test/ng/root-element.spec.js +16 -0
- package/test/ng/sanitize-uri.spec.js +249 -0
- package/test/ng/sce.spec.js +660 -0
- package/test/ng/scope.spec.js +3442 -0
- package/test/ng/template-request.spec.js +236 -0
- package/test/ng/timeout.spec.js +351 -0
- package/test/ng/url-utils.spec.js +156 -0
- package/test/ng/utils.spec.js +144 -0
- package/test/original-test.html +21 -0
- package/test/public.spec.js +34 -0
- package/test/sanitize/bing-html.spec.js +36 -0
- package/test/server/express.js +158 -0
- package/test/test-utils.js +11 -0
- package/tsconfig.json +17 -0
- package/types/angular.d.ts +138 -0
- package/types/global.d.ts +9 -0
- package/types/index.d.ts +2357 -0
- package/types/jqlite.d.ts +558 -0
- package/vite.config.js +14 -0
|
@@ -0,0 +1,2133 @@
|
|
|
1
|
+
import { jqLite, JQLite, dealoc, kebabToCamel } from "../src/jqLite";
|
|
2
|
+
import { angularInit } from "../src/loader";
|
|
3
|
+
import { createInjector } from "../src/injector";
|
|
4
|
+
import { publishExternalAPI } from "../src/public";
|
|
5
|
+
import { equals, forEach } from "../src/core/utils";
|
|
6
|
+
import { browserTrigger } from "./test-utils";
|
|
7
|
+
|
|
8
|
+
describe("jqLite", () => {
|
|
9
|
+
let scope;
|
|
10
|
+
let a;
|
|
11
|
+
let b;
|
|
12
|
+
let c;
|
|
13
|
+
let injector;
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
a = jqLite("<div>A</div>")[0];
|
|
17
|
+
b = jqLite("<div>B</div>")[0];
|
|
18
|
+
c = jqLite("<div>C</div>")[0];
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
publishExternalAPI();
|
|
23
|
+
injector = createInjector(["ng"]);
|
|
24
|
+
scope = injector.get("$rootScope");
|
|
25
|
+
jasmine.addMatchers({
|
|
26
|
+
toJqEqual() {
|
|
27
|
+
return {
|
|
28
|
+
compare(_actual_, expected) {
|
|
29
|
+
let msg = "Unequal length";
|
|
30
|
+
const message = () => {
|
|
31
|
+
return msg;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
let value =
|
|
35
|
+
_actual_ && expected && _actual_.length === expected.length;
|
|
36
|
+
for (let i = 0; value && i < expected.length; i++) {
|
|
37
|
+
const actual = jqLite(_actual_[i])[0];
|
|
38
|
+
const expect = jqLite(expected[i])[0];
|
|
39
|
+
value = value && equals(expect, actual);
|
|
40
|
+
msg = `Not equal at index: ${i} - Expected: ${expect} - Actual: ${actual}`;
|
|
41
|
+
}
|
|
42
|
+
return { pass: value, message };
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
afterEach(() => {
|
|
50
|
+
dealoc(a);
|
|
51
|
+
dealoc(b);
|
|
52
|
+
dealoc(c);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should be jqLite by default", () => {
|
|
56
|
+
expect(jqLite).toBe(JQLite);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("construction", () => {
|
|
60
|
+
it("should allow construction with text node", () => {
|
|
61
|
+
const text = a.firstChild;
|
|
62
|
+
const selected = jqLite(text);
|
|
63
|
+
expect(selected.length).toEqual(1);
|
|
64
|
+
expect(selected[0]).toEqual(text);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should allow construction with html", () => {
|
|
68
|
+
const nodes = jqLite("<div>1</div><span>2</span>");
|
|
69
|
+
expect(nodes[0].parentNode).toBeDefined();
|
|
70
|
+
expect(nodes[0].parentNode.nodeType).toBe(11); /** Document Fragment * */
|
|
71
|
+
expect(nodes[0].parentNode).toBe(nodes[1].parentNode);
|
|
72
|
+
expect(nodes.length).toEqual(2);
|
|
73
|
+
expect(nodes[0].innerHTML).toEqual("1");
|
|
74
|
+
expect(nodes[1].innerHTML).toEqual("2");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should allow construction of html with leading whitespace", () => {
|
|
78
|
+
const nodes = jqLite(" \n\r \r\n<div>1</div><span>2</span>");
|
|
79
|
+
expect(nodes[0].parentNode).toBeDefined();
|
|
80
|
+
expect(nodes[0].parentNode.nodeType).toBe(11); /** Document Fragment * */
|
|
81
|
+
expect(nodes[0].parentNode).toBe(nodes[1].parentNode);
|
|
82
|
+
expect(nodes.length).toBe(2);
|
|
83
|
+
expect(nodes[0].innerHTML).toBe("1");
|
|
84
|
+
expect(nodes[1].innerHTML).toBe("2");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// See https://github.com/jquery/jquery/issues/1987 for details.
|
|
88
|
+
it("should properly handle dash-delimited node names", () => {
|
|
89
|
+
const nodeNames =
|
|
90
|
+
"thead tbody tfoot colgroup caption tr th td div kung".split(" ");
|
|
91
|
+
let nodeNamesTested = 0;
|
|
92
|
+
let nodes;
|
|
93
|
+
let customNodeName;
|
|
94
|
+
|
|
95
|
+
nodeNames.forEach((nodeName) => {
|
|
96
|
+
customNodeName = `${nodeName}-foo`;
|
|
97
|
+
nodes = jqLite(`<${customNodeName}>Hello, world !</${customNodeName}>`);
|
|
98
|
+
|
|
99
|
+
expect(nodes.length).toBe(1);
|
|
100
|
+
expect(nodes[0].nodeName.toLowerCase()).toBe(customNodeName);
|
|
101
|
+
expect(nodes.html()).toBe("Hello, world !");
|
|
102
|
+
|
|
103
|
+
nodeNamesTested++;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
expect(nodeNamesTested).toBe(10);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should allow creation of comment tags", () => {
|
|
110
|
+
const nodes = jqLite("<!-- foo -->");
|
|
111
|
+
expect(nodes.length).toBe(1);
|
|
112
|
+
expect(nodes[0].nodeType).toBe(8);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should allow creation of script tags", () => {
|
|
116
|
+
const nodes = jqLite("<script></script>");
|
|
117
|
+
expect(nodes.length).toBe(1);
|
|
118
|
+
expect(nodes[0].tagName.toUpperCase()).toBe("SCRIPT");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("should wrap document fragment", () => {
|
|
122
|
+
const fragment = jqLite(window.document.createDocumentFragment());
|
|
123
|
+
expect(fragment.length).toBe(1);
|
|
124
|
+
expect(fragment[0].nodeType).toBe(11);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should allow construction of <option> elements", () => {
|
|
128
|
+
const nodes = jqLite("<option>");
|
|
129
|
+
expect(nodes.length).toBe(1);
|
|
130
|
+
expect(nodes[0].nodeName.toLowerCase()).toBe("option");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("should allow construction of multiple <option> elements", () => {
|
|
134
|
+
const nodes = jqLite("<option></option><option></option>");
|
|
135
|
+
expect(nodes.length).toBe(2);
|
|
136
|
+
expect(nodes[0].nodeName.toLowerCase()).toBe("option");
|
|
137
|
+
expect(nodes[1].nodeName.toLowerCase()).toBe("option");
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Special tests for the construction of elements which are restricted (in the HTML5 spec) to
|
|
141
|
+
// being children of specific nodes.
|
|
142
|
+
[
|
|
143
|
+
"caption",
|
|
144
|
+
"colgroup",
|
|
145
|
+
"col",
|
|
146
|
+
"optgroup",
|
|
147
|
+
"opt",
|
|
148
|
+
"tbody",
|
|
149
|
+
"td",
|
|
150
|
+
"tfoot",
|
|
151
|
+
"th",
|
|
152
|
+
"thead",
|
|
153
|
+
"tr",
|
|
154
|
+
].forEach((name) => {
|
|
155
|
+
it(
|
|
156
|
+
"should allow construction of <$NAME$> elements".replace(
|
|
157
|
+
"$NAME$",
|
|
158
|
+
name,
|
|
159
|
+
),
|
|
160
|
+
() => {
|
|
161
|
+
const nodes = jqLite("<$NAME$>".replace("$NAME$", name));
|
|
162
|
+
expect(nodes.length).toBe(1);
|
|
163
|
+
expect(nodes[0].nodeName.toLowerCase()).toBe(name);
|
|
164
|
+
},
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe("security", () => {
|
|
169
|
+
it("shouldn't crash at attempts to close the table wrapper", () => {
|
|
170
|
+
expect(() => {
|
|
171
|
+
// This test case attempts to close the tags which wrap input
|
|
172
|
+
// based on matching done in wrapMap, escaping the wrapper & thus
|
|
173
|
+
// triggering an error when descending.
|
|
174
|
+
const el = jqLite("<td></td></tr></tbody></table><td></td>");
|
|
175
|
+
expect(el.length).toBe(2);
|
|
176
|
+
expect(el[0].nodeName.toLowerCase()).toBe("td");
|
|
177
|
+
expect(el[1].nodeName.toLowerCase()).toBe("td");
|
|
178
|
+
}).not.toThrow();
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("shouldn't unsanitize sanitized code", (done) => {
|
|
182
|
+
let counter = 0;
|
|
183
|
+
const assertCount = 13;
|
|
184
|
+
const container = jqLite("<div></div>");
|
|
185
|
+
|
|
186
|
+
function donePartial() {
|
|
187
|
+
counter++;
|
|
188
|
+
if (counter === assertCount) {
|
|
189
|
+
container.remove();
|
|
190
|
+
delete window.xss;
|
|
191
|
+
done();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
jqLite(window.document.body).append(container);
|
|
195
|
+
window.xss = jasmine.createSpy("xss");
|
|
196
|
+
|
|
197
|
+
// Thanks to Masato Kinugawa from Cure53 for providing the following test cases.
|
|
198
|
+
// Note: below test cases need to invoke the xss function with consecutive
|
|
199
|
+
// decimal parameters for the assertions to be correct.
|
|
200
|
+
[
|
|
201
|
+
'<img alt="<x" title="/><img src=url404 onerror=xss(0)>">',
|
|
202
|
+
'<img alt="\n<x" title="/>\n<img src=url404 onerror=xss(1)>">',
|
|
203
|
+
"<style><style/><img src=url404 onerror=xss(2)>",
|
|
204
|
+
"<xmp><xmp/><img src=url404 onerror=xss(3)>",
|
|
205
|
+
"<title><title /><img src=url404 onerror=xss(4)>",
|
|
206
|
+
"<iframe><iframe/><img src=url404 onerror=xss(5)>",
|
|
207
|
+
"<noframes><noframes/><img src=url404 onerror=xss(6)>",
|
|
208
|
+
"<noscript><noscript/><img src=url404 onerror=xss(7)>",
|
|
209
|
+
'<foo" alt="" title="/><img src=url404 onerror=xss(8)>">',
|
|
210
|
+
'<img alt="<x" title="" src="/><img src=url404 onerror=xss(9)>">',
|
|
211
|
+
"<noscript/><img src=url404 onerror=xss(10)>",
|
|
212
|
+
"<noembed><noembed/><img src=url404 onerror=xss(11)>",
|
|
213
|
+
|
|
214
|
+
"<option><style></option></select><img src=url404 onerror=xss(12)></style>",
|
|
215
|
+
].forEach((htmlString, index) => {
|
|
216
|
+
const element = jqLite("<div></div>");
|
|
217
|
+
|
|
218
|
+
container.append(element);
|
|
219
|
+
element.append(jqLite(htmlString));
|
|
220
|
+
|
|
221
|
+
setTimeout(() => {
|
|
222
|
+
expect(window.xss).not.toHaveBeenCalledWith(index);
|
|
223
|
+
donePartial();
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe("_data", () => {
|
|
231
|
+
it("should provide access to the events present on the element", () => {
|
|
232
|
+
const element = jqLite("<i>foo</i>");
|
|
233
|
+
// TODO: REMOVE angular becomes TESTED
|
|
234
|
+
angular.element = jqLite;
|
|
235
|
+
expect(angular.element._data(element[0]).events).toBeUndefined();
|
|
236
|
+
|
|
237
|
+
element.on("click", () => {});
|
|
238
|
+
expect(angular.element._data(element[0]).events.click).toBeDefined();
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
describe("inheritedData", () => {
|
|
243
|
+
it("should retrieve data attached to the current element", () => {
|
|
244
|
+
const element = jqLite("<i>foo</i>");
|
|
245
|
+
element.data("myData", "abc");
|
|
246
|
+
expect(element.inheritedData("myData")).toBe("abc");
|
|
247
|
+
dealoc(element);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("should walk up the dom to find data", () => {
|
|
251
|
+
const element = jqLite("<ul><li><p><b>deep deep</b><p></li></ul>");
|
|
252
|
+
const deepChild = jqLite(element[0].getElementsByTagName("b")[0]);
|
|
253
|
+
element.data("myData", "abc");
|
|
254
|
+
expect(deepChild.inheritedData("myData")).toBe("abc");
|
|
255
|
+
dealoc(element);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it("should return undefined when no data was found", () => {
|
|
259
|
+
const element = jqLite("<ul><li><p><b>deep deep</b><p></li></ul>");
|
|
260
|
+
const deepChild = jqLite(element[0].getElementsByTagName("b")[0]);
|
|
261
|
+
expect(deepChild.inheritedData("myData")).toBeFalsy();
|
|
262
|
+
dealoc(element);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it("should work with the child html element instead if the current element is the document obj", () => {
|
|
266
|
+
const item = {};
|
|
267
|
+
const doc = jqLite(window.document);
|
|
268
|
+
const html = doc.find("html");
|
|
269
|
+
|
|
270
|
+
html.data("item", item);
|
|
271
|
+
expect(doc.inheritedData("item")).toBe(item);
|
|
272
|
+
expect(html.inheritedData("item")).toBe(item);
|
|
273
|
+
dealoc(doc);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it("should return null values", () => {
|
|
277
|
+
const ul = jqLite("<ul><li><p><b>deep deep</b><p></li></ul>");
|
|
278
|
+
const li = ul.find("li");
|
|
279
|
+
const b = li.find("b");
|
|
280
|
+
|
|
281
|
+
ul.data("foo", "bar");
|
|
282
|
+
li.data("foo", null);
|
|
283
|
+
expect(b.inheritedData("foo")).toBe(null);
|
|
284
|
+
expect(li.inheritedData("foo")).toBe(null);
|
|
285
|
+
expect(ul.inheritedData("foo")).toBe("bar");
|
|
286
|
+
|
|
287
|
+
dealoc(ul);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it("should pass through DocumentFragment boundaries via host", () => {
|
|
291
|
+
const host = jqLite("<div></div>");
|
|
292
|
+
const frag = window.document.createDocumentFragment();
|
|
293
|
+
const $frag = jqLite(frag);
|
|
294
|
+
frag.host = host[0];
|
|
295
|
+
host.data("foo", 123);
|
|
296
|
+
host.append($frag);
|
|
297
|
+
expect($frag.inheritedData("foo")).toBe(123);
|
|
298
|
+
|
|
299
|
+
dealoc(host);
|
|
300
|
+
dealoc($frag);
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
describe("scope", () => {
|
|
305
|
+
it("should retrieve scope attached to the current element", () => {
|
|
306
|
+
const element = jqLite("<i>foo</i>");
|
|
307
|
+
element.data("$scope", scope);
|
|
308
|
+
expect(element.scope()).toBe(scope);
|
|
309
|
+
dealoc(element);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it("should retrieve isolate scope attached to the current element", () => {
|
|
313
|
+
const element = jqLite("<i>foo</i>");
|
|
314
|
+
element.data("$isolateScope", scope);
|
|
315
|
+
expect(element.isolateScope()).toBe(scope);
|
|
316
|
+
dealoc(element);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it("should retrieve scope attached to the html element if it's requested on the document", () => {
|
|
320
|
+
const doc = jqLite(window.document);
|
|
321
|
+
const html = doc.find("html");
|
|
322
|
+
const scope = {};
|
|
323
|
+
|
|
324
|
+
html.data("$scope", scope);
|
|
325
|
+
|
|
326
|
+
expect(doc.scope().$id).toBe(scope.$id);
|
|
327
|
+
expect(html.scope().$id).toBe(scope.$id);
|
|
328
|
+
dealoc(doc);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it("should walk up the dom to find scope", () => {
|
|
332
|
+
const element = jqLite("<ul><li><p><b>deep deep</b><p></li></ul>");
|
|
333
|
+
const deepChild = jqLite(element[0].getElementsByTagName("b")[0]);
|
|
334
|
+
element.data("$scope", scope);
|
|
335
|
+
expect(deepChild.scope()).toBe(scope);
|
|
336
|
+
dealoc(element);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it("should return undefined when no scope was found", () => {
|
|
340
|
+
const element = jqLite("<ul><li><p><b>deep deep</b><p></li></ul>");
|
|
341
|
+
const deepChild = jqLite(element[0].getElementsByTagName("b")[0]);
|
|
342
|
+
expect(deepChild.scope()).toBeFalsy();
|
|
343
|
+
dealoc(element);
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
describe("isolateScope", () => {
|
|
348
|
+
it("should retrieve isolate scope attached to the current element", () => {
|
|
349
|
+
const element = jqLite("<i>foo</i>");
|
|
350
|
+
element.data("$isolateScope", scope);
|
|
351
|
+
expect(element.isolateScope()).toBe(scope);
|
|
352
|
+
dealoc(element);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it("should not walk up the dom to find scope", () => {
|
|
356
|
+
const element = jqLite("<ul><li><p><b>deep deep</b><p></li></ul>");
|
|
357
|
+
const deepChild = jqLite(element[0].getElementsByTagName("b")[0]);
|
|
358
|
+
element.data("$isolateScope", scope);
|
|
359
|
+
expect(deepChild.isolateScope()).toBeUndefined();
|
|
360
|
+
dealoc(element);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it("should return undefined when no scope was found", () => {
|
|
364
|
+
const element = jqLite("<div></div>");
|
|
365
|
+
expect(element.isolateScope()).toBeFalsy();
|
|
366
|
+
dealoc(element);
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
describe("injector", () => {
|
|
371
|
+
it("should retrieve injector attached to the current element or its parent", () => {
|
|
372
|
+
const template = jqLite("<div><span></span></div>");
|
|
373
|
+
const span = template.children().eq(0);
|
|
374
|
+
const injector = angularInit(template[0]);
|
|
375
|
+
|
|
376
|
+
expect(span.injector()).toBe(injector);
|
|
377
|
+
dealoc(template);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it("should retrieve injector attached to the html element if it's requested on document", () => {
|
|
381
|
+
const doc = jqLite(window.document);
|
|
382
|
+
const html = doc.find("html");
|
|
383
|
+
const injector = {};
|
|
384
|
+
|
|
385
|
+
html.data("$injector", injector);
|
|
386
|
+
|
|
387
|
+
expect(doc.injector()).toBe(injector);
|
|
388
|
+
expect(html.injector()).toBe(injector);
|
|
389
|
+
dealoc(doc);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it("should do nothing with a noncompiled template", () => {
|
|
393
|
+
const template = jqLite("<div><span></span></div>");
|
|
394
|
+
expect(template.injector()).toBeUndefined();
|
|
395
|
+
dealoc(template);
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
describe("controller", () => {
|
|
400
|
+
it("should retrieve controller attached to the current element or its parent", () => {
|
|
401
|
+
const div = jqLite("<div><span></span></div>");
|
|
402
|
+
const span = div.find("span");
|
|
403
|
+
|
|
404
|
+
div.data("$ngControllerController", "ngController");
|
|
405
|
+
span.data("$otherController", "other");
|
|
406
|
+
|
|
407
|
+
expect(span.controller()).toBe("ngController");
|
|
408
|
+
expect(span.controller("ngController")).toBe("ngController");
|
|
409
|
+
expect(span.controller("other")).toBe("other");
|
|
410
|
+
|
|
411
|
+
expect(div.controller()).toBe("ngController");
|
|
412
|
+
expect(div.controller("ngController")).toBe("ngController");
|
|
413
|
+
expect(div.controller("other")).toBeUndefined();
|
|
414
|
+
|
|
415
|
+
dealoc(div);
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
describe("data", () => {
|
|
420
|
+
it("should set and get and remove data", () => {
|
|
421
|
+
const selected = jqLite([a, b, c]);
|
|
422
|
+
|
|
423
|
+
expect(selected.data("prop")).toBeUndefined();
|
|
424
|
+
expect(selected.data("prop", "value")).toBe(selected);
|
|
425
|
+
expect(selected.data("prop")).toBe("value");
|
|
426
|
+
expect(jqLite(a).data("prop")).toBe("value");
|
|
427
|
+
expect(jqLite(b).data("prop")).toBe("value");
|
|
428
|
+
expect(jqLite(c).data("prop")).toBe("value");
|
|
429
|
+
|
|
430
|
+
jqLite(a).data("prop", "new value");
|
|
431
|
+
expect(jqLite(a).data("prop")).toBe("new value");
|
|
432
|
+
expect(selected.data("prop")).toBe("new value");
|
|
433
|
+
expect(jqLite(b).data("prop")).toBe("value");
|
|
434
|
+
expect(jqLite(c).data("prop")).toBe("value");
|
|
435
|
+
|
|
436
|
+
expect(selected.removeData("prop")).toBe(selected);
|
|
437
|
+
expect(jqLite(a).data("prop")).toBeUndefined();
|
|
438
|
+
expect(jqLite(b).data("prop")).toBeUndefined();
|
|
439
|
+
expect(jqLite(c).data("prop")).toBeUndefined();
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
it("should only remove the specified value when providing a property name to removeData", () => {
|
|
443
|
+
const selected = jqLite(a);
|
|
444
|
+
|
|
445
|
+
expect(selected.data("prop1")).toBeUndefined();
|
|
446
|
+
|
|
447
|
+
selected.data("prop1", "value");
|
|
448
|
+
selected.data("prop2", "doublevalue");
|
|
449
|
+
|
|
450
|
+
expect(selected.data("prop1")).toBe("value");
|
|
451
|
+
expect(selected.data("prop2")).toBe("doublevalue");
|
|
452
|
+
|
|
453
|
+
selected.removeData("prop1");
|
|
454
|
+
|
|
455
|
+
expect(selected.data("prop1")).toBeUndefined();
|
|
456
|
+
expect(selected.data("prop2")).toBe("doublevalue");
|
|
457
|
+
|
|
458
|
+
selected.removeData("prop2");
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
it("should not remove event handlers on removeData()", () => {
|
|
462
|
+
let log = "";
|
|
463
|
+
const elm = jqLite(a);
|
|
464
|
+
elm.on("click", () => {
|
|
465
|
+
log += "click;";
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
elm.removeData();
|
|
469
|
+
browserTrigger(a, "click");
|
|
470
|
+
expect(log).toBe("click;");
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
it("should allow to set data after removeData() with event handlers present", () => {
|
|
474
|
+
const elm = jqLite(a);
|
|
475
|
+
elm.on("click", () => {});
|
|
476
|
+
elm.data("key1", "value1");
|
|
477
|
+
elm.removeData();
|
|
478
|
+
elm.data("key2", "value2");
|
|
479
|
+
expect(elm.data("key1")).not.toBeDefined();
|
|
480
|
+
expect(elm.data("key2")).toBe("value2");
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
it("should allow to set data after removeData() without event handlers present", () => {
|
|
484
|
+
const elm = jqLite(a);
|
|
485
|
+
elm.data("key1", "value1");
|
|
486
|
+
elm.removeData();
|
|
487
|
+
elm.data("key2", "value2");
|
|
488
|
+
expect(elm.data("key1")).not.toBeDefined();
|
|
489
|
+
expect(elm.data("key2")).toBe("value2");
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
it("should remove user data on cleanData()", () => {
|
|
493
|
+
const selected = jqLite([a, b, c]);
|
|
494
|
+
|
|
495
|
+
selected.data("prop", "value");
|
|
496
|
+
jqLite(b).data("prop", "new value");
|
|
497
|
+
|
|
498
|
+
jqLite.cleanData(selected);
|
|
499
|
+
|
|
500
|
+
expect(jqLite(a).data("prop")).toBeUndefined();
|
|
501
|
+
expect(jqLite(b).data("prop")).toBeUndefined();
|
|
502
|
+
expect(jqLite(c).data("prop")).toBeUndefined();
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
it("should remove event handlers on cleanData()", () => {
|
|
506
|
+
const selected = jqLite([a, b, c]);
|
|
507
|
+
|
|
508
|
+
let log = "";
|
|
509
|
+
const elm = jqLite(b);
|
|
510
|
+
elm.on("click", () => {
|
|
511
|
+
log += "click;";
|
|
512
|
+
});
|
|
513
|
+
jqLite.cleanData(selected);
|
|
514
|
+
|
|
515
|
+
browserTrigger(b, "click");
|
|
516
|
+
expect(log).toBe("");
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
it("should remove user data & event handlers on cleanData()", () => {
|
|
520
|
+
const selected = jqLite([a, b, c]);
|
|
521
|
+
|
|
522
|
+
let log = "";
|
|
523
|
+
const elm = jqLite(b);
|
|
524
|
+
elm.on("click", () => {
|
|
525
|
+
log += "click;";
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
selected.data("prop", "value");
|
|
529
|
+
jqLite(a).data("prop", "new value");
|
|
530
|
+
|
|
531
|
+
jqLite.cleanData(selected);
|
|
532
|
+
|
|
533
|
+
browserTrigger(b, "click");
|
|
534
|
+
expect(log).toBe("");
|
|
535
|
+
|
|
536
|
+
expect(jqLite(a).data("prop")).toBeUndefined();
|
|
537
|
+
expect(jqLite(b).data("prop")).toBeUndefined();
|
|
538
|
+
expect(jqLite(c).data("prop")).toBeUndefined();
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
it("should not break on cleanData(), if element has no data", () => {
|
|
542
|
+
const selected = jqLite([a, b, c]);
|
|
543
|
+
spyOn(jqLite, "_data").and.returnValue(undefined);
|
|
544
|
+
expect(() => {
|
|
545
|
+
jqLite.cleanData(selected);
|
|
546
|
+
}).not.toThrow();
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
it("should add and remove data on SVGs", () => {
|
|
550
|
+
const svg = jqLite("<svg><rect></rect></svg>");
|
|
551
|
+
|
|
552
|
+
svg.data("svg-level", 1);
|
|
553
|
+
expect(svg.data("svg-level")).toBe(1);
|
|
554
|
+
|
|
555
|
+
svg.children().data("rect-level", 2);
|
|
556
|
+
expect(svg.children().data("rect-level")).toBe(2);
|
|
557
|
+
|
|
558
|
+
svg.remove();
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
it("should not add to the cache if the node is a comment or text node", () => {
|
|
562
|
+
const initial = Object.keys(jqLite.cache).length;
|
|
563
|
+
const nodes = jqLite("<!-- some comment --> and some text");
|
|
564
|
+
expect(Object.keys(jqLite.cache).length).toEqual(initial);
|
|
565
|
+
nodes.data("someKey");
|
|
566
|
+
expect(Object.keys(jqLite.cache).length).toEqual(initial);
|
|
567
|
+
nodes.data("someKey", "someValue");
|
|
568
|
+
expect(Object.keys(jqLite.cache).length).toEqual(initial);
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
it("should provide the non-wrapped data calls", () => {
|
|
572
|
+
const node = document.createElement("div");
|
|
573
|
+
document.body.appendChild(node);
|
|
574
|
+
|
|
575
|
+
expect(jqLite.hasData(node)).toBe(false);
|
|
576
|
+
expect(jqLite.data(node, "foo")).toBeUndefined();
|
|
577
|
+
expect(jqLite.hasData(node)).toBe(false);
|
|
578
|
+
|
|
579
|
+
jqLite.data(node, "foo", "bar");
|
|
580
|
+
|
|
581
|
+
expect(jqLite.hasData(node)).toBe(true);
|
|
582
|
+
expect(jqLite.data(node, "foo")).toBe("bar");
|
|
583
|
+
expect(jqLite(node).data("foo")).toBe("bar");
|
|
584
|
+
|
|
585
|
+
expect(jqLite.data(node)).toBe(jqLite(node).data());
|
|
586
|
+
|
|
587
|
+
jqLite.removeData(node, "foo");
|
|
588
|
+
expect(jqLite.data(node, "foo")).toBeUndefined();
|
|
589
|
+
|
|
590
|
+
jqLite.data(node, "bar", "baz");
|
|
591
|
+
jqLite.removeData(node);
|
|
592
|
+
jqLite.removeData(node);
|
|
593
|
+
expect(jqLite.data(node, "bar")).toBeUndefined();
|
|
594
|
+
|
|
595
|
+
jqLite(node).remove();
|
|
596
|
+
expect(jqLite.hasData(node)).toBe(false);
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
it("should emit $destroy event if element removed via remove()", function () {
|
|
600
|
+
var log = "";
|
|
601
|
+
var element = jqLite(a);
|
|
602
|
+
element.on("$destroy", function () {
|
|
603
|
+
log += "destroy;";
|
|
604
|
+
});
|
|
605
|
+
element.remove();
|
|
606
|
+
expect(log).toEqual("destroy;");
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
it("should emit $destroy event if an element is removed via html('')", () => {
|
|
610
|
+
let log = [];
|
|
611
|
+
const element = jqLite("<div><span>x</span></div>");
|
|
612
|
+
element.find("span").on("$destroy", () => log.push("destroyed"));
|
|
613
|
+
element.html("");
|
|
614
|
+
expect(element.html()).toBe("");
|
|
615
|
+
expect(log).toEqual(["destroyed"]);
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
it("should emit $destroy event if an element is removed via empty()", () => {
|
|
619
|
+
let log = [];
|
|
620
|
+
const element = jqLite("<div><span>x</span></div>");
|
|
621
|
+
element.find("span").on("$destroy", () => log.push("destroyed"));
|
|
622
|
+
|
|
623
|
+
element.empty();
|
|
624
|
+
|
|
625
|
+
expect(element.html()).toBe("");
|
|
626
|
+
expect(log).toEqual(["destroyed"]);
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
it("should keep data if an element is removed via detach()", () => {
|
|
630
|
+
const root = jqLite("<div><span>abc</span></div>");
|
|
631
|
+
const span = root.find("span");
|
|
632
|
+
const data = span.data();
|
|
633
|
+
|
|
634
|
+
span.data("foo", "bar");
|
|
635
|
+
span.detach();
|
|
636
|
+
|
|
637
|
+
expect(data).toEqual({ foo: "bar" });
|
|
638
|
+
|
|
639
|
+
span.remove();
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
it("should retrieve all data if called without params", () => {
|
|
643
|
+
const element = jqLite(a);
|
|
644
|
+
expect(element.data()).toEqual({});
|
|
645
|
+
|
|
646
|
+
element.data("foo", "bar");
|
|
647
|
+
expect(element.data()).toEqual({ foo: "bar" });
|
|
648
|
+
|
|
649
|
+
element.data().baz = "xxx";
|
|
650
|
+
expect(element.data()).toEqual({ foo: "bar", baz: "xxx" });
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
it("should create a new data object if called without args", () => {
|
|
654
|
+
const element = jqLite(a);
|
|
655
|
+
const data = element.data();
|
|
656
|
+
|
|
657
|
+
expect(data).toEqual({});
|
|
658
|
+
element.data("foo", "bar");
|
|
659
|
+
expect(data).toEqual({ foo: "bar" });
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
it("should create a new data object if called with a single object arg", () => {
|
|
663
|
+
const element = jqLite(a);
|
|
664
|
+
const newData = { foo: "bar" };
|
|
665
|
+
|
|
666
|
+
element.data(newData);
|
|
667
|
+
expect(element.data()).toEqual({ foo: "bar" });
|
|
668
|
+
expect(element.data()).not.toBe(newData); // create a copy
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
it("should merge existing data object with a new one if called with a single object arg", () => {
|
|
672
|
+
const element = jqLite(a);
|
|
673
|
+
element.data("existing", "val");
|
|
674
|
+
expect(element.data()).toEqual({ existing: "val" });
|
|
675
|
+
|
|
676
|
+
const oldData = element.data();
|
|
677
|
+
const newData = { meLike: "turtles", youLike: "carrots" };
|
|
678
|
+
|
|
679
|
+
expect(element.data(newData)).toBe(element);
|
|
680
|
+
expect(element.data()).toEqual({
|
|
681
|
+
meLike: "turtles",
|
|
682
|
+
youLike: "carrots",
|
|
683
|
+
existing: "val",
|
|
684
|
+
});
|
|
685
|
+
expect(element.data()).toBe(oldData); // merge into the old object
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
describe("data cleanup", () => {
|
|
689
|
+
it("should remove data on element removal", () => {
|
|
690
|
+
const div = jqLite("<div><span>text</span></div>");
|
|
691
|
+
const span = div.find("span");
|
|
692
|
+
|
|
693
|
+
span.data("name", "AngularJS");
|
|
694
|
+
span.remove();
|
|
695
|
+
expect(span.data("name")).toBeUndefined();
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
it("should remove event listeners on element removal", () => {
|
|
699
|
+
const div = jqLite("<div><span>text</span></div>");
|
|
700
|
+
const span = div.find("span");
|
|
701
|
+
let log = "";
|
|
702
|
+
|
|
703
|
+
span.on("click", () => {
|
|
704
|
+
log += "click;";
|
|
705
|
+
});
|
|
706
|
+
browserTrigger(span, "click");
|
|
707
|
+
expect(log).toEqual("click;");
|
|
708
|
+
|
|
709
|
+
span.remove();
|
|
710
|
+
|
|
711
|
+
browserTrigger(span);
|
|
712
|
+
expect(log).toEqual("click;");
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
it("should work if the descendants of the element change while it's being removed", () => {
|
|
716
|
+
const div = jqLite("<div><p><span>text</span></p></div>");
|
|
717
|
+
div.find("p").on("$destroy", () => {
|
|
718
|
+
div.find("span").remove();
|
|
719
|
+
});
|
|
720
|
+
expect(() => {
|
|
721
|
+
div.remove();
|
|
722
|
+
}).not.toThrow();
|
|
723
|
+
});
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
describe("camelCasing keys", () => {
|
|
727
|
+
it("should camelCase the key in a setter", () => {
|
|
728
|
+
const element = jqLite(a);
|
|
729
|
+
|
|
730
|
+
element.data("a-B-c-d-42--e", "z-x");
|
|
731
|
+
expect(element.data()).toEqual({ "a-BCD-42-E": "z-x" });
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
it("should camelCase the key in a getter", () => {
|
|
735
|
+
const element = jqLite(a);
|
|
736
|
+
|
|
737
|
+
element.data()["a-BCD-42-E"] = "x-c";
|
|
738
|
+
expect(element.data("a-B-c-d-42--e")).toBe("x-c");
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
it("should camelCase the key in a mass setter", () => {
|
|
742
|
+
const element = jqLite(a);
|
|
743
|
+
|
|
744
|
+
element.data({ "a-B-c-d-42--e": "c-v", "r-t-v": 42 });
|
|
745
|
+
expect(element.data()).toEqual({ "a-BCD-42-E": "c-v", rTV: 42 });
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
it("should ignore non-camelCase keys in the data in a getter", () => {
|
|
749
|
+
const element = jqLite(a);
|
|
750
|
+
|
|
751
|
+
element.data()["a-b"] = "b-n";
|
|
752
|
+
expect(element.data("a-b")).toBe(undefined);
|
|
753
|
+
});
|
|
754
|
+
});
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
describe("attr", () => {
|
|
758
|
+
it("should read, write and remove attr", () => {
|
|
759
|
+
const selector = jqLite([a, b]);
|
|
760
|
+
|
|
761
|
+
expect(selector.attr("prop", "value")).toEqual(selector);
|
|
762
|
+
expect(jqLite(a).attr("prop")).toEqual("value");
|
|
763
|
+
expect(jqLite(b).attr("prop")).toEqual("value");
|
|
764
|
+
|
|
765
|
+
expect(selector.attr({ prop: "new value" })).toEqual(selector);
|
|
766
|
+
expect(jqLite(a).attr("prop")).toEqual("new value");
|
|
767
|
+
expect(jqLite(b).attr("prop")).toEqual("new value");
|
|
768
|
+
|
|
769
|
+
jqLite(b).attr({ prop: "new value 2" });
|
|
770
|
+
expect(jqLite(selector).attr("prop")).toEqual("new value");
|
|
771
|
+
expect(jqLite(b).attr("prop")).toEqual("new value 2");
|
|
772
|
+
|
|
773
|
+
selector[0].removeAttribute("prop");
|
|
774
|
+
selector[1].removeAttribute("prop");
|
|
775
|
+
expect(jqLite(a).attr("prop")).toBeFalsy();
|
|
776
|
+
expect(jqLite(b).attr("prop")).toBeFalsy();
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
it("should read boolean attributes as strings", () => {
|
|
780
|
+
const select = jqLite("<select>");
|
|
781
|
+
expect(select.attr("multiple")).toBeUndefined();
|
|
782
|
+
expect(jqLite("<select multiple>").attr("multiple")).toBe("multiple");
|
|
783
|
+
expect(jqLite('<select multiple="">').attr("multiple")).toBe("multiple");
|
|
784
|
+
expect(jqLite('<select multiple="x">').attr("multiple")).toBe("multiple");
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
it("should add/remove boolean attributes", () => {
|
|
788
|
+
const select = jqLite("<select>");
|
|
789
|
+
select.attr("multiple", false);
|
|
790
|
+
expect(select.attr("multiple")).toBeUndefined();
|
|
791
|
+
|
|
792
|
+
select.attr("multiple", true);
|
|
793
|
+
expect(select.attr("multiple")).toBe("multiple");
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
it("should not take properties into account when getting respective boolean attributes", () => {
|
|
797
|
+
// Use a div and not a select as the latter would itself reflect the multiple attribute
|
|
798
|
+
// to a property.
|
|
799
|
+
const div = jqLite("<div>");
|
|
800
|
+
|
|
801
|
+
div[0].multiple = true;
|
|
802
|
+
expect(div.attr("multiple")).toBe(undefined);
|
|
803
|
+
|
|
804
|
+
div.attr("multiple", "multiple");
|
|
805
|
+
div[0].multiple = false;
|
|
806
|
+
expect(div.attr("multiple")).toBe("multiple");
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
it("should not set properties when setting respective boolean attributes", () => {
|
|
810
|
+
// Use a div and not a select as the latter would itself reflect the multiple attribute
|
|
811
|
+
// to a property.
|
|
812
|
+
const div = jqLite("<div>");
|
|
813
|
+
|
|
814
|
+
// Check the initial state.
|
|
815
|
+
expect(div[0].multiple).toBe(undefined);
|
|
816
|
+
|
|
817
|
+
div.attr("multiple", "multiple");
|
|
818
|
+
expect(div[0].multiple).toBe(undefined);
|
|
819
|
+
|
|
820
|
+
div.attr("multiple", "");
|
|
821
|
+
expect(div[0].multiple).toBe(undefined);
|
|
822
|
+
|
|
823
|
+
div.attr("multiple", false);
|
|
824
|
+
expect(div[0].multiple).toBe(undefined);
|
|
825
|
+
|
|
826
|
+
div.attr("multiple", null);
|
|
827
|
+
expect(div[0].multiple).toBe(undefined);
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
it("should normalize the case of boolean attributes", () => {
|
|
831
|
+
const input = jqLite("<input readonly>");
|
|
832
|
+
expect(input.attr("readonly")).toBe("readonly");
|
|
833
|
+
expect(input.attr("readOnly")).toBe("readonly");
|
|
834
|
+
expect(input.attr("READONLY")).toBe("readonly");
|
|
835
|
+
|
|
836
|
+
input.attr("readonly", false);
|
|
837
|
+
expect(input[0].getAttribute("readonly")).toBe(null);
|
|
838
|
+
|
|
839
|
+
input.attr("readOnly", "READonly");
|
|
840
|
+
expect(input.attr("readonly")).toBe("readonly");
|
|
841
|
+
expect(input.attr("readOnly")).toBe("readonly");
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
it("should return undefined for non-existing attributes", () => {
|
|
845
|
+
const elm = jqLite('<div class="any">a</div>');
|
|
846
|
+
expect(elm.attr("non-existing")).toBeUndefined();
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
it("should return undefined for non-existing attributes on input", () => {
|
|
850
|
+
const elm = jqLite("<input>");
|
|
851
|
+
expect(elm.attr("readonly")).toBeUndefined();
|
|
852
|
+
expect(elm.attr("readOnly")).toBeUndefined();
|
|
853
|
+
expect(elm.attr("disabled")).toBeUndefined();
|
|
854
|
+
});
|
|
855
|
+
|
|
856
|
+
it("should do nothing when setting or getting on attribute nodes", () => {
|
|
857
|
+
const attrNode = jqLite(window.document.createAttribute("myattr"));
|
|
858
|
+
expect(attrNode).toBeDefined();
|
|
859
|
+
expect(attrNode[0].nodeType).toEqual(2);
|
|
860
|
+
expect(attrNode.attr("some-attribute", "somevalue")).toEqual(attrNode);
|
|
861
|
+
expect(attrNode.attr("some-attribute")).toBeUndefined();
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
it("should do nothing when setting or getting on text nodes", () => {
|
|
865
|
+
const textNode = jqLite(window.document.createTextNode("some text"));
|
|
866
|
+
expect(textNode).toBeDefined();
|
|
867
|
+
expect(textNode[0].nodeType).toEqual(3);
|
|
868
|
+
expect(textNode.attr("some-attribute", "somevalue")).toEqual(textNode);
|
|
869
|
+
expect(textNode.attr("some-attribute")).toBeUndefined();
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
it("should do nothing when setting or getting on comment nodes", () => {
|
|
873
|
+
const comment = jqLite(window.document.createComment("some comment"));
|
|
874
|
+
expect(comment).toBeDefined();
|
|
875
|
+
expect(comment[0].nodeType).toEqual(8);
|
|
876
|
+
expect(comment.attr("some-attribute", "somevalue")).toEqual(comment);
|
|
877
|
+
expect(comment.attr("some-attribute")).toBeUndefined();
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
it("should remove the attribute for a null value", () => {
|
|
881
|
+
const elm = jqLite('<div attribute="value">a</div>');
|
|
882
|
+
elm.attr("attribute", null);
|
|
883
|
+
expect(elm[0].hasAttribute("attribute")).toBe(false);
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
it("should not remove the attribute for an empty string as a value", () => {
|
|
887
|
+
const elm = jqLite('<div attribute="value">a</div>');
|
|
888
|
+
elm.attr("attribute", "");
|
|
889
|
+
expect(elm[0].getAttribute("attribute")).toBe("");
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
it("should remove the boolean attribute for a false value", () => {
|
|
893
|
+
const elm = jqLite("<select multiple>");
|
|
894
|
+
elm.attr("multiple", false);
|
|
895
|
+
expect(elm[0].hasAttribute("multiple")).toBe(false);
|
|
896
|
+
});
|
|
897
|
+
|
|
898
|
+
it("should remove the boolean attribute for a null value", () => {
|
|
899
|
+
const elm = jqLite("<select multiple>");
|
|
900
|
+
elm.attr("multiple", null);
|
|
901
|
+
expect(elm[0].hasAttribute("multiple")).toBe(false);
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
it("should not remove the boolean attribute for an empty string as a value", () => {
|
|
905
|
+
const elm = jqLite("<select multiple>");
|
|
906
|
+
elm.attr("multiple", "");
|
|
907
|
+
expect(elm[0].getAttribute("multiple")).toBe("multiple");
|
|
908
|
+
});
|
|
909
|
+
|
|
910
|
+
it("should not fail on elements without the getAttribute method", () => {
|
|
911
|
+
forEach([window, document], (node) => {
|
|
912
|
+
expect(() => {
|
|
913
|
+
const elem = jqLite(node);
|
|
914
|
+
elem.attr("foo");
|
|
915
|
+
elem.attr("bar", "baz");
|
|
916
|
+
elem.attr("bar");
|
|
917
|
+
}).not.toThrow();
|
|
918
|
+
});
|
|
919
|
+
});
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
describe("prop", () => {
|
|
923
|
+
it("should read element property", () => {
|
|
924
|
+
const elm = jqLite('<div class="foo">a</div>');
|
|
925
|
+
expect(elm.prop("className")).toBe("foo");
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
it("should set element property to a value", () => {
|
|
929
|
+
const elm = jqLite('<div class="foo">a</div>');
|
|
930
|
+
elm.prop("className", "bar");
|
|
931
|
+
expect(elm[0].className).toBe("bar");
|
|
932
|
+
expect(elm.prop("className")).toBe("bar");
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
it("should set boolean element property", () => {
|
|
936
|
+
const elm = jqLite('<input type="checkbox">');
|
|
937
|
+
expect(elm.prop("checked")).toBe(false);
|
|
938
|
+
|
|
939
|
+
elm.prop("checked", true);
|
|
940
|
+
expect(elm.prop("checked")).toBe(true);
|
|
941
|
+
|
|
942
|
+
elm.prop("checked", "");
|
|
943
|
+
expect(elm.prop("checked")).toBe(false);
|
|
944
|
+
|
|
945
|
+
elm.prop("checked", "lala");
|
|
946
|
+
expect(elm.prop("checked")).toBe(true);
|
|
947
|
+
|
|
948
|
+
elm.prop("checked", null);
|
|
949
|
+
expect(elm.prop("checked")).toBe(false);
|
|
950
|
+
});
|
|
951
|
+
});
|
|
952
|
+
|
|
953
|
+
describe("text", () => {
|
|
954
|
+
it('should return `""` on empty', () => {
|
|
955
|
+
expect(jqLite().length).toEqual(0);
|
|
956
|
+
expect(jqLite().text()).toEqual("");
|
|
957
|
+
});
|
|
958
|
+
|
|
959
|
+
it("should read/write value", () => {
|
|
960
|
+
const element = jqLite("<div>ab</div><span>c</span>");
|
|
961
|
+
expect(element.length).toEqual(2);
|
|
962
|
+
expect(element[0].innerHTML).toEqual("ab");
|
|
963
|
+
expect(element[1].innerHTML).toEqual("c");
|
|
964
|
+
expect(element.text()).toEqual("abc");
|
|
965
|
+
expect(element.text("xyz") === element).toBeTruthy();
|
|
966
|
+
expect(element.text()).toEqual("xyzxyz");
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
it("should return text only for element or text nodes", () => {
|
|
970
|
+
expect(jqLite("<div>foo</div>").text()).toBe("foo");
|
|
971
|
+
expect(jqLite(window.document.createComment("foo")).text()).toBe("");
|
|
972
|
+
});
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
describe("val", () => {
|
|
976
|
+
it("should read, write value", () => {
|
|
977
|
+
const input = jqLite('<input type="text"/>');
|
|
978
|
+
expect(input.val("abc")).toEqual(input);
|
|
979
|
+
expect(input[0].value).toEqual("abc");
|
|
980
|
+
expect(input.val()).toEqual("abc");
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
it("should get an array of selected elements from a multi select", () => {
|
|
984
|
+
expect(
|
|
985
|
+
jqLite(
|
|
986
|
+
"<select multiple>" +
|
|
987
|
+
"<option selected>test 1</option>" +
|
|
988
|
+
"<option selected>test 2</option>" +
|
|
989
|
+
"</select>",
|
|
990
|
+
).val(),
|
|
991
|
+
).toEqual(["test 1", "test 2"]);
|
|
992
|
+
|
|
993
|
+
expect(
|
|
994
|
+
jqLite(
|
|
995
|
+
"<select multiple>" +
|
|
996
|
+
"<option selected>test 1</option>" +
|
|
997
|
+
"<option>test 2</option>" +
|
|
998
|
+
"</select>",
|
|
999
|
+
).val(),
|
|
1000
|
+
).toEqual(["test 1"]);
|
|
1001
|
+
|
|
1002
|
+
// In jQuery < 3.0 .val() on select[multiple] with no selected options returns an
|
|
1003
|
+
// null instead of an empty array.
|
|
1004
|
+
expect(
|
|
1005
|
+
jqLite(
|
|
1006
|
+
"<select multiple>" +
|
|
1007
|
+
"<option>test 1</option>" +
|
|
1008
|
+
"<option>test 2</option>" +
|
|
1009
|
+
"</select>",
|
|
1010
|
+
).val(),
|
|
1011
|
+
).toEqual([]);
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
it("should get an empty array from a multi select if no elements are chosen", () => {
|
|
1015
|
+
// In jQuery < 3.0 .val() on select[multiple] with no selected options returns an
|
|
1016
|
+
// null instead of an empty array.
|
|
1017
|
+
// See https://github.com/jquery/jquery/issues/2562 for more details.
|
|
1018
|
+
|
|
1019
|
+
expect(
|
|
1020
|
+
jqLite(
|
|
1021
|
+
"<select multiple>" +
|
|
1022
|
+
"<optgroup>" +
|
|
1023
|
+
"<option>test 1</option>" +
|
|
1024
|
+
"<option>test 2</option>" +
|
|
1025
|
+
"</optgroup>" +
|
|
1026
|
+
"<option>test 3</option>" +
|
|
1027
|
+
"</select>",
|
|
1028
|
+
).val(),
|
|
1029
|
+
).toEqual([]);
|
|
1030
|
+
|
|
1031
|
+
expect(
|
|
1032
|
+
jqLite(
|
|
1033
|
+
"<select multiple>" +
|
|
1034
|
+
"<optgroup disabled>" +
|
|
1035
|
+
"<option>test 1</option>" +
|
|
1036
|
+
"<option>test 2</option>" +
|
|
1037
|
+
"</optgroup>" +
|
|
1038
|
+
"<option disabled>test 3</option>" +
|
|
1039
|
+
"</select>",
|
|
1040
|
+
).val(),
|
|
1041
|
+
).toEqual([]);
|
|
1042
|
+
});
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
describe("html", () => {
|
|
1046
|
+
it("should return `undefined` on empty", () => {
|
|
1047
|
+
expect(jqLite().length).toEqual(0);
|
|
1048
|
+
expect(jqLite().html()).toEqual(undefined);
|
|
1049
|
+
});
|
|
1050
|
+
|
|
1051
|
+
it("should read/write a value", () => {
|
|
1052
|
+
const element = jqLite("<div>abc</div>");
|
|
1053
|
+
expect(element.length).toEqual(1);
|
|
1054
|
+
expect(element[0].innerHTML).toEqual("abc");
|
|
1055
|
+
expect(element.html()).toEqual("abc");
|
|
1056
|
+
expect(element.html("xyz") === element).toBeTruthy();
|
|
1057
|
+
expect(element.html()).toEqual("xyz");
|
|
1058
|
+
});
|
|
1059
|
+
});
|
|
1060
|
+
|
|
1061
|
+
describe("empty", () => {
|
|
1062
|
+
it("should write a value", () => {
|
|
1063
|
+
const element = jqLite("<div>abc</div>");
|
|
1064
|
+
expect(element.length).toEqual(1);
|
|
1065
|
+
expect(element.empty() === element).toBeTruthy();
|
|
1066
|
+
expect(element.html()).toEqual("");
|
|
1067
|
+
});
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
describe("on", () => {
|
|
1071
|
+
it("should bind to window on hashchange", () => {
|
|
1072
|
+
let eventFn;
|
|
1073
|
+
const window = {
|
|
1074
|
+
document: {},
|
|
1075
|
+
location: {},
|
|
1076
|
+
alert: () => {},
|
|
1077
|
+
setInterval: () => {},
|
|
1078
|
+
length: 10, // pretend you are an array
|
|
1079
|
+
addEventListener(type, fn) {
|
|
1080
|
+
expect(type).toEqual("hashchange");
|
|
1081
|
+
eventFn = fn;
|
|
1082
|
+
},
|
|
1083
|
+
removeEventListener: () => {},
|
|
1084
|
+
};
|
|
1085
|
+
window.window = window;
|
|
1086
|
+
|
|
1087
|
+
let log;
|
|
1088
|
+
const jWindow = jqLite(window).on("hashchange", () => {
|
|
1089
|
+
log = "works!";
|
|
1090
|
+
});
|
|
1091
|
+
eventFn({ type: "hashchange" });
|
|
1092
|
+
expect(log).toEqual("works!");
|
|
1093
|
+
dealoc(jWindow);
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
it("should bind to all elements and return functions", () => {
|
|
1097
|
+
const selected = jqLite([a, b]);
|
|
1098
|
+
let log = "";
|
|
1099
|
+
expect(
|
|
1100
|
+
selected.on("click", function () {
|
|
1101
|
+
log += `click on: ${jqLite(this).text()};`;
|
|
1102
|
+
}),
|
|
1103
|
+
).toEqual(selected);
|
|
1104
|
+
browserTrigger(a, "click");
|
|
1105
|
+
expect(log).toEqual("click on: A;");
|
|
1106
|
+
browserTrigger(b, "click");
|
|
1107
|
+
expect(log).toEqual("click on: A;click on: B;");
|
|
1108
|
+
});
|
|
1109
|
+
|
|
1110
|
+
it("should not bind to comment or text nodes", () => {
|
|
1111
|
+
const nodes = jqLite("<!-- some comment -->Some text");
|
|
1112
|
+
const someEventHandler = jasmine.createSpy("someEventHandler");
|
|
1113
|
+
|
|
1114
|
+
nodes.on("someEvent", someEventHandler);
|
|
1115
|
+
nodes.triggerHandler("someEvent");
|
|
1116
|
+
|
|
1117
|
+
expect(someEventHandler).not.toHaveBeenCalled();
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
it("should bind to all events separated by space", () => {
|
|
1121
|
+
const elm = jqLite(a);
|
|
1122
|
+
const callback = jasmine.createSpy("callback");
|
|
1123
|
+
|
|
1124
|
+
elm.on("click keypress", callback);
|
|
1125
|
+
elm.on("click", callback);
|
|
1126
|
+
|
|
1127
|
+
browserTrigger(a, "click");
|
|
1128
|
+
expect(callback).toHaveBeenCalled();
|
|
1129
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
1130
|
+
|
|
1131
|
+
callback.calls.reset();
|
|
1132
|
+
browserTrigger(a, "keypress");
|
|
1133
|
+
expect(callback).toHaveBeenCalled();
|
|
1134
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
it("should set event.target", () => {
|
|
1138
|
+
const elm = jqLite(a);
|
|
1139
|
+
elm.on("click", (event) => {
|
|
1140
|
+
expect(event.target).toBe(a);
|
|
1141
|
+
});
|
|
1142
|
+
|
|
1143
|
+
browserTrigger(a, "click");
|
|
1144
|
+
});
|
|
1145
|
+
|
|
1146
|
+
it("should have event.isDefaultPrevented method", () => {
|
|
1147
|
+
const element = jqLite(a);
|
|
1148
|
+
|
|
1149
|
+
element.on("click", (e) => {
|
|
1150
|
+
expect(e.isDefaultPrevented()).toBe(false);
|
|
1151
|
+
e.preventDefault();
|
|
1152
|
+
expect(e.isDefaultPrevented()).toBe(true);
|
|
1153
|
+
});
|
|
1154
|
+
|
|
1155
|
+
browserTrigger(a, "click");
|
|
1156
|
+
});
|
|
1157
|
+
|
|
1158
|
+
it("should stop triggering handlers when stopImmediatePropagation is called", () => {
|
|
1159
|
+
const element = jqLite(a);
|
|
1160
|
+
const clickSpy1 = jasmine.createSpy("clickSpy1");
|
|
1161
|
+
const clickSpy2 = jasmine.createSpy("clickSpy2").and.callFake((event) => {
|
|
1162
|
+
event.stopImmediatePropagation();
|
|
1163
|
+
});
|
|
1164
|
+
const clickSpy3 = jasmine.createSpy("clickSpy3");
|
|
1165
|
+
const clickSpy4 = jasmine.createSpy("clickSpy4");
|
|
1166
|
+
|
|
1167
|
+
element.on("click", clickSpy1);
|
|
1168
|
+
element.on("click", clickSpy2);
|
|
1169
|
+
element.on("click", clickSpy3);
|
|
1170
|
+
element[0].addEventListener("click", clickSpy4);
|
|
1171
|
+
|
|
1172
|
+
browserTrigger(element, "click");
|
|
1173
|
+
|
|
1174
|
+
expect(clickSpy1).toHaveBeenCalled();
|
|
1175
|
+
expect(clickSpy2).toHaveBeenCalled();
|
|
1176
|
+
expect(clickSpy3).not.toHaveBeenCalled();
|
|
1177
|
+
expect(clickSpy4).not.toHaveBeenCalled();
|
|
1178
|
+
});
|
|
1179
|
+
|
|
1180
|
+
it("should execute stopPropagation when stopImmediatePropagation is called", () => {
|
|
1181
|
+
const element = jqLite(a);
|
|
1182
|
+
const clickSpy = jasmine.createSpy("clickSpy");
|
|
1183
|
+
|
|
1184
|
+
clickSpy.and.callFake((event) => {
|
|
1185
|
+
spyOn(event, "stopPropagation");
|
|
1186
|
+
event.stopImmediatePropagation();
|
|
1187
|
+
expect(event.stopPropagation).toHaveBeenCalled();
|
|
1188
|
+
});
|
|
1189
|
+
|
|
1190
|
+
element.on("click", clickSpy);
|
|
1191
|
+
|
|
1192
|
+
browserTrigger(element, "click");
|
|
1193
|
+
expect(clickSpy).toHaveBeenCalled();
|
|
1194
|
+
});
|
|
1195
|
+
|
|
1196
|
+
it("should have event.isImmediatePropagationStopped method", () => {
|
|
1197
|
+
const element = jqLite(a);
|
|
1198
|
+
const clickSpy = jasmine.createSpy("clickSpy");
|
|
1199
|
+
|
|
1200
|
+
clickSpy.and.callFake((event) => {
|
|
1201
|
+
expect(event.isImmediatePropagationStopped()).toBe(false);
|
|
1202
|
+
event.stopImmediatePropagation();
|
|
1203
|
+
expect(event.isImmediatePropagationStopped()).toBe(true);
|
|
1204
|
+
});
|
|
1205
|
+
|
|
1206
|
+
element.on("click", clickSpy);
|
|
1207
|
+
|
|
1208
|
+
browserTrigger(element, "click");
|
|
1209
|
+
expect(clickSpy).toHaveBeenCalled();
|
|
1210
|
+
});
|
|
1211
|
+
|
|
1212
|
+
describe("mouseenter-mouseleave", () => {
|
|
1213
|
+
let root;
|
|
1214
|
+
let parent;
|
|
1215
|
+
let child;
|
|
1216
|
+
let log;
|
|
1217
|
+
|
|
1218
|
+
function setup(html, parentNode, childNode) {
|
|
1219
|
+
log = "";
|
|
1220
|
+
root = jqLite(html);
|
|
1221
|
+
parent = root.find(parentNode);
|
|
1222
|
+
child = parent.find(childNode);
|
|
1223
|
+
|
|
1224
|
+
parent.on("mouseenter", () => {
|
|
1225
|
+
log += "parentEnter;";
|
|
1226
|
+
});
|
|
1227
|
+
parent.on("mouseleave", () => {
|
|
1228
|
+
log += "parentLeave;";
|
|
1229
|
+
});
|
|
1230
|
+
|
|
1231
|
+
child.on("mouseenter", () => {
|
|
1232
|
+
log += "childEnter;";
|
|
1233
|
+
});
|
|
1234
|
+
child.on("mouseleave", () => {
|
|
1235
|
+
log += "childLeave;";
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
function browserMoveTrigger(from, to) {
|
|
1240
|
+
const fireEvent = function (type, element, relatedTarget) {
|
|
1241
|
+
let evnt;
|
|
1242
|
+
evnt = window.document.createEvent("MouseEvents");
|
|
1243
|
+
|
|
1244
|
+
const originalPreventDefault = evnt.preventDefault;
|
|
1245
|
+
|
|
1246
|
+
evnt.preventDefault = () => {
|
|
1247
|
+
fakeProcessDefault = false;
|
|
1248
|
+
return originalPreventDefault.apply(evnt, arguments);
|
|
1249
|
+
};
|
|
1250
|
+
|
|
1251
|
+
const x = 0;
|
|
1252
|
+
const y = 0;
|
|
1253
|
+
evnt.initMouseEvent(
|
|
1254
|
+
type,
|
|
1255
|
+
true,
|
|
1256
|
+
true,
|
|
1257
|
+
window,
|
|
1258
|
+
0,
|
|
1259
|
+
x,
|
|
1260
|
+
y,
|
|
1261
|
+
x,
|
|
1262
|
+
y,
|
|
1263
|
+
false,
|
|
1264
|
+
false,
|
|
1265
|
+
false,
|
|
1266
|
+
false,
|
|
1267
|
+
0,
|
|
1268
|
+
relatedTarget,
|
|
1269
|
+
);
|
|
1270
|
+
|
|
1271
|
+
element.dispatchEvent(evnt);
|
|
1272
|
+
};
|
|
1273
|
+
fireEvent("mouseout", from[0], to[0]);
|
|
1274
|
+
fireEvent("mouseover", to[0], from[0]);
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
afterEach(() => {
|
|
1278
|
+
dealoc(root);
|
|
1279
|
+
});
|
|
1280
|
+
|
|
1281
|
+
it("should fire mouseenter when coming from outside the browser window", () => {
|
|
1282
|
+
setup(
|
|
1283
|
+
"<div>root<p>parent<span>child</span></p><ul></ul></div>",
|
|
1284
|
+
"p",
|
|
1285
|
+
"span",
|
|
1286
|
+
);
|
|
1287
|
+
|
|
1288
|
+
browserMoveTrigger(root, parent);
|
|
1289
|
+
expect(log).toEqual("parentEnter;");
|
|
1290
|
+
|
|
1291
|
+
browserMoveTrigger(parent, child);
|
|
1292
|
+
expect(log).toEqual("parentEnter;childEnter;");
|
|
1293
|
+
|
|
1294
|
+
browserMoveTrigger(child, parent);
|
|
1295
|
+
expect(log).toEqual("parentEnter;childEnter;childLeave;");
|
|
1296
|
+
|
|
1297
|
+
browserMoveTrigger(parent, root);
|
|
1298
|
+
expect(log).toEqual("parentEnter;childEnter;childLeave;parentLeave;");
|
|
1299
|
+
});
|
|
1300
|
+
|
|
1301
|
+
it("should fire the mousenter on SVG elements", () => {
|
|
1302
|
+
setup(
|
|
1303
|
+
"<div>" +
|
|
1304
|
+
'<svg xmlns="http://www.w3.org/2000/svg"' +
|
|
1305
|
+
' viewBox="0 0 18.75 18.75"' +
|
|
1306
|
+
' width="18.75"' +
|
|
1307
|
+
' height="18.75"' +
|
|
1308
|
+
' version="1.1">' +
|
|
1309
|
+
' <path d="M0,0c0,4.142,3.358,7.5,7.5,7.5s7.5-3.358,7.5-7.5-3.358-7.5-7.5-7.5-7.5,3.358-7.5,7.5"' +
|
|
1310
|
+
' fill-rule="nonzero"' +
|
|
1311
|
+
' fill="#CCC"' +
|
|
1312
|
+
" ng-attr-fill=\"{{data.color || '#CCC'}}\"/>" +
|
|
1313
|
+
"</svg>" +
|
|
1314
|
+
"</div>",
|
|
1315
|
+
"svg",
|
|
1316
|
+
"path",
|
|
1317
|
+
);
|
|
1318
|
+
|
|
1319
|
+
browserMoveTrigger(parent, child);
|
|
1320
|
+
expect(log).toEqual("childEnter;");
|
|
1321
|
+
});
|
|
1322
|
+
});
|
|
1323
|
+
|
|
1324
|
+
it("should throw an error if eventData or a selector is passed", () => {
|
|
1325
|
+
const elm = jqLite(a);
|
|
1326
|
+
const anObj = {};
|
|
1327
|
+
const aString = "";
|
|
1328
|
+
const aValue = 45;
|
|
1329
|
+
const callback = () => {};
|
|
1330
|
+
|
|
1331
|
+
expect(() => {
|
|
1332
|
+
elm.on("click", anObj, callback);
|
|
1333
|
+
}).toThrow();
|
|
1334
|
+
|
|
1335
|
+
expect(() => {
|
|
1336
|
+
elm.on("click", null, aString, callback);
|
|
1337
|
+
}).toThrow();
|
|
1338
|
+
|
|
1339
|
+
expect(() => {
|
|
1340
|
+
elm.on("click", aValue, callback);
|
|
1341
|
+
}).toThrow();
|
|
1342
|
+
});
|
|
1343
|
+
});
|
|
1344
|
+
|
|
1345
|
+
describe("off", () => {
|
|
1346
|
+
it("should do nothing when no listener was registered with bound", () => {
|
|
1347
|
+
const aElem = jqLite(a);
|
|
1348
|
+
|
|
1349
|
+
aElem.off();
|
|
1350
|
+
aElem.off("click");
|
|
1351
|
+
aElem.off("click", () => {});
|
|
1352
|
+
});
|
|
1353
|
+
|
|
1354
|
+
it("should do nothing when a specific listener was not registered", () => {
|
|
1355
|
+
const aElem = jqLite(a);
|
|
1356
|
+
aElem.on("click", () => {});
|
|
1357
|
+
|
|
1358
|
+
aElem.off("mouseenter", () => {});
|
|
1359
|
+
});
|
|
1360
|
+
|
|
1361
|
+
it("should deregister all listeners", () => {
|
|
1362
|
+
const aElem = jqLite(a);
|
|
1363
|
+
const clickSpy = jasmine.createSpy("click");
|
|
1364
|
+
const mouseoverSpy = jasmine.createSpy("mouseover");
|
|
1365
|
+
|
|
1366
|
+
aElem.on("click", clickSpy);
|
|
1367
|
+
aElem.on("mouseover", mouseoverSpy);
|
|
1368
|
+
|
|
1369
|
+
browserTrigger(a, "click");
|
|
1370
|
+
expect(clickSpy).toHaveBeenCalled();
|
|
1371
|
+
browserTrigger(a, "mouseover");
|
|
1372
|
+
expect(mouseoverSpy).toHaveBeenCalled();
|
|
1373
|
+
|
|
1374
|
+
clickSpy.calls.reset();
|
|
1375
|
+
mouseoverSpy.calls.reset();
|
|
1376
|
+
|
|
1377
|
+
aElem.off();
|
|
1378
|
+
|
|
1379
|
+
browserTrigger(a, "click");
|
|
1380
|
+
expect(clickSpy).not.toHaveBeenCalled();
|
|
1381
|
+
browserTrigger(a, "mouseover");
|
|
1382
|
+
expect(mouseoverSpy).not.toHaveBeenCalled();
|
|
1383
|
+
});
|
|
1384
|
+
|
|
1385
|
+
it("should deregister listeners for specific type", () => {
|
|
1386
|
+
const aElem = jqLite(a);
|
|
1387
|
+
const clickSpy = jasmine.createSpy("click");
|
|
1388
|
+
const mouseoverSpy = jasmine.createSpy("mouseover");
|
|
1389
|
+
|
|
1390
|
+
aElem.on("click", clickSpy);
|
|
1391
|
+
aElem.on("mouseover", mouseoverSpy);
|
|
1392
|
+
|
|
1393
|
+
browserTrigger(a, "click");
|
|
1394
|
+
expect(clickSpy).toHaveBeenCalled();
|
|
1395
|
+
browserTrigger(a, "mouseover");
|
|
1396
|
+
expect(mouseoverSpy).toHaveBeenCalled();
|
|
1397
|
+
|
|
1398
|
+
clickSpy.calls.reset();
|
|
1399
|
+
mouseoverSpy.calls.reset();
|
|
1400
|
+
|
|
1401
|
+
aElem.off("click");
|
|
1402
|
+
|
|
1403
|
+
browserTrigger(a, "click");
|
|
1404
|
+
expect(clickSpy).not.toHaveBeenCalled();
|
|
1405
|
+
browserTrigger(a, "mouseover");
|
|
1406
|
+
expect(mouseoverSpy).toHaveBeenCalled();
|
|
1407
|
+
|
|
1408
|
+
mouseoverSpy.calls.reset();
|
|
1409
|
+
|
|
1410
|
+
aElem.off("mouseover");
|
|
1411
|
+
browserTrigger(a, "mouseover");
|
|
1412
|
+
expect(mouseoverSpy).not.toHaveBeenCalled();
|
|
1413
|
+
});
|
|
1414
|
+
|
|
1415
|
+
it("should deregister all listeners for types separated by spaces", () => {
|
|
1416
|
+
const aElem = jqLite(a);
|
|
1417
|
+
const clickSpy = jasmine.createSpy("click");
|
|
1418
|
+
const mouseoverSpy = jasmine.createSpy("mouseover");
|
|
1419
|
+
|
|
1420
|
+
aElem.on("click", clickSpy);
|
|
1421
|
+
aElem.on("mouseover", mouseoverSpy);
|
|
1422
|
+
|
|
1423
|
+
browserTrigger(a, "click");
|
|
1424
|
+
expect(clickSpy).toHaveBeenCalled();
|
|
1425
|
+
browserTrigger(a, "mouseover");
|
|
1426
|
+
expect(mouseoverSpy).toHaveBeenCalled();
|
|
1427
|
+
|
|
1428
|
+
clickSpy.calls.reset();
|
|
1429
|
+
mouseoverSpy.calls.reset();
|
|
1430
|
+
|
|
1431
|
+
aElem.off("click mouseover");
|
|
1432
|
+
|
|
1433
|
+
browserTrigger(a, "click");
|
|
1434
|
+
expect(clickSpy).not.toHaveBeenCalled();
|
|
1435
|
+
browserTrigger(a, "mouseover");
|
|
1436
|
+
expect(mouseoverSpy).not.toHaveBeenCalled();
|
|
1437
|
+
});
|
|
1438
|
+
|
|
1439
|
+
it("should deregister specific listener", () => {
|
|
1440
|
+
const aElem = jqLite(a);
|
|
1441
|
+
const clickSpy1 = jasmine.createSpy("click1");
|
|
1442
|
+
const clickSpy2 = jasmine.createSpy("click2");
|
|
1443
|
+
|
|
1444
|
+
aElem.on("click", clickSpy1);
|
|
1445
|
+
aElem.on("click", clickSpy2);
|
|
1446
|
+
|
|
1447
|
+
browserTrigger(a, "click");
|
|
1448
|
+
expect(clickSpy1).toHaveBeenCalled();
|
|
1449
|
+
expect(clickSpy2).toHaveBeenCalled();
|
|
1450
|
+
|
|
1451
|
+
clickSpy1.calls.reset();
|
|
1452
|
+
clickSpy2.calls.reset();
|
|
1453
|
+
|
|
1454
|
+
aElem.off("click", clickSpy1);
|
|
1455
|
+
|
|
1456
|
+
browserTrigger(a, "click");
|
|
1457
|
+
expect(clickSpy1).not.toHaveBeenCalled();
|
|
1458
|
+
expect(clickSpy2).toHaveBeenCalled();
|
|
1459
|
+
|
|
1460
|
+
clickSpy2.calls.reset();
|
|
1461
|
+
|
|
1462
|
+
aElem.off("click", clickSpy2);
|
|
1463
|
+
browserTrigger(a, "click");
|
|
1464
|
+
expect(clickSpy2).not.toHaveBeenCalled();
|
|
1465
|
+
});
|
|
1466
|
+
|
|
1467
|
+
it("should correctly deregister the mouseenter/mouseleave listeners", () => {
|
|
1468
|
+
const aElem = jqLite(a);
|
|
1469
|
+
const onMouseenter = jasmine.createSpy("onMouseenter");
|
|
1470
|
+
const onMouseleave = jasmine.createSpy("onMouseleave");
|
|
1471
|
+
|
|
1472
|
+
aElem.on("mouseenter", onMouseenter);
|
|
1473
|
+
aElem.on("mouseleave", onMouseleave);
|
|
1474
|
+
aElem.off("mouseenter", onMouseenter);
|
|
1475
|
+
aElem.off("mouseleave", onMouseleave);
|
|
1476
|
+
aElem.on("mouseenter", onMouseenter);
|
|
1477
|
+
aElem.on("mouseleave", onMouseleave);
|
|
1478
|
+
|
|
1479
|
+
browserTrigger(a, "mouseover");
|
|
1480
|
+
expect(onMouseenter).toHaveBeenCalled();
|
|
1481
|
+
|
|
1482
|
+
browserTrigger(a, "mouseout");
|
|
1483
|
+
expect(onMouseleave).toHaveBeenCalled();
|
|
1484
|
+
});
|
|
1485
|
+
|
|
1486
|
+
it(
|
|
1487
|
+
"should call a `mouseenter/leave` listener only once when `mouseenter/leave` and `mouseover/out` " +
|
|
1488
|
+
"are triggered simultaneously",
|
|
1489
|
+
() => {
|
|
1490
|
+
const aElem = jqLite(a);
|
|
1491
|
+
const onMouseenter = jasmine.createSpy("mouseenter");
|
|
1492
|
+
const onMouseleave = jasmine.createSpy("mouseleave");
|
|
1493
|
+
|
|
1494
|
+
aElem.on("mouseenter", onMouseenter);
|
|
1495
|
+
aElem.on("mouseleave", onMouseleave);
|
|
1496
|
+
|
|
1497
|
+
browserTrigger(a, "mouseenter");
|
|
1498
|
+
browserTrigger(a, "mouseover");
|
|
1499
|
+
expect(onMouseenter).toHaveBeenCalled();
|
|
1500
|
+
|
|
1501
|
+
browserTrigger(a, "mouseleave");
|
|
1502
|
+
browserTrigger(a, "mouseout");
|
|
1503
|
+
expect(onMouseleave).toHaveBeenCalled();
|
|
1504
|
+
},
|
|
1505
|
+
);
|
|
1506
|
+
|
|
1507
|
+
it("should call a `mouseenter/leave` listener when manually triggering the event", () => {
|
|
1508
|
+
const aElem = jqLite(a);
|
|
1509
|
+
const onMouseenter = jasmine.createSpy("mouseenter");
|
|
1510
|
+
const onMouseleave = jasmine.createSpy("mouseleave");
|
|
1511
|
+
|
|
1512
|
+
aElem.on("mouseenter", onMouseenter);
|
|
1513
|
+
aElem.on("mouseleave", onMouseleave);
|
|
1514
|
+
|
|
1515
|
+
aElem.triggerHandler("mouseenter");
|
|
1516
|
+
expect(onMouseenter).toHaveBeenCalled();
|
|
1517
|
+
|
|
1518
|
+
aElem.triggerHandler("mouseleave");
|
|
1519
|
+
expect(onMouseleave).toHaveBeenCalled();
|
|
1520
|
+
});
|
|
1521
|
+
|
|
1522
|
+
it("should deregister specific listener within the listener and call subsequent listeners", () => {
|
|
1523
|
+
const aElem = jqLite(a);
|
|
1524
|
+
const clickSpy = jasmine.createSpy("click");
|
|
1525
|
+
const clickOnceSpy = jasmine.createSpy("clickOnce").and.callFake(() => {
|
|
1526
|
+
aElem.off("click", clickOnceSpy);
|
|
1527
|
+
});
|
|
1528
|
+
|
|
1529
|
+
aElem.on("click", clickOnceSpy);
|
|
1530
|
+
aElem.on("click", clickSpy);
|
|
1531
|
+
|
|
1532
|
+
browserTrigger(a, "click");
|
|
1533
|
+
expect(clickOnceSpy).toHaveBeenCalled();
|
|
1534
|
+
expect(clickSpy).toHaveBeenCalled();
|
|
1535
|
+
|
|
1536
|
+
browserTrigger(a, "click");
|
|
1537
|
+
expect(clickOnceSpy).toHaveBeenCalled();
|
|
1538
|
+
expect(clickSpy).toHaveBeenCalledTimes(2);
|
|
1539
|
+
});
|
|
1540
|
+
|
|
1541
|
+
it("should deregister specific listener for multiple types separated by spaces", () => {
|
|
1542
|
+
const aElem = jqLite(a);
|
|
1543
|
+
const leaderSpy = jasmine.createSpy("leader");
|
|
1544
|
+
const extraSpy = jasmine.createSpy("extra");
|
|
1545
|
+
|
|
1546
|
+
aElem.on("click", leaderSpy);
|
|
1547
|
+
aElem.on("click", extraSpy);
|
|
1548
|
+
aElem.on("mouseover", leaderSpy);
|
|
1549
|
+
|
|
1550
|
+
browserTrigger(a, "click");
|
|
1551
|
+
browserTrigger(a, "mouseover");
|
|
1552
|
+
expect(leaderSpy).toHaveBeenCalledTimes(2);
|
|
1553
|
+
expect(extraSpy).toHaveBeenCalled();
|
|
1554
|
+
|
|
1555
|
+
leaderSpy.calls.reset();
|
|
1556
|
+
extraSpy.calls.reset();
|
|
1557
|
+
|
|
1558
|
+
aElem.off("click mouseover", leaderSpy);
|
|
1559
|
+
|
|
1560
|
+
browserTrigger(a, "click");
|
|
1561
|
+
browserTrigger(a, "mouseover");
|
|
1562
|
+
expect(leaderSpy).not.toHaveBeenCalled();
|
|
1563
|
+
expect(extraSpy).toHaveBeenCalled();
|
|
1564
|
+
});
|
|
1565
|
+
|
|
1566
|
+
describe("native listener deregistration", () => {
|
|
1567
|
+
it(
|
|
1568
|
+
"should deregister the native listener when all jqLite listeners for given type are gone " +
|
|
1569
|
+
'after off("eventName", listener) call',
|
|
1570
|
+
() => {
|
|
1571
|
+
const aElem = jqLite(a);
|
|
1572
|
+
const addEventListenerSpy = spyOn(
|
|
1573
|
+
aElem[0],
|
|
1574
|
+
"addEventListener",
|
|
1575
|
+
).and.callThrough();
|
|
1576
|
+
const removeEventListenerSpy = spyOn(
|
|
1577
|
+
aElem[0],
|
|
1578
|
+
"removeEventListener",
|
|
1579
|
+
).and.callThrough();
|
|
1580
|
+
let nativeListenerFn;
|
|
1581
|
+
|
|
1582
|
+
const jqLiteListener = () => {};
|
|
1583
|
+
aElem.on("click", jqLiteListener);
|
|
1584
|
+
|
|
1585
|
+
expect(addEventListenerSpy).toHaveBeenCalledOnceWith(
|
|
1586
|
+
"click",
|
|
1587
|
+
jasmine.any(Function),
|
|
1588
|
+
);
|
|
1589
|
+
nativeListenerFn = addEventListenerSpy.calls.mostRecent().args[1];
|
|
1590
|
+
expect(removeEventListenerSpy).not.toHaveBeenCalled();
|
|
1591
|
+
|
|
1592
|
+
aElem.off("click", jqLiteListener);
|
|
1593
|
+
expect(removeEventListenerSpy).toHaveBeenCalledOnceWith(
|
|
1594
|
+
"click",
|
|
1595
|
+
nativeListenerFn,
|
|
1596
|
+
);
|
|
1597
|
+
},
|
|
1598
|
+
);
|
|
1599
|
+
|
|
1600
|
+
it(
|
|
1601
|
+
"should deregister the native listener when all jqLite listeners for given type are gone " +
|
|
1602
|
+
'after off("eventName") call',
|
|
1603
|
+
() => {
|
|
1604
|
+
const aElem = jqLite(a);
|
|
1605
|
+
const addEventListenerSpy = spyOn(
|
|
1606
|
+
aElem[0],
|
|
1607
|
+
"addEventListener",
|
|
1608
|
+
).and.callThrough();
|
|
1609
|
+
const removeEventListenerSpy = spyOn(
|
|
1610
|
+
aElem[0],
|
|
1611
|
+
"removeEventListener",
|
|
1612
|
+
).and.callThrough();
|
|
1613
|
+
let nativeListenerFn;
|
|
1614
|
+
|
|
1615
|
+
aElem.on("click", () => {});
|
|
1616
|
+
expect(addEventListenerSpy).toHaveBeenCalledOnceWith(
|
|
1617
|
+
"click",
|
|
1618
|
+
jasmine.any(Function),
|
|
1619
|
+
);
|
|
1620
|
+
nativeListenerFn = addEventListenerSpy.calls.mostRecent().args[1];
|
|
1621
|
+
expect(removeEventListenerSpy).not.toHaveBeenCalled();
|
|
1622
|
+
|
|
1623
|
+
aElem.off("click");
|
|
1624
|
+
expect(removeEventListenerSpy).toHaveBeenCalledOnceWith(
|
|
1625
|
+
"click",
|
|
1626
|
+
nativeListenerFn,
|
|
1627
|
+
);
|
|
1628
|
+
},
|
|
1629
|
+
);
|
|
1630
|
+
|
|
1631
|
+
it(
|
|
1632
|
+
"should deregister the native listener when all jqLite listeners for given type are gone " +
|
|
1633
|
+
'after off("eventName1 eventName2") call',
|
|
1634
|
+
() => {
|
|
1635
|
+
const aElem = jqLite(a);
|
|
1636
|
+
const addEventListenerSpy = spyOn(
|
|
1637
|
+
aElem[0],
|
|
1638
|
+
"addEventListener",
|
|
1639
|
+
).and.callThrough();
|
|
1640
|
+
const removeEventListenerSpy = spyOn(
|
|
1641
|
+
aElem[0],
|
|
1642
|
+
"removeEventListener",
|
|
1643
|
+
).and.callThrough();
|
|
1644
|
+
let nativeListenerFn;
|
|
1645
|
+
|
|
1646
|
+
aElem.on("click", () => {});
|
|
1647
|
+
expect(addEventListenerSpy).toHaveBeenCalledOnceWith(
|
|
1648
|
+
"click",
|
|
1649
|
+
jasmine.any(Function),
|
|
1650
|
+
);
|
|
1651
|
+
nativeListenerFn = addEventListenerSpy.calls.mostRecent().args[1];
|
|
1652
|
+
addEventListenerSpy.calls.reset();
|
|
1653
|
+
|
|
1654
|
+
aElem.on("dblclick", () => {});
|
|
1655
|
+
expect(addEventListenerSpy).toHaveBeenCalledOnceWith(
|
|
1656
|
+
"dblclick",
|
|
1657
|
+
nativeListenerFn,
|
|
1658
|
+
);
|
|
1659
|
+
|
|
1660
|
+
expect(removeEventListenerSpy).not.toHaveBeenCalled();
|
|
1661
|
+
|
|
1662
|
+
aElem.off("click dblclick");
|
|
1663
|
+
|
|
1664
|
+
expect(removeEventListenerSpy).toHaveBeenCalledWith(
|
|
1665
|
+
"click",
|
|
1666
|
+
nativeListenerFn,
|
|
1667
|
+
);
|
|
1668
|
+
expect(removeEventListenerSpy).toHaveBeenCalledWith(
|
|
1669
|
+
"dblclick",
|
|
1670
|
+
nativeListenerFn,
|
|
1671
|
+
);
|
|
1672
|
+
expect(removeEventListenerSpy).toHaveBeenCalledTimes(2);
|
|
1673
|
+
},
|
|
1674
|
+
);
|
|
1675
|
+
|
|
1676
|
+
it(
|
|
1677
|
+
"should deregister the native listener when all jqLite listeners for given type are gone " +
|
|
1678
|
+
"after off() call",
|
|
1679
|
+
() => {
|
|
1680
|
+
const aElem = jqLite(a);
|
|
1681
|
+
const addEventListenerSpy = spyOn(
|
|
1682
|
+
aElem[0],
|
|
1683
|
+
"addEventListener",
|
|
1684
|
+
).and.callThrough();
|
|
1685
|
+
const removeEventListenerSpy = spyOn(
|
|
1686
|
+
aElem[0],
|
|
1687
|
+
"removeEventListener",
|
|
1688
|
+
).and.callThrough();
|
|
1689
|
+
let nativeListenerFn;
|
|
1690
|
+
|
|
1691
|
+
aElem.on("click", () => {});
|
|
1692
|
+
expect(addEventListenerSpy).toHaveBeenCalledOnceWith(
|
|
1693
|
+
"click",
|
|
1694
|
+
jasmine.any(Function),
|
|
1695
|
+
);
|
|
1696
|
+
nativeListenerFn = addEventListenerSpy.calls.mostRecent().args[1];
|
|
1697
|
+
addEventListenerSpy.calls.reset();
|
|
1698
|
+
|
|
1699
|
+
aElem.on("dblclick", () => {});
|
|
1700
|
+
expect(addEventListenerSpy).toHaveBeenCalledOnceWith(
|
|
1701
|
+
"dblclick",
|
|
1702
|
+
nativeListenerFn,
|
|
1703
|
+
);
|
|
1704
|
+
|
|
1705
|
+
aElem.off();
|
|
1706
|
+
|
|
1707
|
+
expect(removeEventListenerSpy).toHaveBeenCalledWith(
|
|
1708
|
+
"click",
|
|
1709
|
+
nativeListenerFn,
|
|
1710
|
+
);
|
|
1711
|
+
expect(removeEventListenerSpy).toHaveBeenCalledWith(
|
|
1712
|
+
"dblclick",
|
|
1713
|
+
nativeListenerFn,
|
|
1714
|
+
);
|
|
1715
|
+
expect(removeEventListenerSpy).toHaveBeenCalledTimes(2);
|
|
1716
|
+
},
|
|
1717
|
+
);
|
|
1718
|
+
});
|
|
1719
|
+
|
|
1720
|
+
it("should throw an error if a selector is passed", () => {
|
|
1721
|
+
const aElem = jqLite(a);
|
|
1722
|
+
aElem.on("click", () => {});
|
|
1723
|
+
expect(() => {
|
|
1724
|
+
aElem.off("click", () => {}, ".test");
|
|
1725
|
+
}).toThrow();
|
|
1726
|
+
});
|
|
1727
|
+
});
|
|
1728
|
+
|
|
1729
|
+
describe("one", () => {
|
|
1730
|
+
it("should only fire the callback once", () => {
|
|
1731
|
+
const element = jqLite(a);
|
|
1732
|
+
const spy = jasmine.createSpy("click");
|
|
1733
|
+
|
|
1734
|
+
element.one("click", spy);
|
|
1735
|
+
browserTrigger(element, "click");
|
|
1736
|
+
expect(spy).toHaveBeenCalled();
|
|
1737
|
+
|
|
1738
|
+
browserTrigger(element, "click");
|
|
1739
|
+
expect(spy).toHaveBeenCalled();
|
|
1740
|
+
});
|
|
1741
|
+
|
|
1742
|
+
it("should deregister when off is called", () => {
|
|
1743
|
+
const element = jqLite(a);
|
|
1744
|
+
const spy = jasmine.createSpy("click");
|
|
1745
|
+
|
|
1746
|
+
element.one("click", spy);
|
|
1747
|
+
element.off("click", spy);
|
|
1748
|
+
|
|
1749
|
+
browserTrigger(element, "click");
|
|
1750
|
+
expect(spy).not.toHaveBeenCalled();
|
|
1751
|
+
});
|
|
1752
|
+
|
|
1753
|
+
it("should return the same event object just as on() does", () => {
|
|
1754
|
+
const element = jqLite(a);
|
|
1755
|
+
let eventA;
|
|
1756
|
+
let eventB;
|
|
1757
|
+
element.on("click", (event) => {
|
|
1758
|
+
eventA = event;
|
|
1759
|
+
});
|
|
1760
|
+
element.one("click", (event) => {
|
|
1761
|
+
eventB = event;
|
|
1762
|
+
});
|
|
1763
|
+
|
|
1764
|
+
browserTrigger(element, "click");
|
|
1765
|
+
expect(eventA).toEqual(eventB);
|
|
1766
|
+
});
|
|
1767
|
+
|
|
1768
|
+
it("should not remove other event handlers of the same type after execution", () => {
|
|
1769
|
+
const element = jqLite(a);
|
|
1770
|
+
const calls = [];
|
|
1771
|
+
element.one("click", (event) => {
|
|
1772
|
+
calls.push("one");
|
|
1773
|
+
});
|
|
1774
|
+
element.on("click", (event) => {
|
|
1775
|
+
calls.push("on");
|
|
1776
|
+
});
|
|
1777
|
+
|
|
1778
|
+
browserTrigger(element, "click");
|
|
1779
|
+
browserTrigger(element, "click");
|
|
1780
|
+
|
|
1781
|
+
expect(calls).toEqual(["one", "on", "on"]);
|
|
1782
|
+
});
|
|
1783
|
+
});
|
|
1784
|
+
|
|
1785
|
+
describe("replaceWith", () => {
|
|
1786
|
+
it("should replaceWith", () => {
|
|
1787
|
+
const root = jqLite("<div>").html("before-<div></div>after");
|
|
1788
|
+
const div = root.find("div");
|
|
1789
|
+
expect(div.replaceWith("<span>span-</span><b>bold-</b>")).toEqual(div);
|
|
1790
|
+
expect(root.text()).toEqual("before-span-bold-after");
|
|
1791
|
+
});
|
|
1792
|
+
|
|
1793
|
+
it("should replaceWith text", () => {
|
|
1794
|
+
const root = jqLite("<div>").html("before-<div></div>after");
|
|
1795
|
+
const div = root.find("div");
|
|
1796
|
+
expect(div.replaceWith("text-")).toEqual(div);
|
|
1797
|
+
expect(root.text()).toEqual("before-text-after");
|
|
1798
|
+
});
|
|
1799
|
+
});
|
|
1800
|
+
|
|
1801
|
+
describe("children", () => {
|
|
1802
|
+
it("should only select element nodes", () => {
|
|
1803
|
+
const root = jqLite(
|
|
1804
|
+
"<div><!-- some comment -->before-<div></div>after-<span></span>",
|
|
1805
|
+
);
|
|
1806
|
+
const div = root.find("div");
|
|
1807
|
+
const span = root.find("span");
|
|
1808
|
+
expect(root.children()).toJqEqual([div, span]);
|
|
1809
|
+
});
|
|
1810
|
+
});
|
|
1811
|
+
|
|
1812
|
+
describe("append", () => {
|
|
1813
|
+
it("should append", () => {
|
|
1814
|
+
const root = jqLite("<div>");
|
|
1815
|
+
expect(root.append("<span>abc</span>")).toEqual(root);
|
|
1816
|
+
expect(root.html().toLowerCase()).toEqual("<span>abc</span>");
|
|
1817
|
+
});
|
|
1818
|
+
it("should append text", () => {
|
|
1819
|
+
const root = jqLite("<div>");
|
|
1820
|
+
expect(root.append("text")).toEqual(root);
|
|
1821
|
+
expect(root.html()).toEqual("text");
|
|
1822
|
+
});
|
|
1823
|
+
it("should append to document fragment", () => {
|
|
1824
|
+
const root = jqLite(window.document.createDocumentFragment());
|
|
1825
|
+
expect(root.append("<p>foo</p>")).toBe(root);
|
|
1826
|
+
expect(root.children().length).toBe(1);
|
|
1827
|
+
});
|
|
1828
|
+
it("should not append anything if parent node is not of type element or docfrag", () => {
|
|
1829
|
+
const root = jqLite(jqLite("<p>some text node</p>")[0].childNodes);
|
|
1830
|
+
expect(root.append("<p>foo</p>")).toBe(root);
|
|
1831
|
+
expect(root.children().length).toBe(0);
|
|
1832
|
+
});
|
|
1833
|
+
});
|
|
1834
|
+
|
|
1835
|
+
describe("prepend", () => {
|
|
1836
|
+
it("should prepend to empty", () => {
|
|
1837
|
+
const root = jqLite("<div>");
|
|
1838
|
+
expect(root.prepend("<span>abc</span>")).toEqual(root);
|
|
1839
|
+
expect(root.html().toLowerCase()).toEqual("<span>abc</span>");
|
|
1840
|
+
});
|
|
1841
|
+
it("should prepend to content", () => {
|
|
1842
|
+
const root = jqLite("<div>text</div>");
|
|
1843
|
+
expect(root.prepend("<span>abc</span>")).toEqual(root);
|
|
1844
|
+
expect(root.html().toLowerCase()).toEqual("<span>abc</span>text");
|
|
1845
|
+
});
|
|
1846
|
+
it("should prepend text to content", () => {
|
|
1847
|
+
const root = jqLite("<div>text</div>");
|
|
1848
|
+
expect(root.prepend("abc")).toEqual(root);
|
|
1849
|
+
expect(root.html().toLowerCase()).toEqual("abctext");
|
|
1850
|
+
});
|
|
1851
|
+
it("should prepend array to empty in the right order", () => {
|
|
1852
|
+
const root = jqLite("<div>");
|
|
1853
|
+
expect(root.prepend([a, b, c])).toBe(root);
|
|
1854
|
+
expect(root.html()).toEqual("<div>A</div><div>B</div><div>C</div>");
|
|
1855
|
+
});
|
|
1856
|
+
it("should prepend array to content in the right order", () => {
|
|
1857
|
+
const root = jqLite("<div>text</div>");
|
|
1858
|
+
expect(root.prepend([a, b, c])).toBe(root);
|
|
1859
|
+
expect(root.html()).toBe("<div>A</div><div>B</div><div>C</div>text");
|
|
1860
|
+
});
|
|
1861
|
+
});
|
|
1862
|
+
|
|
1863
|
+
describe("remove", () => {
|
|
1864
|
+
it("should remove", () => {
|
|
1865
|
+
const root = jqLite("<div><span>abc</span></div>");
|
|
1866
|
+
const span = root.find("span");
|
|
1867
|
+
expect(span.remove()).toEqual(span);
|
|
1868
|
+
expect(root.html()).toEqual("");
|
|
1869
|
+
});
|
|
1870
|
+
});
|
|
1871
|
+
|
|
1872
|
+
describe("detach", () => {
|
|
1873
|
+
it("should detach", () => {
|
|
1874
|
+
const root = jqLite("<div><span>abc</span></div>");
|
|
1875
|
+
const span = root.find("span");
|
|
1876
|
+
expect(span.detach()).toEqual(span);
|
|
1877
|
+
expect(root.html()).toEqual("");
|
|
1878
|
+
});
|
|
1879
|
+
});
|
|
1880
|
+
|
|
1881
|
+
describe("after", () => {
|
|
1882
|
+
it("should after", () => {
|
|
1883
|
+
const root = jqLite("<div><span></span></div>");
|
|
1884
|
+
const span = root.find("span");
|
|
1885
|
+
expect(span.after("<i></i><b></b>")).toEqual(span);
|
|
1886
|
+
expect(root.html().toLowerCase()).toEqual("<span></span><i></i><b></b>");
|
|
1887
|
+
});
|
|
1888
|
+
|
|
1889
|
+
it("should allow taking text", () => {
|
|
1890
|
+
const root = jqLite("<div><span></span></div>");
|
|
1891
|
+
const span = root.find("span");
|
|
1892
|
+
span.after("abc");
|
|
1893
|
+
expect(root.html().toLowerCase()).toEqual("<span></span>abc");
|
|
1894
|
+
});
|
|
1895
|
+
|
|
1896
|
+
it("should not throw when the element has no parent", () => {
|
|
1897
|
+
const span = jqLite("<span></span>");
|
|
1898
|
+
expect(() => {
|
|
1899
|
+
span.after("abc");
|
|
1900
|
+
}).not.toThrow();
|
|
1901
|
+
expect(span.length).toBe(1);
|
|
1902
|
+
expect(span[0].outerHTML).toBe("<span></span>");
|
|
1903
|
+
});
|
|
1904
|
+
});
|
|
1905
|
+
|
|
1906
|
+
describe("parent", () => {
|
|
1907
|
+
it("should return parent or an empty set when no parent", () => {
|
|
1908
|
+
const parent = jqLite("<div><p>abc</p></div>");
|
|
1909
|
+
const child = parent.find("p");
|
|
1910
|
+
|
|
1911
|
+
expect(parent.parent()).toBeTruthy();
|
|
1912
|
+
expect(parent.parent().length).toEqual(0);
|
|
1913
|
+
|
|
1914
|
+
expect(child.parent().length).toBe(1);
|
|
1915
|
+
expect(child.parent()[0]).toBe(parent[0]);
|
|
1916
|
+
});
|
|
1917
|
+
|
|
1918
|
+
it("should return empty set when no parent", () => {
|
|
1919
|
+
const element = jqLite("<div>abc</div>");
|
|
1920
|
+
expect(element.parent()).toBeTruthy();
|
|
1921
|
+
expect(element.parent().length).toEqual(0);
|
|
1922
|
+
});
|
|
1923
|
+
|
|
1924
|
+
it("should return empty jqLite object when parent is a document fragment", () => {
|
|
1925
|
+
// this is quite unfortunate but jQuery 1.5.1 behaves this way
|
|
1926
|
+
const fragment = window.document.createDocumentFragment();
|
|
1927
|
+
const child = jqLite("<p>foo</p>");
|
|
1928
|
+
|
|
1929
|
+
fragment.appendChild(child[0]);
|
|
1930
|
+
expect(child[0].parentNode).toBe(fragment);
|
|
1931
|
+
expect(child.parent().length).toBe(0);
|
|
1932
|
+
});
|
|
1933
|
+
});
|
|
1934
|
+
|
|
1935
|
+
describe("find", () => {
|
|
1936
|
+
it("should find child by name", () => {
|
|
1937
|
+
const root = jqLite("<div><div>text</div></div>");
|
|
1938
|
+
const innerDiv = root.find("div");
|
|
1939
|
+
expect(innerDiv.length).toEqual(1);
|
|
1940
|
+
expect(innerDiv.html()).toEqual("text");
|
|
1941
|
+
});
|
|
1942
|
+
|
|
1943
|
+
it("should find child by name and not care about text nodes", () => {
|
|
1944
|
+
const divs = jqLite(
|
|
1945
|
+
"<div><span>aa</span></div>text<div><span>bb</span></div>",
|
|
1946
|
+
);
|
|
1947
|
+
const innerSpan = divs.find("span");
|
|
1948
|
+
expect(innerSpan.length).toEqual(2);
|
|
1949
|
+
});
|
|
1950
|
+
});
|
|
1951
|
+
|
|
1952
|
+
describe("eq", () => {
|
|
1953
|
+
it("should select the nth element ", () => {
|
|
1954
|
+
const element = jqLite(
|
|
1955
|
+
"<div><span>aa</span></div><div><span>bb</span></div>",
|
|
1956
|
+
);
|
|
1957
|
+
expect(element.find("span").eq(0).html()).toBe("aa");
|
|
1958
|
+
expect(element.find("span").eq(-1).html()).toBe("bb");
|
|
1959
|
+
expect(element.find("span").eq(20).length).toBe(0);
|
|
1960
|
+
});
|
|
1961
|
+
});
|
|
1962
|
+
|
|
1963
|
+
describe("triggerHandler", () => {
|
|
1964
|
+
it("should trigger all registered handlers for an event", () => {
|
|
1965
|
+
const element = jqLite("<span>poke</span>");
|
|
1966
|
+
const pokeSpy = jasmine.createSpy("poke");
|
|
1967
|
+
const clickSpy1 = jasmine.createSpy("clickSpy1");
|
|
1968
|
+
const clickSpy2 = jasmine.createSpy("clickSpy2");
|
|
1969
|
+
|
|
1970
|
+
element.on("poke", pokeSpy);
|
|
1971
|
+
element.on("click", clickSpy1);
|
|
1972
|
+
element.on("click", clickSpy2);
|
|
1973
|
+
|
|
1974
|
+
expect(pokeSpy).not.toHaveBeenCalled();
|
|
1975
|
+
expect(clickSpy1).not.toHaveBeenCalled();
|
|
1976
|
+
expect(clickSpy2).not.toHaveBeenCalled();
|
|
1977
|
+
|
|
1978
|
+
element.triggerHandler("poke");
|
|
1979
|
+
expect(pokeSpy).toHaveBeenCalled();
|
|
1980
|
+
expect(clickSpy1).not.toHaveBeenCalled();
|
|
1981
|
+
expect(clickSpy2).not.toHaveBeenCalled();
|
|
1982
|
+
|
|
1983
|
+
element.triggerHandler("click");
|
|
1984
|
+
expect(clickSpy1).toHaveBeenCalled();
|
|
1985
|
+
expect(clickSpy2).toHaveBeenCalled();
|
|
1986
|
+
});
|
|
1987
|
+
|
|
1988
|
+
it("should pass in a dummy event", () => {
|
|
1989
|
+
// we need the event to have at least preventDefault because AngularJS will call it on
|
|
1990
|
+
// all anchors with no href automatically
|
|
1991
|
+
|
|
1992
|
+
const element = jqLite("<a>poke</a>");
|
|
1993
|
+
const pokeSpy = jasmine.createSpy("poke");
|
|
1994
|
+
let event;
|
|
1995
|
+
|
|
1996
|
+
element.on("click", pokeSpy);
|
|
1997
|
+
|
|
1998
|
+
element.triggerHandler("click");
|
|
1999
|
+
event = pokeSpy.calls.mostRecent().args[0];
|
|
2000
|
+
expect(event.preventDefault).toBeDefined();
|
|
2001
|
+
expect(event.target).toEqual(element[0]);
|
|
2002
|
+
expect(event.type).toEqual("click");
|
|
2003
|
+
});
|
|
2004
|
+
|
|
2005
|
+
it("should pass extra parameters as an additional argument", () => {
|
|
2006
|
+
const element = jqLite("<a>poke</a>");
|
|
2007
|
+
const pokeSpy = jasmine.createSpy("poke");
|
|
2008
|
+
let data;
|
|
2009
|
+
|
|
2010
|
+
element.on("click", pokeSpy);
|
|
2011
|
+
|
|
2012
|
+
element.triggerHandler("click", [{ hello: "world" }]);
|
|
2013
|
+
data = pokeSpy.calls.mostRecent().args[1];
|
|
2014
|
+
expect(data.hello).toBe("world");
|
|
2015
|
+
});
|
|
2016
|
+
|
|
2017
|
+
it("should mark event as prevented if preventDefault is called", () => {
|
|
2018
|
+
const element = jqLite("<a>poke</a>");
|
|
2019
|
+
const pokeSpy = jasmine.createSpy("poke");
|
|
2020
|
+
let event;
|
|
2021
|
+
|
|
2022
|
+
element.on("click", pokeSpy);
|
|
2023
|
+
element.triggerHandler("click");
|
|
2024
|
+
event = pokeSpy.calls.mostRecent().args[0];
|
|
2025
|
+
|
|
2026
|
+
expect(event.isDefaultPrevented()).toBe(false);
|
|
2027
|
+
event.preventDefault();
|
|
2028
|
+
expect(event.isDefaultPrevented()).toBe(true);
|
|
2029
|
+
});
|
|
2030
|
+
|
|
2031
|
+
it("should support handlers that deregister themselves", () => {
|
|
2032
|
+
const element = jqLite("<a>poke</a>");
|
|
2033
|
+
const clickSpy = jasmine.createSpy("click");
|
|
2034
|
+
const clickOnceSpy = jasmine.createSpy("clickOnce").and.callFake(() => {
|
|
2035
|
+
element.off("click", clickOnceSpy);
|
|
2036
|
+
});
|
|
2037
|
+
|
|
2038
|
+
element.on("click", clickOnceSpy);
|
|
2039
|
+
element.on("click", clickSpy);
|
|
2040
|
+
|
|
2041
|
+
element.triggerHandler("click");
|
|
2042
|
+
expect(clickOnceSpy).toHaveBeenCalled();
|
|
2043
|
+
expect(clickSpy).toHaveBeenCalled();
|
|
2044
|
+
|
|
2045
|
+
element.triggerHandler("click");
|
|
2046
|
+
expect(clickOnceSpy).toHaveBeenCalled();
|
|
2047
|
+
expect(clickSpy).toHaveBeenCalledTimes(2);
|
|
2048
|
+
});
|
|
2049
|
+
|
|
2050
|
+
it("should accept a custom event instead of eventName", () => {
|
|
2051
|
+
const element = jqLite("<a>poke</a>");
|
|
2052
|
+
const pokeSpy = jasmine.createSpy("poke");
|
|
2053
|
+
const customEvent = {
|
|
2054
|
+
type: "click",
|
|
2055
|
+
someProp: "someValue",
|
|
2056
|
+
};
|
|
2057
|
+
let actualEvent;
|
|
2058
|
+
|
|
2059
|
+
element.on("click", pokeSpy);
|
|
2060
|
+
element.triggerHandler(customEvent);
|
|
2061
|
+
actualEvent = pokeSpy.calls.mostRecent().args[0];
|
|
2062
|
+
expect(actualEvent.preventDefault).toBeDefined();
|
|
2063
|
+
expect(actualEvent.someProp).toEqual("someValue");
|
|
2064
|
+
expect(actualEvent.target).toEqual(element[0]);
|
|
2065
|
+
expect(actualEvent.type).toEqual("click");
|
|
2066
|
+
});
|
|
2067
|
+
|
|
2068
|
+
it("should stop triggering handlers when stopImmediatePropagation is called", () => {
|
|
2069
|
+
const element = jqLite(a);
|
|
2070
|
+
const clickSpy1 = jasmine.createSpy("clickSpy1");
|
|
2071
|
+
const clickSpy2 = jasmine.createSpy("clickSpy2").and.callFake((event) => {
|
|
2072
|
+
event.stopImmediatePropagation();
|
|
2073
|
+
});
|
|
2074
|
+
const clickSpy3 = jasmine.createSpy("clickSpy3");
|
|
2075
|
+
|
|
2076
|
+
element.on("click", clickSpy1);
|
|
2077
|
+
element.on("click", clickSpy2);
|
|
2078
|
+
element.on("click", clickSpy3);
|
|
2079
|
+
|
|
2080
|
+
element.triggerHandler("click");
|
|
2081
|
+
|
|
2082
|
+
expect(clickSpy1).toHaveBeenCalled();
|
|
2083
|
+
expect(clickSpy2).toHaveBeenCalled();
|
|
2084
|
+
expect(clickSpy3).not.toHaveBeenCalled();
|
|
2085
|
+
});
|
|
2086
|
+
|
|
2087
|
+
it("should have event.isImmediatePropagationStopped method", () => {
|
|
2088
|
+
const element = jqLite(a);
|
|
2089
|
+
const clickSpy = jasmine.createSpy("clickSpy");
|
|
2090
|
+
let event;
|
|
2091
|
+
|
|
2092
|
+
element.on("click", clickSpy);
|
|
2093
|
+
element.triggerHandler("click");
|
|
2094
|
+
event = clickSpy.calls.mostRecent().args[0];
|
|
2095
|
+
|
|
2096
|
+
expect(event.isImmediatePropagationStopped()).toBe(false);
|
|
2097
|
+
event.stopImmediatePropagation();
|
|
2098
|
+
expect(event.isImmediatePropagationStopped()).toBe(true);
|
|
2099
|
+
});
|
|
2100
|
+
});
|
|
2101
|
+
|
|
2102
|
+
describe("kebabToCamel", () => {
|
|
2103
|
+
it("should leave non-dashed strings alone", () => {
|
|
2104
|
+
expect(kebabToCamel("foo")).toBe("foo");
|
|
2105
|
+
expect(kebabToCamel("")).toBe("");
|
|
2106
|
+
expect(kebabToCamel("fooBar")).toBe("fooBar");
|
|
2107
|
+
});
|
|
2108
|
+
|
|
2109
|
+
it("should convert dash-separated strings to camelCase", () => {
|
|
2110
|
+
expect(kebabToCamel("foo-bar")).toBe("fooBar");
|
|
2111
|
+
expect(kebabToCamel("foo-bar-baz")).toBe("fooBarBaz");
|
|
2112
|
+
expect(kebabToCamel("foo:bar_baz")).toBe("foo:bar_baz");
|
|
2113
|
+
});
|
|
2114
|
+
|
|
2115
|
+
it("should convert leading dashes followed by a lowercase letter", () => {
|
|
2116
|
+
expect(kebabToCamel("-foo-bar")).toBe("FooBar");
|
|
2117
|
+
});
|
|
2118
|
+
|
|
2119
|
+
it("should not convert dashes followed by a non-letter", () => {
|
|
2120
|
+
expect(kebabToCamel("foo-42- -a-B")).toBe("foo-42- A-B");
|
|
2121
|
+
});
|
|
2122
|
+
|
|
2123
|
+
it("should not convert browser specific css properties in a special way", () => {
|
|
2124
|
+
expect(kebabToCamel("-ms-foo-bar")).toBe("MsFooBar");
|
|
2125
|
+
expect(kebabToCamel("-moz-foo-bar")).toBe("MozFooBar");
|
|
2126
|
+
expect(kebabToCamel("-webkit-foo-bar")).toBe("WebkitFooBar");
|
|
2127
|
+
});
|
|
2128
|
+
|
|
2129
|
+
it("should not collapse sequences of dashes", () => {
|
|
2130
|
+
expect(kebabToCamel("foo---bar-baz--qaz")).toBe("foo--BarBaz-Qaz");
|
|
2131
|
+
});
|
|
2132
|
+
});
|
|
2133
|
+
});
|