<style>
.center{
display: flex;
justify-content: center;
}
.large_txt{
font-size: x-large;
}
.lighten_txt{
color: #aa0000;
}
</style>
# Playwright 範例
<a class="center large_txt" href="http://www.uitestingplayground.com/">
UI Test Automation Playground
</a>
### <a href='http://www.uitestingplayground.com/classattr'>Class Attribute</a>
撰寫一個每次執行時都觸發 alert popup 的測試案例.
- 獲取 <span class="lighten_txt">dialog</span> 訊息
- 透過 <span class="lighten_txt">css class</span> 及屬性取得指定元件
```python
from playwright.sync_api import sync_playwright
def handle_dialog(dialog):
print(dialog.type)
print(dialog.message)
dialog.dismiss()
def run(playwright):
browser = playwright.chromium.launch(headless=False, slow_mo=1000)
context = browser.new_context()
page = context.new_page()
page.goto("http://www.uitestingplayground.com/classattr")
# page.on("dialog", lambda dialog: print(dialog.message))
# 只有 lambda dialog: print(dialog.message) 會卡在彈跳視窗,
# 需要在透過 dialog.dismiss() 關閉
# playwright 在處理 dialog 事件會自動呼叫 dialog.dismiss()
page.once("dialog", handle_dialog)
page.click(".btn-primary:has-text('Button')")
context.close()
browser.close()
with sync_playwright() as playwright:
run(playwright)
```
### <a href="http://www.uitestingplayground.com/loaddelay">Load Delays</a>
撰寫一個經過等待頁面轉換後, 偵測指定元件的測試案例.
- Auto-waiting
- 透過 <span class="lighten_txt">css class</span> 及屬性取得指定元件
```python
def test_load_delay(page):
page.goto("http://www.uitestingplayground.com/loaddelay")
assert page.query_selector(".btn-primary:has-text('Button Appearing After Delay')").is_visible()
```
### <a href="http://www.uitestingplayground.com/ajax">AJAX Data</a>
撰寫一個可以等待指定元件出現的測試案例.
- Auto-waiting
- 透過 <span class="lighten_txt">ID</span> 和 <span class="lighten_txt">DOM結構</span> 取得指定元件
```python
def test_ajax(page):
page.goto("http://www.uitestingplayground.com/ajax")
page.click("text=Button Triggering AJAX Request")
assert page.inner_text('#content > p:nth-child(1):has-text("Data loaded with AJAX get request.")')
# assert page.inner_text("div[id='content'] p:nth-child(1):has-text('Data loaded with AJAX get request.')")
```
- [補充 nth 用法](https://playwright.dev/python/docs/selectors/#pick-n-th-match-from-the-query-result)
### <a href="http://www.uitestingplayground.com/textinput">Text Input</a>
撰寫一個輸入訊息後, 可以正確修改元件內容的測試案例.
- 透過 <span class="lighten_txt">ID</span> 取得指定元件
- <span class="lighten_txt">fill()</span>
:::spoiler
```python
def test_text_input(page):
page.goto("http://www.uitestingplayground.com/textinput")
assert page.query_selector(
"#updatingButton").inner_text() == "Button That Should Change it's Name Based on Input Value"
new_button_name = 'Change_btn_Name'
page.fill(selector='#newButtonName', value=new_button_name)
page.click(selector='#updatingButton')
assert page.query_selector("#updatingButton").inner_text() == new_button_name
```
:::
### <a href="http://www.uitestingplayground.com/dynamictable">Dynamic Table</a>
撰寫一個可以在動態表格取得指定值的測試.
- 透過 <span class="lighten_txt">DOM</span> 和透過 <span class="lighten_txt">nth</span> 取得指定元件
:::spoiler
```python
def get_chrome_row(target_list: list) -> str:
for row in target_list:
if 'Chrome' in row:
return row
return 'Not Found'
def test_dynamic_table(page):
page.goto("http://www.uitestingplayground.com/dynamictable")
page.query_selector(selector="div[role=table]").inner_text()
# 取得表的內容
table_content_by_path = page.query_selector(
"body>section:nth-child(2)>div:nth-child(1)>div:nth-child(6)>div:nth-child(3)").inner_text()
table_content_by_role = page.query_selector(selector="div[role=table]").inner_text()
assert table_content_by_path in table_content_by_role
# 將 tab 以 空格 替換, 並將表的內容以換行切割
table_list = table_content_by_role.replace('\t', ' ').split('\n')
print(table_list)
chrome_row = get_chrome_row(target_list=table_list)
warning_text = page.query_selector('.bg-warning').inner_text()
print(warning_text)
# print(warning_text.split(': ')[1]) →取得 CPU ?%
# print(table_list[0])
assert warning_text.split(': ')[1] in chrome_row
```
:::
### <a href="http://www.uitestingplayground.com/progressbar">Progress Bar</a>
撰寫一個可以在指定條件按下暫停的測試.
- 透過 <span class="lighten_txt">ID</span> 及屬性得指定元件
```python
def test_progressbar(page):
page.goto("http://www.uitestingplayground.com/progressbar")
page.click('#startButton')
# page.inner_text("#progressBar[aria-valuenow='75']")
page.inner_text("#progressBar:has-text('75%')")
print(page.query_selector("#progressBar").inner_html())
page.click('#stopButton')
assert "Result: 0" in page.inner_text('#result')
```
### <a href="http://www.uitestingplayground.com/visibility">Visibility</a>
撰寫一個可以檢查元件是否有被正確隱藏的測試.
- 透過 <span class="lighten_txt">ID</span> 及屬性得指定元件
- <span class="lighten_txt">bouding_box()</span>
:::spoiler
```python
def assert_find_attribute_status(page, target: str, attribute: str, status: str):
assert status in page.query_selector(f"#{target}").get_attribute(attribute)
def assert_compare_position(page):
hiding_layer = page.query_selector("#hidingLayer").bounding_box()
overlapped_button = page.query_selector("#overlappedButton").bounding_box()
assert int(hiding_layer['x']) == int(overlapped_button['x']) and \
int(hiding_layer['y']) == int(overlapped_button['y'])
def test_visibility(page):
page.goto('http://www.uitestingplayground.com/visibility')
# before click, all button is visible
for item in page.query_selector_all(".btn"):
assert item.is_visible()
page.click(selector="#hideButton")
# after click hideButton, check btn status
assert page.query_selector("#removedButton") is None
assert_find_attribute_status(page=page,
target='zeroWidthButton',
attribute='class',
status='zerowidth')
# assert page.query_selector('#zeroWidthButton').is_hidden()
assert_compare_position(page)
assert_find_attribute_status(page=page,
target='transparentButton',
attribute='style',
status='opacity: 0;')
# assert page.query_selector('#invisibleButton').is_hidden()
assert_find_attribute_status(page=page,
target='notdisplayedButton',
attribute='style',
status='display: none;')
# assert page.query_selector('#notdisplayedButton').is_hidden()
assert_find_attribute_status(page=page,
target='offscreenButton',
attribute='class',
status='offscreen')
```
:::
### <a href="http://www.uitestingplayground.com/sampleapp">Sample App</a>
撰寫一個可以檢視登入狀態的測試.
- <span class="lighten_txt">css with[ ]</span>
- <span class="lighten_txt">.css class with[ ]</span>
- <span class="lighten_txt">css class</span>
:::spoiler
```python
def test_sampleapp(page):
page.goto('http://www.uitestingplayground.com/sampleapp')
# before login
assert page.query_selector("#loginstatus").inner_text() == 'User logged out.'
assert page.query_selector(".btn-primary").inner_text() == 'Log In'
# login
user_login_name = 'ooo'
page.query_selector(".form-control[name='UserName']").fill(value=user_login_name)
page.query_selector(".form-control[name='Password']").fill(value='pwd')
page.query_selector(".btn-primary").click()
# after login
assert page.query_selector("#loginstatus").inner_text() == f'Welcome, {user_login_name}!'
assert page.query_selector(".btn-primary").inner_text() == 'Log Out'
```
```python
def test_sampleapp_with_wrong_password(page):
page.goto('http://www.uitestingplayground.com/sampleapp')
# login
user_login_name = 'ooo'
page.query_selector("css=[name=UserName]").fill(value=user_login_name)
page.query_selector(".form-control[name='Password']").fill(value='777')
page.query_selector(".btn-primary").click()
assert page.query_selector("#loginstatus").inner_text() == "Invalid username/password"
```
:::
### <a href="http://www.uitestingplayground.com/mouseover">Mouse Over</a>
撰寫一個即使 css style 變動時, 還能正確執行的測試.
- <span class="lighten_txt">get_attribute()</span>
- <span class="lighten_txt">hover()</span>
- <span class="lighten_txt">dblclick()</span>
:::spoiler
```python
def test_mouseover(page):
page.goto('http://www.uitestingplayground.com/mouseover')
# before hover
assert page.query_selector(selector=".text-primary:text('Click me')").get_attribute('title') == 'Click me'
# hover
page.query_selector(selector=":text('Click me')").hover()
assert page.query_selector(selector=":text('Click me')").get_attribute('title') == 'Active Link'
# dbclick
page.query_selector(selector=":text('Click me')").dblclick()
assert int(page.query_selector(selector="#clickCount").inner_text()) == 2
```
:::
### <a href="http://www.uitestingplayground.com/scrollbars">Scrollbars</a>
寫一個透過scroll操作, 找出隱藏在 Scrollview 中按鈕的測試.
- <span class="lighten_txt">bounding_box()</span>
- <span class="lighten_txt">透過多個Css Class找目標</span>
- <span class="lighten_txt">scroll_into_view_if_needed()</span>
- <span class="lighten_txt">wait_for_timeout</span>
:::spoiler
```python
def test_scroll_view(page):
page.goto("http://www.uitestingplayground.com/scrollbars")
find_hiding_button = page.query_selector(selector=".btn.btn-primary")
before_scroll = page.query_selector(selector=".btn.btn-primary").bounding_box()
find_hiding_button.scroll_into_view_if_needed()
after_scroll = page.query_selector(selector=".btn.btn-primary").bounding_box()
page.wait_for_timeout(timeout=1000)
print(f'Before:{before_scroll}, After{after_scroll}')
```
:::
<hr>
<!-- [End to End 目錄](https://hackmd.io/F41miM4aRP2eljbPy6grCg) -->
###### tags: `Playwright` `End to End`