我想要获取所有<custom-tag>个 node 的属性以及类型<custom-text>或类型<custom-number>的子 node 的innerText

DevTools中的一个简化版本是


const headersMap = new Map();
var headers = Object.create(null);
document.querySelectorAll("h2").forEach(el => {
    
    headers[el.id] = el.innerText
    headersMap.set(el.id, el.innerText)    
});
console.log("h2 count > 2 === " , (headersMap.size>2))
console.table(Array.from(headersMap, ([name, value]) => ({ name, value })));

对于API testing page人,它看起来是这样的

console output from code above

这是我的剧作家try

test('API Testing - H2 count greater than 2', async ({ }) => {     
    await test.step('API Testing - get titles', async() => {

        await page.goto('https://playwright.dev/docs/api-testing');
        
        const headersList = await page.locator('h2');
        var headersMap = await headersList.evaluateAll(node => {
            const headersMap = new Map();
            var headers = Object.create(null);
            headers[node.id] = node.innerText
            headersMap.set(node.id, node.innerText)    
            return headersMap;
        });
        await expect(headersMap.size).toBeGreaterThan(2);
        page.pause();
        
    });
});

但它报告说:

   Error: expect(received).toBeGreaterThan(expected)
   Matcher error: received value must be a number or bigint
   Received has value: undefined
      47 |             return headersMap;
      48 |         });
    > 49 |         await expect(headersMap.size).toBeGreaterThan(2);
         |                                       ^
      50 |         page.pause();

问题

  • 我如何创建一个对象,用forEach填充它并返回它?
  • 必须进行哪些更改才能使my_locator.evaluateAll()返回 map ?

推荐答案

当您使用locator.evaluateAll()时,在回调中会得到一个array.我会调用参数nodes而不是node,这样您就可以清楚地知道需要迭代它了.

第二个问题:映射不容易序列化.试试看:

const m = new Map();
m.set("hello", "world");
console.log(m.get("hello")); // => "world"
console.log(JSON.stringify(m)); // => {}

传入和传出evaluate个调用的所有数据都将被反/序列化,这将销毁您的 map .除非您有令人信服的理由使用 map ,否则我只会使用普通的旧对象.

这里有一个 Select :

import {expect, test} from "@playwright/test"; // ^1.30.0

test("playwright docs page has correct headers", async ({page}) => {
  const url = "https://playwright.dev/docs/api-testing";
  await page.goto(url, {waitUntil: "domcontentloaded"});
  const headers = await page.locator("h2").evaluateAll(nodes =>
    Object.fromEntries(
      nodes.map(node => [node.id, node.textContent.trim()])
    )
  );
  const expected = {
    "writing-api-test": "Writing API Test​",
    "using-request-context": "Using request context​",
    "sending-api-requests-from-ui-tests": "Sending API requests from UI tests​",
    "reusing-authentication-state": "Reusing authentication state​",
    "context-request-vs-global-request": "Context request vs global request​",
  };
  expect(headers).toEqual(expected);
});

请注意,您不需要await定位器定义,只需要一个操作.通常使用.textContent而不是.innerText.修剪您的HTML字符串以使其标准化.注意那些头中有趣的​&ZeroWidthSpace;(考虑只抓取文本 node 而忽略<a>).不需要await个非定位器断言.

尽管如此,上面的方法并不完全是最佳实践,因为它没有使用web first断言.我会重写它,直接在定位器上使用.toHaveText().

await expect(page.locator("h2")).toHaveText([
  "Writing API Test​",
  "Using request context​",
  "Sending API requests from UI tests​",
  "Reusing authentication state​",
  "Context request vs global request​",
]);

ID可以单独测试,而且可能不会有太大影响.作为最后的手段,您可以 Select pollretry来等待谓词为真,但如果您确定它们始终静态地出现在页面上,那么打破Web优先的规则可能是可以的.

Javascript相关问答推荐

Vue v模型检测父参考更改

除了在Angular 16中使用快照之外,什么是可行且更灵活的替代方案?

在JS中获取名字和姓氏的首字母

react/redux中的formData在expressjs中返回未定义的req.params.id

django无法解析余数:[0] from carray[0]'

jQuery提交按钮重新加载页面,即使在WordPress中使用preventDefault()

React Code不在装载上渲染数据,但在渲染上工作

有没有可能使滑动img动画以更快的速度连续?

将本机导航路由react 到导航栏中未列出的屏幕?

JS,当你点击卡片下方的绿色空间,而它是在它的背后转动时,

对路由DOM嵌套路由作出react

本地库中的chartjs-4.4.2和chartjs-plugin-注解

Reaction组件在本应被设置隐藏时仍显示

如何在我的Next.js项目中.blob()我的图像文件?

Reaction-SWR-无更新组件

更新Redux存储中的对象数组

Node.js错误: node 不可单击或不是元素

如何在脚本编译后直接将RxJ模块导入浏览器(无需Angel、webpack、LiteServer)

FindByIdAndUpdate在嵌套对象中创建_id

我无法在Api Reaction本机上发出GET请求