2017-10-06 03:45:26 +02:00
|
|
|
// Copyright 2017 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')
|
|
|
|
|
2018-12-21 01:22:39 +01:00
|
|
|
import 'dart:convert';
|
|
|
|
|
|
|
|
import 'package:source_maps/source_maps.dart';
|
2017-10-06 03:45:26 +02:00
|
|
|
import 'package:test/test.dart';
|
|
|
|
|
|
|
|
import 'package:sass/sass.dart';
|
|
|
|
import 'package:sass/src/exception.dart';
|
|
|
|
|
2019-06-06 20:42:44 +02:00
|
|
|
import 'test_importer.dart';
|
|
|
|
|
2019-11-06 01:28:26 +01:00
|
|
|
void main() {
|
2017-10-06 03:45:26 +02:00
|
|
|
test("uses an importer to resolve an @import", () {
|
|
|
|
var css = compileString('@import "orange";', importers: [
|
2019-06-06 20:42:44 +02:00
|
|
|
TestImporter((url) => Uri.parse("u:$url"), (url) {
|
2018-10-12 00:06:26 +02:00
|
|
|
var color = url.path;
|
2018-11-16 00:16:24 +01:00
|
|
|
return ImporterResult('.$color {color: $color}', indented: false);
|
2017-10-06 03:45:26 +02:00
|
|
|
})
|
|
|
|
]);
|
|
|
|
|
|
|
|
expect(css, equals(".orange {\n color: orange;\n}"));
|
|
|
|
});
|
|
|
|
|
|
|
|
test("passes the canonicalized URL to the importer", () {
|
|
|
|
var css = compileString('@import "orange";', importers: [
|
2019-06-06 20:42:44 +02:00
|
|
|
TestImporter((url) => Uri.parse('u:blue'), (url) {
|
2018-10-12 00:06:26 +02:00
|
|
|
var color = url.path;
|
2018-11-16 00:16:24 +01:00
|
|
|
return ImporterResult('.$color {color: $color}', indented: false);
|
2017-10-06 03:45:26 +02:00
|
|
|
})
|
|
|
|
]);
|
|
|
|
|
|
|
|
expect(css, equals(".blue {\n color: blue;\n}"));
|
|
|
|
});
|
|
|
|
|
|
|
|
test("only invokes the importer once for a given canonicalization", () {
|
|
|
|
var css = compileString("""
|
|
|
|
@import "orange";
|
|
|
|
@import "orange";
|
|
|
|
""", importers: [
|
2019-06-06 20:42:44 +02:00
|
|
|
TestImporter(
|
2018-10-12 00:06:26 +02:00
|
|
|
(url) => Uri.parse('u:blue'),
|
2017-10-06 03:45:26 +02:00
|
|
|
expectAsync1((url) {
|
2018-10-12 00:06:26 +02:00
|
|
|
var color = url.path;
|
2018-11-16 00:16:24 +01:00
|
|
|
return ImporterResult('.$color {color: $color}', indented: false);
|
2017-10-06 03:45:26 +02:00
|
|
|
}, count: 1))
|
|
|
|
]);
|
|
|
|
|
|
|
|
expect(css, equals("""
|
|
|
|
.blue {
|
|
|
|
color: blue;
|
|
|
|
}
|
|
|
|
|
|
|
|
.blue {
|
|
|
|
color: blue;
|
|
|
|
}"""));
|
|
|
|
});
|
|
|
|
|
2018-05-30 23:47:37 +02:00
|
|
|
test("resolves URLs relative to the pre-canonicalized URL", () {
|
|
|
|
var times = 0;
|
2018-10-12 00:06:26 +02:00
|
|
|
var css = compileString('@import "foo:bar/baz";',
|
|
|
|
importers: [
|
2019-06-06 20:42:44 +02:00
|
|
|
TestImporter(
|
2018-10-12 00:06:26 +02:00
|
|
|
expectAsync1((url) {
|
|
|
|
times++;
|
2018-11-16 00:16:24 +01:00
|
|
|
if (times == 1) return Uri(path: 'first');
|
2018-10-12 00:06:26 +02:00
|
|
|
|
|
|
|
expect(url, equals(Uri.parse('foo:bar/bang')));
|
2018-11-16 00:16:24 +01:00
|
|
|
return Uri(path: 'second');
|
2018-10-12 00:06:26 +02:00
|
|
|
}, count: 2),
|
|
|
|
expectAsync1((url) {
|
2018-11-16 00:16:24 +01:00
|
|
|
return ImporterResult(
|
2018-10-12 00:06:26 +02:00
|
|
|
times == 1
|
|
|
|
? '''
|
2018-05-30 23:47:37 +02:00
|
|
|
.first {url: "$url"}
|
|
|
|
@import "bang";
|
|
|
|
'''
|
2018-10-12 00:06:26 +02:00
|
|
|
: '.second {url: "$url"}',
|
|
|
|
indented: false);
|
|
|
|
}, count: 2))
|
|
|
|
],
|
|
|
|
logger: Logger.quiet);
|
2018-05-30 23:47:37 +02:00
|
|
|
|
|
|
|
expect(css, equalsIgnoringWhitespace('''
|
|
|
|
.first { url: "first"; }
|
|
|
|
.second { url: "second"; }
|
|
|
|
'''));
|
|
|
|
});
|
|
|
|
|
2018-12-21 01:22:39 +01:00
|
|
|
test("uses an importer's source map URL", () {
|
2021-03-17 03:25:39 +01:00
|
|
|
late SingleMapping map;
|
2018-12-21 01:22:39 +01:00
|
|
|
compileString('@import "orange";',
|
|
|
|
importers: [
|
2019-06-06 20:42:44 +02:00
|
|
|
TestImporter((url) => Uri.parse("u:$url"), (url) {
|
2018-12-21 01:22:39 +01:00
|
|
|
var color = url.path;
|
|
|
|
return ImporterResult('.$color {color: $color}',
|
|
|
|
sourceMapUrl: Uri.parse("u:blue"), indented: false);
|
|
|
|
})
|
|
|
|
],
|
|
|
|
sourceMap: (map_) => map = map_);
|
|
|
|
|
|
|
|
expect(map.urls, contains("u:blue"));
|
|
|
|
});
|
|
|
|
|
|
|
|
test("uses a data: source map URL if the importer doesn't provide one", () {
|
2021-03-17 03:25:39 +01:00
|
|
|
late SingleMapping map;
|
2018-12-21 01:22:39 +01:00
|
|
|
compileString('@import "orange";',
|
|
|
|
importers: [
|
2019-06-06 20:42:44 +02:00
|
|
|
TestImporter((url) => Uri.parse("u:$url"), (url) {
|
2018-12-21 01:22:39 +01:00
|
|
|
var color = url.path;
|
|
|
|
return ImporterResult('.$color {color: $color}', indented: false);
|
|
|
|
})
|
|
|
|
],
|
|
|
|
sourceMap: (map_) => map = map_);
|
|
|
|
|
|
|
|
expect(
|
|
|
|
map.urls,
|
|
|
|
contains(Uri.dataFromString(".orange {color: orange}", encoding: utf8)
|
|
|
|
.toString()));
|
|
|
|
});
|
|
|
|
|
2017-10-06 03:45:26 +02:00
|
|
|
test("wraps an error in canonicalize()", () {
|
|
|
|
expect(() {
|
|
|
|
compileString('@import "orange";', importers: [
|
2021-03-17 03:25:39 +01:00
|
|
|
TestImporter(
|
|
|
|
(url) {
|
|
|
|
throw "this import is bad actually";
|
|
|
|
} as Uri Function(Uri),
|
|
|
|
expectAsync1((_) => null, count: 0)) // TODO: no as
|
2017-10-06 03:45:26 +02:00
|
|
|
]);
|
2021-03-17 03:25:39 +01:00
|
|
|
}, throwsA(predicate((dynamic error) {
|
2021-03-10 02:04:09 +01:00
|
|
|
// TODO: no dynamic
|
2018-06-15 22:58:13 +02:00
|
|
|
expect(error, const TypeMatcher<SassException>());
|
2017-10-06 03:45:26 +02:00
|
|
|
expect(
|
|
|
|
error.toString(), startsWith("Error: this import is bad actually"));
|
|
|
|
return true;
|
|
|
|
})));
|
|
|
|
});
|
|
|
|
|
|
|
|
test("wraps an error in load()", () {
|
|
|
|
expect(() {
|
|
|
|
compileString('@import "orange";', importers: [
|
2019-06-06 20:42:44 +02:00
|
|
|
TestImporter((url) => Uri.parse("u:$url"), (url) {
|
2017-10-06 03:45:26 +02:00
|
|
|
throw "this import is bad actually";
|
|
|
|
})
|
|
|
|
]);
|
2021-03-17 03:25:39 +01:00
|
|
|
}, throwsA(predicate((dynamic error) {
|
2021-03-10 02:04:09 +01:00
|
|
|
// TODO: no dynamic
|
2018-06-15 22:58:13 +02:00
|
|
|
expect(error, const TypeMatcher<SassException>());
|
2017-10-06 03:45:26 +02:00
|
|
|
expect(
|
|
|
|
error.toString(), startsWith("Error: this import is bad actually"));
|
|
|
|
return true;
|
|
|
|
})));
|
|
|
|
});
|
|
|
|
|
|
|
|
test("prefers .message to .toString() for an importer error", () {
|
|
|
|
expect(() {
|
|
|
|
compileString('@import "orange";', importers: [
|
2019-06-06 20:42:44 +02:00
|
|
|
TestImporter((url) => Uri.parse("u:$url"), (url) {
|
2018-11-16 00:16:24 +01:00
|
|
|
throw FormatException("bad format somehow");
|
2017-10-06 03:45:26 +02:00
|
|
|
})
|
|
|
|
]);
|
2021-03-17 03:25:39 +01:00
|
|
|
}, throwsA(predicate((dynamic error) {
|
2021-03-10 02:04:09 +01:00
|
|
|
// TODO: no dynamic
|
2018-06-15 22:58:13 +02:00
|
|
|
expect(error, const TypeMatcher<SassException>());
|
2017-10-06 03:45:26 +02:00
|
|
|
// FormatException.toString() starts with "FormatException:", but
|
|
|
|
// the error message should not.
|
|
|
|
expect(error.toString(), startsWith("Error: bad format somehow"));
|
|
|
|
return true;
|
|
|
|
})));
|
|
|
|
});
|
2020-11-10 18:44:37 +01:00
|
|
|
|
|
|
|
test("avoids importer when only load() returns null", () {
|
|
|
|
expect(() {
|
|
|
|
compileString('@import "orange";', importers: [
|
|
|
|
TestImporter((url) => Uri.parse("u:$url"), (url) => null)
|
|
|
|
]);
|
2021-03-17 03:25:39 +01:00
|
|
|
}, throwsA(predicate((dynamic error) {
|
2021-03-10 02:04:09 +01:00
|
|
|
// TODO: no dynamic
|
2020-11-10 18:44:37 +01:00
|
|
|
expect(error, const TypeMatcher<SassException>());
|
|
|
|
expect(error.toString(),
|
|
|
|
startsWith("Error: Can't find stylesheet to import"));
|
|
|
|
return true;
|
|
|
|
})));
|
|
|
|
});
|
2017-10-06 03:45:26 +02:00
|
|
|
}
|