integration_test.go (7472B)
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 js_test 15 16 import ( 17 "path/filepath" 18 "strings" 19 "testing" 20 21 qt "github.com/frankban/quicktest" 22 "github.com/gohugoio/hugo/htesting" 23 "github.com/gohugoio/hugo/hugolib" 24 ) 25 26 func TestBuildVariants(t *testing.T) { 27 c := qt.New(t) 28 29 mainWithImport := ` 30 -- config.toml -- 31 disableKinds=["page", "section", "taxonomy", "term", "sitemap", "robotsTXT"] 32 -- assets/js/main.js -- 33 import { hello1, hello2 } from './util1'; 34 hello1(); 35 hello2(); 36 -- assets/js/util1.js -- 37 import { hello3 } from './util2'; 38 export function hello1() { 39 return 'abcd'; 40 } 41 export function hello2() { 42 return hello3(); 43 } 44 -- assets/js/util2.js -- 45 export function hello3() { 46 return 'efgh'; 47 } 48 -- layouts/index.html -- 49 {{ $js := resources.Get "js/main.js" | js.Build }} 50 JS Content:{{ $js.Content }}:End: 51 52 ` 53 54 c.Run("Basic", func(c *qt.C) { 55 b := hugolib.NewIntegrationTestBuilder(hugolib.IntegrationTestConfig{T: c, NeedsOsFS: true, TxtarString: mainWithImport}).Build() 56 57 b.AssertFileContent("public/index.html", `abcd`) 58 }) 59 60 c.Run("Edit Import", func(c *qt.C) { 61 b := hugolib.NewIntegrationTestBuilder(hugolib.IntegrationTestConfig{T: c, Running: true, NeedsOsFS: true, TxtarString: mainWithImport}).Build() 62 63 b.AssertFileContent("public/index.html", `abcd`) 64 b.EditFileReplace("assets/js/util1.js", func(s string) string { return strings.ReplaceAll(s, "abcd", "1234") }).Build() 65 b.AssertFileContent("public/index.html", `1234`) 66 }) 67 68 c.Run("Edit Import Nested", func(c *qt.C) { 69 b := hugolib.NewIntegrationTestBuilder(hugolib.IntegrationTestConfig{T: c, Running: true, NeedsOsFS: true, TxtarString: mainWithImport}).Build() 70 71 b.AssertFileContent("public/index.html", `efgh`) 72 b.EditFileReplace("assets/js/util2.js", func(s string) string { return strings.ReplaceAll(s, "efgh", "1234") }).Build() 73 b.AssertFileContent("public/index.html", `1234`) 74 }) 75 } 76 77 func TestBuildWithModAndNpm(t *testing.T) { 78 if !htesting.IsCI() { 79 t.Skip("skip (relative) long running modules test when running locally") 80 } 81 82 c := qt.New(t) 83 84 files := ` 85 -- config.toml -- 86 baseURL = "https://example.org" 87 disableKinds=["page", "section", "taxonomy", "term", "sitemap", "robotsTXT"] 88 [module] 89 [[module.imports]] 90 path="github.com/gohugoio/hugoTestProjectJSModImports" 91 -- go.mod -- 92 module github.com/gohugoio/tests/testHugoModules 93 94 go 1.16 95 96 require github.com/gohugoio/hugoTestProjectJSModImports v0.10.0 // indirect 97 -- package.json -- 98 { 99 "dependencies": { 100 "date-fns": "^2.16.1" 101 } 102 } 103 104 ` 105 b := hugolib.NewIntegrationTestBuilder( 106 hugolib.IntegrationTestConfig{ 107 T: c, 108 NeedsOsFS: true, 109 NeedsNpmInstall: true, 110 TxtarString: files, 111 Verbose: true, 112 }).Build() 113 114 b.AssertFileContent("public/js/main.js", ` 115 greeting: "greeting configured in mod2" 116 Hello1 from mod1: $ 117 return "Hello2 from mod1"; 118 var Hugo = "Rocks!"; 119 Hello3 from mod2. Date from date-fns: ${today} 120 Hello from lib in the main project 121 Hello5 from mod2. 122 var myparam = "Hugo Rocks!"; 123 shim cwd 124 `) 125 126 // React JSX, verify the shimming. 127 b.AssertFileContent("public/js/like.js", filepath.FromSlash(`@v0.10.0/assets/js/shims/react.js 128 module.exports = window.ReactDOM; 129 `)) 130 } 131 132 func TestBuildWithNpm(t *testing.T) { 133 if !htesting.IsCI() { 134 t.Skip("skip (relative) long running modules test when running locally") 135 } 136 137 c := qt.New(t) 138 139 files := ` 140 -- assets/js/included.js -- 141 console.log("included"); 142 -- assets/js/main.js -- 143 import "./included"; 144 import { toCamelCase } from "to-camel-case"; 145 146 console.log("main"); 147 console.log("To camel:", toCamelCase("space case")); 148 -- assets/js/myjsx.jsx -- 149 import * as React from 'react' 150 import * as ReactDOM from 'react-dom' 151 152 ReactDOM.render( 153 <h1>Hello, world!</h1>, 154 document.getElementById('root') 155 ); 156 -- assets/js/myts.ts -- 157 function greeter(person: string) { 158 return "Hello, " + person; 159 } 160 let user = [0, 1, 2]; 161 document.body.textContent = greeter(user); 162 -- config.toml -- 163 disablekinds = ['taxonomy', 'term', 'page'] 164 -- content/p1.md -- 165 Content. 166 -- data/hugo.toml -- 167 slogan = "Hugo Rocks!" 168 -- i18n/en.yaml -- 169 hello: 170 other: "Hello" 171 -- i18n/fr.yaml -- 172 hello: 173 other: "Bonjour" 174 -- layouts/index.html -- 175 {{ $options := dict "minify" false "externals" (slice "react" "react-dom") }} 176 {{ $js := resources.Get "js/main.js" | js.Build $options }} 177 JS: {{ template "print" $js }} 178 {{ $jsx := resources.Get "js/myjsx.jsx" | js.Build $options }} 179 JSX: {{ template "print" $jsx }} 180 {{ $ts := resources.Get "js/myts.ts" | js.Build (dict "sourcemap" "inline")}} 181 TS: {{ template "print" $ts }} 182 {{ $ts2 := resources.Get "js/myts.ts" | js.Build (dict "sourcemap" "external" "TargetPath" "js/myts2.js")}} 183 TS2: {{ template "print" $ts2 }} 184 {{ define "print" }}RelPermalink: {{.RelPermalink}}|MIME: {{ .MediaType }}|Content: {{ .Content | safeJS }}{{ end }} 185 -- package.json -- 186 { 187 "scripts": {}, 188 189 "dependencies": { 190 "to-camel-case": "1.0.0" 191 } 192 } 193 ` 194 195 b := hugolib.NewIntegrationTestBuilder( 196 hugolib.IntegrationTestConfig{ 197 T: c, 198 NeedsOsFS: true, 199 NeedsNpmInstall: true, 200 TxtarString: files, 201 }).Build() 202 203 b.AssertFileContent("public/js/myts.js", `//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJz`) 204 b.AssertFileContent("public/js/myts2.js.map", `"version": 3,`) 205 b.AssertFileContent("public/index.html", ` 206 console.log("included"); 207 if (hasSpace.test(string)) 208 var React = __toESM(__require("react")); 209 function greeter(person) { 210 `) 211 } 212 213 func TestBuildError(t *testing.T) { 214 c := qt.New(t) 215 216 filesTemplate := ` 217 -- config.toml -- 218 disableKinds=["page", "section", "taxonomy", "term", "sitemap", "robotsTXT"] 219 -- assets/js/main.js -- 220 // A comment. 221 import { hello1, hello2 } from './util1'; 222 hello1(); 223 hello2(); 224 -- assets/js/util1.js -- 225 /* Some 226 comments. 227 */ 228 import { hello3 } from './util2'; 229 export function hello1() { 230 return 'abcd'; 231 } 232 export function hello2() { 233 return hello3(); 234 } 235 -- assets/js/util2.js -- 236 export function hello3() { 237 return 'efgh'; 238 } 239 -- layouts/index.html -- 240 {{ $js := resources.Get "js/main.js" | js.Build }} 241 JS Content:{{ $js.Content }}:End: 242 243 ` 244 245 c.Run("Import from main not found", func(c *qt.C) { 246 c.Parallel() 247 files := strings.Replace(filesTemplate, "import { hello1, hello2 }", "import { hello1, hello2, FOOBAR }", 1) 248 b, err := hugolib.NewIntegrationTestBuilder(hugolib.IntegrationTestConfig{T: c, NeedsOsFS: true, TxtarString: files}).BuildE() 249 b.Assert(err, qt.IsNotNil) 250 b.Assert(err.Error(), qt.Contains, `main.js:2:25": No matching export`) 251 }) 252 253 c.Run("Import from import not found", func(c *qt.C) { 254 c.Parallel() 255 files := strings.Replace(filesTemplate, "import { hello3 } from './util2';", "import { hello3, FOOBAR } from './util2';", 1) 256 b, err := hugolib.NewIntegrationTestBuilder(hugolib.IntegrationTestConfig{T: c, NeedsOsFS: true, TxtarString: files}).BuildE() 257 b.Assert(err, qt.IsNotNil) 258 b.Assert(err.Error(), qt.Contains, `util1.js:4:17": No matching export in`) 259 }) 260 261 }