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  }