Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
package.src.directive.class.class.spec.js Maven / Gradle / Ivy
import { dealoc, JQLite } from "../../shared/jqlite/jqlite";
import { Angular } from "../../loader";
import { valueFn } from "../../shared/utils";
describe("ngClass", () => {
let element;
let $compile;
let $rootScope;
let injector;
beforeEach(() => {
window.angular = new Angular();
window.angular.module("test", []);
injector = window.angular.bootstrap(document.getElementById("dummy"), [
"test",
]);
$compile = injector.get("$compile");
$rootScope = injector.get("$rootScope");
});
afterEach(() => {
dealoc(element);
});
it("should add new and remove old classes dynamically", () => {
element = $compile('
')(
$rootScope,
);
$rootScope.dynClass = "A";
expect(element[0].classList.contains("existing")).toBe(true);
expect(element[0].classList.contains("A")).toBe(true);
$rootScope.dynClass = "B";
expect(element[0].classList.contains("existing")).toBe(true);
expect(element[0].classList.contains("A")).toBe(false);
expect(element[0].classList.contains("B")).toBe(true);
delete $rootScope.dynClass;
expect(element[0].classList.contains("existing")).toBe(true);
expect(element[0].classList.contains("A")).toBe(false);
expect(element[0].classList.contains("B")).toBe(false);
});
it("should add new and remove old classes with same names as Object.prototype properties dynamically", () => {
element = $compile('
')(
$rootScope,
);
$rootScope.dynClass = {
watch: true,
hasOwnProperty: true,
isPrototypeOf: true,
};
expect(element[0].classList.contains("existing")).toBe(true);
expect(element[0].classList.contains("watch")).toBe(true);
expect(element[0].classList.contains("hasOwnProperty")).toBe(true);
expect(element[0].classList.contains("isPrototypeOf")).toBe(true);
$rootScope.dynClass.watch = false;
expect(element[0].classList.contains("existing")).toBe(true);
expect(element[0].classList.contains("watch")).toBe(false);
expect(element[0].classList.contains("hasOwnProperty")).toBe(true);
expect(element[0].classList.contains("isPrototypeOf")).toBe(true);
delete $rootScope.dynClass;
expect(element[0].classList.contains("existing")).toBe(true);
expect(element[0].classList.contains("watch")).toBe(false);
expect(element[0].classList.contains("hasOwnProperty")).toBe(false);
expect(element[0].classList.contains("isPrototypeOf")).toBe(false);
});
it("should support adding multiple classes via an array", () => {
element = $compile(
"
",
)($rootScope);
expect(element[0].classList.contains("existing")).toBeTruthy();
expect(element[0].classList.contains("A")).toBeTruthy();
expect(element[0].classList.contains("B")).toBeTruthy();
});
it(
"should support adding multiple classes conditionally via a map of class names to boolean " +
"expressions",
() => {
element = $compile(
'' +
"
",
)($rootScope);
$rootScope.conditionA = true;
expect(element[0].classList.contains("existing")).toBeTruthy();
expect(element[0].classList.contains("A")).toBeTruthy();
expect(element[0].classList.contains("B")).toBeFalsy();
expect(element[0].classList.contains("AnotB")).toBeTruthy();
$rootScope.conditionB = function () {
return true;
};
expect(element[0].classList.contains("existing")).toBeTruthy();
expect(element[0].classList.contains("A")).toBeTruthy();
expect(element[0].classList.contains("B")).toBeTruthy();
expect(element[0].classList.contains("AnotB")).toBeFalsy();
},
);
it("should not break when passed non-string/array/object, truthy values", () => {
element = $compile('
')($rootScope);
expect(element[0].classList.contains("42")).toBeTruthy();
});
it("should support adding multiple classes via an array mixed with conditionally via a map", () => {
element = $compile(
"
",
)($rootScope);
expect(element[0].classList.contains("existing")).toBeTruthy();
expect(element[0].classList.contains("A")).toBeTruthy();
expect(element[0].classList.contains("B")).toBeFalsy();
$rootScope.condition = true;
expect(element[0].classList.contains("B")).toBeTruthy();
});
it("should remove classes when the referenced object is the same but its property is changed", () => {
element = $compile('
')($rootScope);
$rootScope.classes = { A: true, B: true };
expect(element[0].classList.contains("A")).toBeTruthy();
expect(element[0].classList.contains("B")).toBeTruthy();
$rootScope.classes.A = false;
expect(element[0].classList.contains("A")).toBeFalsy();
expect(element[0].classList.contains("B")).toBeTruthy();
});
it("should support adding multiple classes via a space delimited string", () => {
element = $compile('
')(
$rootScope,
);
expect(element[0].classList.contains("existing")).toBeTruthy();
expect(element[0].classList.contains("A")).toBeTruthy();
expect(element[0].classList.contains("B")).toBeTruthy();
});
it("should support adding multiple classes via a space delimited string inside an array", () => {
element = $compile(
"
",
)($rootScope);
expect(element[0].classList.contains("existing")).toBeTruthy();
expect(element[0].classList.contains("A")).toBeTruthy();
expect(element[0].classList.contains("B")).toBeTruthy();
expect(element[0].classList.contains("C")).toBeTruthy();
});
it("should preserve class added post compilation with pre-existing classes", () => {
element = $compile('
')(
$rootScope,
);
$rootScope.dynClass = "A";
expect(element[0].classList.contains("existing")).toBe(true);
// add extra class, change model and eval
element[0].classList.add("newClass");
$rootScope.dynClass = "B";
expect(element[0].classList.contains("existing")).toBe(true);
expect(element[0].classList.contains("B")).toBe(true);
expect(element[0].classList.contains("newClass")).toBe(true);
});
it('should preserve class added post compilation without pre-existing classes"', () => {
element = $compile('
')($rootScope);
$rootScope.dynClass = "A";
expect(element[0].classList.contains("A")).toBe(true);
// add extra class, change model and eval
element[0].classList.add("newClass");
$rootScope.dynClass = "B";
expect(element[0].classList.contains("B")).toBe(true);
expect(element[0].classList.contains("newClass")).toBe(true);
});
it('should preserve other classes with similar name"', () => {
element = $compile(
'
',
)($rootScope);
$rootScope.dynCls = "panel";
$rootScope.dynCls = "foo";
expect(element[0].className).toBe("ui-panel ui-selected foo");
});
it("should not add duplicate classes", () => {
element = $compile('
')(
$rootScope,
);
$rootScope.dynCls = "panel";
expect(element[0].className).toBe("panel bar");
});
it("should remove classes even if it was specified via class attribute", () => {
element = $compile('
')(
$rootScope,
);
$rootScope.dynCls = "panel";
$rootScope.dynCls = "window";
expect(element[0].className).toBe("bar window");
});
it("should remove classes even if they were added by another code", () => {
element = $compile('
')($rootScope);
$rootScope.dynCls = "foo";
element[0].classList.add("foo");
$rootScope.dynCls = "";
});
it("should convert undefined and null values to an empty string", () => {
element = $compile('
')($rootScope);
$rootScope.dynCls = [undefined, null];
});
it("should ngClass odd/even", () => {
element = $compile(
'',
)($rootScope);
const e1 = JQLite(element[0].childNodes[1]);
const e2 = JQLite(element[0].childNodes[3]);
expect(e1[0].classList.contains("existing")).toBeTruthy();
expect(e1[0].classList.contains("odd")).toBeTruthy();
expect(e2[0].classList.contains("existing")).toBeTruthy();
expect(e2[0].classList.contains("even")).toBeTruthy();
});
it("should allow both ngClass and ngClassOdd/Even on the same element", () => {
element = $compile(
"" +
' " +
"",
)($rootScope);
$rootScope.$apply();
const e1 = JQLite(element[0].childNodes[1]);
const e2 = JQLite(element[0].childNodes[3]);
expect(e1[0].classList.contains("plainClass")).toBeTruthy();
expect(e1[0].classList.contains("odd")).toBeTruthy();
expect(e1[0].classList.contains("even")).toBeFalsy();
expect(e2[0].classList.contains("plainClass")).toBeTruthy();
expect(e2[0].classList.contains("even")).toBeTruthy();
expect(e2[0].classList.contains("odd")).toBeFalsy();
});
it("should allow ngClassOdd/Even on the same element with overlapping classes", () => {
element = $compile(
"" +
'" +
" " +
"",
)($rootScope);
const e1 = element.children().eq(0)[0];
const e2 = element.children().eq(1)[0];
const e3 = element.children().eq(2)[0];
expect(e1).toHaveClass("same");
expect(e1).toHaveClass("odd");
expect(e1).not.toHaveClass("even");
expect(e2).toHaveClass("same");
expect(e2).not.toHaveClass("odd");
expect(e2).toHaveClass("even");
expect(e3).toHaveClass("same");
expect(e3).toHaveClass("odd");
expect(e3).not.toHaveClass("even");
});
it("should allow ngClass with overlapping classes", () => {
element = $compile(
"
",
)($rootScope)[0];
expect(element).toHaveClass("same");
expect(element).not.toHaveClass("yes");
expect(element).toHaveClass("no");
$rootScope.$apply("test = true");
expect(element).toHaveClass("same");
expect(element).toHaveClass("yes");
expect(element).not.toHaveClass("no");
});
it("should allow both ngClass and ngClassOdd/Even with multiple classes", () => {
element = $compile(
"" +
" " +
"",
)($rootScope);
$rootScope.$apply();
const e1 = JQLite(element[0].childNodes[1]);
const e2 = JQLite(element[0].childNodes[3]);
expect(e1[0].classList.contains("A")).toBeTruthy();
expect(e1[0].classList.contains("B")).toBeTruthy();
expect(e1[0].classList.contains("C")).toBeTruthy();
expect(e1[0].classList.contains("D")).toBeTruthy();
expect(e1[0].classList.contains("E")).toBeFalsy();
expect(e1[0].classList.contains("F")).toBeFalsy();
expect(e2[0].classList.contains("A")).toBeTruthy();
expect(e2[0].classList.contains("B")).toBeTruthy();
expect(e2[0].classList.contains("E")).toBeTruthy();
expect(e2[0].classList.contains("F")).toBeTruthy();
expect(e2[0].classList.contains("C")).toBeFalsy();
expect(e2[0].classList.contains("D")).toBeFalsy();
});
it("should reapply ngClass when interpolated class attribute changes", () => {
element = $compile(
"",
)($rootScope);
const e1 = element.children().eq(0)[0];
const e2 = element.children().eq(1)[0];
$rootScope.$apply('two = "two"; five = true');
expect(e1).toHaveClass("one");
expect(e1).toHaveClass("two");
expect(e1).toHaveClass("three");
expect(e1).not.toHaveClass("four");
expect(e1).toHaveClass("five");
expect(e2).toHaveClass("one");
expect(e2).toHaveClass("two");
expect(e2).toHaveClass("three");
expect(e2).not.toHaveClass("four");
expect(e2).toHaveClass("five");
$rootScope.$apply('two = "another-two"');
expect(e1).toHaveClass("one");
expect(e1).not.toHaveClass("two");
expect(e1).toHaveClass("another-two");
expect(e1).toHaveClass("three");
expect(e1).not.toHaveClass("four");
expect(e1).toHaveClass("five");
expect(e2).toHaveClass("one");
expect(e2).not.toHaveClass("two");
expect(e2).toHaveClass("another-two");
expect(e2).toHaveClass("three");
expect(e2).not.toHaveClass("four");
expect(e2).toHaveClass("five");
$rootScope.$apply('two = "two-more"; four = "four"');
expect(e1).toHaveClass("one");
expect(e1).not.toHaveClass("two");
expect(e1).not.toHaveClass("another-two");
expect(e1).toHaveClass("two-more");
expect(e1).toHaveClass("three");
expect(e1).not.toHaveClass("four");
expect(e1).toHaveClass("five");
expect(e2).toHaveClass("one");
expect(e2).not.toHaveClass("two");
expect(e2).not.toHaveClass("another-two");
expect(e2).toHaveClass("two-more");
expect(e2).toHaveClass("three");
expect(e2).toHaveClass("four");
expect(e2).toHaveClass("five");
$rootScope.$apply("five = false");
expect(e1).toHaveClass("one");
expect(e1).not.toHaveClass("two");
expect(e1).not.toHaveClass("another-two");
expect(e1).toHaveClass("two-more");
expect(e1).toHaveClass("three");
expect(e1).not.toHaveClass("four");
expect(e1).not.toHaveClass("five");
expect(e2).toHaveClass("one");
expect(e2).not.toHaveClass("two");
expect(e2).not.toHaveClass("another-two");
expect(e2).toHaveClass("two-more");
expect(e2).toHaveClass("three");
expect(e2).toHaveClass("four");
expect(e2).not.toHaveClass("five");
});
it("should not mess up class value due to observing an interpolated class attribute", () => {
$rootScope.foo = true;
$rootScope.$watch("anything", () => {
$rootScope.foo = false;
});
element = $compile('
')($rootScope);
expect(element[0].classList.contains("foo")).toBe(false);
});
it("should update ngClassOdd/Even when an item is added to the model", () => {
element = $compile(
"" +
'i " +
"",
)($rootScope);
$rootScope.items = ["b", "c", "d"];
$rootScope.items.unshift("a");
const e1 = JQLite(element[0].childNodes[1]);
const e4 = JQLite(element[0].childNodes[3]);
expect(e1[0].classList.contains("odd")).toBeTruthy();
expect(e1[0].classList.contains("even")).toBeFalsy();
expect(e4[0].classList.contains("even")).toBeTruthy();
expect(e4[0].classList.contains("odd")).toBeFalsy();
});
it("should update ngClassOdd/Even when model is changed by filtering", () => {
element = $compile(
"" +
' " +
"",
)($rootScope);
$rootScope.items = ["a", "b", "a"];
$rootScope.items = ["a", "a"];
const e1 = JQLite(element[0].childNodes[1]);
const e2 = JQLite(element[0].childNodes[3]);
expect(e1[0].classList.contains("odd")).toBeTruthy();
expect(e1[0].classList.contains("even")).toBeFalsy();
expect(e2[0].classList.contains("even")).toBeTruthy();
expect(e2[0].classList.contains("odd")).toBeFalsy();
});
it("should update ngClassOdd/Even when model is changed by sorting", () => {
element = $compile(
"" +
'i " +
"",
)($rootScope);
$rootScope.items = ["a", "b"];
$rootScope.items = ["b", "a"];
const e1 = JQLite(element[0].childNodes[1]);
const e2 = JQLite(element[0].childNodes[3]);
expect(e1[0].classList.contains("odd")).toBeTruthy();
expect(e1[0].classList.contains("even")).toBeFalsy();
expect(e2[0].classList.contains("even")).toBeTruthy();
expect(e2[0].classList.contains("odd")).toBeFalsy();
});
it("should add/remove the correct classes when the expression and `$index` change simultaneously", () => {
element = $compile(
"",
)($rootScope);
const odd = element.children().eq(0)[0];
const even = element.children().eq(1)[0];
$rootScope.$apply('$index = 0; foo = "class1"');
expect(odd).toHaveClass("class1");
expect(odd).not.toHaveClass("class2");
expect(even).not.toHaveClass("class1");
expect(even).not.toHaveClass("class2");
$rootScope.$apply('$index = 1; foo = "class2"');
expect(odd).not.toHaveClass("class1");
expect(odd).not.toHaveClass("class2");
expect(even).not.toHaveClass("class1");
expect(even).toHaveClass("class2");
$rootScope.$apply('foo = "class1"');
expect(odd).not.toHaveClass("class1");
expect(odd).not.toHaveClass("class2");
expect(even).toHaveClass("class1");
expect(even).not.toHaveClass("class2");
$rootScope.$apply("$index = 2");
expect(odd).toHaveClass("class1");
expect(odd).not.toHaveClass("class2");
expect(even).not.toHaveClass("class1");
expect(even).not.toHaveClass("class2");
});
it("should support mixed array/object variable with a mutating object", () => {
element = $compile('
')($rootScope);
$rootScope.classVar = [{ orange: true }];
expect(element[0]).toHaveClass("orange");
$rootScope.classVar[0].orange = false;
expect(element[0]).not.toHaveClass("orange");
});
// // https://github.com/angular/angular.js/issues/15905
it("should support a mixed literal-array/object variable", () => {
element = $compile('
')($rootScope);
$rootScope.classVar = { orange: true };
expect(element[0]).toHaveClass("orange");
$rootScope.classVar.orange = false;
expect(element[0]).not.toHaveClass("orange");
});
it("should support a one-time mixed literal-array/object variable", () => {
element = $compile('
')(
$rootScope,
);
$rootScope.classVar1 = { orange: true };
expect(element[0]).toHaveClass("orange");
$rootScope.classVar1.orange = false;
expect(element[0]).not.toHaveClass("orange");
});
it("should do value stabilization as expected when one-time binding", () => {
element = $compile('
')($rootScope);
$rootScope.$apply('className = "foo"');
expect(element[0]).toHaveClass("foo");
$rootScope.$apply('className = "bar"');
expect(element[0]).toHaveClass("foo");
});
it("should remove the watcher when static array one-time binding", () => {
element = $compile('
')($rootScope);
$rootScope.$apply('className = "foo"');
expect(element[0]).toHaveClass("foo");
$rootScope.$apply('className = "bar"');
expect(element[0]).toHaveClass("foo");
expect(element[0]).not.toHaveClass("bar");
});
it("should remove the watcher when static map one-time binding", () => {
element = $compile('
')(
$rootScope,
);
$rootScope.$apply("fooPresent = true");
expect(element[0]).toHaveClass("foo");
$rootScope.$apply("fooPresent = false");
expect(element[0]).toHaveClass("foo");
});
it("should track changes of mutating object inside an array", () => {
$rootScope.classVar = [{ orange: true }];
element = $compile('
')($rootScope);
expect(element[0]).toHaveClass("orange");
$rootScope.$apply("classVar[0].orange = false");
expect(element[0]).not.toHaveClass("orange");
});
// https://github.com/angular/angular.js/issues/15960#issuecomment-299109412
it("should always reevaluate filters with non-primitive inputs within literals", () => {
dealoc(document.getElementById("dummy"));
injector = window.angular.bootstrap(document.getElementById("dummy"), [
"test",
($filterProvider) => {
$filterProvider.register(
"foo",
valueFn((o) => o.a || o.b),
);
},
]);
injector.invoke(($rootScope, $compile) => {
$rootScope.testObj = {};
element = $compile('')(
$rootScope,
)[0];
$rootScope.$apply();
expect(element).not.toHaveClass("x");
$rootScope.$apply("testObj.a = true");
expect(element).toHaveClass("x");
});
});
describe("large objects", () => {
let getProp;
let veryLargeObj;
beforeEach(() => {
getProp = jasmine.createSpy("getProp");
veryLargeObj = {};
Object.defineProperty(veryLargeObj, "prop", {
get: getProp,
enumerable: true,
});
});
it("should not be copied when using an expression", () => {
element = $compile('
')($rootScope)[0];
$rootScope.fooClass = { foo: veryLargeObj };
expect(element).toHaveClass("foo");
expect(getProp).not.toHaveBeenCalled();
});
it("should not be copied when using a literal", () => {
element = $compile('
')(
$rootScope,
)[0];
$rootScope.veryLargeObj = veryLargeObj;
expect(element).toHaveClass("foo");
expect(getProp).not.toHaveBeenCalled();
});
it("should not be copied when inside an array", () => {
element = $compile('
')(
$rootScope,
)[0];
$rootScope.veryLargeObj = veryLargeObj;
expect(element).toHaveClass("foo");
expect(getProp).not.toHaveBeenCalled();
});
it("should not be copied when using one-time binding", () => {
element = $compile(
'
',
)($rootScope)[0];
$rootScope.veryLargeObj = veryLargeObj;
expect(element).toHaveClass("foo");
expect(element).not.toHaveClass("bar");
expect(getProp).not.toHaveBeenCalled();
$rootScope.$apply('veryLargeObj.bar = "bar"');
expect(element).toHaveClass("foo");
expect(element).not.toHaveClass("bar");
expect(getProp).not.toHaveBeenCalled();
$rootScope.$apply('bar = "bar"');
expect(element).toHaveClass("foo");
expect(element).toHaveClass("bar");
expect(getProp).not.toHaveBeenCalled();
$rootScope.$apply('veryLargeObj.bar = "qux"');
expect(element).toHaveClass("foo");
expect(element).toHaveClass("bar");
expect(getProp).not.toHaveBeenCalled();
});
});
});
// describe("ngClass animations", () => {
// let body;
// let element;
// let $rootElement;
// afterEach(() => {
// dealoc(element);
// });
// it("should avoid calling addClass accidentally when removeClass is going on", () => {
// module("ngAnimateMock");
// inject(($compile, $rootScope, $animate, $timeout) => {
// element = angular.element('
');
// const body = JQLite(document.body);
// body.append(element);
// $compile(element)($rootScope);
// expect($animate.queue.length).toBe(0);
// $rootScope.val = "one";
// ;
// expect($animate.queue.shift().event).toBe("addClass");
// expect($animate.queue.length).toBe(0);
// $rootScope.val = "";
// ;
// expect($animate.queue.shift().event).toBe("removeClass"); // only removeClass is called
// expect($animate.queue.length).toBe(0);
// $rootScope.val = "one";
// ;
// expect($animate.queue.shift().event).toBe("addClass");
// expect($animate.queue.length).toBe(0);
// $rootScope.val = "two";
// ;
// expect($animate.queue.shift().event).toBe("addClass");
// expect($animate.queue.shift().event).toBe("removeClass");
// expect($animate.queue.length).toBe(0);
// });
// });
// it("should combine the ngClass evaluation with the enter animation", () => {
// // mocks are not used since the enter delegation method is called before addClass and
// // it makes it impossible to test to see that addClass is called first
// module("ngAnimate");
// module("ngAnimateMock");
// module(($animateProvider) => {
// $animateProvider.register(".crazy", () => ({
// enter(element, done) {
// element.data("state", "crazy-enter");
// done();
// },
// }));
// });
// inject(
// ($compile, $rootScope, $browser, $rootElement, $animate, $document) => {
// $animate.enabled(true);
// $rootScope.val = "crazy";
// element = angular.element('
');
// JQLite($document[0].body).append($rootElement);
// $compile(element)($rootScope);
// let enterComplete = false;
// $animate.enter(element, $rootElement, null).then(() => {
// enterComplete = true;
// });
// // jquery doesn't compare both elements properly so let's use the nodes
// expect(element.parent()[0]).toEqual($rootElement[0]);
// expect(element[0].classList.contains("crazy")).toBe(false);
// expect(enterComplete).toBe(false);
// ;
// $animate.flush();
// ;
// expect(element[0].classList.contains("crazy")).toBe(true);
// expect(enterComplete).toBe(true);
// expect(element.data("state")).toBe("crazy-enter");
// },
// );
// });
// it("should not remove classes if they're going to be added back right after", () => {
// module("ngAnimateMock");
// inject(($rootScope, $compile, $animate) => {
// let className;
// $rootScope.one = true;
// $rootScope.two = true;
// $rootScope.three = true;
// element = angular.element(
// '
',
// );
// $compile(element)($rootScope);
// ;
// // this fires twice due to the class observer firing
// let item = $animate.queue.shift();
// expect(item.event).toBe("addClass");
// expect(item.args[1]).toBe("one two three");
// expect($animate.queue.length).toBe(0);
// $rootScope.three = false;
// ;
// item = $animate.queue.shift();
// expect(item.event).toBe("removeClass");
// expect(item.args[1]).toBe("three");
// expect($animate.queue.length).toBe(0);
// $rootScope.two = false;
// $rootScope.three = true;
// ;
// item = $animate.queue.shift();
// expect(item.event).toBe("addClass");
// expect(item.args[1]).toBe("three");
// item = $animate.queue.shift();
// expect(item.event).toBe("removeClass");
// expect(item.args[1]).toBe("two");
// expect($animate.queue.length).toBe(0);
// });
// });
// });