Access multiple renderers with spectron - mocha.js

I'm working on an Electron application. The main process opens a first renderer (browserWindow). When the user click on a button, this renderer sends an IPC message to the main process. When this message is received, the main process opens a second, different, renderer. Those two renderers live concurently. The application works fine.
Then, using Spectron to test this app, how to access both renderers ? The problem is app.rendererProcess always returns the first renderer.
This is the same problem with app.client which always contains the WebdriverIO browser object of the first renderer and never the second.
Is there a way to list all the process of a Spectron application in a test? Is it possible to access the browser object of the second renderer ?
With AVA:
test.(async t => {
// the application is open before the test
// at this point, the first renderer is open
// click on the button to open the second renderer
await t.context.app.client.click('#bt_openSecondRenderer');
// wait for the second renderer to open
// error: this element doesn't exist
await t.context.app.client.click('elt_of_the_scnd_renderer');
});
I'm using AVA but I don't think it is the problem. So if anyone know how to make this works with Mocha or anything else, it would be very helpfull.
Thanks !

Following the philosophy given by Tim answer, instead of using BrowserWindow, we can use WebDriverIO to focus the desired window:
test.(async t => {
// here, t.context.app.client handles the first window
await t.context.app.client.windowByIndex(1).then(() => {
// here, t.context.app.client handles the second window
});
});

Like a user, Specton can only interact with the focused window. This should work but I haven't tested it:
// The docs say that app.electron gives you access to all the Electron APIs
// This should get you a list of BrowserWindows
const windows = await t.context.app.electron.BrowserWindow.getAllWindows();
// Focus the window you want to interact with
windows[1].focus();
// Do your clicking
await t.context.app.client.click('elt_of_the_scnd_renderer');

it('Switch window', async () => {
await app.client.waitUntilWindowLoaded(100000)
.windowByIndex(0);
.windowByIndex(1);
})

Related

How to capture and display text for auto appearing and disappearing pop-up using cypress

i Would like to know the method on How to capture and display text for auto appearing and disappearing pop-up using cypress.
I had used the window methods for capturing the text and displaying it, but it doesn't capture the message.
The pop-up/alert is designed to appear whenever user generates a report and it automatically disappears after 3 secs.
Please help
Depends on what creates the popup.
For window alert, this question How can we test the alert and text uses stub to capture the call.
It asserts the stub is called with certain text.
const stub = cy.stub()
cy.on ('window:alert', stub)
cy.get('button').contains('Generate Report').click()
.then(() => {
expect(stub).to.be.calledWith('I am an alert box!')
})
From Cypress Window-Alert
If the popup is generated by framework, e.g React the approach is the same as any text on the page.
You might need to use cy.clock() to control the timing, presuming you want to assert the appear/disappear cycle.

Why Cypress test is not able to trigger a script in a child window?

I have a pop up window containing a script in its head. And this script should be triggered by click on the window button. But after click on this button the script does not run. Could you suggest the reason?
Steps to reproduce:
Click on a button in the main window.
Child window containing a simple form is open.
Move to the child window, fill in the form fields and click on submit button.
Expected result: The click triggers a script located in the child window head. The script process the form and submit it.
Actual result: an error arises: "submitMyForm is not defined" (reference: submitMyForm() is a method containing in the script mentioned above).
So the problem is that the child window form fields can be populated and form button can be clicked but the script bounded to the button by means of the link <a href="javascript:submitMyForm();"> does not work as the function submitMyForm() is not found. Obviously the reason of the test failure is stubbing the child window which is performed to prevent having 2 windows at the same time. After this the child window is opening in the same browser tab as Cypress is not able to work with 2 windows open in the same time. But in this case the script stops working neither from the test nor by performing the click manually.
Here is a code snippet from the Cypress test:
const pop_url = `/dir1/dir2/file.php?id=${sectionId}`; // Here is a new window URL
cy.window().then( win => {
const stub = cy.stub(win, 'open').as('windowopen');
newSurveySectionListObj.AddNewBtnClick(); // Triggers form opening in the new window
cy.get('#windowopen').should('be.called.with', pop_url);
cy.window().then( $win => {
$win.location.href = pop_url
newSurveySectionListObj.typeDropdownSelect('Matrix'); // works fine
newSurveySectionListObj.modalDescriptionFldType('Cypress test string'); // works fine
newSurveySectionListObj.responseTypeDropdownSelect('Checkbox'); // works fine
cy.get('a[href="javascript:submitMyForm();"]').click(); // Does not work despite the button is clicked. An error "submitMyForm is // not defined" arises
});
});
You are going beyond what Cypress is capable of/designed for.
I would question why you are using a separate window in your app? You will run afoul of pop-up blockers that will prevent the new window being opened anyway. A percentage of users won't be able to work it out.
There are 2 approaches to this:
Use a modal dialog to achieve this (not great on mobile)
Use another route/page to display your form, return to the prev page when done
These have the advantage that they won't break with pop-up blockers, and your Cypress tests will work, as they are still in the same window.

Work Around for drag and drop in playwright python

I am trying to implement a drag and drop functionality(I was able to see there is an open issue regarding this) with the currently available mouse actions but so far not able to do that. so i am looking for a work around for that, is there anyway we can implement drag and drop in playwright python. below is the code that i am trying to use.
await page.mouse.move(472, 399)
await page.mouse.down()
await page.mouse.move(991, 313)
await page.mouse.up()
Thank you
I assume in your case the HTML5 drag and drop is not working.
Unfortunately at the time of writing this the current playwright python (1.10.x) won't trigger dragstart and drop events through the mouse.down, mouse.move and mouse.up API.
The following code however should work (using sync_api),
# This element should have the draggable attribute value as true
src_elem = page.query_selector('div.foo')
# This element should be the element as the drop target
dest_elem = page.query_selector('div.bar')
# Create a data transfer JSHandle instance
data_transfer = page.evaluate_handle('() => new DataTransfer()')
src_elem.dispatch_event('dragstart', { 'dataTransfer': data_transfer })
dest_elem.dispatch_event('drop', { 'dataTransfer': data_transfer })
# Now check whether the dropped effect is achieved
dest_elem.wait_for_selector('ENTER SELECTOR AFTER DROP EFFECT')

XamarinForms Shell OnResume - previous page is showing

I want to achieve lock mechanism in XF 4.5.0 Shell app.
I have static timer that counts how much seconds passed, and based on some logic present either screen that user was before put the app in behind (user went to instagram, but app is in the background running)
So, my OnResume() method looks like this:
private bool IsUserExists()
{
if (!string.IsNullOrWhiteSpace(GlobalAppSettings.Email) && !string.IsNullOrWhiteSpace(GlobalAppSettings.Password) && !string.IsNullOrWhiteSpace(GlobalAppSettings.Pin))
{
return true;
}
else
{
return false;
}
}
protected override void OnResume()
{
if ((!OnSleepOrPauseTime.HasValue || OnSleepOrPauseTime.Value.AddSeconds(5) <= DateTime.Now)
&&(IsUserExists()))
{
Xamarin.Forms.Device.BeginInvokeOnMainThread(async () =>
{
await Shell.Current.GoToAsync(Routes.LoginPinPage, false);
});
}
}
The problem: user sees for a like half second the screen where he was before, and then it redirects to LoginPinPage.
The happy path: Should be that user doesnt see that flickering page that was before exiting form an app, just immediately lock screen.
Possible solution: That crossed on my mind, before leaving the app to somehow redirect in background app to login pin screen?
PushAsync has 2 overloads - docs
By default the PushAsync method pushes the new page with animation. I think that this is the so-called "flickering" that you are referring to.
You can try to use the second overload and pass false for the animated property and see if it makes any difference.
PushAsync(new LoginPinPage(), false);
If you want to redirect the user on app leave - you can use another of the Application's lifecycle methods - OnSleep and invoke your navigation there. But I suggest to try it without animations first.
Keep in mind that, should you choose to use the OnSleep method, you will also have to push the page without animations. I have just tested pushing with animations and I do indeed see the flickering that you are mentioning. Setting the animated flag to false, removed any flickering for me.

After resume sometimes show the Home Screen on Nativescript-Vue

I have a problem with my application and his navigation.
My app have four screens but sometimes when tap the android home button in the second screen (or any other) and after resume the app, this show the home screen and not the last screen, any ideas to resolve this?
Update:
Sometimes after resume the app, this show the correct screen (the last showed) but I don't know how this happen (it's the same source code), I tested this in many versions of android simulator (4.4, 5.0, 7.0 y 8.0). Can this be a bug?
Screen Recording:
https://i.imgur.com/VhWFhWU.gifv
Code:
https://play.nativescript.org/?template=play-vue&id=wKkYCe&v=2
Thanks
It should be easy if you are using single frame in your application. You could listen to resume event of activity and call $navigateBack with a reference to first item in the back stack.
if (application.android) {
application.android.on(application.AndroidApplication.activityResumedEvent,
() => {
const backStack = frame.topmost().backStack[0];
if (backStack) {
setTimeout(() => {
this.$navigateBack({}, backStack);
}, 0);
}
}, this);
}
Playground Sample

Resources