I'm using the page-object-model in developing my automated tests in playwright. As such, I'm building a class to hold my locators and expose the locators, but not necessarily the used selector. Does the locator have a way to share its selector?
exports.MyWebPageModel = class MyWebPageModel {
constructor(page) {
this.myMultiSelect = page.locator('#select-group select');
this.submitButton = page.locator('#submit-btn');
}
}
test('validate multi-select submission', ({page}) -> {
const myPage = new MyWebPageModel(page);
const selectChoices = ['choice1', 'choice2', 'choice4'];
await myPage.myMultiSelect.selectOptions(selectedChoices);
Promise.all([
page.waitForNavigation(),
myPage.submitButton.click()
]);
/* do tests on new page, click it's back button to return to previous page */
const allSelectedValues = await page.$eval(myPage.myMultiSelect.???, e => Array.from(e.selectedOptions).map(option => option.value)); // get the selected options from select element
expect(allSelectedValues).toEqual(selectedChoices); // verify the selected options matches selectChoices.
});
I'm using the page-object-model in developing my automated tests in playwright. As such, I'm building a class to hold my locators and expose the locators, but not necessarily the used selector. Does the locator have a way to share its selector?
exports.MyWebPageModel = class MyWebPageModel {
constructor(page) {
this.myMultiSelect = page.locator('#select-group select');
this.submitButton = page.locator('#submit-btn');
}
}
test('validate multi-select submission', ({page}) -> {
const myPage = new MyWebPageModel(page);
const selectChoices = ['choice1', 'choice2', 'choice4'];
await myPage.myMultiSelect.selectOptions(selectedChoices);
Promise.all([
page.waitForNavigation(),
myPage.submitButton.click()
]);
/* do tests on new page, click it's back button to return to previous page */
const allSelectedValues = await page.$eval(myPage.myMultiSelect.???, e => Array.from(e.selectedOptions).map(option => option.value)); // get the selected options from select element
expect(allSelectedValues).toEqual(selectedChoices); // verify the selected options matches selectChoices.
});
Share
Improve this question
edited Nov 22, 2022 at 10:27
robd
9,8336 gold badges44 silver badges61 bronze badges
asked Apr 28, 2022 at 13:54
MachtynMachtyn
3,2728 gold badges43 silver badges69 bronze badges
1
-
Promise.all([
must be awaited or you have a race condition.page.$eval
is strongly discouraged. – ggorlen Commented Jan 1 at 3:05
3 Answers
Reset to default 6By doing the following:
const myLoc = page.locator('#myElement');
Object.getOwnPropertyNames(myLoc).forEach(prop => {
console.log(prop + " = " + row_locator[prop]);
});
I was able to discover there is a _selector
, which returns the internal selector used for the Locator object.
So the answer is to use the locator's "private" property _selector
. This is the value that is used when generating a locator error.
So, given a table:
<table id="colors">
<thead>
<trow>
<th>Key</th>
<th>Color</th>
</trow>
</thead>
<tbody>
<trow>
<td>R</td><td>Red</td>
</trow>
<trow>
<td>B</td><td>Blue</td>
</trow>
<trow>
<td>G</td><td>Green</td>
</trow>
</tbody>
</table>
And, perhaps you build your playwright object as follows:
exports.ColorTable = class ColorTable {
constructor(page) {
this.page = page;
this.table = this.page.locator("#colors");
this.tableData = this.table.locator('tbody tr');
}
}
The result of the following
const myT = new ColorTable(page);
console.log(myT.tableData._selector);
might look like: Locator@#colors >> tbody tr
Well this is one way, but not sure if it will work for all possible locators!.
// Get a selector from a playwright locator
import { Locator } from "@playwright/test";
export function extractSelector(locator: Locator) {
const selector = locator.toString();
const parts = selector.split("@");
if (parts.length !== 2) { throw Error("extractSelector: susupect that this is not a locator"); }
if (parts[0] !== "Locator") { throw Error("extractSelector: did not find locator"); }
return parts[1];
}
I am 95% sure that you can not get the selector which was previuously used. However there is way to get selector by changing your class and making the selectors as public class attributes.
exports.MyWebPageModel = class MyWebPageModel {
//think it can be declared as const
public let multiSelectSelector:string = '#select-group select';
public let submitButtonSelector:string = '#submit-btn';
constructor(page) {
this.myMultiSelect = page.locator(this.multiSelectLocator);
this.submitButton = page.locator(this.submitButton);
}
}