github.com/xgoffin/jenkins-library@v1.154.0/cmd/npmExecuteLint_test.go (about) 1 package cmd 2 3 import ( 4 "errors" 5 "github.com/SAP/jenkins-library/pkg/command" 6 "github.com/SAP/jenkins-library/pkg/mock" 7 "github.com/SAP/jenkins-library/pkg/npm" 8 "github.com/stretchr/testify/assert" 9 "path/filepath" 10 "testing" 11 ) 12 13 type mockLintUtilsBundle struct { 14 *mock.FilesMock 15 execRunner *mock.ExecMockRunner 16 } 17 18 func (u *mockLintUtilsBundle) getExecRunner() command.ExecRunner { 19 return u.execRunner 20 } 21 22 func (u *mockLintUtilsBundle) getGeneralPurposeConfig(configURL string) { 23 u.AddFile(filepath.Join(".pipeline", ".eslintrc.json"), []byte(`abc`)) 24 } 25 26 func newLintMockUtilsBundle() mockLintUtilsBundle { 27 utils := mockLintUtilsBundle{FilesMock: &mock.FilesMock{}, execRunner: &mock.ExecMockRunner{}} 28 return utils 29 } 30 31 func TestNpmExecuteLint(t *testing.T) { 32 defaultConfig := npmExecuteLintOptions{RunScript: "ci-lint"} 33 34 t.Run("Call with ci-lint script and one package.json", func(t *testing.T) { 35 lintUtils := newLintMockUtilsBundle() 36 lintUtils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"\" } }")) 37 38 npmUtils := npm.NewNpmMockUtilsBundle() 39 npmUtils.ExecRunner = lintUtils.execRunner 40 npmUtils.FilesMock = lintUtils.FilesMock 41 42 config := defaultConfig 43 config.FailOnError = true 44 45 npmExecutor := npm.NpmExecutorMock{Utils: npmUtils, Config: npm.NpmConfig{RunScripts: []string{"ci-lint"}, RunOptions: []string{"--silent"}}} 46 err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config) 47 48 assert.NoError(t, err) 49 }) 50 51 t.Run("Call default with ESLint config from user", func(t *testing.T) { 52 lintUtils := newLintMockUtilsBundle() 53 lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }")) 54 lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }")) 55 56 config := defaultConfig 57 config.DefaultNpmRegistry = "foo.bar" 58 59 npmUtils := newNpmMockUtilsBundle() 60 npmUtils.execRunner = lintUtils.execRunner 61 npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}} 62 63 err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config) 64 65 if assert.NoError(t, err) { 66 if assert.Equal(t, 2, len(lintUtils.execRunner.Calls)) { 67 assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{"eslint", ".", "-f", "checkstyle", "-o", "./0_defaultlint.xml", "--ignore-pattern", "node_modules/", "--ignore-pattern", ".eslintrc.js"}}, lintUtils.execRunner.Calls[1]) 68 } 69 } 70 }) 71 72 t.Run("Call default with two ESLint configs from user", func(t *testing.T) { 73 lintUtils := newLintMockUtilsBundle() 74 lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }")) 75 lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }")) 76 lintUtils.AddFile(filepath.Join("src", ".eslintrc.json"), []byte("{\"name\": \"Test\" }")) 77 78 config := defaultConfig 79 config.DefaultNpmRegistry = "foo.bar" 80 81 npmUtils := newNpmMockUtilsBundle() 82 npmUtils.execRunner = lintUtils.execRunner 83 npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}} 84 85 err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config) 86 87 if assert.NoError(t, err) { 88 if assert.Equal(t, 3, len(lintUtils.execRunner.Calls)) { 89 assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{"eslint", ".", "-f", "checkstyle", "-o", "./0_defaultlint.xml", "--ignore-pattern", "node_modules/", "--ignore-pattern", ".eslintrc.js"}}, lintUtils.execRunner.Calls[1]) 90 assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{"eslint", "src/**/*.js", "-f", "checkstyle", "-o", "./1_defaultlint.xml", "--ignore-pattern", "node_modules/", "--ignore-pattern", ".eslintrc.js"}}, lintUtils.execRunner.Calls[2]) 91 } 92 } 93 }) 94 95 t.Run("Default without ESLint config", func(t *testing.T) { 96 lintUtils := newLintMockUtilsBundle() 97 lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }")) 98 99 config := defaultConfig 100 config.DefaultNpmRegistry = "foo.bar" 101 102 npmUtils := newNpmMockUtilsBundle() 103 npmUtils.execRunner = lintUtils.execRunner 104 npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}} 105 106 err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config) 107 108 if assert.NoError(t, err) { 109 if assert.Equal(t, 3, len(lintUtils.execRunner.Calls)) { 110 assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"install", "eslint@^7.0.0", "typescript@^3.7.4", "@typescript-eslint/parser@^3.0.0", "@typescript-eslint/eslint-plugin@^3.0.0"}}, lintUtils.execRunner.Calls[1]) 111 assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{"--no-install", "eslint", ".", "--ext", ".js,.jsx,.ts,.tsx", "-c", ".pipeline/.eslintrc.json", "-f", "checkstyle", "-o", "./defaultlint.xml", "--ignore-pattern", ".eslintrc.js"}}, lintUtils.execRunner.Calls[2]) 112 } 113 } 114 }) 115 116 t.Run("Call with ci-lint script and failOnError", func(t *testing.T) { 117 lintUtils := newLintMockUtilsBundle() 118 lintUtils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"\" } }")) 119 lintUtils.execRunner = &mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{"npm run ci-lint --silent": errors.New("exit 1")}} 120 121 config := defaultConfig 122 config.FailOnError = true 123 config.DefaultNpmRegistry = "foo.bar" 124 125 npmUtils := newNpmMockUtilsBundle() 126 npmUtils.execRunner = lintUtils.execRunner 127 npmUtils.FilesMock = lintUtils.FilesMock 128 npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}} 129 130 err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config) 131 132 if assert.EqualError(t, err, "ci-lint script execution failed with error: failed to run npm script ci-lint: exit 1. This might be the result of severe linting findings, or some other issue while executing the script. Please examine the linting results in the UI, the cilint.xml file, if available, or the log above. ") { 133 if assert.Equal(t, 2, len(lintUtils.execRunner.Calls)) { 134 assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run", "ci-lint", "--silent"}}, lintUtils.execRunner.Calls[1]) 135 } 136 } 137 }) 138 139 t.Run("Call default with ESLint config from user and failOnError", func(t *testing.T) { 140 lintUtils := newLintMockUtilsBundle() 141 lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }")) 142 lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }")) 143 lintUtils.execRunner = &mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{"eslint . -f checkstyle -o ./0_defaultlint.xml --ignore-pattern node_modules/ --ignore-pattern .eslintrc.js": errors.New("exit 1")}} 144 145 config := defaultConfig 146 config.FailOnError = true 147 config.DefaultNpmRegistry = "foo.bar" 148 149 npmUtils := newNpmMockUtilsBundle() 150 npmUtils.execRunner = lintUtils.execRunner 151 npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}} 152 153 err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config) 154 155 if assert.EqualError(t, err, "Lint execution failed. This might be the result of severe linting findings, problems with the provided ESLint configuration (.eslintrc.json), or another issue. Please examine the linting results in the UI or in 0_defaultlint.xml, if available, or the log above. ") { 156 if assert.Equal(t, 2, len(lintUtils.execRunner.Calls)) { 157 assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{"eslint", ".", "-f", "checkstyle", "-o", "./0_defaultlint.xml", "--ignore-pattern", "node_modules/", "--ignore-pattern", ".eslintrc.js"}}, lintUtils.execRunner.Calls[1]) 158 } 159 } 160 }) 161 162 t.Run("Find ESLint configs", func(t *testing.T) { 163 lintUtils := newLintMockUtilsBundle() 164 lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }")) 165 lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }")) 166 lintUtils.AddFile("src/.eslintrc.json", []byte("{\"name\": \"Test\" }")) 167 lintUtils.AddFile("node_modules/.eslintrc.json", []byte("{\"name\": \"Test\" }")) // should be filtered out 168 lintUtils.AddFile(".pipeline/.eslintrc.json", []byte("{\"name\": \"Test\" }")) // should be filtered out 169 170 eslintConfigs := findEslintConfigs(&lintUtils) 171 if assert.Equal(t, 2, len(eslintConfigs)) { 172 assert.Contains(t, eslintConfigs, ".eslintrc.json") 173 assert.Contains(t, eslintConfigs, filepath.Join("src", ".eslintrc.json")) 174 } 175 }) 176 177 t.Run("Call with ci-lint script and install", func(t *testing.T) { 178 lintUtils := newLintMockUtilsBundle() 179 lintUtils.AddFile("package.json", []byte("{\"name\": \"test\", \"scripts\": { \"ci-lint\": \"\" } }")) 180 181 npmUtils := npm.NewNpmMockUtilsBundle() 182 npmUtils.ExecRunner = lintUtils.execRunner 183 npmUtils.FilesMock = lintUtils.FilesMock 184 185 config := defaultConfig 186 config.Install = true 187 188 npmExecutor := npm.NpmExecutorMock{Utils: npmUtils, Config: npm.NpmConfig{RunScripts: []string{"ci-lint"}, RunOptions: []string{"--silent"}, Install: true}} 189 err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config) 190 191 assert.NoError(t, err) 192 }) 193 194 t.Run("Call with default and install", func(t *testing.T) { 195 lintUtils := newLintMockUtilsBundle() 196 lintUtils.AddFile("package.json", []byte("{\"name\": \"test\"}")) 197 198 npmUtils := npm.NewNpmMockUtilsBundle() 199 npmUtils.ExecRunner = lintUtils.execRunner 200 npmUtils.FilesMock = lintUtils.FilesMock 201 202 config := defaultConfig 203 config.Install = true 204 205 npmExecutor := npm.NpmExecutorMock{Utils: npmUtils, Config: npm.NpmConfig{RunScripts: []string{"ci-lint"}, RunOptions: []string{"--silent"}, Install: true}} 206 err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config) 207 208 assert.NoError(t, err) 209 }) 210 211 t.Run("Call with custom runScript", func(t *testing.T) { 212 lintUtils := newLintMockUtilsBundle() 213 lintUtils.AddFile("package.json", []byte("{\"name\": \"test\", \"scripts\": { \"lint:ci\": \"\" } }")) 214 215 npmUtils := npm.NewNpmMockUtilsBundle() 216 npmUtils.ExecRunner = lintUtils.execRunner 217 npmUtils.FilesMock = lintUtils.FilesMock 218 219 config := defaultConfig 220 config.RunScript = "lint:ci" 221 222 npmExecutor := npm.NpmExecutorMock{Utils: npmUtils, Config: npm.NpmConfig{RunScripts: []string{"lint:ci"}, RunOptions: []string{"--silent"}}} 223 err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config) 224 225 assert.NoError(t, err) 226 }) 227 228 t.Run("Call with empty runScript and failOnError", func(t *testing.T) { 229 lintUtils := newLintMockUtilsBundle() 230 lintUtils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"\" } }")) 231 lintUtils.execRunner = &mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{"npm run ci-lint --silent": errors.New("exit 1")}} 232 233 config := defaultConfig 234 config.FailOnError = true 235 config.RunScript = "" 236 237 npmUtils := newNpmMockUtilsBundle() 238 npmUtils.execRunner = lintUtils.execRunner 239 npmUtils.FilesMock = lintUtils.FilesMock 240 npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}} 241 242 err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config) 243 244 assert.EqualError(t, err, "runScript is not allowed to be empty!") 245 }) 246 }