2015-02-05 16:08:05 -05:00
|
|
|
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib';
|
2015-03-09 06:37:59 -04:00
|
|
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
2015-04-02 17:40:49 -04:00
|
|
|
import {SelectorMatcher} from 'angular2/src/render/dom/compiler/selector';
|
|
|
|
import {CssSelector} from 'angular2/src/render/dom/compiler/selector';
|
2015-02-05 16:08:05 -05:00
|
|
|
import {List, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
|
2014-10-28 17:46:55 -04:00
|
|
|
|
|
|
|
export function main() {
|
|
|
|
describe('SelectorMatcher', () => {
|
2015-02-06 18:41:02 -05:00
|
|
|
var matcher, matched, selectableCollector, s1, s2, s3, s4;
|
2014-10-28 17:46:55 -04:00
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
function reset() { matched = ListWrapper.create(); }
|
2014-10-28 17:46:55 -04:00
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
reset();
|
2015-02-06 18:41:02 -05:00
|
|
|
s1 = s2 = s3 = s4 = null;
|
|
|
|
selectableCollector = (selector, context) => {
|
|
|
|
ListWrapper.push(matched, selector);
|
|
|
|
ListWrapper.push(matched, context);
|
2015-05-26 12:25:39 -04:00
|
|
|
};
|
2014-10-28 17:46:55 -04:00
|
|
|
matcher = new SelectorMatcher();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should select by element name case insensitive', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
matcher.addSelectables(s1 = CssSelector.parse('someTag'), 1);
|
2014-10-28 17:46:55 -04:00
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('SOMEOTHERTAG')[0], selectableCollector))
|
|
|
|
.toEqual(false);
|
2014-10-28 17:46:55 -04:00
|
|
|
expect(matched).toEqual([]);
|
|
|
|
|
2015-03-19 12:01:42 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('SOMETAG')[0], selectableCollector)).toEqual(true);
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matched).toEqual([s1[0], 1]);
|
2014-10-28 17:46:55 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should select by class name case insensitive', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
matcher.addSelectables(s1 = CssSelector.parse('.someClass'), 1);
|
|
|
|
matcher.addSelectables(s2 = CssSelector.parse('.someClass.class2'), 2);
|
2014-10-28 17:46:55 -04:00
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('.SOMEOTHERCLASS')[0], selectableCollector))
|
|
|
|
.toEqual(false);
|
2014-10-28 17:46:55 -04:00
|
|
|
expect(matched).toEqual([]);
|
|
|
|
|
2015-03-19 12:01:42 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('.SOMECLASS')[0], selectableCollector)).toEqual(true);
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matched).toEqual([s1[0], 1]);
|
2014-10-28 17:46:55 -04:00
|
|
|
|
|
|
|
reset();
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('.someClass.class2')[0], selectableCollector))
|
|
|
|
.toEqual(true);
|
|
|
|
expect(matched).toEqual([s1[0], 1, s2[0], 2]);
|
2014-10-28 17:46:55 -04:00
|
|
|
});
|
|
|
|
|
2014-11-11 20:33:47 -05:00
|
|
|
it('should select by attr name case insensitive independent of the value', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
matcher.addSelectables(s1 = CssSelector.parse('[someAttr]'), 1);
|
|
|
|
matcher.addSelectables(s2 = CssSelector.parse('[someAttr][someAttr2]'), 2);
|
2014-10-28 17:46:55 -04:00
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('[SOMEOTHERATTR]')[0], selectableCollector))
|
|
|
|
.toEqual(false);
|
2014-10-28 17:46:55 -04:00
|
|
|
expect(matched).toEqual([]);
|
|
|
|
|
2015-03-19 12:01:42 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('[SOMEATTR]')[0], selectableCollector)).toEqual(true);
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matched).toEqual([s1[0], 1]);
|
2014-10-28 17:46:55 -04:00
|
|
|
|
2014-11-11 20:33:47 -05:00
|
|
|
reset();
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('[SOMEATTR=someValue]')[0], selectableCollector))
|
|
|
|
.toEqual(true);
|
|
|
|
expect(matched).toEqual([s1[0], 1]);
|
2014-11-11 20:33:47 -05:00
|
|
|
|
2014-10-28 17:46:55 -04:00
|
|
|
reset();
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('[someAttr][someAttr2]')[0], selectableCollector))
|
|
|
|
.toEqual(true);
|
|
|
|
expect(matched).toEqual([s1[0], 1, s2[0], 2]);
|
2014-10-28 17:46:55 -04:00
|
|
|
});
|
|
|
|
|
2014-11-11 20:33:47 -05:00
|
|
|
it('should select by attr name only once if the value is from the DOM', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
matcher.addSelectables(s1 = CssSelector.parse('[some-decor]'), 1);
|
2014-11-11 20:33:47 -05:00
|
|
|
|
|
|
|
var elementSelector = new CssSelector();
|
2015-01-08 12:11:33 -05:00
|
|
|
var element = el('<div attr></div>');
|
2015-03-09 06:37:59 -04:00
|
|
|
var empty = DOM.getAttribute(element, 'attr');
|
2014-11-11 20:33:47 -05:00
|
|
|
elementSelector.addAttribute('some-decor', empty);
|
|
|
|
matcher.match(elementSelector, selectableCollector);
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matched).toEqual([s1[0], 1]);
|
2014-11-11 20:33:47 -05:00
|
|
|
});
|
|
|
|
|
2014-10-28 17:46:55 -04:00
|
|
|
it('should select by attr name and value case insensitive', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
matcher.addSelectables(s1 = CssSelector.parse('[someAttr=someValue]'), 1);
|
2014-10-28 17:46:55 -04:00
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('[SOMEATTR=SOMEOTHERATTR]')[0], selectableCollector))
|
|
|
|
.toEqual(false);
|
2014-10-28 17:46:55 -04:00
|
|
|
expect(matched).toEqual([]);
|
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('[SOMEATTR=SOMEVALUE]')[0], selectableCollector))
|
|
|
|
.toEqual(true);
|
|
|
|
expect(matched).toEqual([s1[0], 1]);
|
2014-10-28 17:46:55 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should select by element name, class name and attribute name with value', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
matcher.addSelectables(s1 = CssSelector.parse('someTag.someClass[someAttr=someValue]'), 1);
|
2014-10-28 17:46:55 -04:00
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('someOtherTag.someOtherClass[someOtherAttr]')[0],
|
|
|
|
selectableCollector))
|
|
|
|
.toEqual(false);
|
2014-10-28 17:46:55 -04:00
|
|
|
expect(matched).toEqual([]);
|
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('someTag.someOtherClass[someOtherAttr]')[0],
|
|
|
|
selectableCollector))
|
|
|
|
.toEqual(false);
|
2014-10-28 17:46:55 -04:00
|
|
|
expect(matched).toEqual([]);
|
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('someTag.someClass[someOtherAttr]')[0],
|
|
|
|
selectableCollector))
|
|
|
|
.toEqual(false);
|
2014-10-28 17:46:55 -04:00
|
|
|
expect(matched).toEqual([]);
|
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(
|
|
|
|
matcher.match(CssSelector.parse('someTag.someClass[someAttr]')[0], selectableCollector))
|
|
|
|
.toEqual(false);
|
2014-10-28 17:46:55 -04:00
|
|
|
expect(matched).toEqual([]);
|
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('someTag.someClass[someAttr=someValue]')[0],
|
|
|
|
selectableCollector))
|
|
|
|
.toEqual(true);
|
|
|
|
expect(matched).toEqual([s1[0], 1]);
|
2014-10-28 17:46:55 -04:00
|
|
|
});
|
|
|
|
|
2015-03-19 18:38:48 -04:00
|
|
|
it('should select by many attributes and independent of the value', () => {
|
|
|
|
matcher.addSelectables(s1 = CssSelector.parse('input[type=text][control]'), 1);
|
|
|
|
|
|
|
|
var cssSelector = new CssSelector();
|
|
|
|
cssSelector.setElement('input');
|
|
|
|
cssSelector.addAttribute('type', 'text');
|
|
|
|
cssSelector.addAttribute('control', 'one');
|
|
|
|
|
|
|
|
expect(matcher.match(cssSelector, selectableCollector)).toEqual(true);
|
|
|
|
expect(matched).toEqual([s1[0], 1]);
|
|
|
|
});
|
|
|
|
|
2014-10-28 17:46:55 -04:00
|
|
|
it('should select independent of the order in the css selector', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
matcher.addSelectables(s1 = CssSelector.parse('[someAttr].someClass'), 1);
|
|
|
|
matcher.addSelectables(s2 = CssSelector.parse('.someClass[someAttr]'), 2);
|
|
|
|
matcher.addSelectables(s3 = CssSelector.parse('.class1.class2'), 3);
|
|
|
|
matcher.addSelectables(s4 = CssSelector.parse('.class2.class1'), 4);
|
2014-10-28 17:46:55 -04:00
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('[someAttr].someClass')[0], selectableCollector))
|
|
|
|
.toEqual(true);
|
|
|
|
expect(matched).toEqual([s1[0], 1, s2[0], 2]);
|
2014-10-28 17:46:55 -04:00
|
|
|
|
|
|
|
reset();
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('.someClass[someAttr]')[0], selectableCollector))
|
|
|
|
.toEqual(true);
|
|
|
|
expect(matched).toEqual([s1[0], 1, s2[0], 2]);
|
2014-10-28 17:46:55 -04:00
|
|
|
|
|
|
|
reset();
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('.class1.class2')[0], selectableCollector))
|
|
|
|
.toEqual(true);
|
|
|
|
expect(matched).toEqual([s3[0], 3, s4[0], 4]);
|
2014-10-28 17:46:55 -04:00
|
|
|
|
|
|
|
reset();
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('.class2.class1')[0], selectableCollector))
|
|
|
|
.toEqual(true);
|
|
|
|
expect(matched).toEqual([s4[0], 4, s3[0], 3]);
|
2014-10-28 17:46:55 -04:00
|
|
|
});
|
2015-03-12 04:44:49 -04:00
|
|
|
|
|
|
|
it('should not select with a matching :not selector', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
matcher.addSelectables(CssSelector.parse('p:not(.someClass)'), 1);
|
|
|
|
matcher.addSelectables(CssSelector.parse('p:not([someAttr])'), 2);
|
|
|
|
matcher.addSelectables(CssSelector.parse(':not(.someClass)'), 3);
|
|
|
|
matcher.addSelectables(CssSelector.parse(':not(p)'), 4);
|
|
|
|
matcher.addSelectables(CssSelector.parse(':not(p[someAttr])'), 5);
|
2015-03-12 04:44:49 -04:00
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('p.someClass[someAttr]')[0], selectableCollector))
|
|
|
|
.toEqual(false);
|
2015-03-12 04:44:49 -04:00
|
|
|
expect(matched).toEqual([]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should select with a non matching :not selector', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
matcher.addSelectables(s1 = CssSelector.parse('p:not(.someClass)'), 1);
|
|
|
|
matcher.addSelectables(s2 = CssSelector.parse('p:not(.someOtherClass[someAttr])'), 2);
|
|
|
|
matcher.addSelectables(s3 = CssSelector.parse(':not(.someClass)'), 3);
|
|
|
|
matcher.addSelectables(s4 = CssSelector.parse(':not(.someOtherClass[someAttr])'), 4);
|
2015-03-12 04:44:49 -04:00
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('p[someOtherAttr].someOtherClass')[0],
|
|
|
|
selectableCollector))
|
|
|
|
.toEqual(true);
|
|
|
|
expect(matched).toEqual([s1[0], 1, s2[0], 2, s3[0], 3, s4[0], 4]);
|
2015-03-19 12:01:42 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should select with one match in a list', () => {
|
2015-05-26 12:25:39 -04:00
|
|
|
matcher.addSelectables(s1 = CssSelector.parse('input[type=text], textbox'), 1);
|
2015-03-19 12:01:42 -04:00
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('textbox')[0], selectableCollector)).toEqual(true);
|
|
|
|
expect(matched).toEqual([s1[1], 1]);
|
2015-03-19 12:01:42 -04:00
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
reset();
|
|
|
|
expect(matcher.match(CssSelector.parse('input[type=text]')[0], selectableCollector))
|
|
|
|
.toEqual(true);
|
|
|
|
expect(matched).toEqual([s1[0], 1]);
|
2015-03-19 12:01:42 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should not select twice with two matches in a list', () => {
|
2015-05-26 12:25:39 -04:00
|
|
|
matcher.addSelectables(s1 = CssSelector.parse('input, .someClass'), 1);
|
2015-03-19 12:01:42 -04:00
|
|
|
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(matcher.match(CssSelector.parse('input.someclass')[0], selectableCollector))
|
|
|
|
.toEqual(true);
|
|
|
|
expect(matched.length).toEqual(2);
|
|
|
|
expect(matched).toEqual([s1[0], 1]);
|
2015-03-12 04:44:49 -04:00
|
|
|
});
|
2014-10-28 17:46:55 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
describe('CssSelector.parse', () => {
|
|
|
|
it('should detect element names', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
var cssSelector = CssSelector.parse('sometag')[0];
|
2014-10-28 17:46:55 -04:00
|
|
|
expect(cssSelector.element).toEqual('sometag');
|
|
|
|
expect(cssSelector.toString()).toEqual('sometag');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should detect class names', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
var cssSelector = CssSelector.parse('.someClass')[0];
|
2014-10-28 17:46:55 -04:00
|
|
|
expect(cssSelector.classNames).toEqual(['someclass']);
|
|
|
|
|
|
|
|
expect(cssSelector.toString()).toEqual('.someclass');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should detect attr names', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
var cssSelector = CssSelector.parse('[attrname]')[0];
|
2014-11-11 20:33:47 -05:00
|
|
|
expect(cssSelector.attrs).toEqual(['attrname', '']);
|
|
|
|
|
|
|
|
expect(cssSelector.toString()).toEqual('[attrname]');
|
2014-10-28 17:46:55 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should detect attr values', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
var cssSelector = CssSelector.parse('[attrname=attrvalue]')[0];
|
2014-11-11 20:33:47 -05:00
|
|
|
expect(cssSelector.attrs).toEqual(['attrname', 'attrvalue']);
|
2014-10-28 17:46:55 -04:00
|
|
|
expect(cssSelector.toString()).toEqual('[attrname=attrvalue]');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should detect multiple parts', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
var cssSelector = CssSelector.parse('sometag[attrname=attrvalue].someclass')[0];
|
2014-10-28 17:46:55 -04:00
|
|
|
expect(cssSelector.element).toEqual('sometag');
|
2014-11-11 20:33:47 -05:00
|
|
|
expect(cssSelector.attrs).toEqual(['attrname', 'attrvalue']);
|
2014-10-28 17:46:55 -04:00
|
|
|
expect(cssSelector.classNames).toEqual(['someclass']);
|
|
|
|
|
|
|
|
expect(cssSelector.toString()).toEqual('sometag.someclass[attrname=attrvalue]');
|
|
|
|
});
|
2015-03-12 04:44:49 -04:00
|
|
|
|
2015-03-19 18:38:48 -04:00
|
|
|
it('should detect multiple attributes', () => {
|
|
|
|
var cssSelector = CssSelector.parse('input[type=text][control]')[0];
|
|
|
|
expect(cssSelector.element).toEqual('input');
|
|
|
|
expect(cssSelector.attrs).toEqual(['type', 'text', 'control', '']);
|
|
|
|
|
|
|
|
expect(cssSelector.toString()).toEqual('input[type=text][control]');
|
|
|
|
});
|
|
|
|
|
2015-03-12 04:44:49 -04:00
|
|
|
it('should detect :not', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
var cssSelector = CssSelector.parse('sometag:not([attrname=attrvalue].someclass)')[0];
|
2015-03-12 04:44:49 -04:00
|
|
|
expect(cssSelector.element).toEqual('sometag');
|
|
|
|
expect(cssSelector.attrs.length).toEqual(0);
|
|
|
|
expect(cssSelector.classNames.length).toEqual(0);
|
|
|
|
|
|
|
|
var notSelector = cssSelector.notSelector;
|
|
|
|
expect(notSelector.element).toEqual(null);
|
|
|
|
expect(notSelector.attrs).toEqual(['attrname', 'attrvalue']);
|
|
|
|
expect(notSelector.classNames).toEqual(['someclass']);
|
|
|
|
|
|
|
|
expect(cssSelector.toString()).toEqual('sometag:not(.someclass[attrname=attrvalue])');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should detect :not without truthy', () => {
|
2015-03-19 12:01:42 -04:00
|
|
|
var cssSelector = CssSelector.parse(':not([attrname=attrvalue].someclass)')[0];
|
2015-03-12 04:44:49 -04:00
|
|
|
expect(cssSelector.element).toEqual("*");
|
|
|
|
|
|
|
|
var notSelector = cssSelector.notSelector;
|
|
|
|
expect(notSelector.attrs).toEqual(['attrname', 'attrvalue']);
|
|
|
|
expect(notSelector.classNames).toEqual(['someclass']);
|
|
|
|
|
|
|
|
expect(cssSelector.toString()).toEqual('*:not(.someclass[attrname=attrvalue])');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should throw when nested :not', () => {
|
2015-05-26 12:25:39 -04:00
|
|
|
expect(() => { CssSelector.parse('sometag:not(:not([attrname=attrvalue].someclass))')[0]; })
|
|
|
|
.toThrowError('Nesting :not is not allowed in a selector');
|
2015-03-12 04:44:49 -04:00
|
|
|
});
|
2015-03-19 12:01:42 -04:00
|
|
|
|
|
|
|
it('should detect lists of selectors', () => {
|
|
|
|
var cssSelectors = CssSelector.parse('.someclass,[attrname=attrvalue], sometag');
|
|
|
|
expect(cssSelectors.length).toEqual(3);
|
|
|
|
|
|
|
|
expect(cssSelectors[0].classNames).toEqual(['someclass']);
|
|
|
|
expect(cssSelectors[1].attrs).toEqual(['attrname', 'attrvalue']);
|
|
|
|
expect(cssSelectors[2].element).toEqual('sometag');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should detect lists of selectors with :not', () => {
|
2015-05-26 12:25:39 -04:00
|
|
|
var cssSelectors =
|
|
|
|
CssSelector.parse('input[type=text], :not(textarea), textbox:not(.special)');
|
2015-03-19 12:01:42 -04:00
|
|
|
expect(cssSelectors.length).toEqual(3);
|
|
|
|
|
|
|
|
expect(cssSelectors[0].element).toEqual('input');
|
|
|
|
expect(cssSelectors[0].attrs).toEqual(['type', 'text']);
|
|
|
|
|
|
|
|
expect(cssSelectors[1].element).toEqual('*');
|
|
|
|
expect(cssSelectors[1].notSelector.element).toEqual('textarea');
|
|
|
|
|
|
|
|
expect(cssSelectors[2].element).toEqual('textbox');
|
|
|
|
expect(cssSelectors[2].notSelector.classNames).toEqual(['special']);
|
|
|
|
});
|
2014-10-28 17:46:55 -04:00
|
|
|
});
|
|
|
|
}
|