Notes - Playwright-Go

Best Practices

Use locators

Locators come with auto waiting and retry-ability. Auto waiting means that Playwright performs a range of actionability checks on the elements, such as ensuring the element is visible and enabled before it performs the click. To make tests resilient, we recommend prioritizing user-facing attributes and explicit contracts.

page.getByRole('button', { name: 'submit' });

Use codegen to generate locators

To pick a locator run the codegen command followed by the URL that you would like to pick a locator from.

npx playwright codegen your-url(playwright.dev)

Tips

How to wait for one of several pages to show out?

Use regular expression to check each one of the pages may be showed out.

// Repair tab
// auditRepairURL = `https://blueiq.cloudblue.com/Audit/RepairDetailLOB.aspx`

// Test tab
// auditTestURL = `https://blueiq.cloudblue.com/Audit/AssetConfiguration.aspx`

// Not found tab
// auditSummaryURL = "https://blueiq.cloudblue.com/Audit/Summary.aspx"

// Any one of the above three cases
var reAssetURLs = regexp.MustCompile("RepairDetailLOB|AssetConfiguration|Summary")

// It will be done if any one of the above url reached
err = iq.page.WaitForURL(reAssetURLs, playwright.PageWaitForURLOptions{
	WaitUntil: playwright.WaitUntilStateDomcontentloaded,
})

// check which url reached
url := iq.page.URL()

How to get the page ready?

For page.Goto() function using *WaitUntilState options for fine adjustment.

// Other options: WaitUntilStateDomcontentloaded / WaitUntilStateLoad
_, err := iq.page.Goto(blueIQURL, playwright.PageGotoOptions{
    WaitUntil: playwright.WaitUntilStateNetworkidle,
})

Or use WaitForLoadState function if you already in the page.

// LoadStateLoad - not ready, can't get threshold remaining
// LoadStateDomcontentloaded - page doesn't show out but you can get the data - faster
// LoadStateNetworkidle - page is visible and ready - stable but slower
err = iq.page.WaitForLoadState(playwright.PageWaitForLoadStateOptions{State: playwright.LoadStateNetworkidle})

// Or use Locator.WaitFor
err = iq.page.Locator(auditRepairThresholdRemainingID).WaitFor()

Note: This function will not work if your page is re-directing to other pages, like searching an asset tag in BlueIQ and re-directing to repair page. Use the above WaitForURL function instead in this case.

Selector

See Element Selectors

Select element by label

Excerpt of page source

    <tr>
        <td>
            <input id="ctl32_ctl04_ctl07_divDropDown_ctl70" type="checkbox">
            <label for="ctl32_ctl04_ctl07_divDropDown_ctl70">Vancouver,&nbsp;BC&nbsp;(RL)</label>
        </td>
    </tr>
1
2
3
// See https://playwright.dev/docs/selectors#text-selector
err = page.Click("text=Vancouver") // ok
err = page.Click("text=Vancouver, BC (RL)") // ok
// not work
err = page.Click("text=Vancouver,&nbsp;BC&nbsp;(RL)") 

XPath

1
2
3
4
5
// div text is 'Employee Name'
page.WaitForSelector("//div[text()='Employee Name']")

// parent of the div element
page.WaitForSelector("//div[text()='Employee Name']/..")

Number Only

Class identifiers are allowed to start with a number, but ID identifiers are not. You can’t use an ID selector starting as a number: '#123' is not a valid selector.

You can use escape the number as `#\31 23` or `id=123`

Common Commands

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// launch with options
pw.Chromium.Launch(playwright.BrowserTypeLaunchOptions{
	Headless: playwright.Bool(true),
})
	
// context with options
context, err := browser.NewContext(playwright.BrowserNewContextOptions{
    Locale: playwright.String("en-US"),
    Geolocation: &playwright.BrowserNewContextOptionsGeolocation{
        Longitude: playwright.Float(12.492507),
        Latitude:  playwright.Float(41.889938),
    },
    Permissions:       []string{"geolocation"},
    Viewport:          device.Viewport,
    UserAgent:         playwright.String(device.UserAgent),
    DeviceScaleFactor: playwright.Float(device.DeviceScaleFactor),
    IsMobile:          playwright.Bool(device.IsMobile),
    HasTouch:          playwright.Bool(device.HasTouch),
})
		
// new page with option
page, err := browser.NewPage(playwright.BrowserNewContextOptions{
	RecordVideo: &playwright.BrowserNewContextOptionsRecordVideo{
    	Dir: playwright.String("videos/"),
	},
})
	
// go to page with option
page.Goto("http://whatsmyuseragent.org/", playwright.PageGotoOptions{
	WaitUntil: playwright.WaitUntilStateNetworkidle,
})
	
// screen shot
page.Screenshot(playwright.PageScreenshotOptions{
	Path: playwright.String("foo.png"),
})

// save as pdf
page.PDF(playwright.PagePdfOptions{
	Path: playwright.String("playwright-example.pdf"),
})
				
// click
page.Click("text=download")

// type
page.Type(loginInputUserNameID, iq.userName)
// type with optional delay
page.Type("#ctl32_ctl04_ctl11_txtValue",today, playwright.PageTypeOptions{Delay: playwright.Float(100.0)})

// Eval
page.EvalOnSelectorAll("ul.todo-list > li", "el => el.length")

Select HTML Element

Wait for selector

1
2
// prefer to use WaitForSelector rather than time.Sleep
page.WaitForSelector("//div[text()='Employee Name']")

Get option value of a Select element

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// HTML Tag
// <option value="10" selected="1">Oct</option>

// get the option value
value,err := page.Locator("#month").Evaluate("e=>e.value", "") // 10

// also this works
value,err := page.Locator("#month").InputValue() // 10

// get the option text
label,err := page.Locator("#month").Evaluate("e=>e.selectedOptions[0].text", "") // Oct

// Note: InnerText() will return all the option texts of a select
// page.Locator("#month").InnerText() 
//Jan
//Feb
//Mar
//Apr
//...

Set an option value

You can set the select options according to Label, Value, Index or Elements

1
2
3
4
5
6
7
8
    // by label
    v,err:=page.SelectOption("#ctl32_ctl04_ctl03_ddValue",playwright.SelectOptionValues{Labels: playwright.StringSlice("Canada")})
    
    // by index (int); 0 based?
    v,err=page.SelectOption("#ctl32_ctl04_ctl15_ddValue",playwright.SelectOptionValues{Indexes: playwright.IntSlice(1)})
    
    // by value (string)
    v,err=page.SelectOption("#ctl32_ctl04_ctl15_ddValue",playwright.SelectOptionValues{Values: playwright.StringSlice("2")})

Note: You can’t select the text with &nbsp; space in the label for now. See &nbsp; Space Problem

iFrame

See Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    frameElement, err := page.QuerySelector("#myframe")
    if err != nil {
        log.Fatalf("could not find #myframe iframe: %v\n", err)
    }
    
    frame, err := frameElement.ContentFrame()
    if err != nil {
        log.Fatalf("could not get content frame: %v\n", err)
    }
    
    fmt.Println(frame.URL())
    fmt.Println(frame.InnerHTML("body"))

Download Files

  • All the downloaded files belonging to the browser context are deleted when the browser context is closed.
  • Browser context must be created with the acceptDownloads set to true when user needs access to the downloaded content.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    // 1. Browser instance
    browser, err := pw.Chromium.Launch(playwright.BrowserTypeLaunchOptions{
        Headless: playwright.Bool(false),
        DownloadsPath: playwright.String(`C:\Andrew\prj\rl\learn`),
    })
    
    // 2. Browser context
    c, err := browser.NewContext(playwright.BrowserNewContextOptions{
        HttpCredentials: &playwright.BrowserNewContextOptionsHttpCredentials{
            Username: playwright.String(`CORPORATE\my-win-id`),
            Password: playwright.String("my-password"),
        },
        AcceptDownloads: playwright.Bool(true),
    })
    
    // 3. Download
    download,err:=page.ExpectDownload(func() error {
        return page.Click("#ctl32_ctl05_ctl04_ctl00_Menu > div:nth-child(6) > a")
    })
    
    // 4. Save the file
    fileName := download.SuggestedFilename()
    err = download.SaveAs(path.Join("./", fileName))

Run JavaScript function on selector

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 1. simple example
page.EvalOnSelector("//div[text()='Employee Name']/../../..",`(el) => el.nodeName`) // TBODY

// 2. complex function example
// run function on the selector
f:=`
(el) => {
	let result = "", name = "", client = "", liq = "";
	let sep = "$" // can't use comma, because the comma is used in name
	
	if (el.nodeName==="TBODY"){
		for (let j=1;j<el.rows.length;j++){
		    name = el.rows[j].cells[1].textContent
		    client = el.rows[j].cells[6].textContent
		    liq = el.rows[j].cells[7].textContent
			result = result + name + sep + client + sep + liq + "\n"
		}
	}

	return result
}
`
csvStats, _ := page.EvalOnSelector("//div[text()='Employee Name']/../../..", f)

Headless Mode

Browser will be lunched in headless mode by default.

To run in non-headless mode:

1
2
3
browser, err := pw.Chromium.Launch(playwright.BrowserTypeLaunchOptions{
  Headless: playwright.Bool(false),
})

HTTP authentication example?

Use browser.NewContext() for HTTP authentication

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// ignore all error handling
func main() {
	pw, _ := playwright.Run()
	browser, _ := pw.Chromium.Launch(playwright.BrowserTypeLaunchOptions{
		Headless: playwright.Bool(false),
	})
	
	c, _ := browser.NewContext(playwright.BrowserNewContextOptions{
		HttpCredentials: &playwright.BrowserNewContextOptionsHttpCredentials{
			Username: playwright.String(`CORPORATE\my-windows-id`),
			Password: playwright.String("my-windows-password"),
		},
	})

	page, _ := c.NewPage()
	if _, err = page.Goto("http://blueiqreports.na.cloudblue.com/BlueIQ/Pages/Report.aspx?ItemPath=%2fOperations%2fUser+Metrics&ViewMode=Detail"); err != nil {
		log.Fatalf("could not goto: %v", err)
	}

	fmt.Println("success")

	browser.Close()
	pw.Stop()
}

Event

How to listen for console event?

See here

1
2
3
4
messages := make(chan playwright.ConsoleMessage, 1) 
page.On("console", func(message playwright.ConsoleMessage) { 
    messages <- message 
}) 
updatedupdated2024-10-232024-10-23