Playwright中如何保持登錄狀態
引言
在編寫UI自動化測試用例的時候,通常會采用每個測試用例前打開新頁面重新進行登錄,以減少用例間的影響,比如一個測試用例執行失敗會影響到下一個測試用例的執行,或者下一個用例的開始依賴於上一個用例的結束頁面。但是這種方式會使得測試用例的執行時間大幅度上升,尤其是在測試用例劃分的顆粒度比較小的時候;加入一個項目中有2000個測試用例,登錄操作耗時2秒,那麼光耗費在登錄上面的時間就有4000秒,達到一個多小時瞭,嚴重影響測試執行效率,再假如項目中使用瞭驗證碼限制登錄的情況,那麼就更復雜瞭。所以,如果可以將登錄狀態保持住,開始測試用例的時候打開新頁面,跳過登錄直接進入到待測系統中,就可以大幅度提高測試執行效率。通常,每種UI自動化測試工具都會有類似的功能,這裡以Playwright為例來介紹如何實現。
功能實現
在Playwright中提供瞭現成的方法,通過 context.storage_state(path='<文件路徑>’) ,可以將當前瀏覽器上下文的全部狀態保存下來,在創建瀏覽器上下文時,添加 storage_state 參數即可讀取保存的文件,從而完全恢復之前的瀏覽器狀態。示例代碼如下
# 首次登陸系統 from playwright.sync_api import sync_playwright with sync_playwright() as playwright: browser = playwright.chromium.launch() context = browser.new_context() page = context.new_page() # 登陸系統 page.goto('<login url>') page.fill('<username>', '<username selector>') page.fill('<password>', '<password selector>') page.click('<login button selector>') # 判斷是否登陸成功 assert 'Welcome' in page.title() # 保存狀態文件 context.storage_state(path='login_data.json')
# 使用已保存的狀態文件跳過登錄狀態直接訪問系統 with sync_playwright() as playwright: browser = playwright.chromium.launch() # 創建瀏覽器上下文時加載狀態文件 context = browser.new_context(storage_state='login_data.json') page = context.new_page() # 直接訪問登錄後的URL page.goto('<welcome url>') # 判斷是否訪問到登錄後的頁面 assert 'Welcome' in page.title()
結合Pytest
通過以上代碼驗證瞭這種實現方式的可用性,還是很好用的。結合Pytest測試框架,可以通過fixture的形式提供一個已登錄的page對象,可以直接在測試用例中使用,實現方式如下:
@pytest.fixture() def logged_page(): ss_file = 'login_data.json' with sync_playwright() as playwright: browser = playwright.chromium.launch() # 判斷是否存在狀態文件,有的話就加載 if os.path.isfile(ss_file): context = browser.new_context(storage_state=ss_file) else: context = browser.new_context() page = context.new_page() # 直接跳轉至登錄後頁面,前提是未登錄用戶訪問待測系統會自動跳轉至登錄頁面,如果你的系統邏輯不一樣,需要修改 page.goto('<welcome url>') # 通過title判斷是否成功進入系統,如果沒有需要進行登錄,一般在第一次訪問系統,或登錄信息過期等原因會觸發 if 'Welcome' not in page.title(): page.fill('<username>', '<username selector>') page.fill('<password>', '<password selector>') page.click('<login button selector>') yield page # 測試執行結束後保存狀態文件,前提是測試用例中不能退出系統,安全起見加上異常處理 try: context.storage_state(path=ss_file) except Exception as e: print(e)
結合Clent-Page Object模式
如前,結合Pytest已經可以實現一個很好用的fixture,在很多場景下已經夠用瞭,不過我在項目中結合Clent-Page Object模式進行瞭另一種實現,核心代碼如下:
class Client(ABC): playwright = None browser = None def __init__(self, url: str, *, storage_state_name: str = None): self.url = url self.context = None self.main_page = None self.storage_state_file_path = None if storage_state_name is not None: self.storage_state_file_path = os.path.join('storage_state', f'{storage_state_name}.json') @abstractmethod def register_page(self): pass @abstractmethod def login(self, **kwargs): pass @abstractmethod def is_logged(self): pass def start(self) -> None: Client.playwright = sync_playwright().start() Client.browser = Client.playwright.chromium.launch(**BROWSER_CONFIG) if self.storage_state_file_path is not None and os.path.isfile(self.storage_state_file_path): self.context = Client.browser.new_context(**CONTEXT_CONFIG, storage_state=self.storage_state_file_path) else: self.context = Client.browser.new_context(**CONTEXT_CONFIG) self.main_page = self.context.new_page() self.main_page.goto(self.url) self.register_page() def close(self) -> None: if self.storage_state_file_path is not None: if not os.path.exists('storage_state'): os.mkdir('storage_state') self.context.storage_state(path=self.storage_state_file_path) self.main_page.close() self.context.close() def logged_user(client, url, *, scope = 'function', storage_state_name = None, **kwargs): @pytest.fixture(scope=scope) def user_fixture(): user = client(url, storage_state_name=storage_state_name) user.start() logger.info(f'用戶登錄: {kwargs}') if not user.is_logged(): user.login(**kwargs) yield user user.close()
繼承Client類,使用 logger_user 函數來生成不同終端用戶的fixture,以實現繼承Pytest。
到此這篇關於Playwright中如何保持登錄狀態的文章就介紹到這瞭,更多相關Playwright保持登錄狀態內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Python使用pytest-playwright的原因分析
- 微軟開源最強Python自動化神器Playwright(不用寫一行代碼)
- Playwright快速上手指南(入門教程)
- Python Playwright的使用詳解
- python palywright庫基本使用