mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Merge branch 'master'
This commit is contained in:
85
unit-tests/css-tree-parser/css-tree-parser.ts
Normal file
85
unit-tests/css-tree-parser/css-tree-parser.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { cssTreeParse } from "@nativescript/core/css/css-tree-parser";
|
||||
import { parse as reworkCssParse } from "@nativescript/core/css";
|
||||
import { assert } from "chai";
|
||||
|
||||
describe("css-tree parser compatible with rework ", () => {
|
||||
it("basic selector", () => {
|
||||
const testCase = ".test { color: red; }";
|
||||
const reworkAST = reworkCssParse(testCase, { source: "file.css" });
|
||||
const cssTreeAST = cssTreeParse(testCase, "file.css");
|
||||
|
||||
assert.deepEqual(cssTreeAST, reworkAST);
|
||||
});
|
||||
|
||||
it("@keyframes", () => {
|
||||
const testCase = ".test { animation-name: test; } @keyframes test { from { background-color: red; } to { background-color: blue; } } .test { color: red; }";
|
||||
const reworkAST = reworkCssParse(testCase, { source: "file.css" });
|
||||
const cssTreeAST = cssTreeParse(testCase, "file.css");
|
||||
|
||||
assert.deepEqual(cssTreeAST, reworkAST);
|
||||
});
|
||||
|
||||
it("@media", () => {
|
||||
const testCase = "@media screen and (max-width: 600px) { body { background-color: olive; } } .test { color: red; }";
|
||||
const reworkAST = reworkCssParse(testCase, { source: "file.css" });
|
||||
const cssTreeAST = cssTreeParse(testCase, "file.css");
|
||||
|
||||
assert.deepEqual(cssTreeAST, reworkAST);
|
||||
});
|
||||
|
||||
it("@supports", () => {
|
||||
const testCase = "@supports not (display: grid) { div { float: right; } } .test { color: red; }";
|
||||
const reworkAST = reworkCssParse(testCase, { source: "file.css" });
|
||||
const cssTreeAST = cssTreeParse(testCase, "file.css");
|
||||
|
||||
assert.deepEqual(cssTreeAST, reworkAST);
|
||||
});
|
||||
|
||||
it("@page", () => {
|
||||
const testCase = "@page :first { margin: 2cm; } .test { color: red; }";
|
||||
const reworkAST = reworkCssParse(testCase, { source: "file.css" });
|
||||
const cssTreeAST = cssTreeParse(testCase, "file.css");
|
||||
|
||||
assert.deepEqual(cssTreeAST, reworkAST);
|
||||
});
|
||||
|
||||
it("@document", () => {
|
||||
const testCase = "@document url(\"https://www.example.com/\") { h1 { color: green; } } .test { color: red; }";
|
||||
const reworkAST = reworkCssParse(testCase, { source: "file.css" });
|
||||
const cssTreeAST = cssTreeParse(testCase, "file.css");
|
||||
|
||||
assert.deepEqual(cssTreeAST, reworkAST);
|
||||
});
|
||||
|
||||
it("@font-face", () => {
|
||||
const testCase = "@font-face { font-family: \"Open Sans\"; src: url(\"/fonts/OpenSans-Regular-webfont.woff2\") format(\"woff2\"), url(\"/fonts/OpenSans-Regular-webfont.woff\") format(\"woff\"); } .test { color: red; }";
|
||||
const reworkAST = reworkCssParse(testCase, { source: "file.css" });
|
||||
const cssTreeAST = cssTreeParse(testCase, "file.css");
|
||||
|
||||
assert.deepEqual(cssTreeAST, reworkAST);
|
||||
});
|
||||
|
||||
it("@import", () => {
|
||||
const testCase = "@import url('landscape.css') screen and (orientation:landscape); @import url(\"fineprint.css\") print; .test { color: red; }";
|
||||
const reworkAST = reworkCssParse(testCase, { source: "file.css" });
|
||||
const cssTreeAST = cssTreeParse(testCase, "file.css");
|
||||
|
||||
assert.deepEqual(cssTreeAST, reworkAST);
|
||||
});
|
||||
|
||||
it("@charset", () => {
|
||||
const testCase = "@charset \"utf-8\"; .test { color: red; }";
|
||||
const reworkAST = reworkCssParse(testCase, { source: "file.css" });
|
||||
const cssTreeAST = cssTreeParse(testCase, "file.css");
|
||||
|
||||
assert.deepEqual(cssTreeAST, reworkAST);
|
||||
});
|
||||
|
||||
it("@namespace", () => {
|
||||
const testCase = "@namespace svg url(http://www.w3.org/2000/svg); .test { color: red; }";
|
||||
const reworkAST = reworkCssParse(testCase, { source: "file.css" });
|
||||
const cssTreeAST = cssTreeParse(testCase, "file.css");
|
||||
|
||||
assert.deepEqual(cssTreeAST, reworkAST);
|
||||
});
|
||||
});
|
||||
@@ -10,19 +10,16 @@ import {
|
||||
CSS3Parser,
|
||||
TokenObjectType,
|
||||
CSSNativeScript,
|
||||
} from "tns-core-modules/css/parser";
|
||||
import {
|
||||
parse
|
||||
} from "tns-core-modules/css";
|
||||
} from "@nativescript/core/css/parser";
|
||||
|
||||
import * as fs from "fs";
|
||||
import * as shadyCss from 'shady-css-parser';
|
||||
import * as reworkCss from 'css';
|
||||
import * as shadyCss from "shady-css-parser";
|
||||
import * as reworkCss from "css";
|
||||
|
||||
const parseCss: any = require('parse-css');
|
||||
const gonzales: any = require('gonzales');
|
||||
const parseCss: any = require("parse-css");
|
||||
const gonzales: any = require("gonzales");
|
||||
const parserlib: any = require("parserlib");
|
||||
const csstree: any = require('css-tree');
|
||||
const csstree: any = require("css-tree");
|
||||
|
||||
describe("css", () => {
|
||||
describe("parser", () => {
|
||||
@@ -45,7 +42,7 @@ describe("css", () => {
|
||||
describe("values", () => {
|
||||
describe("url", () => {
|
||||
test(parseURL, "url('smiley.gif') ", { start: 0, end: 19, value: "smiley.gif" });
|
||||
test(parseURL, ' url("frown.gif") ', { start: 0, end: 19, value: "frown.gif" });
|
||||
test(parseURL, " url(\"frown.gif\") ", { start: 0, end: 19, value: "frown.gif" });
|
||||
test(parseURL, " url(lucky.gif)", { start: 0, end: 16, value: "lucky.gif" });
|
||||
test(parseURL, "url(lucky.gif) #FF0000", 15, null);
|
||||
test(parseURL, "repeat url(lucky.gif) #FF0000", 6, { start: 6, end: 22, value: "lucky.gif" });
|
||||
@@ -56,6 +53,8 @@ describe("css", () => {
|
||||
test(parseColor, " #85456789 ", { start: 0, end: 12, value: 0x85456789 });
|
||||
test(parseColor, " rgb(255, 8, 128) ", { start: 0, end: 18, value: 0xFFFF0880 });
|
||||
test(parseColor, " rgba(255, 8, 128, 0.5) ", { start: 0, end: 24, value: 0x80FF0880 });
|
||||
test(parseColor, " hsl(330.9, 100%, 51.6%) ", { start: 0, end: 25, value: 0xFFFF0880 });
|
||||
test(parseColor, " hsla(330.9, 100%, 51.6%, 0.5) ", { start: 0, end: 31, value: 0x80FF0880 });
|
||||
test(parseColor, "#FF0000 url(lucky.gif)", 8, null);
|
||||
test(parseColor, "url(lucky.gif) #FF0000 repeat", 15, { start: 15, end: 23, value: 0xFFFF0000 });
|
||||
});
|
||||
@@ -90,8 +89,8 @@ describe("css", () => {
|
||||
});
|
||||
describe("background", () => {
|
||||
test(parseBackground, " #996633 ", { start: 0, end: 12, value: { color: 0xFF996633 }});
|
||||
test(parseBackground, ' #00ff00 url("smiley.gif") repeat-y ', { start: 0, end: 37, value: { color: 0xFF00FF00, image: "smiley.gif", repeat: "repeat-y" }});
|
||||
test(parseBackground, ' url(smiley.gif) no-repeat top 50% left 100% #00ff00', { start: 0, end: 56, value: {
|
||||
test(parseBackground, " #00ff00 url(\"smiley.gif\") repeat-y ", { start: 0, end: 37, value: { color: 0xFF00FF00, image: "smiley.gif", repeat: "repeat-y" }});
|
||||
test(parseBackground, " url(smiley.gif) no-repeat top 50% left 100% #00ff00", { start: 0, end: 56, value: {
|
||||
color: 0xFF00FF00,
|
||||
image: "smiley.gif",
|
||||
repeat: "no-repeat",
|
||||
@@ -101,7 +100,7 @@ describe("css", () => {
|
||||
y: { align: "top", offset: { value: 0.5, unit: "%" }}
|
||||
}
|
||||
}});
|
||||
test(parseBackground, ' url(smiley.gif) no-repeat top 50% left 100% / 100px 100px #00ff00', { start: 0, end: 70, value: {
|
||||
test(parseBackground, " url(smiley.gif) no-repeat top 50% left 100% / 100px 100px #00ff00", { start: 0, end: 70, value: {
|
||||
color: 0xFF00FF00,
|
||||
image: "smiley.gif",
|
||||
repeat: "no-repeat",
|
||||
@@ -112,24 +111,24 @@ describe("css", () => {
|
||||
},
|
||||
size: { x: { value: 100, unit: "px" }, y: { value: 100, unit: "px" }}
|
||||
}});
|
||||
test(parseBackground, ' linear-gradient(to right top) ', { start: 0, end: 32, value: {
|
||||
test(parseBackground, " linear-gradient(to right top) ", { start: 0, end: 32, value: {
|
||||
image: {
|
||||
angle: Math.PI * 1/4,
|
||||
angle: Math.PI * 1 / 4,
|
||||
colors: []
|
||||
}
|
||||
}});
|
||||
test(parseBackground, ' linear-gradient(45deg, #0000FF, #00FF00) ', { start: 0, end: 43, value: {
|
||||
test(parseBackground, " linear-gradient(45deg, #0000FF, #00FF00) ", { start: 0, end: 43, value: {
|
||||
image: {
|
||||
angle: Math.PI * 1/4,
|
||||
angle: Math.PI * 1 / 4,
|
||||
colors: [
|
||||
{ argb: 0xFF0000FF },
|
||||
{ argb: 0xFF00FF00 }
|
||||
]
|
||||
}
|
||||
}});
|
||||
test(parseBackground, 'linear-gradient(0deg, blue, green 40%, red)', { start: 0, end: 43, value: {
|
||||
test(parseBackground, "linear-gradient(0deg, blue, green 40%, red)", { start: 0, end: 43, value: {
|
||||
image: {
|
||||
angle: Math.PI * 0/4,
|
||||
angle: Math.PI * 0 / 4,
|
||||
colors: [
|
||||
{ argb: 0xFF0000FF },
|
||||
{ argb: 0xFF008000, offset: { value: 0.4, unit: "%" }},
|
||||
@@ -175,11 +174,11 @@ describe("css", () => {
|
||||
test(parseSelector, `[src ${attributeTest} "val"]`, { start: 0, end: 12 + attributeTest.length, value: [[[{ type: "[]", property: "src", test: attributeTest, value: "val"}], undefined]]});
|
||||
});
|
||||
test(parseSelector, "listview > .image", { start: 0, end: 17, value: [
|
||||
[[{ type: "", identifier: "listview"}], ">"],
|
||||
[[{ type: "", identifier: "listview"}], ">"],
|
||||
[[{ type: ".", identifier: "image"}], undefined]
|
||||
]});
|
||||
test(parseSelector, "listview .image", { start: 0, end: 16, value: [
|
||||
[[{ type: "", identifier: "listview"}], " "],
|
||||
[[{ type: "", identifier: "listview"}], " "],
|
||||
[[{ type: ".", identifier: "image"}], undefined]
|
||||
]});
|
||||
test(parseSelector, "button:hover", { start: 0, end: 12, value: [[[{ type: "", identifier: "button" }, { type: ":", identifier: "hover"}], undefined]]});
|
||||
@@ -227,15 +226,23 @@ describe("css", () => {
|
||||
|
||||
let original = themeCoreLightIos.replace(/\/\*([^\/]|\/[^\*])*\*\//g, "").replace(/\n/g, " ");
|
||||
let roundtrip = stylesheet.map(m => {
|
||||
if (!m) return "";
|
||||
if (typeof m === "string") return m;
|
||||
if (!m) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (typeof m === "string") {
|
||||
return m;
|
||||
}
|
||||
|
||||
return m.text;
|
||||
}).join("");
|
||||
|
||||
let lastIndex = Math.min(original.length, roundtrip.length);
|
||||
for(var i = 0; i < lastIndex; i++)
|
||||
if (original[i] != roundtrip[i])
|
||||
for (var i = 0; i < lastIndex; i++) {
|
||||
if (original[i] !== roundtrip[i]) {
|
||||
assert.equal(roundtrip.substr(i, 50), original.substr(i, 50), "Round-tripped CSS string differ at index: " + i);
|
||||
}
|
||||
}
|
||||
|
||||
assert.equal(roundtrip.length, original.length, "Expected round-tripped string lengths to match.");
|
||||
});
|
||||
@@ -317,7 +324,7 @@ describe("css", () => {
|
||||
const parser = new CSS3Parser(".btn-primary{border-color:rgba(255,0,0,0)}");
|
||||
const stylesheet = parser.parseAStylesheet();
|
||||
|
||||
assert.deepEqual(stylesheet, {rules:[
|
||||
assert.deepEqual(stylesheet, {rules: [
|
||||
{
|
||||
type: "qualified-rule",
|
||||
prelude: [{ type: 2, text: "." }, { type: 6, text: "btn-primary" }],
|
||||
@@ -368,6 +375,7 @@ describe("css", () => {
|
||||
const [startSec, startMSec] = process.hrtime();
|
||||
action();
|
||||
const [endSec, endMSec] = process.hrtime();
|
||||
|
||||
return (endSec - startSec) * 1000 + (endMSec - startMSec) / 1000000;
|
||||
}
|
||||
const charCodeByCharCodeDuration = trapDuration(() => {
|
||||
@@ -388,7 +396,7 @@ describe("css", () => {
|
||||
let char;
|
||||
let c = 0;
|
||||
for (let i = 0; i < themeCoreLightIos.length; i++) {
|
||||
const char = themeCoreLightIos[i];
|
||||
char = themeCoreLightIos[i];
|
||||
if ((char >= "a" && char <= "z") || (char >= "A" && char <= "Z") || char === "_") {
|
||||
c++;
|
||||
}
|
||||
@@ -400,7 +408,7 @@ describe("css", () => {
|
||||
let char;
|
||||
let c = 0;
|
||||
for (let i = 0; i < themeCoreLightIos.length; i++) {
|
||||
const char = themeCoreLightIos[i];
|
||||
char = themeCoreLightIos[i];
|
||||
if (compareCharRegEx.test(char)) {
|
||||
c++;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Observable } from "tns-core-modules/data/observable";
|
||||
import { Observable } from "@nativescript/core/data/observable";
|
||||
import { assert } from "chai";
|
||||
|
||||
describe("observable", () => {
|
||||
|
||||
@@ -3,19 +3,20 @@ import "tslib";
|
||||
import * as moduleAlias from "module-alias";
|
||||
import * as path from "path";
|
||||
|
||||
const tnsCoreModules = path.resolve(__dirname, "..", "tns-core-modules");
|
||||
const tnsCoreModules = path.resolve(__dirname, "..", "nativescript-core");
|
||||
|
||||
moduleAlias.addPath(tnsCoreModules);
|
||||
moduleAlias.addAliases({
|
||||
// NOTE: require("tns-core-modules/platform") with these aliases will work in node but fail in Angular AoT
|
||||
"tns-core-modules/platform": path.resolve(__dirname, "polyfills", "platform"),
|
||||
"tns-core-modules/file-system/file-system-access": path.resolve(__dirname, "polyfills", "file-system-access"),
|
||||
"tns-core-modules/utils/utils": path.resolve(tnsCoreModules, "utils/utils-common"),
|
||||
// NOTE: require("@nativescript/core/platform") with these aliases will work in node but fail in Angular AoT
|
||||
"@nativescript/core/platform": path.resolve(__dirname, "polyfills", "platform"),
|
||||
"@nativescript/core/file-system/file-system-access": path.resolve(__dirname, "polyfills", "file-system-access"),
|
||||
"@nativescript/core/utils/utils": path.resolve(tnsCoreModules, "utils/utils-common"),
|
||||
"./layout-helper": path.resolve(tnsCoreModules, "utils/layout-helper/layout-helper-common"),
|
||||
"./mainthread-helper": path.resolve(__dirname, "polyfills", "mainthread-helper"),
|
||||
"tns-core-modules/color": path.resolve(tnsCoreModules, "color/color-common"),
|
||||
"tns-core-modules/ui/styling/font": path.resolve(tnsCoreModules, "ui/styling/font-common"),
|
||||
"tns-core-modules/ui/styling/background": path.resolve(tnsCoreModules, "ui/styling/background-common"),
|
||||
"@nativescript/core/color": path.resolve(tnsCoreModules, "color/color-common"),
|
||||
"@nativescript/core/ui/styling/font": path.resolve(tnsCoreModules, "ui/styling/font-common"),
|
||||
"@nativescript/core/ui/styling/background": path.resolve(tnsCoreModules, "ui/styling/background-common"),
|
||||
|
||||
"tns-core-modules": tnsCoreModules,
|
||||
"@nativescript/core": tnsCoreModules,
|
||||
"~": __dirname
|
||||
});
|
||||
|
||||
42
unit-tests/tsconfig.json
Normal file
42
unit-tests/tsconfig.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noEmitOnError": false,
|
||||
"noEmitHelpers": true,
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"noImplicitUseStrict": true,
|
||||
"removeComments": true,
|
||||
"experimentalDecorators": true,
|
||||
"diagnostics": true,
|
||||
"sourceMap": true,
|
||||
"inlineSourceMap": false,
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
],
|
||||
"types": [
|
||||
"node",
|
||||
"chai",
|
||||
"mocha"
|
||||
],
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@nativescript/core/*": [
|
||||
"../nativescript-core/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"../nativescript-core/**/*.ts",
|
||||
"./**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"../nativescript-core/**/*.android.ts",
|
||||
"../nativescript-core/**/*.android.d.ts",
|
||||
"../nativescript-core/**/*.ios.ts",
|
||||
"../nativescript-core/**/*.ios.d.ts",
|
||||
"../nativescript-core/node-modules",
|
||||
"../nativescript-core/references.d.ts",
|
||||
"../nativescript-core/platforms"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { assert } from "chai";
|
||||
import * as parser from "tns-core-modules/css";
|
||||
import * as selector from "tns-core-modules/ui/styling/css-selector";
|
||||
import * as parser from "@nativescript/core/css";
|
||||
import * as selector from "@nativescript/core/ui/styling/css-selector";
|
||||
|
||||
describe("ui", () => {
|
||||
describe("styling", () => {
|
||||
@@ -22,12 +22,14 @@ describe("ui", () => {
|
||||
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);
|
||||
assert.equal(rules.length, 1);
|
||||
|
||||
return rules[0];
|
||||
}
|
||||
|
||||
@@ -51,7 +53,7 @@ describe("ui", () => {
|
||||
button { color: red; }
|
||||
image { color: green; }
|
||||
`);
|
||||
|
||||
|
||||
let buttonQuerry = map.query({ cssType: "button" }).selectors;
|
||||
assert.equal(buttonQuerry.length, 1);
|
||||
assert.includeDeepMembers(buttonQuerry[0].ruleset.declarations, [
|
||||
@@ -76,8 +78,8 @@ describe("ui", () => {
|
||||
".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'
|
||||
}
|
||||
"[src2='src-value']": (view) => view["src2"] === "src-value"
|
||||
};
|
||||
|
||||
let positivelyMatchingView = {
|
||||
cssType: "type",
|
||||
@@ -86,7 +88,7 @@ describe("ui", () => {
|
||||
cssPseudoClasses: new Set(["pseudo"]),
|
||||
"src1": "src",
|
||||
"src2": "src-value"
|
||||
}
|
||||
};
|
||||
|
||||
let negativelyMatchingView = {
|
||||
cssType: "nottype",
|
||||
@@ -95,7 +97,7 @@ describe("ui", () => {
|
||||
cssPseudoClasses: new Set(["notpseudo"]),
|
||||
// Has no "src1"
|
||||
"src2": "not-src-value"
|
||||
}
|
||||
};
|
||||
|
||||
it("simple selectors match", () => {
|
||||
for (let sel in positiveMatches) {
|
||||
@@ -191,7 +193,8 @@ describe("ui", () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
assert.isTrue(sel.match(child));
|
||||
});
|
||||
|
||||
@@ -215,7 +218,7 @@ describe("ui", () => {
|
||||
toString
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let match = map.query(button);
|
||||
assert.equal(match.selectors.length, 1, "Expected match to have one selector.");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {assert} from "chai";
|
||||
const xml = require("tns-core-modules/xml");
|
||||
const xml = require("@nativescript/core/xml");
|
||||
|
||||
describe("angular xml parser", () => {
|
||||
let last_element = null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {assert} from "chai";
|
||||
const xml = require("tns-core-modules/xml");
|
||||
import { assert } from "chai";
|
||||
const xml = require("@nativescript/core/xml");
|
||||
|
||||
describe("xml parser", () => {
|
||||
let last_element = null;
|
||||
@@ -27,7 +27,7 @@ describe("xml parser", () => {
|
||||
assert.equal('TextField', last_element);
|
||||
assert.equal('hello', last_attrs['text']);
|
||||
});
|
||||
|
||||
|
||||
it("resolves entities", () => {
|
||||
parser.parse("<element><>"&'</element>");
|
||||
assert.equal("<>\"&'", last_data);
|
||||
@@ -44,8 +44,8 @@ describe("xml parser", () => {
|
||||
});
|
||||
|
||||
it("resolves <> inside quotes", () => {
|
||||
parser.parse("<element name='<&>' blah=\"b<a&>\"/>");
|
||||
assert.equal("<&>", last_attrs.name);
|
||||
assert.equal("b<a&>", last_attrs.blah);
|
||||
parser.parse("<element name='<&>' blah=\"b<a&>\"/>");
|
||||
assert.equal("<&>", last_attrs.name);
|
||||
assert.equal("b<a&>", last_attrs.blah);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user