playwright-nth方法获取第 n 项

一、nth的作用

获取第 n 项

如果你有一个相同元素的列表,并且唯一能区分它们的方式是顺序,你可以使用 locator.first()locator.last()locator.nth() 从列表中选择特定元素。

二、例子

我们有这样一个页面,有两个相同属性的 密码输入框,我们要第一个密码输入框中输入 密码,如下图。

如果我们通过getByPlaceholder("请输入密码") 定位playwright 会报错

java 复制代码
Call log:
-   - waiting for getByPlaceholder("请输入密码")

	at com.microsoft.playwright.impl.WaitableResult.get(WaitableResult.java:56)
	at com.microsoft.playwright.impl.ChannelOwner.runUntil(ChannelOwner.java:138)
	at com.microsoft.playwright.impl.Connection.sendMessage(Connection.java:131)
	at com.microsoft.playwright.impl.ChannelOwner.sendMessage(ChannelOwner.java:124)
	at com.microsoft.playwright.impl.FrameImpl.fill(FrameImpl.java:310)
	at com.microsoft.playwright.impl.LocatorImpl.fill(LocatorImpl.java:273)
	at com.microsoft.playwright.Locator.fill(Locator.java:3346)
	at TestNth.main(TestNth.java:19)
Caused by: com.microsoft.playwright.impl.DriverException: Error {
  message='Error: strict mode violation: getByPlaceholder("请输入密码") resolved to 2 elements:
    1) <input name="pwd" type="password" placeholder="请输入密码"/> aka getByRole(AriaRole.TEXTBOX, new Page.GetByRoleOptions().setName("请输入密码")).first()
    2) <input name="pwd" type="password" placeholder="请输入密码"/> aka getByRole(AriaRole.TEXTBOX, new Page.GetByRoleOptions().setName("请输入密码")).nth(1)

从提示中我们可以看到,

strict mode violation: getByPlaceholder("请输入密码") resolved to 2 elements

翻译为:

严格模式违规:getByPlaceholder("请输入密码") 解析为 2 个元素

哦~~~原来是解析到了2个元素。这时候,我们nth就派上用场了。

①我们要在第一个框中输入密码。可以这么玩

java 复制代码
Locator nth = placeholder.nth(0);

nth 下标是从0开始,第一个就是0,相信学过编程都应该能理解

下面是完整例子代码

①创建TestPlayWright类

java 复制代码
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.AriaRole;
import com.microsoft.playwright.options.ServiceWorkerPolicy;

import java.util.ArrayList;
import java.util.List;

public class TestPlayWright {
    public Playwright playwright;
    public Browser browser;
    public BrowserContext context;
    public Page page;
    public int slowMo = 200;
    public boolean headless = false;
    public String bowserName = "CHROMIUM";

    public Page getPage() {
        return page;
    }

    public void init(){
        List<String> argslist = new ArrayList<String>();
        argslist.add("--window-position=" + -8 + "," + 0);

        playwright = Playwright.create();
        switch (bowserName) {
            case "CHROMIUM":
                browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setArgs(argslist)
                        .setHeadless(headless)
                        .setSlowMo(slowMo));
                break;
            case "FIREFOX":
                browser = playwright.firefox().launch(new BrowserType.LaunchOptions()
                        .setHeadless(headless).setArgs(argslist)
                        .setSlowMo(slowMo));
                break;
            case "WEBKIT":
                browser = playwright.webkit().launch(new BrowserType.LaunchOptions()
                        .setHeadless(headless).setArgs(argslist)
                        .setSlowMo(slowMo));
                break;
        }
        assert browser != null;
        Browser.NewContextOptions contextOpts = new Browser.NewContextOptions()
                .setServiceWorkers(ServiceWorkerPolicy.BLOCK);  // 屏蔽所有 Service Worker
        context = browser.newContext(contextOpts);
//        # 2. 清除当前上下文的所有 Cookie(推荐)
        context.clearCookies();
        page = context.newPage();
    }
    public void browserClose(){
        if(browser!=null){
            browser.close();
        }
    }
    public void playwrightClose() {
        if(playwright!=null){
            playwright.close();
        }
    }

}

②创建TestNth类

java 复制代码
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;

public class TestNth {

    public static void main(String[] args)  {
        TestPlayWright test = new TestPlayWright();
        //初始化创建page对象
        test.init();
        Page page = test.getPage();
        //打开测试页面
        page.navigate("file:///E:/playwright/testDemo/全类型HTML表单&iframe综合测试页.html");
        //获取 提示文本为【请输入密码】的定位
        Locator placeholder = page.getByPlaceholder("请输入密码");
        //高亮获取的元素
        placeholder.highlight();
        //停2秒
        page.waitForTimeout(2000);
        //获取第一个元素
        Locator nth = placeholder.nth(0);
        //高亮第一个元素
        nth.highlight();
        //第一个 密码输入(password) 输入 密码 第一个密码啊哈哈
        nth.fill("第一个密码啊哈哈");
        //停2秒
        page.waitForTimeout(2000);
//        placeholder.fill("123456");
        //关闭浏览器
        test.browserClose();
        //关闭 playwright
        test.playwrightClose();
    }
}

③执行效果如下图:

测试页面

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>全类型HTML表单&iframe综合测试页</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 8px;
            font-size: 15px;
        }
        .box {
            border: 1px solid #ccc;
            padding: 15px;
            margin: 10px 0;
            border-radius: 6px;
        }
        iframe {
            border: 2px solid #666;
        }
        button, input[type=button], input[type=submit], input[type=reset] {
            padding: 6px 16px;
            cursor: pointer;
        }
        input, select, textarea {
            padding: 5px;
            width: 280px;
        }
        textarea {
            height: 80px;
        }
    </style>
</head>
<body>
    <h2>1. iframe 内嵌框架区域</h2>
    <div class="box">
        <!-- 内嵌百度网页,可替换本地页面 -->
        <iframe src="iframe内嵌子页面.html" width="100%" height="300" title="测试iframe窗口"></iframe>
    </div>

    <h2>2. input 各类输入框全类型</h2>
    <form id="testForm">
        <div class="box">
            <!-- 普通文本输入 -->
            <label>文本输入(text):</label>
            <input type="text" name="username" placeholder="请输入用户名" value="默认文字">
            <br>
			
			<label>文本输入(text):</label>
            <input type="text" name="username" placeholder="请输入用户名" value="默认文字">
            <br>

            <!-- 密码框 -->
            <label>密码输入(password):</label>
			<input type="password" name="pwd" placeholder="请输入密码">
            <br>
			
			<label>密码输入(password):</label>
			<input type="password" name="pwd" placeholder="请输入密码">
            <br>

            <!-- 数字输入 -->
            <label>数字输入(number):</label>
            <input type="number" name="age" min="0" max="150" value="18">
            <br>

            <!-- 邮箱 -->
            <label>邮箱(email):</label>
            <input type="email" name="email" placeholder="test@xxx.com">
            <br>

            <!-- 手机号tel -->
            <label>电话(tel):</label>
            <input type="tel" name="phone" placeholder="13800138000">
            <br>

            <!-- 网址url -->
            <label>网址(url):</label>
            <input type="url" name="link" placeholder="https://xxx.com">
            <br>

            <!-- 搜索框 -->
            <label>搜索框(search):</label>
            <input type="search" name="search" placeholder="关键词搜索">
            <br>

            <!-- 日期选择 -->
            <label>日期(date):</label>
            <input type="date" name="birth">
            <br>

            <!-- 时间选择 -->
            <label>时间(time):</label>
            <input type="time" name="time">
            <br>

            <!-- 日期+时间 -->
            <label>日期时间(datetime-local):</label>
            <input type="datetime-local" name="dt">
            <br>

            <!-- 月份选择 -->
            <label>月份(month):</label>
            <input type="month" name="month">
            <br>

            <!-- 周选择 -->
            <label>周(week):</label>
            <input type="week" name="week">
            <br>

            <!-- 颜色拾取器 -->
            <label>颜色(color):</label>
            <input type="color" name="color" value="#0066ff">
            <br>

            <!-- 范围滑块 -->
            <label>音量滑块(range):</label>
            <input type="range" name="volume" min="0" max="100" value="50">
            <br>

            <!-- 文件上传 -->
            <label>文件上传(file):</label>
            <input type="file" name="file" multiple>
            <br>

            <!-- 隐藏域 页面不可见,提交携带数据 -->
            <input type="hidden" name="hiddenId" value="test001">
        </div>

        <h2>3. 单选框 radio</h2>
        <div class="box">
            <input type="radio" name="gender" id="man" value="男" checked>
            <label for="man">男</label>

            <input type="radio" name="gender" id="woman" value="女">
            <label for="woman">女</label>
        </div>

        <h2>4. 复选框 checkbox</h2>
        <div class="box">
            <input type="checkbox" name="hobby" id="read" value="阅读" checked>
            <label for="read">阅读</label>

            <input type="checkbox" name="hobby" id="game" value="游戏">
            <label for="game">游戏</label>

            <input type="checkbox" name="hobby" id="sport" value="运动">
            <label for="sport">运动</label>
        </div>

        <h2>5. 下拉选择框 select</h2>
        <div class="box">
            <!-- 普通下拉框 -->
            <label>城市单选下拉:</label>
            <select name="city">
                <option value="">请选择城市</option>
                <option value="sh">上海</option>
                <option value="bj">北京</option>
                <option value="gz">广州</option>
                <option value="sz">深圳</option>
            </select>
            <br><br>

            <!-- 多选下拉框 multiple -->
            <label>爱好多选下拉(按住Ctrl多选):</label>
            <select name="mulHobby" multiple size="4">
                <option value="code">编程</option>
                <option value="movie">电影</option>
                <option value="travel">旅行</option>
                <option value="food">美食</option>
            </select>
            <br><br>

            <!-- 分组下拉 optgroup -->
            <label>分组下拉菜单:</label>
            <select name="fruit">
                <optgroup label="热带水果">
                    <option value="mango">芒果</option>
                    <option value="banana">香蕉</option>
                </optgroup>
                <optgroup label="温带水果">
                    <option value="apple">苹果</option>
                    <option value="pear">梨</option>
                </optgroup>
            </select>
        </div>

        <h2>6. 多行文本框 textarea</h2>
        <div class="box">
            <label>留言内容:</label>
            <textarea name="msg" placeholder="请输入多行留言...">默认预置文本内容</textarea>
        </div>

        <h2>7. 各类按钮 Button / input按钮</h2>
        <div class="box">
            <!-- input系列按钮 -->
            <input type="button" value="普通按钮 button" onclick="alert('点击普通input按钮')">
            <input type="submit" value="提交表单 submit">
            <input type="reset" value="重置表单 reset">
            <br><br>
            <!-- button标签按钮,可内嵌html -->
            <button type="button" onclick="alert('点击原生button标签')">原生button按钮</button>
            <button type="submit">button提交按钮</button>
            <button type="reset">button重置按钮</button>
            <button disabled>禁用按钮 disabled</button>
        </div>
    </form>

    <h2>8. 字段集分组 fieldset + legend</h2>
    <fieldset style="width: 320px;">
        <legend>个人基础信息分组</legend>
        <label>昵称:</label>
        <input type="text" name="nick">
    </fieldset>

    <script>
        // 简单测试JS:表单提交拦截打印表单数据
        const form = document.getElementById('testForm');
        form.addEventListener('submit', function(e) {
            e.preventDefault();
            const formData = new FormData(form);
            console.log('表单提交数据:');
            for (let [key, val] of formData) {
                console.log(key, ':', val);
            }
            alert('已阻止页面跳转,数据打印在控制台');
        })
    </script>
</body>
</html>

三、通过葫芦娃ui自动化工具操作

①打开葫芦娃ui自动化工具

②加载对应step.xlsx和data.xlsx

③step.xlsx配置如图:

1、case sheet输入如下

2、创建对应sheet 【测试nth方法】 内容如下,定位方法选择 nth:

④切换到工具,点击运行:

效果和代码一致:

运行效果和上面一样

完全零代码,直接维护excel 就行,谢谢大家的支持,可以点个赞或转发。谢谢大家~

想要工具可以私聊 或者直接打赏哈~