Playwright, how to leave iframe? Or why my elements are not visible - playwright

my question is "How to get an access to other elements which are outside the iframe".\
const frame = this.page.frame({name: "messagecontframe"});
await expect(frame.locator(this.confirmationMessage)).toBeVisible();
const bookingID = await frame.locator("(//td[#class='v1right'])[1]").innerText();
await frame.locator(this.cancelBookingButton).click();
after that actions I need to navigate to another URL and do something on another page, but I simply can't even click something, all elements are not visible for me. I believe that's because "I'm still in iframe". How to solve that problem? Is there something like iframe.leave ?

Related

Playwright - not working with zoomed out site

our team decided to zoom out the whole site. So they did this:
This is breaking my PW tests while clicking on the button.
I get this in the inspector:
selector resolved to visible <button id="add-to-cart-btn" data-partid="04-0001" data-…>ADD TO CART</button>
attempting click action
waiting for element to be visible, enabled and stable
element is visible, enabled and stable
scrolling into view if needed
done scrolling
element is outside of the viewport
I found this is an issue in PW https://github.com/microsoft/playwright/issues/2768
My question is: how can I bypass this in the most efficient way?
Is there a way to override a playwright function that sets the initial loading of the page and set my zoom there?
Since if I do it via JavaScript, then I have to do it every time my page reloads, and that can be really tedious and error-prone in the tests.
This is what I have now, but it is really a hack a like solution:
async removeZoomOutClassFromBodyElement() {
await this.#page.evaluate(() => {
const body = document.querySelector('body');
if (body) {
// Removes the class only if it exists on the body tag
body.classList.remove('zoom-out');
} else {
throw Error(ErrorMessage.BODY_NOT_FOUND);
}
});
}
Can you please advise what would be the best approach here?
Thanks!

How to inject a script (using playwright) that will create an unique attribute on every button of the page?

I am scrapping a site. I am using this code:
const SELECTOR = 'button:has-text("ClickMe") >> nth=1'
const loc = this.page.locator(SELECTOR)
await loc.click()
and inspector shows this:
...
done scrolling
performing click action
<div class="blabla">…</div> intercepts pointer events
I do not understand why this is happening. Very frustrating, what is this interception (intercept pointer event, done by a parent node) ? It works well when I use the console with:
.locator('button:has-text("ClickMe") >> nth=1').element.click()
How could I bypass/solve this interception ? I have thought an idea, do you know if it s possible to add an incremental id, such as my-data-id, on every buttons inside the page... For example, after the DOM has loaded, and before the script executes, I inject a script that will add this my-data-id attribute. So that, I can select directly the buttons I want to click with the unique attribute and I don t suffer anymore looking for the good selector:
[my-data-id=142] for exemple, will select the button #142
[my-data-id=143] for exemple, will select the button #143
You can use force: true to disable actionability checks and more precisely to avoid this error.
const SELECTOR = 'button:has-text("ClickMe") >> nth=1'
const loc = this.page.locator(SELECTOR)
await loc.click({force: true})
See issue log, try adding the environment setting
// playwright.config.ts
process.env.PLAYWRIGHT_NO_LAYOUT_SHIFT_CHECK = '1';
const config = {
// ...
};
export default config;

Testing-library unable to find rc-menu

I'm trying to implement integration tests on our React frontend which uses Ant design. Whenever we create a table, we add an action column in which we have a Menu and Menu Items to perform certain actions.
However, I seem unable to find the correct button in the menu item when using react-testing-library. The menu Ant design uses is rc-menu and I believe it renders outside of the rendered component.
Reading the testing-library documentation, I've tried using baseElement and queryByRole to get the correct DOM element, but it doesn't find anything.
Here's an example of what I'm trying to do. It's all async since the table has to wait on certain data before it gets filled in, just an FYI.
Tried it on codesandbox
const row = await screen.findByRole('row', {
name: /test/i
})
const menu = await within(row).findByRole('menu')
fireEvent.mouseDown(menu)
expect(queryByRole('button', { name: /delete/i })).toBeDisabled()
the menu being opened with the delete action as menu item
I had a same issue testing antd + rc-menu component. Looks like the issue is related to delayed popup rendering. Here is an example how I solved it:
jest.useFakeTimers();
const { queryByTestId, getByText } = renderMyComponent();
const nav = await waitFor(() => getByText("My Menu item text"));
act(() => {
fireEvent.mouseEnter(nav);
jest.runAllTimers(); // ! <- this was a trick !
});
jest.useRealTimers();
expect(queryByTestId("submenu-item-test-id")).toBeTruthy();

How to delete a jqgrid row without reloading the entire grid?

I have a webpage with multiple jqgrids each with inline editing enabled, "action" column (edit icons) enabled and pager disabled. I need to handle the delete event for each row so that I can process the delete without reloading server-side data. I've looked at the approach mentioned in jqGrid Delete a Row and it's very helpful except I have two questions that are stumping me -
Are there more details around the rp_ge parameter in the delOptions.onClickSubmit event?
My column has the delOptions set as this -
delOptions: {onclickSubmit: function(rp_ge, rowid) {return onRowDelete(rp_ge,rowid);}},processing:true }},
Is there a way to get the grid id from within that event? I'd like to have a generic function that I can use to handle delete events from all the grids on the page. The rp_ge parameter has a gbox which sometimes contains the grid id appended? But I have no idea what it is since i'm not able to figure out when it's populated, when it's not.
function onRowDelete(rp_ge, rowid) {
//hardcoded grid id.. don't like it.
var gridid = '#Grid_X';
//what is this gbox?? can i get grid id predictable from it?
//var gridid = rp_ge.gbox.replace("#gbox_", "");
var grid = $('#Grid_X');
rp_ge.processing = true;
var result = grid.delRowData(rowid);
if (result) {
$("#delmod" + grid[0].id).hide();
}
return true;
}
In the jqGrid Delete a Row approach, the code $("#delmod"+grid[0].id).hide(); is hiding the popup delete confirmation dialog manually. What I noticed is that when the dialog pops-up, jqgrid de-emphasizes the background page (makes it light greyish). But after the popup is manually closed (hidden actually?), the background remains de-emphasized. So it looks like the page doesn't have focus (or even disabled). Any way this can be fixed? This can also be seen on the demo that Oleg wrote.
Any help would be appreciated.
(PS - I would've commented on the same post but I don't have enough points to comment on someone else's answer yet.)
In answer to your second point.
Several examples by Oleg such as this one have the following modification.
$("#delmod" + grid[0].id).hide();
is replaced with
$.jgrid.hideModal(
"#delmod"+grid_id,
{gb:"#gbox_"+grid_id,jqm:rp_ge.jqModal,onClose:rp_ge.onClose}
);
This will return focus after the delete operation.

WatiN: Print Dialog

I have a screen that pops up on load with a print dialog using javascript.
I've just started using WatiN to test my application. This screen is the last step of the test.
What happens is sometimes WatiN closes IE before the dialog appears, sometimes it doesn't and the window hangs around. I have ie.Close() in the test TearDown but it still gets left open if the print dialog is showing.
What I'm trying to avoid is having the orphaned IE window. I want it to close all the time.
I looked up DialogHandlers and wrote this:
var printDialogHandler = new PrintDialogHandler(PrintDialogHandler.ButtonsEnum.Cancel);
ie.DialogWatcher.Add(printDialogHandler);
And placed it before the button click that links to the page, but nothing changed.
The examples I saw had code that would do something like:
someDialogHandler.WaitUntilExists() // I might have this function name wrong...
But PrintDialogHandler has no much member.
I initially wasn't trying to test that this dialog comes up (just that the page loads and checking some values on the page) but I guess it would be more complete to wait and test for the existence of the print dialog.
Not exactly sure about your situation, but we had a problem with a popup window that also displayed a print dialog box when loaded. Our main problem was that we forgot to create a new IE instance and attach it to the popup. Here is the working code:
btnCoverSheetPrint.Click(); //Clicking this button will open a new window and a print dialog
IE iePopup = IE.AttachToIE(Find.ByUrl(new Regex(".+_CoverPage.aspx"))); //Match url ending in "_CoverPage.aspx"
WatiN.Core.DialogHandlers.PrintDialogHandler pdhPopup = new WatiN.Core.DialogHandlers.PrintDialogHandler(WatiN.Core.DialogHandlers.PrintDialogHandler.ButtonsEnum.Cancel);
using (new WatiN.Core.DialogHandlers.UseDialogOnce(iePopup.DialogWatcher, pdhPopup)) //This will use the DialogHandler once and then remove it from the DialogWatcher
{
//At this point the popup window will be open, and the print dialog will be canceled
//Use the iePopup object to manage the new window in here.
}
iePopup.Close(); // Close the popup once we are done.
This worked for me:
private void Print_N_Email(Browser ie)
{
//Print and handle dialog.
ie.Div(Find.ById("ContentMenuLeft")).Link(Find.ByText(new Regex("Print.*"))).Click();//orig
Browser ie2 = Browser.AttachTo(typeof(IE), Find.ByUrl(new Regex(".*Print.*")));
System.Threading.Thread.Sleep(1000);
PrintDialogHandler pdh = new PrintDialogHandler(PrintDialogHandler.ButtonsEnum.Cancel);
new UseDialogOnce(ie2.DialogWatcher, pdh);
ie2.Close();
}
You still might want to check your browser AutoClose property ie.AutoClose

Resources