• Playwright for Python:鉴权Authentication



    Playwright 在称为浏览器上下文的隔离环境中执行测试。这种隔离模型提高了可重现性,并防止了级联测试失败。测试可以加载现有的身份验证状态。这消除了在每个测试中进行身份验证的需求,并加快了测试的执行速度。

    核心概念

    无论您选择什么身份验证策略,您很可能会将经过身份验证的浏览器状态存储在文件系统中。

    我们建议创建 playwright/.auth 目录并将其添加到 .gitignore 文件中。您的身份验证程序将生成经过身份验证的浏览器状态并将其保存到该 playwright/.auth 目录中的文件中。稍后,测试将重用此状态并开始已经经过身份验证的状态。

    Bash

    mkdir -p playwright/.auth
    echo "\nplaywright/.auth" >> .gitignore
    
    • 1
    • 2

    PowerShell

    New-Item -ItemType Directory -Force -Path playwright\.auth
    Add-Content -path .gitignore "`r`nplaywright/.auth"
    
    • 1
    • 2

    Batch

    md playwright\.auth
    echo. >> .gitignore
    echo "playwright/.auth" >> .gitignore
    
    • 1
    • 2
    • 3

    每次测试前先注册

    Playwright API可以自动化与登录表单的交互。

    为每个测试重新执行登录可能会降低测试的执行速度。为了缓解这个问题,可以重复使用现有的身份验证状态。

    下面是一个注册流程的示例:

    # test_demo.py
    from playwright.sync_api import Page, expect
    from faker import Faker
    import re
    
    faker = Faker()
    import random
    
    
    def test_example(page: Page) -> None:
        page.goto("https://www.gitlink.org.cn")
        page.locator(selector="//a[text()='登录']/following-sibling::a").click()
        page.get_by_text("邮箱注册").click()
        page.locator(selector="//input[@id='register_register_username']").fill(f"glcc_{random.randint(1, 100)}")
        page.get_by_placeholder("请输入邮箱地址").fill(f"glcc_{random.randint(1, 100)}@gitlink.com")
        page.get_by_placeholder("请输入验证码").fill("123123")
        page.get_by_placeholder("请输入登录密码").fill("12345678")
        page.get_by_placeholder("请确认登录密码").fill("12345678")
        page.get_by_label("我已阅读并接受《GitLink服务协议条款》").check()
        page.locator("button").filter(has_text="注 册").click()
        expect(page, "检查用户注册后是否跳转到个人主页").to_have_title(re.compile("glcc_"), timeout=5_000)
    	
    # main.py
    import pytest
    pytest.main(['--headed', '--browser=chromium', "--browser-channel=chrome"])
    
    • 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

    重复使用已登录状态

    Playwright 提供了一种在测试中重复使用已登录状态的方式。这样你就可以只登录一次,然后在所有测试中跳过登录步骤。

    Web 应用程序使用基于 cookie 或令牌的身份验证,已认证的状态存储在 cookie 或本地存储中。Playwright 提供了 browserContext.storageState([options]) 方法,用于从已认证的上下文中检索存储状态,并创建具有预填充状态的新上下文。

    Cookies 和本地存储状态可以跨不同的浏览器使用,具体取决于应用程序的身份验证模型:某些应用程序可能同时需要 cookies 和本地存储。

    以下代码片段检索来已认证上下文的状态,并使用该状态创建一个新的上下文。

    示例1

    利用其他测试方法中的登录态。

    # test_demo.py
    from playwright.sync_api import Page, expect
    from faker import Faker
    import re
    
    faker = Faker()
    import random
    
    # 创建一个全局变量来保存存储状态
    storage = None
    
    
    def test_register(page: Page) -> None:
        global storage
        page.goto("https://www.gitlink.org.cn")
        page.locator(selector="//a[text()='登录']/following-sibling::a").click()
        page.get_by_text("邮箱注册").click()
        page.locator(selector="//input[@id='register_register_username']").fill(f"glcc_{random.randint(1, 100)}")
        page.get_by_placeholder("请输入邮箱地址").fill(f"glcc_23{random.randint(1, 100)}@gitlink.com")
        page.get_by_placeholder("请输入验证码").fill("123123")
        page.get_by_placeholder("请输入登录密码").fill("12345678")
        page.get_by_placeholder("请确认登录密码").fill("12345678")
        page.get_by_label("我已阅读并接受《GitLink服务协议条款》").check()
        page.locator("button").filter(has_text="注 册").click()
        expect(page, "检查用户注册后是否跳转到个人主页").to_have_title(re.compile("glcc_"), timeout=5_000)
        # 登录成功后获取当前上下文的存储状态,并存储在文件state.json中
        storage = page.context.storage_state(path="state.json")
    
    
    # 在其他测试中,创建新的上下文并使用之前保存的存储状态
    def test_new_project(page: Page) -> None:
        global storage
        """
        第1种写法
        创建新的上下文,使用之前存储的状态文件state.json
         # new_context = page.context.browser.new_context(storage_state=storage)
        # new_page = new_context.new_page()
        """
        
        """
        第2种写法
        直接新建一个页面,使用之前存储的状态文件state.json
        """
        new_page = page.context.browser.new_page(storage_state=storage)
        #  TODO 这两种方式上,虽然用例可以执行成功,但是新开了好几个浏览器窗口
        
        # 执行其他测试操作(此时是登录状态)
        new_page.goto("https://www.gitlink.org.cn")
        new_page.locator("#nHeader img").nth(1).click()
        new_page.get_by_text("新建项目").click()
        expect(new_page, "检查是否跳转到了新建项目页面").to_have_title(re.compile("新建项目"), timeout=5_000)
    	
    # main.py
    import pytest
    pytest.main(['--headed', '--browser=chromium', "--browser-channel=chrome"])
    
    
    • 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
    • 53
    • 54
    • 55
    • 56

    示例2

    将登录态写在contest.py中,作为fixture。

    # contest.py
    import pytest
    import re
    from playwright.sync_api import Page, expect
    
    
    # 定义全局登录
    @pytest.fixture(scope="function", autouse=True)
    def page(page: Page):
        page.goto("https://www.gitlink.org.cn/login")
        page.locator(selector="//input[@id='login_username']").fill("chytest10")
        page.locator(selector="//input[@id='login_password']").fill("12345678")
        page.locator("span").filter(has_text="登 录").click()
        expect(page, "检查用户登录后是否跳转到个人主页").to_have_title(re.compile("chytest10"), timeout=5_000)
        # 登录成功后获取当前上下文的存储状态,并存储在文件state.json中
        storage = page.context.storage_state(path="state.json")
        new_page = page.context.browser.new_page(storage_state=storage)
        yield new_page
    	
    	
    # test_demo.py
    from playwright.sync_api import Page, expect
    import re
    
    def test_new_project_02(page: Page) -> None:
        page.goto("https://www.gitlink.org.cn")
        page.locator("#nHeader img").nth(1).click()
        page.get_by_text("新建项目").click()
        expect(page, "检查是否跳转到了新建项目页面").to_have_title(re.compile("新建项目"), timeout=5_000)
    	
    # main.py
    import pytest
    pytest.main(['--headed', '--browser=chromium', "--browser-channel=chrome"])
    
    
    • 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

    进阶场景

    重用身份验证状态涵盖了基于Cookie和本地存储的身份验证。很少情况下,会使用Session存储来存储与登录状态相关的信息。Session存储是针对特定域的,并且在页面加载时不会被保留。Playwright没有提供API来持久化Session存储,但可以使用以下代码片段来保存/加载Session存储。

    # contest.py
    import pytest
    import re
    import os
    from playwright.sync_api import Page, expect
    
    
    # 定义全局登录
    @pytest.fixture(scope="function", autouse=True)
    def page(page: Page):
        page.goto("https://www.gitlink.org.cn/login")
        page.locator(selector="//input[@id='login_username']").fill("chytest10")
        page.locator(selector="//input[@id='login_password']").fill("12345678")
        page.locator("span").filter(has_text="登 录").click()
        expect(page, "检查用户登录后是否跳转到个人主页").to_have_title(re.compile("chytest10"), timeout=5_000)
        # 获取当前页面的会话存储
        session_storage = page.evaluate("() => JSON.stringify(sessionStorage)")
        # 将会话存储存储为环境变量
        os.environ["SESSION_STORAGE"] = session_storage
        session_storage = os.environ["SESSION_STORAGE"]
        new_context = page.context
        new_context.add_init_script("""(storage => {
          if (window.location.hostname === 'example.com') {
            const entries = JSON.parse(storage)
            for (const [key, value] of Object.entries(entries)) {
              window.sessionStorage.setItem(key, value)
            }
          }
        })('""" + session_storage + "')")
        new_page = new_context.new_page()
        yield new_page
    	
    # test_demo.py
    from playwright.sync_api import Page, expect
    import re
    
    
    def test_new_project_02(page: Page) -> None:
        page.goto("https://www.gitlink.org.cn")
        page.locator("#nHeader img").nth(1).click()
        page.get_by_text("新建项目").click()
        expect(page, "检查是否跳转到了新建项目页面").to_have_title(re.compile("新建项目"), timeout=5_000)
    	
    # main.py
    import pytest
    pytest.main(['--headed', '--browser=chromium', "--browser-channel=chrome"])
    
    
    • 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
  • 相关阅读:
    如果我们是那晚负责修复 B 站崩了的开发人员
    初识VisionPro应用开发
    Java基础 - 练习(一)打印等腰三角形
    【c++】智能指针
    NIST正式发布网络安全框架 2.0最终版:相比之前两个版本的六大重大变化
    10-18 查询同专业的学生(MSSQL)
    jvm优化(二)JVM 内存大小设置
    JVM笔记
    win10 GTX 1650 版本517(需要降级到441.22) 安装Tensorflow-GPU
    Visual Studio Code下C/C++开发环境的配置及使用
  • 原文地址:https://blog.csdn.net/FloraCHY/article/details/132711033