Housekeeping node tests, renamed to unit-tests (#4936)

Add parsers for the background css shorthand property, make ViewBase unit testable in node environment

Add background parser and linear-gradient parser

Use sticky regexes

Simplify some types, introduce generic Parsed<T> instead of & TokenRange

Apply each parser to return a { start, end, value } object

Move the css selector parser to the css/parser and unify types

Add the first steps toward building homegrown css parser

Add somewhat standards compliant tokenizer, add baseline, rework and shady css parsers

Enable all tests again, skip flaky perf test

Improve css parser tokenizer by converting some char token types to simple string

Implement 'parse a stylesheet'

Add gonzales css-parser

Add parseLib and css-tree perf

Add a thin parser layer that will convert CSS3 tokens to values, for now output is compatible with rework

Make root tsc green

Return the requires of tns-core-modules to use relative paths for webpack to work

Implement support for '@import 'url-string';

Fix function parser, function-token is no-longer neglected

Make the style-scope be able to load from "css" and "css-ast" modules

Add a loadAppCss event so theme can be added to snapshot separately from loaded
This commit is contained in:
Panayot Cankov
2017-10-20 10:42:07 +03:00
committed by Hristo Hristov
parent 2eba7c66e4
commit f7a3a36b9c
64 changed files with 2875 additions and 1281 deletions

View File

@@ -148,12 +148,6 @@ allTests["VISUAL-STATE"] = visualStateTests;
import * as valueSourceTests from "./ui/styling/value-source-tests";
allTests["VALUE-SOURCE"] = valueSourceTests;
import * as cssSelectorParserTests from "./ui/styling/css-selector-parser";
allTests["CSS-SELECTOR-PARSER"] = cssSelectorParserTests;
import * as cssSelectorTests from "./ui/styling/css-selector";
allTests["CSS-SELECTOR"] = cssSelectorTests;
import * as buttonTests from "./ui/button/button-tests";
allTests["BUTTON"] = buttonTests;

View File

@@ -1,141 +0,0 @@
import * as parser from "tns-core-modules/ui/styling/css-selector-parser";
import * as TKUnit from "../../TKUnit";
function test(css: string, expected: {}): void {
let result = parser.parse(css);
TKUnit.assertDeepEqual(result, expected);
}
export function test_fairly_complex_selector(): void {
test(` listview#products.mark gridlayout:selected[row="2"] a> b > c >d>e *[src] `, [
{ pos: 2, type: "", ident: "listview" },
{ pos: 10, type: "#", ident: "products" },
{ pos: 19, type: ".", ident: "mark", comb: " " },
{ pos: 25, type: "", ident: "gridlayout" },
{ pos: 35, type: ":", ident: "selected" },
{ pos: 44, type: "[]", prop: "row", test: "=", value: "2", comb: " " },
{ pos: 54, type: "", ident: "a", comb: ">" },
{ pos: 57, type: "", ident: "b", comb: ">" },
{ pos: 63, type: "", ident: "c", comb: ">" },
{ pos: 66, type: "", ident: "d", comb: ">" },
{ pos: 68, type: "", ident: "e", comb: " " },
{ pos: 70, type: "*" },
{ pos: 71, type: "[]", prop: "src" }
]);
}
export function test_typeguard_isUniversal(): void {
let selector = parser.parse("*")[0];
TKUnit.assertTrue(parser.isUniversal(selector));
TKUnit.assertFalse(parser.isType(selector));
TKUnit.assertFalse(parser.isClass(selector));
TKUnit.assertFalse(parser.isId(selector));
TKUnit.assertFalse(parser.isPseudo(selector));
TKUnit.assertFalse(parser.isAttribute(selector));
}
export function test_typeguard_isType(): void {
let selector = parser.parse("button")[0];
TKUnit.assertFalse(parser.isUniversal(selector));
TKUnit.assertTrue(parser.isType(selector));
TKUnit.assertFalse(parser.isClass(selector));
TKUnit.assertFalse(parser.isId(selector));
TKUnit.assertFalse(parser.isPseudo(selector));
TKUnit.assertFalse(parser.isAttribute(selector));
}
export function test_typeguard_isClass(): void {
let selector = parser.parse(".login")[0];
TKUnit.assertFalse(parser.isUniversal(selector));
TKUnit.assertFalse(parser.isType(selector));
TKUnit.assertTrue(parser.isClass(selector));
TKUnit.assertFalse(parser.isId(selector));
TKUnit.assertFalse(parser.isPseudo(selector));
TKUnit.assertFalse(parser.isAttribute(selector));
}
export function test_typeguard_isId(): void {
let selector = parser.parse("#login")[0];
TKUnit.assertFalse(parser.isUniversal(selector));
TKUnit.assertFalse(parser.isType(selector));
TKUnit.assertFalse(parser.isClass(selector));
TKUnit.assertTrue(parser.isId(selector));
TKUnit.assertFalse(parser.isPseudo(selector));
TKUnit.assertFalse(parser.isAttribute(selector));
}
export function test_typeguard_isPseudo(): void {
let selector = parser.parse(":hover")[0];
TKUnit.assertFalse(parser.isUniversal(selector));
TKUnit.assertFalse(parser.isType(selector));
TKUnit.assertFalse(parser.isClass(selector));
TKUnit.assertFalse(parser.isId(selector));
TKUnit.assertTrue(parser.isPseudo(selector));
TKUnit.assertFalse(parser.isAttribute(selector));
}
export function test_typeguard_isAttribute(): void {
let selector = parser.parse("[src]")[0];
TKUnit.assertFalse(parser.isUniversal(selector));
TKUnit.assertFalse(parser.isType(selector));
TKUnit.assertFalse(parser.isClass(selector));
TKUnit.assertFalse(parser.isId(selector));
TKUnit.assertFalse(parser.isPseudo(selector));
TKUnit.assertTrue(parser.isAttribute(selector));
}
export function test_universal_selector(): void {
test(`*`, [{ pos: 0, type: "*" }]);
}
export function test_type_selector(): void {
test(`button`, [{ pos: 0, type: "", ident: "button" }]);
}
export function test_class_selector(): void {
test(`.red`, [{ pos: 0, type: ".", ident: "red" }]);
}
export function test_id_selector(): void {
test(`#login`, [{ pos: 0, type: "#", ident: "login" }]);
}
export function test_pseudoClass(): void {
test(`:hover`, [{ pos: 0, type: ":", ident: "hover" }]);
}
export function test_attribute_no_value(): void {
test(`[src]`, [{ pos: 0, type: "[]", prop: "src" }]);
}
export function test_attribute_equal(): void {
test(`[src = "res://"]`, [{ pos: 0, type: "[]", prop: "src", test: "=", value: `res://` }]);
}
export function test_attribute_all_tests(): void {
["=", "^=", "$=", "*=", "=", "~=", "|="].forEach(t => test(`[src ${t} "val"]`, [{ pos: 0, type: "[]", prop: "src", test: t, value: "val"}]));
}
export function test_direct_parent_comb(): void {
test(`listview > .image`, [
{ pos: 0, type: "", ident: "listview", comb: ">" },
{ pos: 11, type: ".", ident: "image" }
]);
}
export function test_ancestor_comb(): void {
test(`listview .image`, [
{ pos: 0, type: "", ident: "listview", comb: " " },
{ pos: 10, type: ".", ident: "image" }
]);
}
export function test_single_sequence(): void {
test(`button:hover`, [
{ pos: 0, type: "", ident: "button" },
{ pos: 6, type: ":", ident: "hover" }
]);
}
export function test_multiple_sequences(): void {
test(`listview>:selected image.product`, [
{ pos: 0, type: "", ident: "listview", comb: ">" },
{ pos: 9, type: ":", ident: "selected", comb: " " },
{ pos: 19, type: "", ident: "image" },
{ pos: 24, type: ".", ident: "product" }
]);
}
export function test_multiple_attribute_and_pseudo_classes(): void {
test(`button#login[user][pass]:focused:hovered`, [
{ pos: 0, type: "", ident: "button" },
{ pos: 6, type: "#", ident: "login" },
{ pos: 12, type: "[]", prop: "user" },
{ pos: 18, type: "[]", prop: "pass" },
{ pos: 24, type: ":", ident: "focused" },
{ pos: 32, type: ":", ident: "hovered" }
]);
}

View File

@@ -1,269 +0,0 @@
import * as selector from "tns-core-modules/ui/styling/css-selector";
import * as parser from "tns-core-modules/css";
import * as TKUnit from "../../TKUnit";
function create(css: string, source: string = "css-selectors.ts@test"): { rules: selector.RuleSet[], map: selector.SelectorsMap } {
let parse = parser.parse(css, { source });
let rulesAst = parse.stylesheet.rules.filter(n => n.type === "rule");
let rules = selector.fromAstNodes(rulesAst);
let map = new selector.SelectorsMap(rules);
return { rules, map };
}
function createOne(css: string, source: string = "css-selectors.ts@test"): selector.RuleSet {
let {rules} = create(css, source);
TKUnit.assertEqual(rules.length, 1);
return rules[0];
}
export function test_single_selector() {
let rule = createOne(`* { color: red; }`);
TKUnit.assertTrue(rule.selectors[0].match({ cssType: "button" }));
TKUnit.assertTrue(rule.selectors[0].match({ cssType: "image" }));
}
export function test_two_selectors() {
let rule = createOne(`button, image { color: red; }`);
TKUnit.assertTrue(rule.selectors[0].match({ cssType: "button" }));
TKUnit.assertTrue(rule.selectors[1].match({ cssType: "image" }));
TKUnit.assertFalse(rule.selectors[0].match({ cssType: "stacklayout" }));
TKUnit.assertFalse(rule.selectors[1].match({ cssType: "stacklayout" }));
}
export function test_narrow_selection() {
let {map} = create(`
.login { color: blue; }
button { color: red; }
image { color: green; }
`);
let buttonQuerry = map.query({ cssType: "button" }).selectors;
TKUnit.assertEqual(buttonQuerry.length, 1);
TKUnit.assertDeepSuperset(buttonQuerry[0].ruleset.declarations, [
{ property: "color", value: "red" }
]);
let imageQuerry = map.query({ cssType: "image", cssClasses: new Set(["login"]) }).selectors;
TKUnit.assertEqual(imageQuerry.length, 2);
// Note class before type
TKUnit.assertDeepSuperset(imageQuerry[0].ruleset.declarations, [
{ property: "color", value: "green" }
]);
TKUnit.assertDeepSuperset(imageQuerry[1].ruleset.declarations, [
{ property: "color", value: "blue" }
]);
}
let positiveMatches = {
"*": (view) => true,
"type": (view) => view.cssType === "type",
"#id": (view) => view.id === "id",
".class": (view) => view.cssClasses.has("class"),
":pseudo": (view) => view.cssPseudoClasses.has("pseudo"),
"[src1]": (view) => "src1" in view,
"[src2='src-value']": (view) => view['src2'] === 'src-value'
}
let positivelyMatchingView = {
cssType: "type",
id: "id",
cssClasses: new Set(["class"]),
cssPseudoClasses: new Set(["pseudo"]),
"src1": "src",
"src2": "src-value"
}
let negativelyMatchingView = {
cssType: "nottype",
id: "notid",
cssClasses: new Set(["notclass"]),
cssPseudoClasses: new Set(["notpseudo"]),
// Has no "src1"
"src2": "not-src-value"
}
export function test_simple_selectors_match() {
for (let sel in positiveMatches) {
let css = sel + " { color: red; }";
let rule = createOne(css);
TKUnit.assertTrue(rule.selectors[0].match(positivelyMatchingView), "Expected successful match for: " + css);
if (sel !== "*") {
TKUnit.assertFalse(rule.selectors[0].match(negativelyMatchingView), "Expected match failure for: " + css);
}
}
}
export function test_two_selector_sequence_positive_match() {
for (let firstStr in positiveMatches) {
for (let secondStr in positiveMatches) {
if (secondStr !== firstStr && secondStr !== "*" && secondStr !== "type") {
let css = firstStr + secondStr + " { color: red; }";
let rule = createOne(css);
TKUnit.assertTrue(rule.selectors[0].match(positivelyMatchingView), "Expected successful match for: " + css);
if (firstStr !== "*") {
TKUnit.assertFalse(rule.selectors[0].match(negativelyMatchingView), "Expected match failure for: " + css);
}
}
}
}
}
export function test_direct_parent_combinator() {
let rule = createOne(`listview > item:selected { color: red; }`);
TKUnit.assertTrue(rule.selectors[0].match({
cssType: "item",
cssPseudoClasses: new Set(["selected"]),
parent: {
cssType: "listview"
}
}), "Item in list view expected to match");
TKUnit.assertFalse(rule.selectors[0].match({
cssType: "item",
cssPseudoClasses: new Set(["selected"]),
parent: {
cssType: "stacklayout",
parent: {
cssType: "listview"
}
}
}), "Item in stack in list view NOT expected to match.");
}
export function test_ancestor_combinator() {
let rule = createOne(`listview item:selected { color: red; }`);
TKUnit.assertTrue(rule.selectors[0].match({
cssType: "item",
cssPseudoClasses: new Set(["selected"]),
parent: {
cssType: "listview"
}
}), "Item in list view expected to match");
TKUnit.assertTrue(rule.selectors[0].match({
cssType: "item",
cssPseudoClasses: new Set(["selected"]),
parent: {
cssType: "stacklayout",
parent: {
cssType: "listview"
}
}
}), "Item in stack in list view expected to match.");
TKUnit.assertFalse(rule.selectors[0].match({
cssType: "item",
cssPseudoClasses: new Set(["selected"]),
parent: {
cssType: "stacklayout",
parent: {
cssType: "page"
}
}
}), "Item in stack in page NOT expected to match.");
}
export function test_backtracking_css_selector() {
let sel = createOne(`a>b c { color: red; }`).selectors[0];
let child = {
cssType: "c",
parent: {
cssType: "b",
parent: {
cssType: "fail",
parent: {
cssType: "b",
parent: {
cssType: "a"
}
}
}
}
}
TKUnit.assertTrue(sel.match(child));
}
function toString() { return this.cssType; }
export function test_simple_query_match() {
let {map} = create(`list grid[promotion] button:highlighted { color: red; }`);
let list, grid, button;
button = {
cssType: "button",
cssPseudoClasses: new Set<string>(["highlighted"]),
toString,
parent: grid = {
cssType: "grid",
promotion: true,
toString,
parent: list = {
cssType: "list",
toString
}
}
}
let match = map.query(button);
TKUnit.assertEqual(match.selectors.length, 1, "Expected match to have one selector.");
let expected = new Map<selector.Node, selector.Changes>()
.set(grid, { attributes: new Set(["promotion"]) })
.set(button, { pseudoClasses: new Set(["highlighted"]) });
TKUnit.assertDeepEqual(match.changeMap, expected);
}
export function test_query_match_one_child_group() {
let {map} = create(`#prod[special] > gridlayout { color: red; }`);
let gridlayout, prod;
gridlayout = {
cssType: "gridlayout",
toString,
parent: prod = {
id: "prod",
cssType: "listview",
toString
}
};
let match = map.query(gridlayout);
TKUnit.assertEqual(match.selectors.length, 1, "Expected match to have one selector.");
let expected = new Map<selector.Node, selector.Changes>().set(prod, { attributes: new Set(["special"])} );
TKUnit.assertDeepEqual(match.changeMap, expected);
}
export function test_query_match_one_sibling_group() {
let {map} = create(`list button:highlighted+button:disabled { color: red; }`);
let list, button, disabledButton;
list = {
cssType: "list",
toString,
getChildIndex: () => 1,
getChildAt: () => button
};
button = {
cssType: "button",
cssPseudoClasses: new Set<string>(["highlighted"]),
toString,
parent: list
};
disabledButton = {
cssType: "button",
cssPseudoClasses: new Set<string>(["disabled"]),
toString,
parent: list
};
let match = map.query(disabledButton);
TKUnit.assertEqual(match.selectors.length, 1, "Expected match to have one selector.");
let expected = new Map<selector.Node, selector.Changes>()
.set(button, { pseudoClasses: new Set(["highlighted"]) })
.set(disabledButton, { pseudoClasses: new Set(["disabled"]) });
TKUnit.assertDeepEqual(match.changeMap, expected);
}