2018-05-23 00:06:07 +02:00
|
|
|
// 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.
|
|
|
|
|
2018-06-14 01:57:28 +02:00
|
|
|
import 'package:path/path.dart' as p;
|
2018-05-23 00:06:07 +02:00
|
|
|
import 'package:test/test.dart';
|
|
|
|
import 'package:test_descriptor/test_descriptor.dart' as d;
|
|
|
|
import 'package:test_process/test_process.dart';
|
|
|
|
|
|
|
|
import '../../utils.dart';
|
|
|
|
|
|
|
|
/// Defines test that are shared between the Dart and Node.js CLI test suites.
|
|
|
|
void sharedTests(Future<TestProcess> runSass(Iterable<String> arguments)) {
|
2018-06-29 03:20:28 +02:00
|
|
|
test("--poll may not be passed without --watch", () async {
|
|
|
|
var sass = await runSass(["--poll", "-"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits("--poll may not be passed without --watch."));
|
|
|
|
expect(
|
|
|
|
sass.stdout, emitsThrough(contains("Print this usage information.")));
|
|
|
|
await sass.shouldExit(64);
|
2018-05-23 00:06:07 +02:00
|
|
|
});
|
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
for (var poll in [true, false]) {
|
2019-05-18 03:02:12 +02:00
|
|
|
Future<TestProcess> watch(Iterable<String> arguments) => runSass(
|
|
|
|
["--no-source-map", "--watch", ...arguments, if (poll) "--poll"]);
|
2018-06-29 03:20:28 +02:00
|
|
|
|
|
|
|
/// Returns a future that completes after a delay if [poll] is `true`.
|
|
|
|
///
|
|
|
|
/// Modifying a file very quickly after it was processed can go
|
|
|
|
/// unrecognized, especially on Windows where filesystem operations can have
|
|
|
|
/// very high delays.
|
2019-05-31 17:01:49 +02:00
|
|
|
Future<void> tickIfPoll() => poll ? tick : Future.value();
|
2018-06-29 03:20:28 +02:00
|
|
|
|
|
|
|
group("${poll ? 'with' : 'without'} --poll", () {
|
|
|
|
group("when started", () {
|
|
|
|
test("updates a CSS file whose source was modified", () async {
|
|
|
|
await d.file("out.css", "x {y: z}").create();
|
|
|
|
await tick;
|
|
|
|
await d.file("test.scss", "a {b: c}").create();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await sass.kill();
|
2018-06-27 05:10:46 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("a { b: c; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
test("doesn't update a CSS file that wasn't modified", () async {
|
|
|
|
await d.file("test.scss", "a {b: c}").create();
|
|
|
|
await d.file("out.css", "x {y: z}").create();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await sass.kill();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.file("out.css", "x {y: z}").validate();
|
|
|
|
});
|
2018-06-30 03:12:36 +02:00
|
|
|
|
2019-05-03 03:14:25 +02:00
|
|
|
group("continues compiling after an error", () {
|
|
|
|
test("with --error-css", () async {
|
|
|
|
await d.file("test1.scss", "a {b: }").create();
|
|
|
|
await d.file("test2.scss", "x {y: z}").create();
|
|
|
|
|
|
|
|
var message = 'Error: Expected expression.';
|
|
|
|
var sass =
|
|
|
|
await watch(["test1.scss:out1.css", "test2.scss:out2.css"]);
|
|
|
|
await expectLater(sass.stderr, emits(message));
|
|
|
|
await expectLater(
|
|
|
|
sass.stderr, emitsThrough(contains('test1.scss 1:7')));
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emitsThrough('Compiled test2.scss to out2.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await sass.kill();
|
2018-06-30 03:12:36 +02:00
|
|
|
|
2019-05-03 03:14:25 +02:00
|
|
|
await d.file("out1.css", contains(message)).validate();
|
|
|
|
await d
|
|
|
|
.file("out2.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
2018-06-30 03:12:36 +02:00
|
|
|
|
2019-05-03 03:14:25 +02:00
|
|
|
test("with --no-error-css", () async {
|
|
|
|
await d.file("test1.scss", "a {b: }").create();
|
|
|
|
await d.file("test2.scss", "x {y: z}").create();
|
|
|
|
|
|
|
|
var sass = await watch([
|
|
|
|
"--no-error-css",
|
|
|
|
"test1.scss:out1.css",
|
|
|
|
"test2.scss:out2.css"
|
|
|
|
]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stderr, emits('Error: Expected expression.'));
|
|
|
|
await expectLater(
|
|
|
|
sass.stderr, emitsThrough(contains('test1.scss 1:7')));
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emitsThrough('Compiled test2.scss to out2.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d.nothing("out1.css").validate();
|
|
|
|
await d
|
|
|
|
.file("out2.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
2018-06-30 03:12:36 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
test("stops compiling after an error with --stop-on-error", () async {
|
|
|
|
await d.file("test1.scss", "a {b: }").create();
|
|
|
|
await d.file("test2.scss", "x {y: z}").create();
|
|
|
|
|
|
|
|
var sass = await watch([
|
|
|
|
"--stop-on-error",
|
|
|
|
"test1.scss:out1.css",
|
|
|
|
"test2.scss:out2.css"
|
|
|
|
]);
|
2019-05-03 03:14:25 +02:00
|
|
|
|
|
|
|
var message = 'Error: Expected expression.';
|
2018-06-30 03:12:36 +02:00
|
|
|
await expectLater(
|
|
|
|
sass.stderr,
|
|
|
|
emitsInOrder([
|
2019-05-03 03:14:25 +02:00
|
|
|
message,
|
2018-06-30 03:12:36 +02:00
|
|
|
emitsThrough(contains('test1.scss 1:7')),
|
|
|
|
emitsDone
|
|
|
|
]));
|
|
|
|
await sass.shouldExit(65);
|
|
|
|
|
2019-05-03 03:14:25 +02:00
|
|
|
await d.file("out1.css", contains(message)).validate();
|
2018-06-30 03:12:36 +02:00
|
|
|
await d.nothing("out2.css").validate();
|
|
|
|
});
|
2018-05-23 00:06:07 +02:00
|
|
|
});
|
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
group("recompiles a watched file", () {
|
|
|
|
test("when it's modified", () async {
|
|
|
|
await d.file("test.scss", "a {b: c}").create();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.file("test.scss", "x {y: z}").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await sass.kill();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
test("when it's modified when watched from a directory", () async {
|
|
|
|
await d.dir("dir", [d.file("test.scss", "a {b: c}")]).create();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
var sass = await watch(["dir:out"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits(_compiled('dir/test.scss', 'out/test.css')));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.dir("dir", [d.file("test.scss", "x {y: z}")]).create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits(_compiled('dir/test.scss', 'out/test.css')));
|
|
|
|
await sass.kill();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.dir("out", [
|
|
|
|
d.file("test.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
]).validate();
|
|
|
|
});
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2020-03-11 22:48:00 +01:00
|
|
|
test(
|
|
|
|
"when it's modified twice when watched from a directory that is "
|
|
|
|
"also a destination", () async {
|
|
|
|
await d.file("test.scss", "a {b: c}").create();
|
|
|
|
|
|
|
|
var sass = await watch(["."]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to test.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.file("test.scss", "r {o: g}").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to test.css.'));
|
|
|
|
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.file("test.scss", "x {y: z}").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to test.css.'));
|
|
|
|
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
|
|
|
.file("test.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
|
|
|
|
2019-11-04 22:32:27 +01:00
|
|
|
group("when its dependency is modified", () {
|
|
|
|
test("through @import", () async {
|
|
|
|
await d.file("_other.scss", "a {b: c}").create();
|
|
|
|
await d.file("test.scss", "@import 'other'").create();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2019-11-04 22:32:27 +01:00
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2019-11-04 22:32:27 +01:00
|
|
|
await d.file("_other.scss", "x {y: z}").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await sass.kill();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2019-11-04 22:32:27 +01:00
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
|
|
|
|
|
|
|
test("through @use", () async {
|
|
|
|
await d.file("_other.scss", "a {b: c}").create();
|
|
|
|
await d.file("test.scss", "@use 'other'").create();
|
|
|
|
|
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.file("_other.scss", "x {y: z}").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
|
|
|
|
|
|
|
test("through @forward", () async {
|
|
|
|
await d.file("_other.scss", "a {b: c}").create();
|
|
|
|
await d.file("test.scss", "@forward 'other'").create();
|
|
|
|
|
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.file("_other.scss", "x {y: z}").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
2020-02-25 03:50:22 +01:00
|
|
|
|
|
|
|
// Regression test for #550
|
|
|
|
test("with an error that's later fixed", () async {
|
|
|
|
await d.file("_other.scss", "a {b: c}").create();
|
|
|
|
await d.file("test.scss", "@import 'other'").create();
|
|
|
|
|
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.file("_other.scss", "a {b: }").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stderr, emits('Error: Expected expression.'));
|
|
|
|
await expectLater(
|
|
|
|
sass.stderr, emitsThrough(contains('test.scss 1:9')));
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.file("_other.scss", "q {r: s}").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await tick;
|
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("q { r: s; }"))
|
|
|
|
.validate();
|
|
|
|
|
|
|
|
await d.file("_other.scss", "x {y: z}").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await tick;
|
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
.validate();
|
|
|
|
|
|
|
|
await sass.kill();
|
|
|
|
});
|
2018-05-23 00:06:07 +02:00
|
|
|
});
|
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
test("when it's deleted and re-added", () async {
|
|
|
|
await d.file("test.scss", "a {b: c}").create();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
2018-05-23 00:06:07 +02:00
|
|
|
await expectLater(
|
2018-06-29 03:20:28 +02:00
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
2018-05-23 00:06:07 +02:00
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
2018-06-29 03:20:28 +02:00
|
|
|
await tickIfPoll();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
d.file("test.scss").io.deleteSync();
|
|
|
|
await expectLater(sass.stdout, emits('Deleted out.css.'));
|
|
|
|
|
|
|
|
// Windows gets confused at the OS level if we don't wait a bit here.
|
|
|
|
await tick;
|
|
|
|
|
|
|
|
await d.file("test.scss", "x {y: z}").create();
|
2018-05-23 00:06:07 +02:00
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
2018-06-29 03:20:28 +02:00
|
|
|
.file("out.css", equalsIgnoringWhitespace("x { y: z; }"))
|
2018-05-23 00:06:07 +02:00
|
|
|
.validate();
|
|
|
|
});
|
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
test("when it gets a parse error", () async {
|
|
|
|
await d.file("test.scss", "a {b: c}").create();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
2018-05-23 00:06:07 +02:00
|
|
|
await expectLater(
|
2018-06-29 03:20:28 +02:00
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
2018-05-23 00:06:07 +02:00
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
2018-06-29 03:20:28 +02:00
|
|
|
await tickIfPoll();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2019-05-03 03:14:25 +02:00
|
|
|
var message = 'Error: Expected expression.';
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.file("test.scss", "a {b: }").create();
|
2019-05-03 03:14:25 +02:00
|
|
|
await expectLater(sass.stderr, emits(message));
|
2018-05-23 00:06:07 +02:00
|
|
|
await expectLater(
|
2018-06-29 03:20:28 +02:00
|
|
|
sass.stderr, emitsThrough(contains('test.scss 1:7')));
|
2018-05-23 00:06:07 +02:00
|
|
|
await sass.kill();
|
|
|
|
|
2019-05-03 03:14:25 +02:00
|
|
|
await d.file("out.css", contains(message)).validate();
|
2018-05-23 00:06:07 +02:00
|
|
|
});
|
|
|
|
|
2018-06-30 03:12:36 +02:00
|
|
|
test("stops compiling after an error with --stop-on-error", () async {
|
|
|
|
await d.file("test.scss", "a {b: c}").create();
|
|
|
|
|
|
|
|
var sass = await watch(["--stop-on-error", "test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
2019-05-03 03:14:25 +02:00
|
|
|
var message = 'Error: Expected expression.';
|
2018-06-30 03:12:36 +02:00
|
|
|
await d.file("test.scss", "a {b: }").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stderr,
|
|
|
|
emitsInOrder([
|
2019-05-03 03:14:25 +02:00
|
|
|
message,
|
2018-06-30 03:12:36 +02:00
|
|
|
emitsThrough(contains('test.scss 1:7')),
|
|
|
|
emitsDone
|
|
|
|
]));
|
|
|
|
await sass.shouldExit(65);
|
|
|
|
|
2019-05-03 03:14:25 +02:00
|
|
|
await d.file("out.css", contains(message)).validate();
|
2018-06-30 03:12:36 +02:00
|
|
|
});
|
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
group("when its dependency is deleted", () {
|
2019-05-03 03:14:25 +02:00
|
|
|
test("and updates the output", () async {
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.file("_other.scss", "a {b: c}").create();
|
|
|
|
await d.file("test.scss", "@import 'other'").create();
|
|
|
|
|
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
2019-05-03 03:14:25 +02:00
|
|
|
var message = "Error: Can't find stylesheet to import.";
|
2018-06-29 03:20:28 +02:00
|
|
|
d.file("_other.scss").io.deleteSync();
|
2019-05-03 03:14:25 +02:00
|
|
|
await expectLater(sass.stderr, emits(message));
|
2018-06-29 03:20:28 +02:00
|
|
|
await expectLater(
|
|
|
|
sass.stderr, emitsThrough(contains('test.scss 1:9')));
|
|
|
|
await sass.kill();
|
|
|
|
|
2019-05-03 03:14:25 +02:00
|
|
|
await d.file("out.css", contains(message)).validate();
|
2018-06-29 03:20:28 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
test("but another is available", () async {
|
|
|
|
await d.file("_other.scss", "a {b: c}").create();
|
|
|
|
await d.file("test.scss", "@import 'other'").create();
|
|
|
|
await d.dir("dir", [d.file("_other.scss", "x {y: z}")]).create();
|
|
|
|
|
|
|
|
var sass = await watch(["-I", "dir", "test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
d.file("_other.scss").io.deleteSync();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
|
|
|
|
|
|
|
test("which resolves a conflict", () async {
|
|
|
|
await d.file("_other.scss", "a {b: c}").create();
|
|
|
|
await d.file("_other.sass", "x\n y: z").create();
|
|
|
|
await d.file("test.scss", "@import 'other'").create();
|
|
|
|
|
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
|
|
|
await expectLater(sass.stderr,
|
|
|
|
emits("Error: It's not clear which file to import. Found:"));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
d.file("_other.sass").io.deleteSync();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("a { b: c; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
|
|
|
});
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
group("when a dependency is added", () {
|
|
|
|
group("that was missing", () {
|
|
|
|
test("relative to the file", () async {
|
|
|
|
await d.file("test.scss", "@import 'other'").create();
|
|
|
|
|
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
|
|
|
await expectLater(sass.stderr,
|
|
|
|
emits("Error: Can't find stylesheet to import."));
|
|
|
|
await expectLater(
|
|
|
|
sass.stderr, emitsThrough(contains("test.scss 1:9")));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.file("_other.scss", "a {b: c}").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("a { b: c; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
|
|
|
|
|
|
|
test("on a load path", () async {
|
|
|
|
await d.file("test.scss", "@import 'other'").create();
|
|
|
|
await d.dir("dir").create();
|
|
|
|
|
|
|
|
var sass = await watch(["-I", "dir", "test.scss:out.css"]);
|
|
|
|
await expectLater(sass.stderr,
|
|
|
|
emits("Error: Can't find stylesheet to import."));
|
|
|
|
await expectLater(
|
|
|
|
sass.stderr, emitsThrough(contains("test.scss 1:9")));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.dir("dir", [d.file("_other.scss", "a {b: c}")]).create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("a { b: c; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
|
|
|
|
|
|
|
test("on a load path that was created", () async {
|
|
|
|
await d.dir(
|
|
|
|
"dir1", [d.file("test.scss", "@import 'other'")]).create();
|
|
|
|
|
|
|
|
var sass = await watch(["-I", "dir2", "dir1:out"]);
|
|
|
|
await expectLater(sass.stderr,
|
|
|
|
emits("Error: Can't find stylesheet to import."));
|
|
|
|
await expectLater(sass.stderr,
|
|
|
|
emitsThrough(contains("${p.join('dir1', 'test.scss')} 1:9")));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.dir("dir2", [d.file("_other.scss", "a {b: c}")]).create();
|
|
|
|
await expectLater(sass.stdout,
|
|
|
|
emits(_compiled('dir1/test.scss', 'out/test.css')));
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
|
|
|
.file("out/test.css", equalsIgnoringWhitespace("a { b: c; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
test("that conflicts with the previous dependency", () async {
|
|
|
|
await d.file("_other.scss", "a {b: c}").create();
|
|
|
|
await d.file("test.scss", "@import 'other'").create();
|
|
|
|
|
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
2019-05-03 03:14:25 +02:00
|
|
|
var message = "Error: It's not clear which file to import. Found:";
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.file("_other.sass", "x\n y: z").create();
|
2019-05-03 03:14:25 +02:00
|
|
|
await expectLater(sass.stderr, emits(message));
|
2018-06-29 03:20:28 +02:00
|
|
|
await sass.kill();
|
|
|
|
|
2019-05-03 03:14:25 +02:00
|
|
|
await d.file("out.css", contains(message)).validate();
|
2018-06-29 03:20:28 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
group("that overrides the previous dependency", () {
|
|
|
|
test("on an import path", () async {
|
|
|
|
await d.file("test.scss", "@import 'other'").create();
|
|
|
|
await d.dir("dir2", [d.file("_other.scss", "a {b: c}")]).create();
|
|
|
|
await d.dir("dir1").create();
|
|
|
|
|
|
|
|
var sass = await watch(
|
|
|
|
["-I", "dir1", "-I", "dir2", "test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.dir("dir1", [d.file("_other.scss", "x {y: z}")]).create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
|
|
|
|
|
|
|
test("because it's relative", () async {
|
|
|
|
await d.file("test.scss", "@import 'other'").create();
|
|
|
|
await d.dir("dir", [d.file("_other.scss", "a {b: c}")]).create();
|
|
|
|
|
|
|
|
var sass = await watch(["-I", "dir", "test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.file("_other.scss", "x {y: z}").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
|
|
|
|
|
|
|
test("because it's not an index", () async {
|
|
|
|
await d.file("test.scss", "@import 'other'").create();
|
|
|
|
await d
|
|
|
|
.dir("other", [d.file("_index.scss", "a {b: c}")]).create();
|
|
|
|
|
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.file("_other.scss", "x {y: z}").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
test("gracefully handles a parse error", () async {
|
|
|
|
await d.dir("dir").create();
|
|
|
|
|
|
|
|
var sass = await watch(["dir:out"]);
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.dir("dir", [d.file("test.scss", "a {b: }")]).create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stderr, emits('Error: Expected expression.'));
|
2018-08-04 00:38:16 +02:00
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.dir("dir", [d.file("test.scss", "a {b: c}")]).create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout,
|
|
|
|
emits('Compiled ${p.join('dir', 'test.scss')} to '
|
|
|
|
'${p.join('out', 'test.css')}.'));
|
2018-06-29 03:20:28 +02:00
|
|
|
await sass.kill();
|
2018-08-04 00:38:16 +02:00
|
|
|
|
|
|
|
await d.dir("out", [
|
|
|
|
d.file("test.css", equalsIgnoringWhitespace("a { b: c; }"))
|
|
|
|
]).validate();
|
2018-06-29 03:20:28 +02:00
|
|
|
});
|
|
|
|
});
|
2019-09-04 01:42:21 +02:00
|
|
|
|
|
|
|
// Regression test for #806
|
|
|
|
test("with a .css extension", () async {
|
|
|
|
await d.file("test.css", "a {b: c}").create();
|
|
|
|
|
|
|
|
var sass = await watch(["test.css:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.css to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.file("test.css", "x {y: z}").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.css to out.css.'));
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
|
|
|
.file("out.css", equalsIgnoringWhitespace("x { y: z; }"))
|
|
|
|
.validate();
|
|
|
|
});
|
2018-05-23 00:06:07 +02:00
|
|
|
});
|
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
group("doesn't recompile the watched file", () {
|
|
|
|
test("when an unrelated file is modified", () async {
|
|
|
|
await d.dir("dir", [
|
|
|
|
d.file("test1.scss", "a {b: c}"),
|
|
|
|
d.file("test2.scss", "a {b: c}")
|
|
|
|
]).create();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
var sass = await watch(["dir:out"]);
|
2018-05-23 00:06:07 +02:00
|
|
|
await expectLater(
|
2018-06-29 03:20:28 +02:00
|
|
|
sass.stdout,
|
|
|
|
emitsInAnyOrder([
|
|
|
|
_compiled('dir/test1.scss', 'out/test1.css'),
|
|
|
|
_compiled('dir/test2.scss', 'out/test2.css')
|
|
|
|
]));
|
2018-05-23 00:06:07 +02:00
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
2018-06-29 03:20:28 +02:00
|
|
|
await tickIfPoll();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.dir("dir", [d.file("test2.scss", "x {y: z}")]).create();
|
2018-05-23 00:06:07 +02:00
|
|
|
await expectLater(
|
2018-06-29 03:20:28 +02:00
|
|
|
sass.stdout, emits(_compiled('dir/test2.scss', 'out/test2.css')));
|
|
|
|
expect(sass.stdout,
|
|
|
|
neverEmits(_compiled('dir/test1.scss', 'out/test1.css')));
|
|
|
|
await tick;
|
2018-05-23 00:06:07 +02:00
|
|
|
await sass.kill();
|
|
|
|
});
|
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
test(
|
|
|
|
"when a potential dependency that's not actually imported is added",
|
|
|
|
() async {
|
2018-05-23 00:06:07 +02:00
|
|
|
await d.file("test.scss", "@import 'other'").create();
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.file("_other.scss", "a {b: c}").create();
|
|
|
|
await d.dir("dir").create();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
|
|
|
var sass = await watch(["-I", "dir", "test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
2018-06-29 03:20:28 +02:00
|
|
|
await tickIfPoll();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.dir("dir", [d.file("_other.scss", "a {b: c}")]).create();
|
|
|
|
expect(sass.stdout, neverEmits('Compiled test.scss to out.css.'));
|
|
|
|
await tick;
|
2018-05-23 00:06:07 +02:00
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d
|
2018-06-29 03:20:28 +02:00
|
|
|
.file("out.css", equalsIgnoringWhitespace("a { b: c; }"))
|
2018-05-23 00:06:07 +02:00
|
|
|
.validate();
|
|
|
|
});
|
2018-06-29 03:20:28 +02:00
|
|
|
});
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
group("deletes the CSS", () {
|
|
|
|
test("when a file is deleted", () async {
|
|
|
|
await d.file("test.scss", "a {b: c}").create();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
|
|
|
var sass = await watch(["test.scss:out.css"]);
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Compiled test.scss to out.css.'));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
2018-06-29 03:20:28 +02:00
|
|
|
await tickIfPoll();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
d.file("test.scss").io.deleteSync();
|
|
|
|
await expectLater(sass.stdout, emits('Deleted out.css.'));
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d.nothing("out.css").validate();
|
|
|
|
});
|
|
|
|
|
|
|
|
test("when a file is deleted within a directory", () async {
|
|
|
|
await d.dir("dir", [d.file("test.scss", "a {b: c}")]).create();
|
|
|
|
|
|
|
|
var sass = await watch(["dir:out"]);
|
2018-05-23 00:06:07 +02:00
|
|
|
await expectLater(
|
2018-06-29 03:20:28 +02:00
|
|
|
sass.stdout, emits(_compiled('dir/test.scss', 'out/test.css')));
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
d.file("dir/test.scss").io.deleteSync();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits('Deleted ${p.join('out', 'test.css')}.'));
|
2018-05-23 00:06:07 +02:00
|
|
|
await sass.kill();
|
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.dir("dir", [d.nothing("out.css")]).validate();
|
2018-05-23 00:06:07 +02:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
test("creates a new CSS file when a Sass file is added", () async {
|
2018-05-23 00:06:07 +02:00
|
|
|
await d.dir("dir").create();
|
|
|
|
|
|
|
|
var sass = await watch(["dir:out"]);
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
2018-06-29 03:20:28 +02:00
|
|
|
await tickIfPoll();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.dir("dir", [d.file("test.scss", "a {b: c}")]).create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits(_compiled('dir/test.scss', 'out/test.css')));
|
2018-05-23 00:06:07 +02:00
|
|
|
await sass.kill();
|
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.dir("out", [
|
|
|
|
d.file("test.css", equalsIgnoringWhitespace("a { b: c; }"))
|
|
|
|
]).validate();
|
|
|
|
});
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
test("doesn't create a new CSS file when a partial is added", () async {
|
|
|
|
await d.dir("dir").create();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
var sass = await watch(["dir:out"]);
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.dir("dir", [d.file("_test.scss", "a {b: c}")]).create();
|
|
|
|
expect(sass.stdout,
|
|
|
|
neverEmits(_compiled('dir/test.scss', 'out/test.css')));
|
|
|
|
await tick;
|
|
|
|
await sass.kill();
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
await d.nothing("out/test.scss").validate();
|
|
|
|
});
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2019-10-30 00:48:21 +01:00
|
|
|
// Regression test for #853.
|
|
|
|
test("doesn't try to compile a CSS file to itself", () async {
|
|
|
|
await d.dir("dir").create();
|
|
|
|
|
|
|
|
var sass = await watch(["dir:dir"]);
|
|
|
|
await expectLater(sass.stdout, _watchingForChanges);
|
|
|
|
await tickIfPoll();
|
|
|
|
|
|
|
|
await d.file("dir/test.css", "a {b: c}").create();
|
|
|
|
await tick;
|
|
|
|
|
|
|
|
// Create a new file that *will* be compiled so that if the first change
|
|
|
|
// did incorrectly trigger a compilation, it would emit a message
|
|
|
|
// before the message for this change.
|
|
|
|
await d.file("dir/test2.scss", "x {y: z}").create();
|
|
|
|
await expectLater(
|
|
|
|
sass.stdout, emits(_compiled('dir/test2.scss', 'dir/test2.css')));
|
|
|
|
|
|
|
|
await sass.kill();
|
|
|
|
|
|
|
|
await d.file("dir/test.css", "a {b: c}").validate();
|
|
|
|
});
|
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
group("doesn't allow", () {
|
|
|
|
test("--stdin", () async {
|
|
|
|
var sass = await watch(["--stdin", "test.scss"]);
|
|
|
|
expect(sass.stdout, emits('--watch is not allowed with --stdin.'));
|
|
|
|
await sass.shouldExit(64);
|
|
|
|
});
|
2018-05-23 00:06:07 +02:00
|
|
|
|
2018-06-29 03:20:28 +02:00
|
|
|
test("printing to stderr", () async {
|
|
|
|
var sass = await watch(["test.scss"]);
|
|
|
|
expect(sass.stdout,
|
|
|
|
emits('--watch is not allowed when printing to stdout.'));
|
|
|
|
await sass.shouldExit(64);
|
|
|
|
});
|
|
|
|
});
|
2018-05-23 00:06:07 +02:00
|
|
|
});
|
2018-06-29 03:20:28 +02:00
|
|
|
}
|
2018-05-23 00:06:07 +02:00
|
|
|
}
|
|
|
|
|
2018-06-13 23:23:21 +02:00
|
|
|
/// Returns the message that Sass prints indicating that [from] was compiled to
|
|
|
|
/// [to], with path separators normalized for the current operating system.
|
|
|
|
String _compiled(String from, String to) =>
|
|
|
|
'Compiled ${p.normalize(from)} to ${p.normalize(to)}.';
|
|
|
|
|
2018-05-23 00:06:07 +02:00
|
|
|
/// Matches the output that indicates that Sass is watching for changes.
|
|
|
|
final _watchingForChanges =
|
|
|
|
emitsInOrder(["Sass is watching for changes. Press Ctrl-C to stop.", ""]);
|