How can I select an element by Id? - playwright

I wonder how I can access an element by ID. I want to submit a form.
await page.click("id= 'next'"); --> not possible
await page.getByRole('button', { id: 'next' }).click(); --> does not compile
await page.getByRole('button', { name: 'Sign in' }).click(); --> work but is language dependent
Selecting elements by their ID seems the most robust to me. Am I missing something?

You can do something like this:
await page.locator("#YourId").click()
or just
await page.click("#YourId");
Playwright recommends some predefined locators so you could also check if some off those fit your use case.

What you are missing in the first example are the square brackets, instead of:
await page.click("id= 'next'");
you should do this:
await page.click("[id='next']");
alternatively, you can use the shorthand version like mentioned in the other answer

Related

How can I use page.waitForSelector in Playwright for one of two selectors?

I am trying to await a div that has one of two possible ids, div#abc or div#efg.
I can await div#abc like this:
await this.page.waitForSelector('div#abc');
But how can I tell Playwright that I also want the step to pass if div#efg is present?
Like with Puppeteer, Playwright selectors can be standard CSS, so just add a comma between the selectors:
await this.page.waitForSelector('div#abc, div#efg');
More general solution that works for any number of async operations:
const firstResolvedPromiseResult = await Promise.race([
this.page.waitForSelector('div#abc'),
this.page.waitForSelector('div#efg'),
]);
But the accepted solution is simpler for this use case.

How can I assert that an element is NOT on the page in playwright?

I'm testing a website that includes a logo, and I want to make sure the logo does not appear on some pages.
How can I assert that an element does NOT exist? I checked the Playwright assertions documentation, but it only has examples of checking for things that do exist.
async assertNoLog(): Promise<boolean> {
await this.page.locator('div#page-id'); // now the page has loaded
// How do I check if logo is on page without throwing an error if it is missing
}
I'm not sure what to write here to assert that my element is not found anywhere on the page.
You can use .count() and assert that it returns 0.
expect(await page.locator('.notexists').count()).toEqual(0);
https://playwright.dev/docs/api/class-locator#locator-count
I wanted to know that an element wasn't on screen, but I also wanted to wait until it was gone, and this is the way to do that:
await expect(locator).toHaveCount(0);
Found here
You can play with the conditions you expect your element to have. For example, at Playwright's homepage you expect an element by the class .navbar__brand to be visible, but you also expect an element by the class .notexists NOT to be visible (in this case this element would not exist). Then you can do:
test('element does exist #pass', async ({ page }) => {
await page.goto('https://playwright.dev/');
const locator = await page.locator('.navbar__brand').isVisible();
expect(locator).toBeTruthy();
});
test('element does NOT exist #fail', async ({ page }) => {
await page.goto('https://playwright.dev/');
const locator = await page.locator('.notexists').isVisible();
expect(locator).toBeTruthy();
});
Doing this, of course, would return the same results:
test('element does exist #pass', async ({ page }) => {
await page.goto('https://playwright.dev/');
expect(await page.locator('.navbar__brand').isVisible()).toBe(true);
});
test('element does NOT exist #fail', async ({ page }) => {
await page.goto('https://playwright.dev/');
expect(await page.locator('.notexists').isVisible()).toBe(true);
});
As I say, the element's conditions are up to you. For example, if you want to assert an element with visibility:hidden is also not present in the DOM, because it simply shouldn't be, you can wrap the visibility and a .isHidden() conditions within a if/else, etc. And of course, feel free to play with booleans (toBe(true)/toBe(false), toBeTruthy()/toBeFalsy()).
These are not the most elegant solutions out there, but I hope they can help.

How to test search with testcafe

I am having the following problem:
That I can't check if "search" works?
My code:
test('/search', async t => {
const search = await Selector('#input').value
await t
.typeText('q[product_name_or_user_fullname_cont]', 'abcd')
.click('[name="commit"]')
})
My page:
I want that the search bar will be checked in testcafe
I searched but did not know where I am wrong.
Help me
Thank you very much
I assume you need to check the search results on the page. Use the assertion methods to compare the actual values with expected ones.

Can I use whileElement(...).atIndex(..) to distinguish multiple scroll page id's

I was getting the following error: Multiple elements were matched
However it turned out that the scrolling page ID was multiple times matched. This means that I need something like this:
await waitFor(element(by.id("someID")).toBeVisible()whileElement(by.id("anotherID")).atIndex(1).scroll(50, 'down')
I tried this, but get the following error:
TypeError: global.waitFor(...).toBeVisible(...).whileElement(...).atIndex is not a function
So my question is, when there are two scroll elements with the same id, can I select one of them with the function atIndex?
Or is there another solution for this?
Thanks in advance
Same issue experienced here. I was able to solve it using a function that scrolls the list until it meets the condition.
something like that:
await tryTap();
...
const tryTap = async() => {
try { await element(by.id('someID')).tap(); }
catch (e) {
await element(by.type("anotherID")).atIndex(1).scroll(50, "down");
await tryTap();
}
}

"select2" Add constant option

I am currently using Select2 in a project and would like to add a option to my select list that shows up regardless of what the user types or searches. The idea is to have a "Add new" option always present in the list.
I do not think my code is necessary here (but if needed I may provide) as the only thing i'm lacking knowledge in this specific topic is on how to keed the option always showing.
I thought of using the matcher attribute, but i'm not sure how.
I've managed to do it setting a new matcher, the problem was I was not sure on how to create a new matcher and still use the select2 default one.
Something else I was missing was the full version of select2.
function newMatcher(term, text){
//The "ADD NEW" String is the text in the option I want to always show up.
//The code after OR looks for the actual results for the user's search
if ((text.toUpperCase().indexOf("ADD NEW") > -1)
|| (text.toUpperCase().indexOf(term.toUpperCase()) > -1)) {
return true;
}
}
$(document).ready(function() {
$.fn.select2.amd.require(['select2/compat/matcher'], function (oldMatcher) {
$('select').select2({
matcher: oldMatcher(newMatcher)
})
})
});

Resources