通过 Codeceptjs 和 Puppeteer 迭代 table 行是否需要 Helper
Does iterating table rows via Codeceptjs and Puppeteer require a Helper
我正在尝试使用 Codeceptjs 中可用的方法来简单地迭代 table 行和 select 行,该行基于迭代当前行的特定单元格中存在的文本。
以下代码在我的页面对象之一中并且部分有效。
async selectSiteById(siteId) {
I.waitForElement('table');
for (let i = 1; i < 5; i++) {
let val = await I.grabTextFrom(`tbody tr:nth-child(${i}) td:nth-child(2)`);
if (val === siteId) {
I.say('Val' + val + ' -- Site Id ' + siteId)
within(`tbody tr:nth-child(${i + 1}) td:nth-child(1)`, () => {
I.click('input');
});
}
break;
}
},
grabTextFrom 拉回我想要的确切值并将其存储到 val。
如果我传入的参数的值刚好在table的第一行,就可以了。但是,无论我做什么,我的代码似乎都只出现在第一行,我不明白为什么?
同样,如果第一行具有传入参数的值,那么我的 within 方法将触发并检查第一列中的输入框,这正是我想要的。
因此,我用于识别给定行中的文本的两段代码(大部分)有效,单击 'that' 行中的复选框的代码也有效。
如果有人能帮助我理解为什么我不能让它遍历 table 的所有行,我将不胜感激。
此外,我似乎无法让 codeceptjs 将 tbody 中的 tr 总数作为一个简单的数组拉回,因此我可以将其用作循环的长度,因此那里的任何指针都会很棒。
为此,我尝试了 - let rowCount = await I.grabNumberOfVisibleElements('tbody tr');
但似乎不起作用。
我确实尝试将我的分手上移一个级别,因为我最初认为它在错误的位置。当我这样做时,运行 我的测试结果出现以下错误。
Sandbox to play around in -- Table check ALL
Object: login
I am on page "/login"
I fill field "#username", "user@somewhere.com"
I fill field "#password", *****
I click "Sign in"
I grab cookie
I click "li[id="resources.admin.name"]"
I click "Sites"
I wait for element "table"
I grab text from "tbody tr:nth-child(1) td:nth-child(2)" √ OK in 7254ms
tableFragment: selectSiteById
I grab text from "tbody tr:nth-child(2) td:nth-child(2)"
I grab text from "tbody tr:nth-child(3) td:nth-child(2)" × "after all" hook: codeceptjs.afterSuite for "Check box of specific
table row" in 4672ms TypeError: Cannot read property '$$' of null
(node:24032) UnhandledPromiseRejectionWarning: Cannot read property
'$$' of null (node:24032) UnhandledPromiseRejectionWarning: Unhandled
promise rejection. This error originated either by throwing inside of
an async function without a catch block, or by rejecting a promise
which was not handled with .catch(). To terminate the node process on
unhandled promise rejection, use the CLI flag
--unhandled-rejections=strict
(see
https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode).
(rejection id: 7) (node:24032) [DEP0018] DeprecationWarning: Unhandled
promise rejections are deprecated. In the future, promise rejections
that are not handled will terminate the Node.js process with a
non-zero exit code.
-- FAILURES:
- Sandbox to play around in
"after all" hook: codeceptjs.afterSuite for "Check box of specific table row":
Cannot read property '$$' of null
Run with --verbose flag to see NodeJS stacktrace
最后,对于与 table 的基本交互,在使用 codeceptjs 时,您是否基本上需要使用 helper 然后使用原生 Puppeteer 编写代码? (我在我的项目中使用了 puppeteer)
<<<<<>>>>>>
更新
谁能帮我理解为什么您似乎无法使用 CodeceptJS 迭代 table 的行?我必须错过一些东西。这是我当前来自 PageObject class 的代码,我不明白第一次迭代成功发生但随后失败的情况。
async test() {
const totalRows = await I.grabAttributeFrom('tbody tr');
I.say('Total Rows: ' + totalRows.length);
for (let i = 1; i < totalRows.length; i++) {
I.say('Current row is: ' + i);
let str = await I.grabTextFrom(
`tbody tr:nth-child(${i}) td:nth-child(2)`,
);
I.say('String value from table is: ' + str);
if (str === 'IDR') {
I.say('Match found in row: ' + i);
within(`tbody tr:nth-child(1) td:nth-child(1) span span`, () => {
I.click('input');
});
break;
}
}
// I.say('Hello');
// let scores = [10, 15, 20, 30];
// for (let score of scores) {
// score += 3;
// I.say(score);
// }
},
输出
Sandbox to play around in -- Table check ALL
Object: login
I am on page "/login"
I fill field "#username", "bob@infdig.com"
I fill field "#password", *****
I click "Sign in"
I grab cookie
I click "li[id="resources.admin.name"]"
I click "Sites"
I grab attribute from "tbody tr"
I wait 5 √ OK in 12226ms
Total Rows: 4 Current row is: 1
sitesPage: test
I grab text from "tbody tr:nth-child(1) td:nth-child(2)" String value from table is: IDH Current row is: 2
I grab text from "tbody tr:nth-child(2) td:nth-child(2)" × "after all" hook: codeceptjs.afterSuite for "More goofing around" in
4682ms TypeError: Cannot read property '$$' of null (node:7180)
UnhandledPromiseRejectionWarning: Cannot read property '$$' of null
(node:7180) UnhandledPromiseRejectionWarning: Unhandled promise
rejection. This error originated either by throwing inside of an async
function without a catch block, or by rejecting a promise which was
not handled with .catch(). To terminate the node process on unhandled
promise rejection, use the CLI flag --unhandled-rejections=strict
(see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode).
(rejection id: 7) (node:7180) [DEP0018] DeprecationWarning: Unhandled
promise rejections are deprecated. In the future, promise rejections
that are not handled will terminate the Node.js process with a
non-zero exit code.
-- FAILURES:
- Sandbox to play around in
"after all" hook: codeceptjs.afterSuite for "More goofing around":
Cannot read property '$$' of null
Run with --verbose flag to see NodeJS stacktrace
谢谢!
鲍勃
我最终走上了辅助路线并构建了一些通用函数来处理表格。我想如果这对那里的任何人都有帮助,我会分享。尝试使用内置的 codeceptjs 方法执行此操作是不可靠的。
人偶助手 class
const { Helper } = codeceptjs;
class Table extends Helper {
// before/after hooks
/**
* @protected
*/
_before() {
// remove if not used
}
/**
* @protected
*/
_after() {
// remove if not used
}
// add custom methods here
// If you need to access other helpers
// use: this.helpers['helperName']
/**
* Get the total rows displayed in a table contained within
* the table body (tbody tr)
*/
async getRowCount() {
//const browser = this.helpers['Puppeteer'].browser;
const page = this.helpers['Puppeteer'].page;
page.waitForSelector('tbody');
const tableRows = 'tbody tr';
let rowCount = await page.$$eval(tableRows, rows => rows.length);
return rowCount;
}
/**
* When a table is present on the page, will check the box
* in column 1 of the header row to select all items listed on
* the current table page (could be more than one page full)
*/
async selectAll() {
const page = this.helpers['Puppeteer'].page;
page.waitForSelector('thead tr th:nth-child(1)');
page.click('thead tr th:nth-child(1)');
}
/**
* Checks the box in column 1 for the row containing the value
* passed in (val), where that value exists in column (col)
* @param {string} val The value you are looking for
* @param {number} col Which column the value will be in
*/
async selectRow(val, col) {
const page = this.helpers['Puppeteer'].page;
page.waitForSelector('tbody');
const tableRows = 'tbody tr';
let rowCount = await page.$$eval(tableRows, rows => rows.length);
for (let i = 0; i < rowCount; i++) {
const str = await page.$eval(
`${tableRows}:nth-child(${i + 1}) td:nth-child(${col})`,
(e) => e.innerText
)
if (str === val) {
await page.waitForSelector(`${tableRows}:nth-child(${i + 1}) td:nth-child(1)`);
await page.click(`${tableRows}:nth-child(${i + 1}) td:nth-child(1)`);
break;
}
}
}
/**
* Will iterate through all rows displayed in the table and check the box
* in column 1 for each row where the value in colum (col) matches.
* @param {string} val The value passed in to look for
* @param {number} col The column to find the value in
*/
async selectAllRows(val, col) {
const page = this.helpers['Puppeteer'].page;
page.waitForSelector('tbody');
const tableRows = 'tbody tr';
let rowCount = await page.$$eval(tableRows, rows => rows.length);
for (let i = 0; i < rowCount; i++) {
const str = await page.$eval(
`${tableRows}:nth-child(${i + 1}) td:nth-child(${col})`,
(e) => e.innerText
)
if (str.includes(val)) {
await page.waitForSelector(`${tableRows}:nth-child(${i + 1}) td:nth-child(1)`);
await page.click(`${tableRows}:nth-child(${i + 1}) td:nth-child(1)`);
continue;
}
}
}
/**
* Locates the row containing the value passed in, in the
* specified column (col)
* @param {string} val Value passed in to look for in each row
* @param {number} col The column to look for the value in
*/
async editRow(val, col) {
const page = this.helpers['Puppeteer'].page;
page.waitForSelector('tbody');
const tableRows = 'tbody tr';
let rowCount = await page.$$eval(tableRows, rows => rows.length);
for (let i = 0; i < rowCount; i++) {
const str = await page.$eval(
`${tableRows}:nth-child(${i + 1}) td:nth-child(${col})`,
(e) => e.innerText
)
if (str === val) {
await page.waitForSelector(`${tableRows}:nth-child(${i + 1}) td:nth-child(1)`);
await page.click(`${tableRows}:nth-child(${i + 1}) td:nth-child(${col})`);
break;
}
}
}
}
module.exports = Table;
我正在尝试使用 Codeceptjs 中可用的方法来简单地迭代 table 行和 select 行,该行基于迭代当前行的特定单元格中存在的文本。
以下代码在我的页面对象之一中并且部分有效。
async selectSiteById(siteId) {
I.waitForElement('table');
for (let i = 1; i < 5; i++) {
let val = await I.grabTextFrom(`tbody tr:nth-child(${i}) td:nth-child(2)`);
if (val === siteId) {
I.say('Val' + val + ' -- Site Id ' + siteId)
within(`tbody tr:nth-child(${i + 1}) td:nth-child(1)`, () => {
I.click('input');
});
}
break;
}
},
grabTextFrom 拉回我想要的确切值并将其存储到 val。
如果我传入的参数的值刚好在table的第一行,就可以了。但是,无论我做什么,我的代码似乎都只出现在第一行,我不明白为什么?
同样,如果第一行具有传入参数的值,那么我的 within 方法将触发并检查第一列中的输入框,这正是我想要的。
因此,我用于识别给定行中的文本的两段代码(大部分)有效,单击 'that' 行中的复选框的代码也有效。
如果有人能帮助我理解为什么我不能让它遍历 table 的所有行,我将不胜感激。
此外,我似乎无法让 codeceptjs 将 tbody 中的 tr 总数作为一个简单的数组拉回,因此我可以将其用作循环的长度,因此那里的任何指针都会很棒。
为此,我尝试了 - let rowCount = await I.grabNumberOfVisibleElements('tbody tr');
但似乎不起作用。
我确实尝试将我的分手上移一个级别,因为我最初认为它在错误的位置。当我这样做时,运行 我的测试结果出现以下错误。
Sandbox to play around in -- Table check ALL Object: login I am on page "/login" I fill field "#username", "user@somewhere.com" I fill field "#password", ***** I click "Sign in" I grab cookie I click "li[id="resources.admin.name"]" I click "Sites" I wait for element "table" I grab text from "tbody tr:nth-child(1) td:nth-child(2)" √ OK in 7254ms
tableFragment: selectSiteById I grab text from "tbody tr:nth-child(2) td:nth-child(2)" I grab text from "tbody tr:nth-child(3) td:nth-child(2)" × "after all" hook: codeceptjs.afterSuite for "Check box of specific
table row" in 4672ms TypeError: Cannot read property '$$' of null (node:24032) UnhandledPromiseRejectionWarning: Cannot read property '$$' of null (node:24032) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag
--unhandled-rejections=strict
(see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 7) (node:24032) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.-- FAILURES:
- Sandbox to play around in "after all" hook: codeceptjs.afterSuite for "Check box of specific table row": Cannot read property '$$' of null
Run with --verbose flag to see NodeJS stacktrace
最后,对于与 table 的基本交互,在使用 codeceptjs 时,您是否基本上需要使用 helper 然后使用原生 Puppeteer 编写代码? (我在我的项目中使用了 puppeteer)
<<<<<>>>>>> 更新
谁能帮我理解为什么您似乎无法使用 CodeceptJS 迭代 table 的行?我必须错过一些东西。这是我当前来自 PageObject class 的代码,我不明白第一次迭代成功发生但随后失败的情况。
async test() {
const totalRows = await I.grabAttributeFrom('tbody tr');
I.say('Total Rows: ' + totalRows.length);
for (let i = 1; i < totalRows.length; i++) {
I.say('Current row is: ' + i);
let str = await I.grabTextFrom(
`tbody tr:nth-child(${i}) td:nth-child(2)`,
);
I.say('String value from table is: ' + str);
if (str === 'IDR') {
I.say('Match found in row: ' + i);
within(`tbody tr:nth-child(1) td:nth-child(1) span span`, () => {
I.click('input');
});
break;
}
}
// I.say('Hello');
// let scores = [10, 15, 20, 30];
// for (let score of scores) {
// score += 3;
// I.say(score);
// }
},
输出
Sandbox to play around in -- Table check ALL Object: login I am on page "/login" I fill field "#username", "bob@infdig.com" I fill field "#password", ***** I click "Sign in" I grab cookie I click "li[id="resources.admin.name"]" I click "Sites" I grab attribute from "tbody tr" I wait 5 √ OK in 12226ms
Total Rows: 4 Current row is: 1 sitesPage: test I grab text from "tbody tr:nth-child(1) td:nth-child(2)" String value from table is: IDH Current row is: 2 I grab text from "tbody tr:nth-child(2) td:nth-child(2)" × "after all" hook: codeceptjs.afterSuite for "More goofing around" in 4682ms TypeError: Cannot read property '$$' of null (node:7180) UnhandledPromiseRejectionWarning: Cannot read property '$$' of null (node:7180) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag
--unhandled-rejections=strict
(see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 7) (node:7180) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.-- FAILURES:
- Sandbox to play around in "after all" hook: codeceptjs.afterSuite for "More goofing around": Cannot read property '$$' of null
Run with --verbose flag to see NodeJS stacktrace
谢谢! 鲍勃
我最终走上了辅助路线并构建了一些通用函数来处理表格。我想如果这对那里的任何人都有帮助,我会分享。尝试使用内置的 codeceptjs 方法执行此操作是不可靠的。
人偶助手 class
const { Helper } = codeceptjs;
class Table extends Helper {
// before/after hooks
/**
* @protected
*/
_before() {
// remove if not used
}
/**
* @protected
*/
_after() {
// remove if not used
}
// add custom methods here
// If you need to access other helpers
// use: this.helpers['helperName']
/**
* Get the total rows displayed in a table contained within
* the table body (tbody tr)
*/
async getRowCount() {
//const browser = this.helpers['Puppeteer'].browser;
const page = this.helpers['Puppeteer'].page;
page.waitForSelector('tbody');
const tableRows = 'tbody tr';
let rowCount = await page.$$eval(tableRows, rows => rows.length);
return rowCount;
}
/**
* When a table is present on the page, will check the box
* in column 1 of the header row to select all items listed on
* the current table page (could be more than one page full)
*/
async selectAll() {
const page = this.helpers['Puppeteer'].page;
page.waitForSelector('thead tr th:nth-child(1)');
page.click('thead tr th:nth-child(1)');
}
/**
* Checks the box in column 1 for the row containing the value
* passed in (val), where that value exists in column (col)
* @param {string} val The value you are looking for
* @param {number} col Which column the value will be in
*/
async selectRow(val, col) {
const page = this.helpers['Puppeteer'].page;
page.waitForSelector('tbody');
const tableRows = 'tbody tr';
let rowCount = await page.$$eval(tableRows, rows => rows.length);
for (let i = 0; i < rowCount; i++) {
const str = await page.$eval(
`${tableRows}:nth-child(${i + 1}) td:nth-child(${col})`,
(e) => e.innerText
)
if (str === val) {
await page.waitForSelector(`${tableRows}:nth-child(${i + 1}) td:nth-child(1)`);
await page.click(`${tableRows}:nth-child(${i + 1}) td:nth-child(1)`);
break;
}
}
}
/**
* Will iterate through all rows displayed in the table and check the box
* in column 1 for each row where the value in colum (col) matches.
* @param {string} val The value passed in to look for
* @param {number} col The column to find the value in
*/
async selectAllRows(val, col) {
const page = this.helpers['Puppeteer'].page;
page.waitForSelector('tbody');
const tableRows = 'tbody tr';
let rowCount = await page.$$eval(tableRows, rows => rows.length);
for (let i = 0; i < rowCount; i++) {
const str = await page.$eval(
`${tableRows}:nth-child(${i + 1}) td:nth-child(${col})`,
(e) => e.innerText
)
if (str.includes(val)) {
await page.waitForSelector(`${tableRows}:nth-child(${i + 1}) td:nth-child(1)`);
await page.click(`${tableRows}:nth-child(${i + 1}) td:nth-child(1)`);
continue;
}
}
}
/**
* Locates the row containing the value passed in, in the
* specified column (col)
* @param {string} val Value passed in to look for in each row
* @param {number} col The column to look for the value in
*/
async editRow(val, col) {
const page = this.helpers['Puppeteer'].page;
page.waitForSelector('tbody');
const tableRows = 'tbody tr';
let rowCount = await page.$$eval(tableRows, rows => rows.length);
for (let i = 0; i < rowCount; i++) {
const str = await page.$eval(
`${tableRows}:nth-child(${i + 1}) td:nth-child(${col})`,
(e) => e.innerText
)
if (str === val) {
await page.waitForSelector(`${tableRows}:nth-child(${i + 1}) td:nth-child(1)`);
await page.click(`${tableRows}:nth-child(${i + 1}) td:nth-child(${col})`);
break;
}
}
}
}
module.exports = Table;