dart-sass/test/compressed_test.dart
Ed Rivas cca9464b09
Add support for running in the browser (#1895)
Closes #25

Co-authored-by: Jonny Gerig Meyer <jonny@oddbird.net>
Co-authored-by: Natalie Weizenbaum <nweiz@google.com>
2023-05-19 13:22:44 -07:00

323 lines
9.5 KiB
Dart

// Copyright 2018 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
@TestOn('vm')
import 'package:test/test.dart';
import 'package:sass/sass.dart';
void main() {
group("in style rules", () {
test("removes unnecessary whitespace and semicolons", () {
expect(_compile("a {x: y}"), equals("a{x:y}"));
});
group("for selectors", () {
test("preserves whitespace where necessary", () {
expect(_compile("a b .c {x: y}"), equals("a b .c{x:y}"));
});
test("removes whitespace after commas", () {
expect(_compile("a, b, .c {x: y}"), equals("a,b,.c{x:y}"));
});
test("doesn't preserve newlines", () {
expect(_compile("a,\nb,\n.c {x: y}"), equals("a,b,.c{x:y}"));
});
test("removes whitespace around combinators", () {
expect(_compile("a > b {x: y}"), equals("a>b{x:y}"));
expect(_compile("a + b {x: y}"), equals("a+b{x:y}"));
expect(_compile("a ~ b {x: y}"), equals("a~b{x:y}"));
});
group("in prefixed pseudos", () {
test("preserves whitespace", () {
expect(_compile("a:nth-child(2n of b) {x: y}"),
equals("a:nth-child(2n of b){x:y}"));
});
test("removes whitespace after commas", () {
expect(_compile("a:nth-child(2n of b, c) {x: y}"),
equals("a:nth-child(2n of b,c){x:y}"));
});
});
group("in attribute selectors with modifiers", () {
test("removes whitespace when quotes are required", () {
expect(_compile('[a=" " b] {x: y}'), equals('[a=" "b]{x:y}'));
});
test("doesn't remove whitespace when quotes aren't required", () {
expect(_compile('[a="b"c] {x: y}'), equals('[a=b c]{x:y}'));
});
});
});
group("for declarations", () {
test("preserves semicolons when necessary", () {
expect(_compile("a {q: r; s: t}"), equals("a{q:r;s:t}"));
});
group("of custom properties", () {
test("folds whitespace for multiline properties", () {
expect(_compile("""
a {
--foo: {
q: r;
b {
s: t;
}
}
}
"""), equals("a{--foo: { q: r; b { s: t; } } }"));
});
test("folds whitespace for single-line properties", () {
expect(_compile("""
a {
--foo: a b\t\tc;
}
"""), equals("a{--foo: a b\tc}"));
});
test("preserves semicolons when necessary", () {
expect(_compile("""
a {
--foo: {
a: b;
};
--bar: x y;
--baz: q r;
}
"""), equals("a{--foo: { a: b; };--bar: x y;--baz: q r}"));
});
});
});
});
group("values:", () {
group("numbers", () {
test("omit the leading 0", () {
expect(_compile("a {b: 0.123}"), equals("a{b:.123}"));
expect(_compile("a {b: 0.123px}"), equals("a{b:.123px}"));
});
});
group("lists", () {
test("don't include spaces after commas", () {
expect(_compile("a {b: x, y, z}"), equals("a{b:x,y,z}"));
});
test("don't include spaces around slashes", () {
expect(_compile("""
@use "sass:list";
a {b: list.slash(x, y, z)}
"""), equals("a{b:x/y/z}"));
});
test("do include spaces when space-separated", () {
expect(_compile("a {b: x y z}"), equals("a{b:x y z}"));
});
});
group("colors", () {
test("use names when they're shortest", () {
expect(_compile("a {b: #f00}"), equals("a{b:red}"));
});
test("use terse hex when it's shortest", () {
expect(_compile("a {b: white}"), equals("a{b:#fff}"));
});
test("use verbose hex when it's shortest", () {
expect(_compile("a {b: darkgoldenrod}"), equals("a{b:#b8860b}"));
});
test("use rgba() when necessary", () {
expect(_compile("a {b: rgba(255, 0, 0, 0.5)}"),
equals("a{b:rgba(255,0,0,.5)}"));
});
test("don't error when there's no name", () {
expect(_compile("a {b: #cc3232}"), equals("a{b:#cc3232}"));
});
});
group("strings", () {
group("emits private-use area characters as literal characters", () {
testCharacter(int character) {
var escape = "\\${character.toRadixString(16)}";
test(escape, () {
expect(
_compile("a {b: $escape}"),
equalsIgnoringWhitespace(
"a{b:${String.fromCharCode(character)}}"));
});
}
group("in the basic multilingual plane", () {
testCharacter(0xe000);
testCharacter(0xf000);
testCharacter(0xf8ff);
});
group("in the supplementary planes", () {
testCharacter(0xf0000);
testCharacter(0xfabcd);
testCharacter(0xffffd);
testCharacter(0x100000);
testCharacter(0x10abcd);
testCharacter(0x10fffd);
});
});
});
});
group("the top level", () {
test("removes whitespace and semicolons between at-rules", () {
expect(_compile("@foo; @bar; @baz;"), equals("@foo;@bar;@baz"));
});
test("removes whitespace between style rules", () {
expect(_compile("a {b: c} x {y: z}"), equals("a{b:c}x{y:z}"));
});
});
group("@supports", () {
test("removes whitespace around the condition", () {
expect(_compile("@supports (display: flex) {a {b: c}}"),
equals("@supports(display: flex){a{b:c}}"));
});
test("preserves whitespace before the condition if necessary", () {
expect(_compile("@supports not (display: flex) {a {b: c}}"),
equals("@supports not (display: flex){a{b:c}}"));
});
});
group("@media", () {
test("removes whitespace around the query", () {
expect(_compile("@media (min-width: 900px) {a {b: c}}"),
equals("@media(min-width: 900px){a{b:c}}"));
});
test("preserves whitespace before the query if necessary", () {
expect(_compile("@media screen {a {b: c}}"),
equals("@media screen{a{b:c}}"));
});
// Removing whitespace after "and", "or", or "not" is forbidden because it
// would cause it to parse as a function token.
group('preserves whitespace when necessary', () {
test('around "and"', () {
expect(
_compile("""
@media screen and (min-width: 900px) and (max-width: 100px) {
a {b: c}
}
"""),
equals("@media screen and (min-width: 900px)and (max-width: 100px)"
"{a{b:c}}"));
});
test('around "or"', () {
expect(
_compile("""
@media (min-width: 900px) or (max-width: 100px) or (print) {
a {b: c}
}
"""),
equals("@media(min-width: 900px)or (max-width: 100px)or (print)"
"{a{b:c}}"));
});
test('after "not"', () {
expect(_compile("""
@media not (min-width: 900px) {
a {b: c}
}
"""), equals("@media not (min-width: 900px){a{b:c}}"));
});
});
test("preserves whitespace around the modifier", () {
expect(_compile("@media only screen {a {b: c}}"),
equals("@media only screen{a{b:c}}"));
});
});
group("@keyframes", () {
test("removes whitespace after the selector", () {
expect(_compile("@keyframes a {from {a: b}}"),
equals("@keyframes a{from{a:b}}"));
});
test("removes whitespace after commas", () {
expect(_compile("@keyframes a {from, to {a: b}}"),
equals("@keyframes a{from,to{a:b}}"));
});
});
group("@import", () {
test("removes whitespace before the URL", () {
expect(_compile('@import "foo.css";'), equals('@import"foo.css"'));
});
test("converts a url() to a string", () {
expect(_compile('@import url(foo.css);'), equals('@import"foo.css"'));
expect(_compile('@import url("foo.css");'), equals('@import"foo.css"'));
});
test("removes whitespace before a media query", () {
expect(_compile('@import "foo.css" screen;'),
equals('@import"foo.css"screen'));
});
test("removes whitespace before a supports condition", () {
expect(_compile('@import "foo.css" supports(display: flex);'),
equals('@import"foo.css"supports(display: flex)'));
});
});
group("comments", () {
test("are removed", () {
expect(_compile("/* foo bar */"), isEmpty);
expect(_compile("""
a {
b: c;
/* foo bar */
d: e;
}
"""), equals("a{b:c;d:e}"));
});
test("remove their parents if they're the only contents", () {
expect(_compile("a {/* foo bar */}"), isEmpty);
expect(_compile("""
a {
/* foo bar */
/* baz bang */
}
"""), isEmpty);
});
test("are preserved with /*!", () {
expect(_compile("/*! foo bar */"), equals("/*! foo bar */"));
expect(
_compile("/*! foo */\n/*! bar */"), equals("/*! foo *//*! bar */"));
expect(_compile("""
a {
/*! foo bar */
}
"""), equals("a{/*! foo bar */}"));
});
});
}
/// Like [compileString], but always produces compressed output.
String _compile(String source) =>
compileString(source, style: OutputStyle.compressed);