node.jsautomationpuppeteer

Clicking Hyperlink Masquerading as Button with Puppeteer


I'm new to Puppeteer. I'm having problems clicking a certain button, I suspect because it's a hyperlink masquerading as button. I'm interested in the element shown on line 3.

1 <div class="pull-right">
2  <button class="btn internal-close">Cancel</button>
3  <a href="#" id="export_people_action" class="btn btn-primary excel">Download</a>
4  <div id="directory_export_people_actions_container" class="btn-group dropup hide pull-right" style="margin-left: 7px;">
5    <a href="#" id="directory_save_and_replace_existing_template" class="btn btn-primary">Download</a>
6    <button class="btn btn btn-primary dropdown-toggle" data-toggle="dropdown">
7      <i class="icon-caret-down" style="margin-left: -2px; margin-right: -3px;">
8      </i>
9    </button>
10    <ul class="dropdown-menu align_left">
11      <li class="">
12        <a href="#" class="trigger_export_people_action">Download Without Updating</a>
13      </li>
14      <li class="">
15        <a href="#" id="directory_save_as_new_template">Save as New Template</a>
16      </li>
17    </ul>
18    <input type="hidden" id="email_later_delay" value="">
19    <input type="hidden" id="temp_download" value="false">
20    <input type="hidden" id="unedited_template" value="">
21  </div>
22 </div>

Here are some things that I've tried:

(1) At first, I thought it worked like any other button, so I used the id.

await page.click('#export_people_action');

Returns an error "Error: No element found for selector: #export_people_action".

(2) Then I started looking more closely, and realized that it's a link. I tried XPath.

const downloadButton = await page.waitForSelector('::-p-xpath(//*[@class="btn btn-primary excel"])');
await downloadButton.click();

Returns an error "TimeoutError: Waiting for selector [[[{"name":"xpath","value":"//*[@class=\"btn btn-primary excel\"]"}]]] failed: Waiting failed: 30000ms exceeded".

I've tried it a few different ways since then, but along those two lines, with no success. I confess I'm at a bit of a loss.


Solution

  • Success! @ggorlen correctly identified that the button was in an iframe.

          await page.waitForSelector('iframe');
          const elementHandle = await page.$(
            'iframe[src="/zephyr/export"]'
          )
          const frame = await elementHandle.contentFrame();
          await delay(100);
          await frame.click('#export_people_action')