首页 > 解决方案 > Pupeteer 点击引导卡

问题描述

我正在尝试使用 puppeteer 编写反应测试,但很难点击元素,除了简单的按钮和链接。我正在尝试单击引导(reactstrap)卡(或其中的图像/文本)以将项目添加到购物车。然后我必须通过检查该项目是否在数据表(组件)上来检查该项目是否已添加到购物车中。这是页面外观的屏幕截图。 在此处输入图像描述

这是浏览器上产品的html部分

<div class="col-sm-2">
   <a class="cartCard card">
      <img alt="SkinnyPop Original Popcorn" src="https://d2d8wwwkmhfcva.cloudfront.net/600x/filters:fill(FFF,true):format(jpg)/d2lnr5mha7bycj.cloudfront.net/product-image/file/large_089fa30f-31a6-4d53-ae00-1dcd2d5f8d81.jpeg" class="cartCarImage card-img">
      <div class="cartCardBody card-body">
         <p data-tip="SkinnyPop Original Popcorn" data-for="Foods1" class="card-text" currentitem="false">SkinnyPop Original Popcorn</p>
         <div class="__react_component_tooltip t20e8f3c7-872c-447a-b947-00036aa0a356 place-top type-light" id="Foods1" data-id="tooltip" style="left: 152px; top: 317px;">
            <style>
               .t20e8f3c7-872c-447a-b947-00036aa0a356 {
               color: #222;
               background: #fff;
               border: 1px solid transparent;
               }
               .t20e8f3c7-872c-447a-b947-00036aa0a356.place-top {
               margin-top: -10px;
               }
               .t20e8f3c7-872c-447a-b947-00036aa0a356.place-top::before {
               border-top: 8px solid transparent;
               }
               .t20e8f3c7-872c-447a-b947-00036aa0a356.place-top::after {
               border-left: 8px solid transparent;
               border-right: 8px solid transparent;
               bottom: -6px;
               left: 50%;
               margin-left: -8px;
               border-top-color: #fff;
               border-top-style: solid;
               border-top-width: 6px;
               }
               .t20e8f3c7-872c-447a-b947-00036aa0a356.place-bottom {
               margin-top: 10px;
               }
               .t20e8f3c7-872c-447a-b947-00036aa0a356.place-bottom::before {
               border-bottom: 8px solid transparent;
               }
               .t20e8f3c7-872c-447a-b947-00036aa0a356.place-bottom::after {
               border-left: 8px solid transparent;
               border-right: 8px solid transparent;
               top: -6px;
               left: 50%;
               margin-left: -8px;
               border-bottom-color: #fff;
               border-bottom-style: solid;
               border-bottom-width: 6px;
               }
               .t20e8f3c7-872c-447a-b947-00036aa0a356.place-left {
               margin-left: -10px;
               }
               .t20e8f3c7-872c-447a-b947-00036aa0a356.place-left::before {
               border-left: 8px solid transparent;
               }
               .t20e8f3c7-872c-447a-b947-00036aa0a356.place-left::after {
               border-top: 5px solid transparent;
               border-bottom: 5px solid transparent;
               right: -6px;
               top: 50%;
               margin-top: -4px;
               border-left-color: #fff;
               border-left-style: solid;
               border-left-width: 6px;
               }
               .t20e8f3c7-872c-447a-b947-00036aa0a356.place-right {
               margin-left: 10px;
               }
               .t20e8f3c7-872c-447a-b947-00036aa0a356.place-right::before {
               border-right: 8px solid transparent;
               }
               .t20e8f3c7-872c-447a-b947-00036aa0a356.place-right::after {
               border-top: 5px solid transparent;
               border-bottom: 5px solid transparent;
               left: -6px;
               top: 50%;
               margin-top: -4px;
               border-right-color: #fff;
               border-right-style: solid;
               border-right-width: 6px;
               }
            </style>
            SkinnyPop Original Popcorn
         </div>
      </div>
   </a>
</div>

这是数据表购物车项目的 html

<div id="cartTable">
   <div class="sc-fzoyTs colVQD">
      <div class="sc-fzoXWK iDAPfj">
         <div class="sc-AxheI cBBklH rdt_Table" role="table">
            <div offset="250px" class="sc-fzqNqU jvuxKt rdt_TableBody" role="rowgroup">
               <div id="row-1" role="row" class="sc-fzokOt egXWdh rdt_TableRow">
                  <div id="cell-YTyZ4X_xd-1" role="cell" data-tag="___react-data-table-allow-propagation___" class="sc-fzozJi sc-fzoLsD sc-fzpans bmdIeB rdt_TableCell">
                     <div>1</div>
                  </div>
                  <div id="cell-C1s2WxpKFG-1" role="cell" data-tag="___react-data-table-allow-propagation___" class="sc-fzozJi sc-fzoLsD sc-fzpans fJfkQJ rdt_TableCell"><img src="https://d2d8wwwkmhfcva.cloudfront.net/600x/filters:fill(FFF,true):format(jpg)/d2lnr5mha7bycj.cloudfront.net/product-image/file/large_089fa30f-31a6-4d53-ae00-1dcd2d5f8d81.jpeg" width="36" class="float-left rounded-circle"></div>
                  <div id="cell-emxpVgIyBK-1" role="cell" data-tag="___react-data-table-allow-propagation___" class="sc-fzozJi sc-fzoLsD sc-fzpans drmANF rdt_TableCell">
                     <div class="cartItemText">SkinnyPop Original Popcorn</div>
                  </div>
                  <div id="cell-G8l-QeN6dF-1" role="cell" data-tag="___react-data-table-allow-propagation___" class="sc-fzozJi sc-fzoLsD sc-fzpans bpmFTx rdt_TableCell">
                     <div>
                        <div><span>$18.31</span></div>
                        <div class="cartItemLinestrike" style="display: none;"><span>$18.31</span></div>
                     </div>
                  </div>
                  <div id="cell-ZmDGwu4kJK-1" role="cell" data-tag="___react-data-table-allow-propagation___" class="sc-fzozJi sc-fzoLsD sc-fzpans iIVAzx rdt_TableCell">
                     <div>
                        <button data-garden-id="buttons.button" data-garden-version="8.13.0" type="button" class="sc-AxiKw cSylWS">
                           <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="trash-alt" class="svg-inline--fa fa-trash-alt fa-w-14 " role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" style="font-size: 14px;">
                              <path fill="currentColor" d="M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm272-256a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z"></path>
                           </svg>
                        </button>
                     </div>
                  </div>
               </div>
            </div>
         </div>
      </div>
   </div>
</div>

我正在尝试通过我拥有的这个功能来选择它们。它适用于按钮和链接。它不适用于产品和购物车项目。

 const clickByElement = async (page, text, element) => {
  let escapedText = escapeXpathString(text);
  let linkHandlers = [];
  if (element === "button")  {
    linkHandlers = await page.$x(`//button[contains(text(), ${escapedText})]`);
  } else if  (element === "link")  {
    linkHandlers = await page.$x(`//a[contains(text(), ${escapedText})]`);
  } else if  (element === "product")  {
     linkHandlers = await page.$x(`//img[contains(., ${escapedText})]`);
    //linkHandlers = await page.$x(`//img[contains(text(), ${escapedText})]`);
    //linkHandlers = await page.$x(`//div[contains(text(), ${escapedText})]`);
    //linkHandlers = await page.$x(`//a[@class='cartCard card']/div[contains(text(), ${escapedText})]`);
  } else if  (element === "cartitem")  {
    linkHandlers = await page.$x(`//div[contains(@class, 'cartItemText') and contains(., ${escapedText})]`);
  }
  if (linkHandlers.length > 0) {
    await linkHandlers[0].click();
  } else {
    throw new Error(`Link not found: ${text}`);
  }
  await timeout(1000);
};

标签: reactjsjestjspuppeteercucumberjsjest-puppeteer

解决方案


您定义的 XPath 表达式有些问题,我举个例子。而不是await page.$x(`//a[@class='cartCard card']/div[contains(text(), ${escapedText})]`)你应该尝试这样的事情(确保你等待元素出现):

await page.waitForXPath('//*[@class="cartItemText" and contains(.,"Skinny")]')
const linkHandlers = await page.$x('//*[@class="cartItemText" and contains(.,"Skinny")]')

await linkHandlers[0].click()

你可知道?如果您在 Chrome DevTools 的“元素”选项卡中右键单击一个元素并选择“复制”:您可以在此处复制元素的确切选择器或 xpath。之后,您可以切换到“控制台”选项卡并使用 Chrome api 测试选择器的内容,以便为您的 puppeteer 脚本准备它。您也可以在此处测试自定义构建的 XPath 表达式。例如:$x('//*[@class="cartItemText" and contains(.,"Skinny")]')[0].innerText应该显示您希望单击的文本("SkinnyPop Original Popcorn"),否则您需要更改访问权限,或者您需要检查是否有更多具有相同选择器的元素等。这可能有助于找到更合适的脚本的选择器。


推荐阅读