...

Source file src/github.com/playwright-community/playwright-go/tests/helper_test.go

Documentation: github.com/playwright-community/playwright-go/tests

     1  package playwright_test
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"log"
     7  	"mime"
     8  	"net"
     9  	"net/http"
    10  	"net/http/httptest"
    11  	"os"
    12  	"path/filepath"
    13  	"reflect"
    14  	"strings"
    15  	"sync"
    16  	"testing"
    17  
    18  	"github.com/playwright-community/playwright-go"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  var pw *playwright.Playwright
    23  var browser playwright.Browser
    24  var context playwright.BrowserContext
    25  var page playwright.Page
    26  var isChromium bool
    27  var isFirefox bool
    28  var isWebKit bool
    29  var browserName = getBrowserName()
    30  var server *testServer
    31  var browserType playwright.BrowserType
    32  var utils *testUtils
    33  
    34  func init() {
    35  	if err := mime.AddExtensionType(".js", "application/javascript"); err != nil {
    36  		log.Fatalf("could not add mime extension type: %v", err)
    37  	}
    38  }
    39  
    40  func TestMain(m *testing.M) {
    41  	BeforeAll()
    42  	code := m.Run()
    43  	AfterAll()
    44  	os.Exit(code)
    45  }
    46  
    47  func BeforeAll() {
    48  	var err error
    49  	pw, err = playwright.Run()
    50  	if err != nil {
    51  		log.Fatalf("could not start Playwright: %v", err)
    52  	}
    53  	if browserName == "chromium" || browserName == "" {
    54  		browserType = pw.Chromium
    55  	} else if browserName == "firefox" {
    56  		browserType = pw.Firefox
    57  	} else if browserName == "webkit" {
    58  		browserType = pw.WebKit
    59  	}
    60  	browser, err = browserType.Launch(playwright.BrowserTypeLaunchOptions{
    61  		Headless: playwright.Bool(os.Getenv("HEADFUL") == ""),
    62  	})
    63  	if err != nil {
    64  		log.Fatalf("could not launch: %v", err)
    65  	}
    66  	isChromium = browserName == "chromium" || browserName == ""
    67  	isFirefox = browserName == "firefox"
    68  	isWebKit = browserName == "webkit"
    69  	server = newTestServer()
    70  	utils = &testUtils{}
    71  }
    72  
    73  func AfterAll() {
    74  	server.testServer.Close()
    75  	if err := pw.Stop(); err != nil {
    76  		log.Fatalf("could not start Playwright: %v", err)
    77  	}
    78  }
    79  
    80  var DEFAULT_CONTEXT_OPTIONS = playwright.BrowserNewContextOptions{
    81  	AcceptDownloads: playwright.Bool(true),
    82  	HasTouch:        playwright.Bool(true),
    83  }
    84  
    85  func BeforeEach(t *testing.T) {
    86  	newContextWithOptions(t, DEFAULT_CONTEXT_OPTIONS)
    87  }
    88  
    89  func newContextWithOptions(t *testing.T, contextOptions playwright.BrowserNewContextOptions) {
    90  	var err error
    91  	context, err = browser.NewContext(contextOptions)
    92  	require.NoError(t, err)
    93  	page, err = context.NewPage()
    94  	require.NoError(t, err)
    95  }
    96  
    97  func Asset(path string) string {
    98  	cwd, err := os.Getwd()
    99  	if err != nil {
   100  		log.Fatalf("could not get cwd: %v", err)
   101  	}
   102  	return filepath.Join(cwd, "assets", path)
   103  }
   104  
   105  func AfterEach(t *testing.T, closeContext ...bool) {
   106  	if len(closeContext) == 0 {
   107  		if err := context.Close(); err != nil {
   108  			t.Errorf("could not close context: %v", err)
   109  		}
   110  	}
   111  	server.AfterEach()
   112  }
   113  
   114  func newTestServer() *testServer {
   115  	ts := &testServer{
   116  		routes:              make(map[string]http.HandlerFunc),
   117  		requestSubscriberes: make(map[string][]chan *http.Request),
   118  	}
   119  	ts.testServer = httptest.NewServer(http.HandlerFunc(ts.serveHTTP))
   120  	ts.PREFIX = ts.testServer.URL
   121  	ts.EMPTY_PAGE = ts.testServer.URL + "/empty.html"
   122  	ts.CROSS_PROCESS_PREFIX = strings.Replace(ts.testServer.URL, "127.0.0.1", "localhost", 1)
   123  	return ts
   124  }
   125  
   126  type testServer struct {
   127  	sync.Mutex
   128  	testServer           *httptest.Server
   129  	routes               map[string]http.HandlerFunc
   130  	requestSubscriberes  map[string][]chan *http.Request
   131  	PREFIX               string
   132  	EMPTY_PAGE           string
   133  	CROSS_PROCESS_PREFIX string
   134  }
   135  
   136  func (t *testServer) AfterEach() {
   137  	t.Lock()
   138  	defer t.Unlock()
   139  	t.routes = make(map[string]http.HandlerFunc)
   140  	t.requestSubscriberes = make(map[string][]chan *http.Request)
   141  }
   142  
   143  func (t *testServer) serveHTTP(w http.ResponseWriter, r *http.Request) {
   144  	t.Lock()
   145  	defer t.Unlock()
   146  	body, err := ioutil.ReadAll(r.Body)
   147  	if err != nil {
   148  		log.Printf("Error reading body: %v", err)
   149  		http.Error(w, "can't read body", http.StatusBadRequest)
   150  		return
   151  	}
   152  	r.Body = ioutil.NopCloser(bytes.NewBuffer(body))
   153  	if handlers, ok := t.requestSubscriberes[r.URL.Path]; ok {
   154  		for _, handler := range handlers {
   155  			handler <- r
   156  		}
   157  	}
   158  	if route, ok := t.routes[r.URL.Path]; ok {
   159  		route(w, r)
   160  		return
   161  	}
   162  	w.Header().Add("Cache-Control", "no-cache, no-store")
   163  	http.FileServer(http.Dir("assets")).ServeHTTP(w, r)
   164  }
   165  
   166  func (s *testServer) SetRoute(path string, f http.HandlerFunc) {
   167  	s.Lock()
   168  	defer s.Unlock()
   169  	s.routes[path] = f
   170  }
   171  
   172  func (s *testServer) SetRedirect(from, to string) {
   173  	s.SetRoute(from, func(w http.ResponseWriter, r *http.Request) {
   174  		http.Redirect(w, r, to, http.StatusFound)
   175  	})
   176  }
   177  
   178  func (s *testServer) WaitForRequestChan(path string) <-chan *http.Request {
   179  	s.Lock()
   180  	defer s.Unlock()
   181  	if _, ok := s.requestSubscriberes[path]; !ok {
   182  		s.requestSubscriberes[path] = make([]chan *http.Request, 0)
   183  	}
   184  	channel := make(chan *http.Request, 1)
   185  	s.requestSubscriberes[path] = append(s.requestSubscriberes[path], channel)
   186  	return channel
   187  }
   188  
   189  func Map(vs interface{}, f func(interface{}) interface{}) []interface{} {
   190  	v := reflect.ValueOf(vs)
   191  	vsm := make([]interface{}, v.Len())
   192  	for i := 0; i < v.Len(); i++ {
   193  		vsm[i] = f(v.Index(i).Interface())
   194  	}
   195  	return vsm
   196  }
   197  
   198  // ChanToSlice reads all data from ch (which must be a chan), returning a
   199  // slice of the data. If ch is a 'T chan' then the return value is of type
   200  // []T inside the returned interface.
   201  // A typical call would be sl := ChanToSlice(ch).([]int)
   202  func ChanToSlice(ch interface{}, amount int) interface{} {
   203  	chv := reflect.ValueOf(ch)
   204  	slv := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(ch).Elem()), 0, 0)
   205  	for i := 0; i < amount; i++ {
   206  		v, ok := chv.Recv()
   207  		if !ok {
   208  			return slv.Interface()
   209  		}
   210  		slv = reflect.Append(slv, v)
   211  	}
   212  	return slv.Interface()
   213  }
   214  
   215  type syncSlice struct {
   216  	sync.Mutex
   217  	slice []interface{}
   218  }
   219  
   220  func (s *syncSlice) Append(v interface{}) {
   221  	s.Lock()
   222  	s.slice = append(s.slice, v)
   223  	s.Unlock()
   224  }
   225  
   226  func (s *syncSlice) Get() interface{} {
   227  	s.Lock()
   228  	defer s.Unlock()
   229  	return s.slice
   230  }
   231  
   232  func newSyncSlice() *syncSlice {
   233  	return &syncSlice{
   234  		slice: make([]interface{}, 0),
   235  	}
   236  }
   237  
   238  type testUtils struct {
   239  }
   240  
   241  func (t *testUtils) AttachFrame(page playwright.Page, frameId string, url string) (playwright.Frame, error) {
   242  	_, err := page.EvaluateHandle(`async ({ frame_id, url }) => {
   243  		const frame = document.createElement('iframe');
   244  		frame.src = url;
   245  		frame.id = frame_id;
   246  		document.body.appendChild(frame);
   247  		await new Promise(x => frame.onload = x);
   248  		return frame;
   249  	}`, map[string]interface{}{
   250  		"frame_id": frameId,
   251  		"url":      url,
   252  	})
   253  	if err != nil {
   254  		return nil, err
   255  	}
   256  	return nil, nil
   257  }
   258  
   259  func (tu *testUtils) VerifyViewport(t *testing.T, page playwright.Page, width, height int) {
   260  	require.Equal(t, page.ViewportSize().Width, width)
   261  	require.Equal(t, page.ViewportSize().Height, height)
   262  	innerWidth, err := page.Evaluate("window.innerWidth")
   263  	require.NoError(t, err)
   264  	require.Equal(t, innerWidth, width)
   265  	innerHeight, err := page.Evaluate("window.innerHeight")
   266  	require.NoError(t, err)
   267  	require.Equal(t, innerHeight, height)
   268  }
   269  
   270  func (tu *testUtils) AssertEval(t *testing.T, page playwright.Page, script string, expected interface{}) {
   271  	result, err := page.Evaluate(script)
   272  	require.NoError(t, err)
   273  	require.Equal(t, expected, result)
   274  }
   275  
   276  func getBrowserName() string {
   277  	browserName, hasEnv := os.LookupEnv("BROWSER")
   278  	if hasEnv {
   279  		return browserName
   280  	}
   281  	return "chromium"
   282  }
   283  
   284  func getFreePort() (int, error) {
   285  	addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
   286  	if err != nil {
   287  		return 0, err
   288  	}
   289  
   290  	l, err := net.ListenTCP("tcp", addr)
   291  	if err != nil {
   292  		return 0, err
   293  	}
   294  	defer l.Close()
   295  	return l.Addr().(*net.TCPAddr).Port, nil
   296  }
   297  

View as plain text