кукловодный эквивалент кипарисового метода () - PullRequest
0 голосов
/ 22 февраля 2019

HTML выглядит следующим образом:

const htmlStr = `
  <div>

    <div>
      <h1>title1</h1>
      <div>
        <a>click me<a>
      </div>
    </div>

    <div>
      <h1>title2</h1>
      <div>
        <a>click me<a>
      </div>
    </div>


    <div>
      <h1>title3</h1>
      <div>
        <a>click me<a>
      </div>
    </div>

  </div>
`

Я хочу нажать первый click me.

С кипарисом я мог бы сделать что-то следующим образом:

cy.contains('div', 'title1').within(() => {
  cy.get('a').click()
})

Для этого примера есть много способов сделать это.Но идея такова: find the nearest <div> who contains text 'title1'. And start from there, find <a> inside it.

В Кукольник Мне бы хотелось, чтобы некоторые из них выглядели следующим образом:

const element = await page.elementContains('div', 'title1') // <- narrow down
await element.click('a')

Как реализовать функции elementContains(), есть идеи?Спасибо!

----- обновление -----

Чтобы сделать его более понятным, с elementContains() это может:

const element1 = await page.elementContains('div', 'title1')
await element1.click('a') // click first `click me`
const element2 = await page.elementContains('div', 'title2')
await element2.click('a') // click second `click me`
const element3 = await page.elementContains('div', 'title3')
await element3.click('a') // click third `click me`

Ответы [ 2 ]

0 голосов
/ 24 февраля 2019

Вы можете легко добавить дополнительные функции к Page, используя prototype.И получите конкретный элемент, используя page.elementHandle .

Единственное отличие между page.evaluate и page.evaluateHandle состоит в том, что page.evaluateHandle возвращает объект на странице (JSHandle).

Создание функции elementContains

Модуль Puppeteer экспортирует классы следующим образом.Вы можете расширить их функциональные возможности, как вы хотите.

// extract the Page class
const { Page } = require("puppeteer/lib/Page");

Обычно создаваемый вами page становится this внутри прототипа.page.evaluateHandle станет this.evaluateHandle.

/**
 * @name elementContains
 * @param {String} selector specific selector globally search and match
 * @param {String} text filter the elements with the specified text
 * @returns {Promise} elementHandle
 */
Page.prototype.elementContains = function elementContains(...args) {
  return this.evaluateHandle((selector, text) => {
    // get all selectors for this specific selector
    const elements = [...document.querySelectorAll(selector)];
    // find element by text
    const results = elements.filter(element => element.innerText.includes(text));
    // get the last element because that's how querySelectorAll serializes the result
    return results[results.length-1]; 
  }, ...args);
};

Создание функции .get

Теперь, когда мы получили нашу замечательную elementContains, пришло время получить функцию get.

/**
 * Replicate the .get function
 * gets an element from the executionContext
 * @param {String} selector
 * @returns {Promise} 
 */
const { JSHandle } = require("puppeteer/lib/JSHandle");
JSHandle.prototype.get = function get(selector) {
  // get the context and evaluate inside
  return this._context.evaluateHandle(
    (element, selector) => {
      return element.querySelector(selector);
    },
    // pass the JSHandle which is itself
    this,
    selector
  );
};

Имеемвесело с новой функцией

(async () => {
  const browser = await puppeteer.launch({
    headless: false
  });

  const page = await browser.newPage();
  await page.setContent(html); // your specified html text

  // get the element
  const elem = await page.elementContains('div', 'title1')

  // use it like any other normal element, click it, eval it, remove it etc.
  const content = await elem.$eval('h1', e=>e.innerText);
  console.log(content) // prints "title1"

  // OR use the built in click function
  const btn = await page.$('a', elem); // <-- pass the handle here
  await btn.click();

  // OR use our .get function to get another element
  const targetBtn = await elem.get('a');
  targetBtn.click(); // click it
})();

Результат: enter image description here

0 голосов
/ 22 февраля 2019

Если я правильно понимаю, это XPath и эквиваленты селектора (https://example.org/ имеет похожую структуру DOM):

'use strict';

const puppeteer = require('puppeteer');

(async function main() {
  try {
    const browser = await puppeteer.launch();
    const [page] = await browser.pages();

    await page.goto('https://example.org/');

    const [elemByXPath] = await page.$x('//div[h1[contains(., "Example Domain")]]//a');

    const elemBySelector = await page.evaluateHandle(
      () => [...document.querySelectorAll('div')]
              .find(
                div => [...div.querySelectorAll('h1')]
                         .some(h1 => h1.innerText.includes('Example Domain'))
              )
              .querySelector('a')
    );

    console.log(elemByXPath.toString());
    console.log(elemBySelector.toString());

    await browser.close();
  } catch (err) {
    console.error(err);
  }
})();
...