github.com/linchen2chris/hugo@v0.0.0-20230307053224-cec209389705/resources/resource_transformers/tocss/dartsass/integration_test.go (about) 1 // Copyright 2021 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package dartsass_test 15 16 import ( 17 "strings" 18 "testing" 19 20 qt "github.com/frankban/quicktest" 21 "github.com/gohugoio/hugo/hugolib" 22 "github.com/gohugoio/hugo/resources/resource_transformers/tocss/dartsass" 23 jww "github.com/spf13/jwalterweatherman" 24 ) 25 26 func TestTransformIncludePaths(t *testing.T) { 27 t.Parallel() 28 if !dartsass.Supports() { 29 t.Skip() 30 } 31 32 files := ` 33 -- assets/scss/main.scss -- 34 @import "moo"; 35 -- node_modules/foo/_moo.scss -- 36 $moolor: #fff; 37 38 moo { 39 color: $moolor; 40 } 41 -- config.toml -- 42 -- layouts/index.html -- 43 {{ $cssOpts := (dict "includePaths" (slice "node_modules/foo") "transpiler" "dartsass" ) }} 44 {{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts | minify }} 45 T1: {{ $r.Content }} 46 ` 47 48 b := hugolib.NewIntegrationTestBuilder( 49 hugolib.IntegrationTestConfig{ 50 T: t, 51 TxtarString: files, 52 NeedsOsFS: true, 53 }).Build() 54 55 b.AssertFileContent("public/index.html", `T1: moo{color:#fff}`) 56 } 57 58 func TestTransformImportRegularCSS(t *testing.T) { 59 t.Parallel() 60 if !dartsass.Supports() { 61 t.Skip() 62 } 63 64 files := ` 65 -- assets/scss/_moo.scss -- 66 $moolor: #fff; 67 68 moo { 69 color: $moolor; 70 } 71 -- assets/scss/another.css -- 72 73 -- assets/scss/main.scss -- 74 @import "moo"; 75 @import "regular.css"; 76 @import "moo"; 77 @import "another.css"; 78 79 /* foo */ 80 -- assets/scss/regular.css -- 81 82 -- config.toml -- 83 -- layouts/index.html -- 84 {{ $r := resources.Get "scss/main.scss" | toCSS (dict "transpiler" "dartsass") }} 85 T1: {{ $r.Content | safeHTML }} 86 87 ` 88 89 b := hugolib.NewIntegrationTestBuilder( 90 hugolib.IntegrationTestConfig{ 91 T: t, 92 TxtarString: files, 93 NeedsOsFS: true, 94 }, 95 ).Build() 96 97 // Dart Sass does not follow regular CSS import, but they 98 // get pulled to the top. 99 b.AssertFileContent("public/index.html", `T1: @import "regular.css"; 100 @import "another.css"; 101 moo { 102 color: #fff; 103 } 104 105 moo { 106 color: #fff; 107 } 108 109 /* foo */`) 110 } 111 112 // Issue 10592 113 func TestTransformImportMountedCSS(t *testing.T) { 114 t.Parallel() 115 if !dartsass.Supports() { 116 t.Skip() 117 } 118 119 files := ` 120 -- assets/main.scss -- 121 @import "import-this-file.css"; 122 @import "foo/import-this-mounted-file.css"; 123 @import "compile-this-file"; 124 @import "foo/compile-this-mounted-file"; 125 a {color: main-scss;} 126 -- assets/_compile-this-file.css -- 127 a {color: compile-this-file-css;} 128 -- assets/_import-this-file.css -- 129 a {color: import-this-file-css;} 130 -- foo/_compile-this-mounted-file.css -- 131 a {color: compile-this-mounted-file-css;} 132 -- foo/_import-this-mounted-file.css -- 133 a {color: import-this-mounted-file-css;} 134 -- layouts/index.html -- 135 {{- $opts := dict "transpiler" "dartsass" }} 136 {{- with resources.Get "main.scss" | toCSS $opts }}{{ .Content | safeHTML }}{{ end }} 137 -- config.toml -- 138 disableKinds = ['RSS','sitemap','taxonomy','term','page','section'] 139 140 [[module.mounts]] 141 source = 'assets' 142 target = 'assets' 143 144 [[module.mounts]] 145 source = 'foo' 146 target = 'assets/foo' 147 ` 148 b := hugolib.NewIntegrationTestBuilder( 149 hugolib.IntegrationTestConfig{ 150 T: t, 151 TxtarString: files, 152 NeedsOsFS: true, 153 }, 154 ).Build() 155 156 b.AssertFileContent("public/index.html", ` 157 @import "import-this-file.css"; 158 @import "foo/import-this-mounted-file.css"; 159 a { 160 color: compile-this-file-css; 161 } 162 163 a { 164 color: compile-this-mounted-file-css; 165 } 166 167 a { 168 color: main-scss; 169 } 170 `) 171 } 172 173 func TestTransformThemeOverrides(t *testing.T) { 174 t.Parallel() 175 if !dartsass.Supports() { 176 t.Skip() 177 } 178 179 files := ` 180 -- assets/scss/components/_boo.scss -- 181 $boolor: green; 182 183 boo { 184 color: $boolor; 185 } 186 -- assets/scss/components/_moo.scss -- 187 $moolor: #ccc; 188 189 moo { 190 color: $moolor; 191 } 192 -- config.toml -- 193 theme = 'mytheme' 194 -- layouts/index.html -- 195 {{ $cssOpts := (dict "includePaths" (slice "node_modules/foo" ) "transpiler" "dartsass" ) }} 196 {{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts | minify }} 197 T1: {{ $r.Content }} 198 -- themes/mytheme/assets/scss/components/_boo.scss -- 199 $boolor: orange; 200 201 boo { 202 color: $boolor; 203 } 204 -- themes/mytheme/assets/scss/components/_imports.scss -- 205 @import "moo"; 206 @import "_boo"; 207 @import "_zoo"; 208 -- themes/mytheme/assets/scss/components/_moo.scss -- 209 $moolor: #fff; 210 211 moo { 212 color: $moolor; 213 } 214 -- themes/mytheme/assets/scss/components/_zoo.scss -- 215 $zoolor: pink; 216 217 zoo { 218 color: $zoolor; 219 } 220 -- themes/mytheme/assets/scss/main.scss -- 221 @import "components/imports"; 222 ` 223 224 b := hugolib.NewIntegrationTestBuilder( 225 hugolib.IntegrationTestConfig{ 226 T: t, 227 TxtarString: files, 228 NeedsOsFS: true, 229 }, 230 ).Build() 231 232 b.AssertFileContent("public/index.html", `T1: moo{color:#ccc}boo{color:green}zoo{color:pink}`) 233 } 234 235 func TestTransformLogging(t *testing.T) { 236 t.Parallel() 237 if !dartsass.Supports() { 238 t.Skip() 239 } 240 241 files := ` 242 -- assets/scss/main.scss -- 243 @warn "foo"; 244 @debug "bar"; 245 246 -- config.toml -- 247 disableKinds = ["term", "taxonomy", "section", "page"] 248 -- layouts/index.html -- 249 {{ $cssOpts := (dict "transpiler" "dartsass" ) }} 250 {{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts }} 251 T1: {{ $r.Content }} 252 ` 253 254 b := hugolib.NewIntegrationTestBuilder( 255 hugolib.IntegrationTestConfig{ 256 T: t, 257 TxtarString: files, 258 NeedsOsFS: true, 259 LogLevel: jww.LevelInfo, 260 }).Build() 261 262 b.AssertLogMatches(`WARN.*Dart Sass: foo`) 263 b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:1:0: bar`) 264 265 } 266 267 func TestTransformErrors(t *testing.T) { 268 t.Parallel() 269 if !dartsass.Supports() { 270 t.Skip() 271 } 272 273 c := qt.New(t) 274 275 const filesTemplate = ` 276 -- config.toml -- 277 -- assets/scss/components/_foo.scss -- 278 /* comment line 1 */ 279 $foocolor: #ccc; 280 281 foo { 282 color: $foocolor; 283 } 284 -- assets/scss/main.scss -- 285 /* comment line 1 */ 286 /* comment line 2 */ 287 @import "components/foo"; 288 /* comment line 4 */ 289 290 $maincolor: #eee; 291 292 body { 293 color: $maincolor; 294 } 295 296 -- layouts/index.html -- 297 {{ $cssOpts := dict "transpiler" "dartsass" }} 298 {{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts | minify }} 299 T1: {{ $r.Content }} 300 301 ` 302 303 c.Run("error in main", func(c *qt.C) { 304 b, err := hugolib.NewIntegrationTestBuilder( 305 hugolib.IntegrationTestConfig{ 306 T: c, 307 TxtarString: strings.Replace(filesTemplate, "$maincolor: #eee;", "$maincolor #eee;", 1), 308 NeedsOsFS: true, 309 }).BuildE() 310 311 b.Assert(err, qt.IsNotNil) 312 b.Assert(err.Error(), qt.Contains, `main.scss:8:13":`) 313 b.Assert(err.Error(), qt.Contains, `: expected ":".`) 314 fe := b.AssertIsFileError(err) 315 b.Assert(fe.ErrorContext(), qt.IsNotNil) 316 b.Assert(fe.ErrorContext().Lines, qt.DeepEquals, []string{" $maincolor #eee;", "", "body {", "\tcolor: $maincolor;", "}"}) 317 b.Assert(fe.ErrorContext().ChromaLexer, qt.Equals, "scss") 318 319 }) 320 321 c.Run("error in import", func(c *qt.C) { 322 b, err := hugolib.NewIntegrationTestBuilder( 323 hugolib.IntegrationTestConfig{ 324 T: c, 325 TxtarString: strings.Replace(filesTemplate, "$foocolor: #ccc;", "$foocolor #ccc;", 1), 326 NeedsOsFS: true, 327 }).BuildE() 328 329 b.Assert(err, qt.IsNotNil) 330 b.Assert(err.Error(), qt.Contains, `_foo.scss:2:10":`) 331 b.Assert(err.Error(), qt.Contains, `: expected ":".`) 332 fe := b.AssertIsFileError(err) 333 b.Assert(fe.ErrorContext(), qt.IsNotNil) 334 b.Assert(fe.ErrorContext().Lines, qt.DeepEquals, []string{"/* comment line 1 */", "$foocolor #ccc;", "", "foo {"}) 335 b.Assert(fe.ErrorContext().ChromaLexer, qt.Equals, "scss") 336 337 }) 338 339 } 340 341 func TestOptionVars(t *testing.T) { 342 t.Parallel() 343 if !dartsass.Supports() { 344 t.Skip() 345 } 346 347 files := ` 348 -- assets/scss/main.scss -- 349 @use "hugo:vars"; 350 351 body { 352 body { 353 background: url(vars.$image) no-repeat center/cover; 354 font-family: vars.$font; 355 } 356 } 357 358 p { 359 color: vars.$color1; 360 font-size: vars.$font_size; 361 } 362 363 b { 364 color: vars.$color2; 365 } 366 -- layouts/index.html -- 367 {{ $image := "images/hero.jpg" }} 368 {{ $font := "Hugo's New Roman" }} 369 {{ $vars := dict "$color1" "blue" "$color2" "green" "font_size" "24px" "image" $image "font" $font }} 370 {{ $cssOpts := (dict "transpiler" "dartsass" "outputStyle" "compressed" "vars" $vars ) }} 371 {{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts }} 372 T1: {{ $r.Content }} 373 ` 374 375 b := hugolib.NewIntegrationTestBuilder( 376 hugolib.IntegrationTestConfig{ 377 T: t, 378 TxtarString: files, 379 NeedsOsFS: true, 380 }).Build() 381 382 b.AssertFileContent("public/index.html", `T1: body body{background:url(images/hero.jpg) no-repeat center/cover;font-family:Hugo's New Roman}p{color:blue;font-size:24px}b{color:green}`) 383 } 384 385 func TestOptionVarsParams(t *testing.T) { 386 t.Parallel() 387 if !dartsass.Supports() { 388 t.Skip() 389 } 390 391 files := ` 392 -- config.toml -- 393 [params] 394 [params.sassvars] 395 color1 = "blue" 396 color2 = "green" 397 font_size = "24px" 398 image = "images/hero.jpg" 399 -- assets/scss/main.scss -- 400 @use "hugo:vars"; 401 402 body { 403 body { 404 background: url(vars.$image) no-repeat center/cover; 405 } 406 } 407 408 p { 409 color: vars.$color1; 410 font-size: vars.$font_size; 411 } 412 413 b { 414 color: vars.$color2; 415 } 416 -- layouts/index.html -- 417 {{ $vars := site.Params.sassvars}} 418 {{ $cssOpts := (dict "transpiler" "dartsass" "outputStyle" "compressed" "vars" $vars ) }} 419 {{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts }} 420 T1: {{ $r.Content }} 421 ` 422 423 b := hugolib.NewIntegrationTestBuilder( 424 hugolib.IntegrationTestConfig{ 425 T: t, 426 TxtarString: files, 427 NeedsOsFS: true, 428 }).Build() 429 430 b.AssertFileContent("public/index.html", `T1: body body{background:url(images/hero.jpg) no-repeat center/cover}p{color:blue;font-size:24px}b{color:green}`) 431 } 432 433 func TestVarsCasting(t *testing.T) { 434 t.Parallel() 435 if !dartsass.Supports() { 436 t.Skip() 437 } 438 439 files := ` 440 -- config.toml -- 441 disableKinds = ["term", "taxonomy", "section", "page"] 442 443 [params] 444 [params.sassvars] 445 color_hex = "#fff" 446 color_rgb = "rgb(255, 255, 255)" 447 color_hsl = "hsl(0, 0%, 100%)" 448 dimension = "24px" 449 percentage = "10%" 450 flex = "5fr" 451 name = "Hugo" 452 url = "https://gohugo.io" 453 integer = 32 454 float = 3.14 455 -- assets/scss/main.scss -- 456 @use "hugo:vars"; 457 @use "sass:meta"; 458 459 @debug meta.type-of(vars.$color_hex); 460 @debug meta.type-of(vars.$color_rgb); 461 @debug meta.type-of(vars.$color_hsl); 462 @debug meta.type-of(vars.$dimension); 463 @debug meta.type-of(vars.$percentage); 464 @debug meta.type-of(vars.$flex); 465 @debug meta.type-of(vars.$name); 466 @debug meta.type-of(vars.$url); 467 @debug meta.type-of(vars.$not_a_number); 468 @debug meta.type-of(vars.$integer); 469 @debug meta.type-of(vars.$float); 470 @debug meta.type-of(vars.$a_number); 471 -- layouts/index.html -- 472 {{ $vars := site.Params.sassvars}} 473 {{ $vars = merge $vars (dict "not_a_number" ("32xxx" | css.Quoted) "a_number" ("234" | css.Unquoted) )}} 474 {{ $cssOpts := (dict "transpiler" "dartsass" "vars" $vars ) }} 475 {{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts }} 476 T1: {{ $r.Content }} 477 ` 478 479 b := hugolib.NewIntegrationTestBuilder( 480 hugolib.IntegrationTestConfig{ 481 T: t, 482 TxtarString: files, 483 NeedsOsFS: true, 484 LogLevel: jww.LevelInfo, 485 }).Build() 486 487 b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:3:0: color`) 488 b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:4:0: color`) 489 b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:5:0: color`) 490 b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:6:0: number`) 491 b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:7:0: number`) 492 b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:8:0: number`) 493 b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:9:0: string`) 494 b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:10:0: string`) 495 b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:11:0: string`) 496 b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:12:0: number`) 497 b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:13:0: number`) 498 b.AssertLogMatches(`INFO.*Dart Sass: .*assets.*main.scss:14:0: number`) 499 500 }