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