github.com/bazelbuild/rules_webtesting@v0.2.0/go/webdriver/webdriver_test.go (about)

     1  // Copyright 2016 Google Inc.
     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  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package webdriver
    16  
    17  import (
    18  	"context"
    19  	"net/url"
    20  	"os"
    21  	"strings"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/bazelbuild/rules_webtesting/go/metadata/capabilities"
    26  	"github.com/bazelbuild/rules_webtesting/go/webtest"
    27  )
    28  
    29  func TestCreateSessionAndQuit(t *testing.T) {
    30  	ctx := context.Background()
    31  
    32  	d, err := CreateSession(ctx, wdAddress(), 3, nil)
    33  	if err != nil {
    34  		t.Fatal(err)
    35  	}
    36  	if d.SessionID() == "" {
    37  		t.Error("session ID should be set")
    38  	}
    39  	if name, _ := d.Capabilities()["browserName"].(string); name == "" {
    40  		t.Error("capabilities browserName should be non-empty")
    41  	}
    42  	if sid, ok := d.Capabilities()["sessionId"]; ok {
    43  		t.Errorf("capabilities should not contain session ID; has sessionId key with value %q", sid)
    44  	}
    45  	if err := d.Quit(ctx); err != nil {
    46  		t.Error(err)
    47  	}
    48  }
    49  
    50  func TestHealthy(t *testing.T) {
    51  	ctx := context.Background()
    52  
    53  	d, err := CreateSession(ctx, wdAddress(), 1, nil)
    54  	if err != nil {
    55  		t.Fatal(err)
    56  	}
    57  	if err := d.Healthy(ctx); err != nil {
    58  		t.Error(err)
    59  	}
    60  	if err := d.Quit(ctx); err != nil {
    61  		t.Error(err)
    62  	}
    63  	if err := d.Healthy(ctx); err == nil {
    64  		t.Error("got nil error from Healthy after quit")
    65  	}
    66  }
    67  
    68  func TestExecuteScript(t *testing.T) {
    69  	testCases := []struct {
    70  		script   string
    71  		args     []interface{}
    72  		value    int
    73  		expected int
    74  		err      bool
    75  	}{
    76  		{
    77  			"return 1 + 2;",
    78  			[]interface{}{},
    79  			0,
    80  			3,
    81  			false,
    82  		},
    83  		{
    84  			"return arguments[0] + arguments[1];",
    85  			[]interface{}{1, 2},
    86  			0,
    87  			3,
    88  			false,
    89  		},
    90  		{
    91  			"return argument[0] + arguments[1];",
    92  			[]interface{}{1, 2},
    93  			0,
    94  			0,
    95  			true,
    96  		},
    97  	}
    98  
    99  	ctx := context.Background()
   100  
   101  	d, err := CreateSession(ctx, wdAddress(), 1, nil)
   102  	if err != nil {
   103  		t.Fatal(err)
   104  	}
   105  	defer d.Quit(ctx)
   106  	for _, tc := range testCases {
   107  		t.Run(tc.script, func(t *testing.T) {
   108  			if err := d.ExecuteScript(ctx, tc.script, tc.args, &tc.value); err != nil {
   109  				if !tc.err {
   110  					t.Errorf("got unexpected err %v for ExecuteScript(%q, %v)", err, tc.script, tc.args)
   111  				}
   112  				return
   113  			}
   114  			if tc.err {
   115  				t.Errorf("got nil err for ExecuteScript(%q, %v)", tc.script, tc.args)
   116  				return
   117  			}
   118  			if tc.value != tc.expected {
   119  				t.Errorf("got %v, expected %v for ExecuteScript(%q, %v)", tc.value, tc.expected, tc.script, tc.args)
   120  			}
   121  		})
   122  	}
   123  }
   124  
   125  func TestExecuteScriptAsync(t *testing.T) {
   126  	testCases := []struct {
   127  		script   string
   128  		args     []interface{}
   129  		value    int
   130  		expected int
   131  		err      bool
   132  	}{
   133  		{
   134  			"arguments[0](1 + 2);",
   135  			[]interface{}{},
   136  			0,
   137  			3,
   138  			false,
   139  		},
   140  		{
   141  			"arguments[2](arguments[0] + arguments[1]);",
   142  			[]interface{}{1, 2},
   143  			0,
   144  			3,
   145  			false,
   146  		},
   147  		{
   148  			"argument[2](argument[0] + argument[1]);",
   149  			[]interface{}{1, 2},
   150  			0,
   151  			0,
   152  			true,
   153  		},
   154  		{
   155  			"return 1 + 2;",
   156  			[]interface{}{1, 2},
   157  			0,
   158  			0,
   159  			true,
   160  		},
   161  	}
   162  
   163  	ctx := context.Background()
   164  
   165  	d, err := CreateSession(ctx, wdAddress(), 1, nil)
   166  	if err != nil {
   167  		t.Fatal(err)
   168  	}
   169  	defer d.Quit(ctx)
   170  
   171  	for _, tc := range testCases {
   172  		t.Run(tc.script, func(t *testing.T) {
   173  			if err := d.ExecuteScriptAsync(ctx, tc.script, tc.args, &tc.value); err != nil {
   174  				if !tc.err {
   175  					t.Errorf("got unexpected err %v for ExecuteScriptAsync(%q, %v)", err, tc.script, tc.args)
   176  				}
   177  				return
   178  			}
   179  			if tc.err {
   180  				t.Errorf("got nil err for ExecuteScriptAsync(%q, %v)", tc.script, tc.args)
   181  				return
   182  			}
   183  			if tc.value != tc.expected {
   184  				t.Errorf("got %v, expected %v for ExecuteScriptAsync(%q, %v)", tc.value, tc.expected, tc.script, tc.args)
   185  			}
   186  		})
   187  	}
   188  }
   189  
   190  func TestCurrentURL(t *testing.T) {
   191  	ctx := context.Background()
   192  
   193  	d, err := CreateSession(ctx, wdAddress(), 3, nil)
   194  	if err != nil {
   195  		t.Fatal(err)
   196  	}
   197  	defer d.Quit(ctx)
   198  
   199  	u, err := d.CurrentURL(ctx)
   200  	if err != nil {
   201  		t.Fatal(err)
   202  	}
   203  	if u == nil {
   204  		t.Fatal("got nil, expected a url.URL ")
   205  	}
   206  }
   207  
   208  func TestNavigateTo(t *testing.T) {
   209  	ctx := context.Background()
   210  
   211  	d, err := CreateSession(ctx, wdAddress(), 3, nil)
   212  	if err != nil {
   213  		t.Fatal(err)
   214  	}
   215  	defer d.Quit(ctx)
   216  
   217  	u, err := url.Parse("https://www.google.com")
   218  
   219  	if err := d.NavigateTo(ctx, u); err != nil {
   220  		t.Fatal(err)
   221  	}
   222  
   223  	cu, err := d.CurrentURL(ctx)
   224  	if err != nil {
   225  		t.Fatal(err)
   226  	}
   227  	if !strings.Contains(cu.Hostname(), "google.com") {
   228  		t.Fatalf("got %s, expected to contain google.com", cu)
   229  	}
   230  }
   231  
   232  func TestScreenshot(t *testing.T) {
   233  	ctx := context.Background()
   234  
   235  	d, err := CreateSession(ctx, wdAddress(), 3, nil)
   236  	if err != nil {
   237  		t.Fatal(err)
   238  	}
   239  	defer d.Quit(ctx)
   240  
   241  	img, err := d.Screenshot(ctx)
   242  	if err != nil {
   243  		t.Fatal(err)
   244  	}
   245  	if img == nil {
   246  		t.Fatal("got nil, expected an image.Image")
   247  	}
   248  }
   249  
   250  func TestWindowHandles(t *testing.T) {
   251  	ctx := context.Background()
   252  
   253  	driver, err := CreateSession(ctx, wdAddress(), 3, nil)
   254  	if err != nil {
   255  		t.Fatal(err)
   256  	}
   257  	defer driver.Quit(ctx)
   258  
   259  	if windows, err := driver.WindowHandles(ctx); err != nil {
   260  		t.Fatal(err)
   261  	} else if len(windows) != 1 {
   262  		t.Fatalf("Got %d handles, expected 1", len(windows))
   263  	}
   264  }
   265  
   266  func TestQuit(t *testing.T) {
   267  	ctx := context.Background()
   268  
   269  	driver, err := CreateSession(ctx, wdAddress(), 3, nil)
   270  	if err != nil {
   271  		t.Fatal(err)
   272  	}
   273  	driver.Quit(ctx)
   274  
   275  	if _, err := driver.WindowHandles(ctx); err == nil {
   276  		t.Fatal("Got nil err, expected unknown session err")
   277  	}
   278  }
   279  
   280  func TestExecuteScriptAsyncWithTimeout(t *testing.T) {
   281  	ctx := context.Background()
   282  
   283  	d, err := CreateSession(ctx, wdAddress(), 3, nil)
   284  	if err != nil {
   285  		t.Fatal(err)
   286  	}
   287  	defer d.Quit(ctx)
   288  
   289  	if err := d.SetScriptTimeout(ctx, 5*time.Second); err != nil {
   290  		t.Fatal(err)
   291  	}
   292  
   293  	start := time.Now()
   294  	if err := d.ExecuteScriptAsyncWithTimeout(ctx, time.Second, "return;", nil, nil); err == nil {
   295  		t.Error("Got nil err, expected timeout err")
   296  	}
   297  	if run := time.Now().Sub(start); run < time.Second || run > 5*time.Second {
   298  		t.Errorf("Got runtime %s, expected < 1 and < 5 seconds", run)
   299  	}
   300  
   301  	start = time.Now()
   302  	if err := d.ExecuteScriptAsync(ctx, "return;", nil, nil); err == nil {
   303  		t.Error("Got nil err, expected timeout err")
   304  	}
   305  	if run := time.Now().Sub(start); run < 5*time.Second {
   306  		t.Errorf("Got runtime %s, expected > 5 seconds", run)
   307  	}
   308  }
   309  
   310  func TestExecuteScriptAsyncWithTimeoutWithCaps(t *testing.T) {
   311  	ctx := context.Background()
   312  
   313  	d, err := CreateSession(ctx, wdAddress(), 3, &capabilities.Capabilities{
   314  		AlwaysMatch: map[string]interface{}{
   315  			"timeouts": map[string]interface{}{
   316  				"script": 5000,
   317  			},
   318  		},
   319  	})
   320  	if err != nil {
   321  		t.Fatal(err)
   322  	}
   323  	defer d.Quit(ctx)
   324  
   325  	start := time.Now()
   326  	if err := d.ExecuteScriptAsyncWithTimeout(ctx, time.Second, "return;", nil, nil); err == nil {
   327  		t.Error("Got nil err, expected timeout err")
   328  	}
   329  	if run := time.Now().Sub(start); run < time.Second || run > 5*time.Second {
   330  		t.Errorf("Got runtime %s, expected < 1 and < 5 seconds", run)
   331  	}
   332  
   333  	start = time.Now()
   334  	if err := d.ExecuteScriptAsync(ctx, "return;", nil, nil); err == nil {
   335  		t.Error("Got nil err, expected timeout err")
   336  	}
   337  	if run := time.Now().Sub(start); run < 5*time.Second {
   338  		t.Errorf("Got runtime %s, expected > 5 seconds", run)
   339  	}
   340  }
   341  
   342  func TestGetWindowRect(t *testing.T) {
   343  	if bi, _ := webtest.GetBrowserInfo(); bi.Environment == "sauce" {
   344  		t.Skip("fails on SauceLabs.")
   345  	}
   346  
   347  	ctx := context.Background()
   348  
   349  	d, err := CreateSession(ctx, wdAddress(), 3, nil)
   350  	if err != nil {
   351  		t.Fatal(err)
   352  	}
   353  	defer d.Quit(ctx)
   354  
   355  	rect, err := d.GetWindowRect(ctx)
   356  	if err != nil {
   357  		t.Fatal(err)
   358  	}
   359  
   360  	if rect.X < 0 {
   361  		t.Errorf("got rect.X == %d, expected >= 0", rect.X)
   362  	}
   363  
   364  	if rect.Y < 0 {
   365  		t.Errorf("got rect.Y == %d, expected >= 0", rect.Y)
   366  	}
   367  
   368  	if rect.Width <= 0 {
   369  		t.Errorf("got rect.Width == %d, expected > 0", rect.Width)
   370  	}
   371  
   372  	if rect.Height <= 0 {
   373  		t.Errorf("got rect.Height == %d, expected > 0", rect.Height)
   374  	}
   375  }
   376  
   377  func TestSetWindowRect(t *testing.T) {
   378  	testCases := []struct {
   379  		name  string
   380  		rect  Rectangle
   381  		check bool
   382  		err   bool
   383  	}{
   384  		{
   385  			"valid",
   386  			Rectangle{
   387  				X:      200,
   388  				Y:      200,
   389  				Width:  500,
   390  				Height: 400,
   391  			},
   392  			true,
   393  			false,
   394  		},
   395  		{
   396  			"zeroes",
   397  			Rectangle{},
   398  			false,
   399  			false,
   400  		},
   401  		{
   402  			"negative location",
   403  			Rectangle{
   404  				X:      -200,
   405  				Y:      -200,
   406  				Width:  500,
   407  				Height: 400,
   408  			},
   409  			false, // what happens is os/wm dependent.
   410  			false,
   411  		},
   412  	}
   413  
   414  	ctx := context.Background()
   415  
   416  	d, err := CreateSession(ctx, wdAddress(), 3, nil)
   417  	if err != nil {
   418  		t.Fatal(err)
   419  	}
   420  	defer d.Quit(ctx)
   421  
   422  	for _, tc := range testCases {
   423  		t.Run(tc.name, func(t *testing.T) {
   424  			err := d.SetWindowRect(ctx, tc.rect)
   425  			if tc.err {
   426  				if err == nil {
   427  					t.Fatal("got nil err, expected non-nil err")
   428  				}
   429  				return
   430  			}
   431  			if err != nil {
   432  				t.Fatal(err)
   433  			}
   434  			if !tc.check {
   435  				return
   436  			}
   437  
   438  			rect, err := d.GetWindowRect(ctx)
   439  			if err != nil {
   440  				t.Fatal(err)
   441  			}
   442  
   443  			if rect != tc.rect {
   444  				t.Errorf("got rect == %+v, expected %+v", rect, tc.rect)
   445  			}
   446  		})
   447  	}
   448  }
   449  
   450  func TestSetWindowSize(t *testing.T) {
   451  	if bi, _ := webtest.GetBrowserInfo(); bi.Environment == "sauce" {
   452  		t.Skip("fails on SauceLabs.")
   453  	}
   454  
   455  	testCases := []struct {
   456  		name   string
   457  		width  float64
   458  		height float64
   459  		check  bool
   460  		err    bool
   461  	}{
   462  		{
   463  			"valid",
   464  			500,
   465  			400,
   466  			true,
   467  			false,
   468  		},
   469  		{
   470  			"zeroes",
   471  			0,
   472  			0,
   473  			false,
   474  			false,
   475  		},
   476  	}
   477  
   478  	ctx := context.Background()
   479  
   480  	d, err := CreateSession(ctx, wdAddress(), 3, nil)
   481  	if err != nil {
   482  		t.Fatal(err)
   483  	}
   484  	defer d.Quit(ctx)
   485  
   486  	for _, tc := range testCases {
   487  		t.Run(tc.name, func(t *testing.T) {
   488  			err := d.SetWindowSize(ctx, tc.width, tc.height)
   489  			if tc.err {
   490  				if err == nil {
   491  					t.Fatal("got nil err, expected non-nil err")
   492  				}
   493  				return
   494  			}
   495  			if err != nil {
   496  				t.Fatal(err)
   497  			}
   498  			if !tc.check {
   499  				return
   500  			}
   501  			rect, err := d.GetWindowRect(ctx)
   502  			if err != nil {
   503  				t.Fatal(err)
   504  			}
   505  
   506  			if tc.width != rect.Width || tc.height != rect.Height {
   507  				t.Errorf("got (w, h) == (%d, %d), expected (%d, %d)", rect.Width, rect.Height, tc.width, tc.height)
   508  			}
   509  		})
   510  	}
   511  }
   512  
   513  func TestSetWindowPosition(t *testing.T) {
   514  	if bi, _ := webtest.GetBrowserInfo(); bi.Environment == "sauce" {
   515  		t.Skip("fails on SauceLabs.")
   516  	}
   517  
   518  	testCases := []struct {
   519  		name  string
   520  		x     float64
   521  		y     float64
   522  		check bool
   523  		err   bool
   524  	}{
   525  		{
   526  			"valid",
   527  			200,
   528  			200,
   529  			true,
   530  			false,
   531  		},
   532  		{
   533  			"zeroes",
   534  			0,
   535  			0,
   536  			false,
   537  			false,
   538  		},
   539  		{
   540  			"negative",
   541  			-200,
   542  			-200,
   543  			false, // what happens is os/wm dependent.
   544  			false,
   545  		},
   546  	}
   547  
   548  	ctx := context.Background()
   549  
   550  	d, err := CreateSession(ctx, wdAddress(), 3, nil)
   551  	if err != nil {
   552  		t.Fatal(err)
   553  	}
   554  	defer d.Quit(ctx)
   555  
   556  	for _, tc := range testCases {
   557  		t.Run(tc.name, func(t *testing.T) {
   558  			err := d.SetWindowPosition(ctx, tc.x, tc.y)
   559  			if tc.err {
   560  				if err == nil {
   561  					t.Fatal("got nil err, expected non-nil err")
   562  				}
   563  				return
   564  			}
   565  			if err != nil {
   566  				t.Fatal(err)
   567  			}
   568  			if !tc.check {
   569  				return
   570  			}
   571  
   572  			rect, err := d.GetWindowRect(ctx)
   573  			if err != nil {
   574  				t.Fatal(err)
   575  			}
   576  
   577  			if rect.X != tc.x || rect.Y != tc.y {
   578  				t.Errorf("got rect == %+v, expected X: %d, Y: %d", rect, tc.x, tc.y)
   579  			}
   580  		})
   581  	}
   582  }
   583  
   584  func wdAddress() string {
   585  	addr := os.Getenv("WEB_TEST_WEBDRIVER_SERVER")
   586  	if !strings.HasSuffix(addr, "/") {
   587  		addr = addr + "/"
   588  	}
   589  	return addr
   590  }