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();
}
}
Related
The scenario I'm trying to test is:
Get an array of elements from the page and read the url property of that element
Test 1 - that the array is not empty
For Each of these elements
Test 2->number of elements - Navigate to the url read above and test there are no errors on the page
So far I've got the code working, but only by including the for loop in the second test, which only registers the above as two tests and does not run the second set (ie: the for loop) in parallel.
When trying to make the second set of tests parallel (as I've done in another test that's based on a static array of pages) I end up with the below code, but the second set of tests is not even detected, ie: if I comment out Test 1, no tests found is reported.
Here's the code structure I'm trying to use. As I said above, it is based upon another test that's using a static array of elements that does seem to work as expected. The main difference with the other test is that everything is within the loop and there is no beforeAll. I'm assuming that's where the crux of the issue is.
import { test, expect, chromium } from '#playwright/test';
const pages = [];
test.describe('Pages Load', () => {
test.beforeAll(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(url);
const allPages = await page
.locator('container id')
.evaluateAll(($elements) => {
return $elements.map((element) => {
const pageTitle = element.querySelector('element id');
const pageURL = element.getAttribute(
'attribute id'
);
return {
title: pageTitle,
url: pageURL,
};
});
});
allPages.forEach(($page) => {
pages.push({
title: $page.title,
url: $page.url,
});
});
});
test('Pages exist', () => {
expect(pages.length).toBeGreaterThan(0);
});
test.describe('No errors on pages', () => {
pages.forEach((page) => {
test.describe(`${page.title}`, () => {
test('No errors', async () => {
// Test goes here
});
});
});
});
});
Update:
I've had a bit more of a play with this and while I know why this code isn't working, I still have no idea how to resolve the issue.
Couple of things I've noticed (and these are just theories/assumptions based on what I've observed):
Firstly, the reason why the above isn't working is because the array isn't set up by the time it get's to the loop, as the beforeAll only appears to happen with each test, not the test.describe. While this is just a theory (can't see anything in the documentation proving or disproving this), it does explain why the second test is ignored, because the array.length is 0
Secondly, when attempting to extract the functionality into a separate function outside of the test, as suggested here, however, this too had no luck, as when it gets to setting up the browser with const browser = await chromium.launch(); in an external function, playwright seems to exit with no errors being thrown. My assumption is that the browser setup needs to be within a test context, though that is just a theory.
Any advice on how I can get the desired results would be greatly appreciated. Many thanks in advance.
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.
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.
I'm using SmartGWT 2.5.
I have a main grid that has its expandable rows in order to display subgrids.
I simply want to display the main grid with all its rows expanded from the start.
I tried to add a listener containing the following code:
ListGridRecord[] records = getRecords();
for (ListGridRecord rec : records) {
expandRecord(rec);
}
I tried with DataArrivedHandler and DrawAreaChangedHandler, but I just get javascript errors client-side or only parts of the rows are expanded. How can I fix this?
If you are talking about Grid Grouping, then you can use the following:
grid.setGroupStartOpen(GroupStartOpen.ALL);
listGrid.addDataArrivedHandler(new DataArrivedHandler() {
#Override
public void onDataArrived(DataArrivedEvent event) {
for (ListGridRecord rec : listGrid.getRecords()) {
listGrid.expandRecord(rec);
}
}
});
Should work (worked with previous versions..)
What error do you get?
Ok finally, I've put a timer of 100 ms within each handler.
The issue was that there was a delay before the full creation of the components (what I want to display is quite complex), and so when the handler was called, not everything was in place yet...
I am using the sortable widget to re-order a list of items. After an item is dragged to a new location, I kick off an AJAX form post to the server to save the new order. How can I undo the sort (e.g. return the drag item to its original position in the list) if I receive an error message from the server?
Basically, I only want the re-order to "stick" if the server confirms that the changes were saved.
Try the following:
$(this).sortable('cancel');
I just encountered this same issue, and for the sake of a complete answer, I wanted to share my solution to this problem:
$('.list').sortable({
items:'.list:not(.loading)',
start: function(event,ui) {
var element = $(ui.item[0]);
element.data('lastParent', element.parent());
},
update: function(event,ui) {
var element = $(ui.item[0]);
if (element.hasClass('loading')) return;
element.addClass('loading');
$.ajax({
url:'/ajax',
context:element,
complete:function(xhr,status) {
$(this).removeClass('loading');
if (xhr.status != 200) {
$($(this).data('lastParent')).append(this);
}
},
});
}
});
You'll need to modify it to suit your codebase, but this is a completely multithread safe solution that works very well for me.
I'm pretty sure that sortable doesn't have any undo-last-drop function -- but it's a great idea!
In the mean time, though, I think your best bet is to write some sort of start that stores the ordering, and then on failure call a revert function. I.e. something like this:
$("list-container").sortable({
start: function () {
/* stash current order of sorted elements in an array */
},
update: function () {
/* ajax call; on failure, re-order based on the stashed order */
}
});
Would love to know if others have a better answer, though.