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  }