Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/tests/unit/dart-sass.test.ts
12924 views
1
/*
2
* dart-sass.test.ts
3
*
4
* Tests for dart-sass functionality.
5
* Validates fixes for:
6
* https://github.com/quarto-dev/quarto-cli/issues/13997 (spaced paths)
7
* https://github.com/quarto-dev/quarto-cli/issues/14267 (accented paths)
8
* https://github.com/quarto-dev/quarto-cli/issues/6651 (enterprise .bat blocking)
9
*
10
* Copyright (C) 2020-2025 Posit Software, PBC
11
*/
12
13
import { unitTest } from "../test.ts";
14
import { assert } from "testing/asserts";
15
import { isWindows } from "../../src/deno_ral/platform.ts";
16
import { join } from "../../src/deno_ral/path.ts";
17
import { dartCommand, dartSassInstallDir } from "../../src/core/dart-sass.ts";
18
19
/**
20
* Helper: create a junction to the real dart-sass install dir at `targetDir`.
21
* Returns cleanup function to remove the junction.
22
*/
23
async function createDartSassJunction(targetDir: string) {
24
const sassInstallDir = dartSassInstallDir();
25
const result = await new Deno.Command("cmd", {
26
args: ["/c", "mklink", "/J", targetDir, sassInstallDir],
27
}).output();
28
29
if (!result.success) {
30
const stderr = new TextDecoder().decode(result.stderr);
31
throw new Error(`Failed to create junction: ${stderr}`);
32
}
33
34
return async () => {
35
await new Deno.Command("cmd", {
36
args: ["/c", "rmdir", targetDir],
37
}).output();
38
};
39
}
40
41
// Test that dartCommand handles spaced paths on Windows (issue #13997)
42
// dart.exe is called directly, bypassing sass.bat and its quoting issues.
43
unitTest(
44
"dartCommand - handles spaced paths on Windows (issue #13997)",
45
async () => {
46
const tempBase = Deno.makeTempDirSync({ prefix: "quarto_test_" });
47
const spacedSassDir = join(tempBase, "Program Files", "dart-sass");
48
const spacedProjectDir = join(tempBase, "My Project");
49
50
let removeJunction: (() => Promise<void>) | undefined;
51
52
try {
53
Deno.mkdirSync(join(tempBase, "Program Files"), { recursive: true });
54
Deno.mkdirSync(spacedProjectDir, { recursive: true });
55
56
removeJunction = await createDartSassJunction(spacedSassDir);
57
58
const inputScss = join(spacedProjectDir, "test style.scss");
59
const outputCss = join(spacedProjectDir, "test style.css");
60
Deno.writeTextFileSync(inputScss, "body { color: red; }");
61
62
const result = await dartCommand([inputScss, outputCss], {
63
installDir: spacedSassDir,
64
});
65
66
assert(
67
result === undefined || result === "",
68
"Sass compile should succeed (no stdout for file-to-file compilation)",
69
);
70
assert(
71
Deno.statSync(outputCss).isFile,
72
"Output CSS file should be created",
73
);
74
} finally {
75
try {
76
if (removeJunction) await removeJunction();
77
await Deno.remove(tempBase, { recursive: true });
78
} catch (e) {
79
console.debug("Test cleanup failed:", e);
80
}
81
}
82
},
83
{ ignore: !isWindows },
84
);
85
86
// Test that dartCommand handles accented characters in paths (issue #14267)
87
// Accented chars in user paths (e.g., C:\Users\Sébastien\) broke when
88
// dart-sass was invoked through a .bat wrapper with UTF-8/OEM mismatch.
89
unitTest(
90
"dartCommand - handles accented characters in paths (issue #14267)",
91
async () => {
92
const tempBase = Deno.makeTempDirSync({ prefix: "quarto_test_" });
93
const accentedSassDir = join(tempBase, "Sébastien", "dart-sass");
94
const accentedProjectDir = join(tempBase, "Sébastien", "project");
95
96
let removeJunction: (() => Promise<void>) | undefined;
97
98
try {
99
Deno.mkdirSync(join(tempBase, "Sébastien"), { recursive: true });
100
Deno.mkdirSync(accentedProjectDir, { recursive: true });
101
102
removeJunction = await createDartSassJunction(accentedSassDir);
103
104
const inputScss = join(accentedProjectDir, "style.scss");
105
const outputCss = join(accentedProjectDir, "style.css");
106
Deno.writeTextFileSync(inputScss, "body { color: blue; }");
107
108
const result = await dartCommand([inputScss, outputCss], {
109
installDir: accentedSassDir,
110
});
111
112
assert(
113
result === undefined || result === "",
114
"Sass compile should succeed with accented path",
115
);
116
assert(
117
Deno.statSync(outputCss).isFile,
118
"Output CSS file should be created at accented path",
119
);
120
} finally {
121
try {
122
if (removeJunction) await removeJunction();
123
await Deno.remove(tempBase, { recursive: true });
124
} catch (e) {
125
console.debug("Test cleanup failed:", e);
126
}
127
}
128
},
129
{ ignore: !isWindows },
130
);
131
132