2024-05-05 04:44:35 -04:00
// Copyright 2024 The Hugo Authors. All rights reserved.
2022-02-09 08:04:57 -05:00
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package scss_test
import (
2022-05-15 05:40:34 -04:00
"path/filepath"
"strings"
2022-02-09 08:04:57 -05:00
"testing"
qt "github.com/frankban/quicktest"
2024-02-29 13:05:23 -05:00
"github.com/gohugoio/hugo/htesting"
2022-02-09 08:04:57 -05:00
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/scss"
)
func TestTransformIncludePaths ( t * testing . T ) {
2022-12-19 12:49:02 -05:00
t . Parallel ( )
2022-02-09 08:04:57 -05:00
if ! scss . Supports ( ) {
t . Skip ( )
}
c := qt . New ( t )
files := `
-- assets / scss / main . scss --
@ import "moo" ;
-- node_modules / foo / _moo . scss --
$ moolor : # fff ;
moo {
color : $ moolor ;
}
-- config . toml --
-- layouts / index . html --
{ { $ cssOpts := ( dict "includePaths" ( slice "node_modules/foo" ) ) } }
{ { $ r := resources . Get "scss/main.scss" | toCSS $ cssOpts | minify } }
T1 : { { $ r . Content } }
`
b := hugolib . NewIntegrationTestBuilder (
hugolib . IntegrationTestConfig {
T : c ,
TxtarString : files ,
NeedsOsFS : true ,
} ) . Build ( )
b . AssertFileContent ( "public/index.html" , ` T1: moo { color:#fff} ` )
}
func TestTransformImportRegularCSS ( t * testing . T ) {
2022-12-19 12:49:02 -05:00
t . Parallel ( )
2022-02-09 08:04:57 -05:00
if ! scss . Supports ( ) {
t . Skip ( )
}
c := qt . New ( t )
files := `
-- assets / scss / _moo . scss --
$ moolor : # fff ;
moo {
color : $ moolor ;
}
-- assets / scss / another . css --
-- assets / scss / main . scss --
@ import "moo" ;
@ import "regular.css" ;
@ import "moo" ;
@ import "another.css" ;
/* foo */
-- assets / scss / regular . css --
-- config . toml --
-- layouts / index . html --
{ { $ r := resources . Get "scss/main.scss" | toCSS } }
T1 : { { $ r . Content | safeHTML } }
`
b := hugolib . NewIntegrationTestBuilder (
hugolib . IntegrationTestConfig {
T : c ,
TxtarString : files ,
NeedsOsFS : true ,
} ) . Build ( )
// LibSass does not support regular CSS imports. There
// is an open bug about it that probably will never be resolved.
// Hugo works around this by preserving them in place:
b . AssertFileContent ( "public/index.html" , `
T1 : moo {
color : # fff ; }
@ import "regular.css" ;
moo {
color : # fff ; }
@ import "another.css" ;
/* foo */
` )
}
func TestTransformThemeOverrides ( t * testing . T ) {
2022-12-19 12:49:02 -05:00
t . Parallel ( )
2022-02-09 08:04:57 -05:00
if ! scss . Supports ( ) {
t . Skip ( )
}
c := qt . New ( t )
files := `
-- assets / scss / components / _boo . scss --
$ boolor : green ;
boo {
color : $ boolor ;
}
-- assets / scss / components / _moo . scss --
$ moolor : # ccc ;
moo {
color : $ moolor ;
}
-- config . toml --
theme = ' mytheme '
-- layouts / index . html --
2022-05-15 05:40:34 -04:00
{ { $ cssOpts := ( dict "includePaths" ( slice "node_modules/foo" ) ) } }
2022-02-09 08:04:57 -05:00
{ { $ r := resources . Get "scss/main.scss" | toCSS $ cssOpts | minify } }
T1 : { { $ r . Content } }
-- themes / mytheme / assets / scss / components / _boo . scss --
$ boolor : orange ;
boo {
color : $ boolor ;
}
-- themes / mytheme / assets / scss / components / _imports . scss --
@ import "moo" ;
@ import "_boo" ;
@ import "_zoo" ;
-- themes / mytheme / assets / scss / components / _moo . scss --
$ moolor : # fff ;
moo {
color : $ moolor ;
}
-- themes / mytheme / assets / scss / components / _zoo . scss --
$ zoolor : pink ;
zoo {
color : $ zoolor ;
}
-- themes / mytheme / assets / scss / main . scss --
@ import "components/imports" ;
`
b := hugolib . NewIntegrationTestBuilder (
hugolib . IntegrationTestConfig {
T : c ,
TxtarString : files ,
NeedsOsFS : true ,
} ) . Build ( )
b . AssertFileContent ( "public/index.html" , ` T1: moo { color:#ccc}boo { color:green}zoo { color:pink} ` )
}
2022-05-15 05:40:34 -04:00
func TestTransformErrors ( t * testing . T ) {
2022-12-19 12:49:02 -05:00
t . Parallel ( )
2022-05-15 05:40:34 -04:00
if ! scss . Supports ( ) {
t . Skip ( )
}
c := qt . New ( t )
const filesTemplate = `
-- config . toml --
theme = ' mytheme '
-- assets / scss / components / _foo . scss --
/* comment line 1 */
$ foocolor : # ccc ;
foo {
color : $ foocolor ;
}
-- themes / mytheme / assets / scss / main . scss --
/* comment line 1 */
/* comment line 2 */
@ import "components/foo" ;
/* comment line 4 */
$ maincolor : # eee ;
body {
color : $ maincolor ;
}
-- layouts / index . html --
{ { $ cssOpts := dict } }
{ { $ r := resources . Get "scss/main.scss" | toCSS $ cssOpts | minify } }
T1 : { { $ r . Content } }
`
c . Run ( "error in main" , func ( c * qt . C ) {
b , err := hugolib . NewIntegrationTestBuilder (
hugolib . IntegrationTestConfig {
T : c ,
TxtarString : strings . Replace ( filesTemplate , "$maincolor: #eee;" , "$maincolor #eee;" , 1 ) ,
NeedsOsFS : true ,
} ) . BuildE ( )
b . Assert ( err , qt . IsNotNil )
b . Assert ( err . Error ( ) , qt . Contains , filepath . FromSlash ( ` themes/mytheme/assets/scss/main.scss:6:1": expected ':' after $maincolor in assignment statement ` ) )
fe := b . AssertIsFileError ( err )
b . Assert ( fe . ErrorContext ( ) , qt . IsNotNil )
b . Assert ( fe . ErrorContext ( ) . Lines , qt . DeepEquals , [ ] string { "/* comment line 4 */" , "" , "$maincolor #eee;" , "" , "body {" } )
b . Assert ( fe . ErrorContext ( ) . ChromaLexer , qt . Equals , "scss" )
} )
c . Run ( "error in import" , func ( c * qt . C ) {
b , err := hugolib . NewIntegrationTestBuilder (
hugolib . IntegrationTestConfig {
T : c ,
TxtarString : strings . Replace ( filesTemplate , "$foocolor: #ccc;" , "$foocolor #ccc;" , 1 ) ,
NeedsOsFS : true ,
} ) . BuildE ( )
b . Assert ( err , qt . IsNotNil )
2022-05-27 04:06:45 -04:00
b . Assert ( err . Error ( ) , qt . Contains , ` assets/scss/components/_foo.scss:2:1": expected ':' after $foocolor in assignment statement ` )
2022-05-15 05:40:34 -04:00
fe := b . AssertIsFileError ( err )
b . Assert ( fe . ErrorContext ( ) , qt . IsNotNil )
b . Assert ( fe . ErrorContext ( ) . Lines , qt . DeepEquals , [ ] string { "/* comment line 1 */" , "$foocolor #ccc;" , "" , "foo {" } )
b . Assert ( fe . ErrorContext ( ) . ChromaLexer , qt . Equals , "scss" )
} )
}
2022-12-19 12:49:02 -05:00
func TestOptionVars ( t * testing . T ) {
t . Parallel ( )
if ! scss . Supports ( ) {
t . Skip ( )
}
files := `
-- assets / scss / main . scss --
@ import "hugo:vars" ;
body {
body {
background : url ( $ image ) no - repeat center / cover ;
2022-12-21 03:17:51 -05:00
font - family : $ font ;
2022-12-19 12:49:02 -05:00
}
}
p {
color : $ color1 ;
font - size : var $ font_size ;
}
b {
color : $ color2 ;
}
-- layouts / index . html --
{ { $ image := "images/hero.jpg" } }
2022-12-21 03:17:51 -05:00
{ { $ font := "Hugo's New Roman" } }
{ { $ vars := dict "$color1" "blue" "$color2" "green" "font_size" "24px" "image" $ image "font" $ font } }
2022-12-19 12:49:02 -05:00
{ { $ cssOpts := ( dict "transpiler" "libsass" "outputStyle" "compressed" "vars" $ vars ) } }
{ { $ r := resources . Get "scss/main.scss" | toCSS $ cssOpts } }
T1 : { { $ r . Content } }
`
b := hugolib . NewIntegrationTestBuilder (
hugolib . IntegrationTestConfig {
T : t ,
TxtarString : files ,
NeedsOsFS : true ,
} ) . Build ( )
2022-12-21 03:17:51 -05:00
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:var 24px}b { color:green} ` )
2022-12-19 12:49:02 -05:00
}
2024-02-29 13:05:23 -05:00
// Note: This test is more or less duplicated in both of the SCSS packages (libsass and dartsass).
func TestBootstrap ( t * testing . T ) {
t . Parallel ( )
if ! scss . Supports ( ) {
t . Skip ( )
}
if ! htesting . IsCI ( ) {
t . Skip ( "skip (slow) test in non-CI environment" )
}
files := `
-- hugo . toml --
disableKinds = [ "term" , "taxonomy" , "section" , "page" ]
[ module ]
[ [ module . imports ] ]
path = "github.com/gohugoio/hugo-mod-bootstrap-scss/v5"
-- go . mod --
module github . com / gohugoio / tests / testHugoModules
-- assets / scss / main . scss --
@ import "bootstrap/bootstrap" ;
-- layouts / index . html --
{ { $ cssOpts := ( dict "transpiler" "libsass" ) } }
{ { $ r := resources . Get "scss/main.scss" | toCSS $ cssOpts } }
Styles : { { $ r . RelPermalink } }
`
b := hugolib . NewIntegrationTestBuilder (
hugolib . IntegrationTestConfig {
T : t ,
TxtarString : files ,
NeedsOsFS : true ,
} ) . Build ( )
b . AssertFileContent ( "public/index.html" , "Styles: /scss/main.css" )
}
2024-04-20 05:05:35 -04:00
2024-05-05 04:44:35 -04:00
// Issue #1239.
2024-04-20 05:05:35 -04:00
func TestRebuildAssetGetMatch ( t * testing . T ) {
t . Parallel ( )
if ! scss . Supports ( ) {
t . Skip ( )
}
files := `
-- assets / scss / main . scss --
b {
color : red ;
}
-- layouts / index . html --
{ { $ r := resources . GetMatch "scss/main.scss" | toCSS } }
T1 : { { $ r . Content } }
`
b := hugolib . NewIntegrationTestBuilder (
hugolib . IntegrationTestConfig {
T : t ,
TxtarString : files ,
NeedsOsFS : true ,
Running : true ,
} ) . Build ( )
b . AssertFileContent ( "public/index.html" , ` color: red ` )
b . EditFiles ( "assets/scss/main.scss" , ` b { color: blue; } ` ) . Build ( )
b . AssertFileContent ( "public/index.html" , ` color: blue ` )
}
2024-05-05 04:44:35 -04:00
func TestRebuildAssetMatchIssue12456 ( t * testing . T ) {
t . Parallel ( )
if ! scss . Supports ( ) {
t . Skip ( )
}
files := `
-- hugo . toml --
disableKinds = [ "term" , "taxonomy" , "section" , "page" ]
disableLiveReload = true
-- assets / a . scss --
h1 {
color : red ;
}
-- assets / dir / b . scss --
h2 {
color : blue ;
}
-- assets / dir / c . scss --
h3 {
color : green ;
}
-- layouts / index . html --
{ { $ a := slice ( resources . Get "a.scss" ) } }
{ { $ b := resources . Match "dir/*.scss" } }
{ { /* Add styles in a specific order. */ } }
{ { $ styles := slice $ a $ b } }
{ { $ stylesheets := slice } }
{ { range $ styles } }
{ { $ stylesheets = $ stylesheets | collections . Append . } }
{ { end } }
{ { range $ stylesheets } }
{ { with . | resources . ToCSS | fingerprint } }
< link as = "style" href = "{{ .RelPermalink }}" rel = "preload stylesheet" >
{ { end } }
{ { end } }
`
b := hugolib . NewIntegrationTestBuilder (
hugolib . IntegrationTestConfig {
T : t ,
TxtarString : files ,
NeedsOsFS : true ,
Running : true ,
// LogLevel: logg.LevelTrace,
} ) . Build ( )
b . AssertFileContent ( "public/index.html" , ` b.60a9f3bdc189ee8a857afd5b7e1b93ad1644de0873761a7c9bc84f781a821942.css ` )
b . EditFiles ( "assets/dir/b.scss" , ` h2 { color: orange; } ` ) . Build ( )
b . AssertFileContent ( "public/index.html" , ` b.46b2d77c7ffe37ee191678f72df991ecb1319f849957151654362f09b0ef467f.css ` )
}