github.com/saucelabs/saucectl@v0.175.1/internal/testcafe/config_test.go (about)

     1  package testcafe
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/saucelabs/saucectl/internal/insights"
    10  	"github.com/saucelabs/saucectl/internal/saucereport"
    11  	"github.com/stretchr/testify/assert"
    12  	"gotest.tools/v3/fs"
    13  )
    14  
    15  func Test_appleDeviceRegex(t *testing.T) {
    16  	tests := []struct {
    17  		deviceName string
    18  		want       bool
    19  	}{
    20  		{
    21  			deviceName: "iPhone Simulator",
    22  			want:       true,
    23  		},
    24  		{
    25  			deviceName: "iphone simulator",
    26  			want:       true,
    27  		},
    28  		{
    29  			deviceName: "iPhone SE (2nd generation) Simulator",
    30  			want:       true,
    31  		},
    32  		{
    33  			deviceName: "iPhone 8 Simulator",
    34  			want:       true,
    35  		},
    36  		{
    37  			deviceName: "iPhone 8 Plus Simulator",
    38  			want:       true,
    39  		},
    40  		{
    41  			deviceName: "iPad Pro (12.9 inch) Simulator",
    42  			want:       true,
    43  		},
    44  		{
    45  			deviceName: "iPad Pro (12.9 inch) (4th generation) Simulator",
    46  			want:       true,
    47  		},
    48  		{
    49  			deviceName: "iPad Air Simulator",
    50  			want:       true,
    51  		},
    52  		{
    53  			deviceName: "iPad (8th generation) Simulator",
    54  			want:       true,
    55  		},
    56  		{
    57  			deviceName: "iPad mini (5th generation) Simulator",
    58  			want:       true,
    59  		},
    60  		{
    61  			deviceName: "Android GoogleAPI Emulator",
    62  			want:       false,
    63  		},
    64  		{
    65  			deviceName: "Google Pixel 3a GoogleAPI Emulator",
    66  			want:       false,
    67  		},
    68  	}
    69  	for _, tt := range tests {
    70  		t.Run(tt.deviceName, func(t *testing.T) {
    71  			got := appleDeviceRegex.MatchString(tt.deviceName)
    72  			if got != tt.want {
    73  				t.Errorf("appleDeviceRegex.MatchString() got = %v, want %v", got, tt.want)
    74  			}
    75  		})
    76  	}
    77  }
    78  
    79  func TestFilterSuites(t *testing.T) {
    80  	testCase := []struct {
    81  		name      string
    82  		config    *Project
    83  		suiteName string
    84  		expConfig Project
    85  		expErr    string
    86  	}{
    87  		{
    88  			name: "filtered suite exists in config",
    89  			config: &Project{Suites: []Suite{
    90  				{
    91  					Name: "suite1",
    92  				},
    93  				{
    94  					Name: "suite2",
    95  				},
    96  			}},
    97  			suiteName: "suite1",
    98  			expConfig: Project{Suites: []Suite{
    99  				{
   100  					Name: "suite1",
   101  				},
   102  			}},
   103  		},
   104  		{
   105  			name: "filtered suite does not exist in config",
   106  			config: &Project{Suites: []Suite{
   107  				{
   108  					Name: "suite1",
   109  				},
   110  				{
   111  					Name: "suite2",
   112  				},
   113  			}},
   114  			suiteName: "suite3",
   115  			expConfig: Project{Suites: []Suite{
   116  				{
   117  					Name: "suite1",
   118  				},
   119  				{
   120  					Name: "suite2",
   121  				},
   122  			}},
   123  			expErr: "no suite named 'suite3' found",
   124  		},
   125  	}
   126  
   127  	for _, tc := range testCase {
   128  		t.Run(tc.name, func(t *testing.T) {
   129  			err := FilterSuites(tc.config, tc.suiteName)
   130  			if err != nil {
   131  				assert.Equal(t, tc.expErr, err.Error())
   132  			}
   133  			assert.True(t, reflect.DeepEqual(*tc.config, tc.expConfig))
   134  		})
   135  	}
   136  }
   137  
   138  func Test_shardSuites_withSplit(t *testing.T) {
   139  	dir := fs.NewDir(t, "testcafe",
   140  		fs.WithFile(".sauceignore", "", fs.WithMode(0644)),
   141  		fs.WithDir("tests",
   142  			fs.WithMode(0755),
   143  			fs.WithDir("dir1",
   144  				fs.WithMode(0755),
   145  				fs.WithFile("example1.tests.js", "", fs.WithMode(0644)),
   146  			),
   147  			fs.WithDir("dir2",
   148  				fs.WithMode(0755),
   149  				fs.WithFile("example2.tests.js", "", fs.WithMode(0644)),
   150  			),
   151  			fs.WithDir("dir3",
   152  				fs.WithMode(0755),
   153  				fs.WithFile("example3.tests.js", "", fs.WithMode(0644)),
   154  			),
   155  		),
   156  	)
   157  	defer dir.Remove()
   158  
   159  	// Beginning state
   160  	rootDir := dir.Path()
   161  	origSuites := []Suite{
   162  		{
   163  			Name:  "Demo Suite",
   164  			Src:   []string{"tests/**/*.js"},
   165  			Shard: "spec",
   166  		},
   167  	}
   168  
   169  	expectedSuites := []Suite{
   170  		{
   171  			Name:  "Demo Suite - tests/dir1/example1.tests.js",
   172  			Src:   []string{"tests/dir1/example1.tests.js"},
   173  			Shard: "spec",
   174  		},
   175  		{
   176  			Name:  "Demo Suite - tests/dir2/example2.tests.js",
   177  			Src:   []string{"tests/dir2/example2.tests.js"},
   178  			Shard: "spec",
   179  		},
   180  		{
   181  			Name:  "Demo Suite - tests/dir3/example3.tests.js",
   182  			Src:   []string{"tests/dir3/example3.tests.js"},
   183  			Shard: "spec",
   184  		},
   185  	}
   186  	var err error
   187  	var suites []Suite
   188  
   189  	// Absolute path
   190  	suites, err = shardSuites(rootDir, origSuites, 1, dir.Join(".sauceignore"))
   191  
   192  	assert.Equal(t, err, nil)
   193  	assert.Equal(t, expectedSuites, suites)
   194  
   195  	// Relative path
   196  	if err := os.Chdir(rootDir); err != nil {
   197  		t.Errorf("Unexpected error %s", err)
   198  	}
   199  	suites, err = shardSuites(".", origSuites, 1, dir.Join(".sauceignore"))
   200  
   201  	assert.Equal(t, err, nil)
   202  	assert.Equal(t, expectedSuites, suites)
   203  }
   204  
   205  func Test_shardSuites_withoutSplit(t *testing.T) {
   206  	dir := fs.NewDir(t, "testcafe",
   207  		fs.WithFile(".sauceignore", "", fs.WithMode(0644)),
   208  	)
   209  	defer dir.Remove()
   210  	origSuites := []Suite{
   211  		{
   212  			Name: "Demo Suite",
   213  			Src:  []string{"tests/**/*.js"},
   214  		},
   215  	}
   216  	var err error
   217  	var suites []Suite
   218  
   219  	// Absolute path
   220  	suites, err = shardSuites("", origSuites, 1, dir.Join(".sauceignore"))
   221  
   222  	assert.Equal(t, err, nil)
   223  	assert.Equal(t, origSuites, suites)
   224  }
   225  
   226  func Test_shardSuites_withSplitNoMatch(t *testing.T) {
   227  	dir := fs.NewDir(t, "testcafe",
   228  		fs.WithFile(".sauceignore", "", fs.WithMode(0644)),
   229  		fs.WithDir("tests",
   230  			fs.WithMode(0755),
   231  			fs.WithDir("dir1",
   232  				fs.WithMode(0755),
   233  				fs.WithFile("example1.tests.js", "", fs.WithMode(0644)),
   234  			),
   235  			fs.WithDir("dir2",
   236  				fs.WithMode(0755),
   237  				fs.WithFile("example2.tests.js", "", fs.WithMode(0644)),
   238  			),
   239  			fs.WithDir("dir3",
   240  				fs.WithMode(0755),
   241  				fs.WithFile("example3.tests.js", "", fs.WithMode(0644)),
   242  			),
   243  		),
   244  	)
   245  	defer dir.Remove()
   246  
   247  	// Beginning state
   248  	rootDir := dir.Path()
   249  	origSuites := []Suite{
   250  		{
   251  			Name:  "Demo Suite",
   252  			Src:   []string{"dummy/**/*.js"},
   253  			Shard: "spec",
   254  		},
   255  	}
   256  
   257  	expectedSuites := make([]Suite, 0)
   258  	var err error
   259  	var suites []Suite
   260  
   261  	// Absolute path
   262  	suites, err = shardSuites(rootDir, origSuites, 1, dir.Join(".sauceignore"))
   263  
   264  	assert.Equal(t, err, errors.New("suite 'Demo Suite' patterns have no matching files"))
   265  	assert.Equal(t, expectedSuites, suites)
   266  
   267  	// Relative path
   268  	if err := os.Chdir(rootDir); err != nil {
   269  		t.Errorf("Unexpected error %s", err)
   270  	}
   271  	suites, err = shardSuites(".", origSuites, 1, dir.Join(".sauceignore"))
   272  
   273  	assert.Equal(t, err, errors.New("suite 'Demo Suite' patterns have no matching files"))
   274  	assert.Equal(t, expectedSuites, suites)
   275  }
   276  
   277  func TestTestcafe_SortByHistory(t *testing.T) {
   278  	testCases := []struct {
   279  		name    string
   280  		suites  []Suite
   281  		history insights.JobHistory
   282  		expRes  []Suite
   283  	}{
   284  		{
   285  			name: "sort suites by job history",
   286  			suites: []Suite{
   287  				Suite{Name: "suite 1"},
   288  				Suite{Name: "suite 2"},
   289  				Suite{Name: "suite 3"},
   290  			},
   291  			history: insights.JobHistory{
   292  				TestCases: []insights.TestCase{
   293  					insights.TestCase{Name: "suite 2"},
   294  					insights.TestCase{Name: "suite 1"},
   295  					insights.TestCase{Name: "suite 3"},
   296  				},
   297  			},
   298  			expRes: []Suite{
   299  				Suite{Name: "suite 2"},
   300  				Suite{Name: "suite 1"},
   301  				Suite{Name: "suite 3"},
   302  			},
   303  		},
   304  		{
   305  			name: "suites is the subset of job history",
   306  			suites: []Suite{
   307  				Suite{Name: "suite 1"},
   308  				Suite{Name: "suite 2"},
   309  			},
   310  			history: insights.JobHistory{
   311  				TestCases: []insights.TestCase{
   312  					insights.TestCase{Name: "suite 2"},
   313  					insights.TestCase{Name: "suite 1"},
   314  					insights.TestCase{Name: "suite 3"},
   315  				},
   316  			},
   317  			expRes: []Suite{
   318  				Suite{Name: "suite 2"},
   319  				Suite{Name: "suite 1"},
   320  			},
   321  		},
   322  		{
   323  			name: "job history is the subset of suites",
   324  			suites: []Suite{
   325  				Suite{Name: "suite 1"},
   326  				Suite{Name: "suite 2"},
   327  				Suite{Name: "suite 3"},
   328  				Suite{Name: "suite 4"},
   329  				Suite{Name: "suite 5"},
   330  			},
   331  			history: insights.JobHistory{
   332  				TestCases: []insights.TestCase{
   333  					insights.TestCase{Name: "suite 2"},
   334  					insights.TestCase{Name: "suite 1"},
   335  					insights.TestCase{Name: "suite 3"},
   336  				},
   337  			},
   338  			expRes: []Suite{
   339  				Suite{Name: "suite 2"},
   340  				Suite{Name: "suite 1"},
   341  				Suite{Name: "suite 3"},
   342  				Suite{Name: "suite 4"},
   343  				Suite{Name: "suite 5"},
   344  			},
   345  		},
   346  	}
   347  
   348  	for _, tc := range testCases {
   349  		t.Run(tc.name, func(t *testing.T) {
   350  			result := SortByHistory(tc.suites, tc.history)
   351  			for i := 0; i < len(result); i++ {
   352  				assert.Equal(t, tc.expRes[i].Name, result[i].Name)
   353  			}
   354  		})
   355  	}
   356  }
   357  
   358  func TestTestcafe_FilterFailedTests(t *testing.T) {
   359  	testcases := []struct {
   360  		name      string
   361  		suiteName string
   362  		report    saucereport.SauceReport
   363  		project   *Project
   364  		expResult string
   365  		expErr    error
   366  	}{
   367  		{
   368  			name:      "it should set failed tests to specified suite",
   369  			suiteName: "my suite",
   370  			report: saucereport.SauceReport{
   371  				Status: saucereport.StatusFailed,
   372  				Suites: []saucereport.Suite{
   373  					{
   374  						Name:   "my suite",
   375  						Status: saucereport.StatusFailed,
   376  						Tests: []saucereport.Test{
   377  							{
   378  								Status: saucereport.StatusFailed,
   379  								Name:   "failed test1",
   380  							},
   381  							{
   382  								Status: saucereport.StatusFailed,
   383  								Name:   "failed test2",
   384  							},
   385  						},
   386  					},
   387  				},
   388  			},
   389  			project: &Project{
   390  				Suites: []Suite{
   391  					{
   392  						Name: "my suite",
   393  					},
   394  				},
   395  			},
   396  			expResult: "failed test1|failed test2",
   397  			expErr:    nil,
   398  		},
   399  		{
   400  			name:      "it should keep the original settings when suiteName doesn't exist in the project",
   401  			suiteName: "my suite2",
   402  			report: saucereport.SauceReport{
   403  				Status: saucereport.StatusFailed,
   404  				Suites: []saucereport.Suite{
   405  					{
   406  						Name:   "my suite",
   407  						Status: saucereport.StatusFailed,
   408  						Tests: []saucereport.Test{
   409  							{
   410  								Status: saucereport.StatusFailed,
   411  								Name:   "failed test1",
   412  							},
   413  							{
   414  								Status: saucereport.StatusFailed,
   415  								Name:   "failed test2",
   416  							},
   417  						},
   418  					},
   419  				},
   420  			},
   421  			project: &Project{
   422  				Suites: []Suite{
   423  					{
   424  						Name: "my suite",
   425  					},
   426  				},
   427  			},
   428  			expResult: "",
   429  			expErr:    errors.New("suite(my suite2) not found"),
   430  		},
   431  		{
   432  			name:      "it should keep the original settings when no failed test in SauceReport",
   433  			suiteName: "my suite",
   434  			report: saucereport.SauceReport{
   435  				Status: saucereport.StatusPassed,
   436  				Suites: []saucereport.Suite{
   437  					{
   438  						Name:   "my suite",
   439  						Status: saucereport.StatusPassed,
   440  						Tests: []saucereport.Test{
   441  							{
   442  								Status: saucereport.StatusPassed,
   443  								Name:   "passed test1",
   444  							},
   445  							{
   446  								Status: saucereport.StatusSkipped,
   447  								Name:   "skipped test2",
   448  							},
   449  						},
   450  					},
   451  				},
   452  			},
   453  			project: &Project{
   454  				Suites: []Suite{
   455  					{
   456  						Name: "my suite",
   457  					},
   458  				},
   459  			},
   460  			expResult: "",
   461  			expErr:    nil,
   462  		},
   463  	}
   464  	for _, tc := range testcases {
   465  		t.Run(tc.name, func(t *testing.T) {
   466  			err := tc.project.FilterFailedTests(tc.suiteName, tc.report)
   467  			assert.Equal(t, tc.expErr, err)
   468  			assert.Equal(t, tc.expResult, tc.project.Suites[0].Filter.TestGrep)
   469  		})
   470  	}
   471  }