options_test.go (5775B)
1 // Copyright 2020 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
15
16 import (
17 "path/filepath"
18 "testing"
19
20 "github.com/gohugoio/hugo/hugofs"
21
22 "github.com/spf13/afero"
23
24 "github.com/gohugoio/hugo/media"
25
26 "github.com/evanw/esbuild/pkg/api"
27
28 qt "github.com/frankban/quicktest"
29 )
30
31 // This test is added to test/warn against breaking the "stability" of the
32 // cache key. It's sometimes needed to break this, but should be avoided if possible.
33 func TestOptionKey(t *testing.T) {
34 c := qt.New(t)
35
36 opts := map[string]any{
37 "TargetPath": "foo",
38 "Target": "es2018",
39 }
40
41 key := (&buildTransformation{optsm: opts}).Key()
42
43 c.Assert(key.Value(), qt.Equals, "jsbuild_7891849149754191852")
44 }
45
46 func TestToBuildOptions(t *testing.T) {
47 c := qt.New(t)
48
49 opts, err := toBuildOptions(Options{mediaType: media.JavascriptType})
50
51 c.Assert(err, qt.IsNil)
52 c.Assert(opts, qt.DeepEquals, api.BuildOptions{
53 Bundle: true,
54 Target: api.ESNext,
55 Format: api.FormatIIFE,
56 Stdin: &api.StdinOptions{
57 Loader: api.LoaderJS,
58 },
59 })
60
61 opts, err = toBuildOptions(Options{
62 Target: "es2018",
63 Format: "cjs",
64 Minify: true,
65 mediaType: media.JavascriptType,
66 AvoidTDZ: true,
67 })
68 c.Assert(err, qt.IsNil)
69 c.Assert(opts, qt.DeepEquals, api.BuildOptions{
70 Bundle: true,
71 Target: api.ES2018,
72 Format: api.FormatCommonJS,
73 MinifyIdentifiers: true,
74 MinifySyntax: true,
75 MinifyWhitespace: true,
76 Stdin: &api.StdinOptions{
77 Loader: api.LoaderJS,
78 },
79 })
80
81 opts, err = toBuildOptions(Options{
82 Target: "es2018", Format: "cjs", Minify: true, mediaType: media.JavascriptType,
83 SourceMap: "inline",
84 })
85 c.Assert(err, qt.IsNil)
86 c.Assert(opts, qt.DeepEquals, api.BuildOptions{
87 Bundle: true,
88 Target: api.ES2018,
89 Format: api.FormatCommonJS,
90 MinifyIdentifiers: true,
91 MinifySyntax: true,
92 MinifyWhitespace: true,
93 Sourcemap: api.SourceMapInline,
94 Stdin: &api.StdinOptions{
95 Loader: api.LoaderJS,
96 },
97 })
98
99 opts, err = toBuildOptions(Options{
100 Target: "es2018", Format: "cjs", Minify: true, mediaType: media.JavascriptType,
101 SourceMap: "inline",
102 })
103 c.Assert(err, qt.IsNil)
104 c.Assert(opts, qt.DeepEquals, api.BuildOptions{
105 Bundle: true,
106 Target: api.ES2018,
107 Format: api.FormatCommonJS,
108 MinifyIdentifiers: true,
109 MinifySyntax: true,
110 MinifyWhitespace: true,
111 Sourcemap: api.SourceMapInline,
112 Stdin: &api.StdinOptions{
113 Loader: api.LoaderJS,
114 },
115 })
116
117 opts, err = toBuildOptions(Options{
118 Target: "es2018", Format: "cjs", Minify: true, mediaType: media.JavascriptType,
119 SourceMap: "external",
120 })
121 c.Assert(err, qt.IsNil)
122 c.Assert(opts, qt.DeepEquals, api.BuildOptions{
123 Bundle: true,
124 Target: api.ES2018,
125 Format: api.FormatCommonJS,
126 MinifyIdentifiers: true,
127 MinifySyntax: true,
128 MinifyWhitespace: true,
129 Sourcemap: api.SourceMapExternal,
130 Stdin: &api.StdinOptions{
131 Loader: api.LoaderJS,
132 },
133 })
134 }
135
136 func TestResolveComponentInAssets(t *testing.T) {
137 c := qt.New(t)
138
139 for _, test := range []struct {
140 name string
141 files []string
142 impPath string
143 expect string
144 }{
145 {"Basic, extension", []string{"foo.js", "bar.js"}, "foo.js", "foo.js"},
146 {"Basic, no extension", []string{"foo.js", "bar.js"}, "foo", "foo.js"},
147 {"Basic, no extension, typescript", []string{"foo.ts", "bar.js"}, "foo", "foo.ts"},
148 {"Not found", []string{"foo.js", "bar.js"}, "moo.js", ""},
149 {"Not found, double js extension", []string{"foo.js.js", "bar.js"}, "foo.js", ""},
150 {"Index file, folder only", []string{"foo/index.js", "bar.js"}, "foo", "foo/index.js"},
151 {"Index file, folder and index", []string{"foo/index.js", "bar.js"}, "foo/index", "foo/index.js"},
152 {"Index file, folder and index and suffix", []string{"foo/index.js", "bar.js"}, "foo/index.js", "foo/index.js"},
153 {"Index ESM file, folder only", []string{"foo/index.esm.js", "bar.js"}, "foo", "foo/index.esm.js"},
154 {"Index ESM file, folder and index", []string{"foo/index.esm.js", "bar.js"}, "foo/index", "foo/index.esm.js"},
155 {"Index ESM file, folder and index and suffix", []string{"foo/index.esm.js", "bar.js"}, "foo/index.esm.js", "foo/index.esm.js"},
156 // We added these index.esm.js cases in v0.101.0. The case below is unlikely to happen in the wild, but add a test
157 // to document Hugo's behavior. We pick the file with the name index.js; anything else would be breaking.
158 {"Index and Index ESM file, folder only", []string{"foo/index.esm.js", "foo/index.js", "bar.js"}, "foo", "foo/index.js"},
159
160 // Issue #8949
161 {"Check file before directory", []string{"foo.js", "foo/index.js"}, "foo", "foo.js"},
162 } {
163 c.Run(test.name, func(c *qt.C) {
164 baseDir := "assets"
165 mfs := afero.NewMemMapFs()
166
167 for _, filename := range test.files {
168 c.Assert(afero.WriteFile(mfs, filepath.Join(baseDir, filename), []byte("let foo='bar';"), 0777), qt.IsNil)
169 }
170
171 bfs := hugofs.DecorateBasePathFs(afero.NewBasePathFs(mfs, baseDir).(*afero.BasePathFs))
172
173 got := resolveComponentInAssets(bfs, test.impPath)
174
175 gotPath := ""
176 if got != nil {
177 gotPath = filepath.ToSlash(got.Path)
178 }
179
180 c.Assert(gotPath, qt.Equals, test.expect)
181 })
182
183 }
184 }