Why does this Spectron code block my Electron app after the first click? - electron

This is the first time I'm trying to create automated tests for an Electron app using Spectron. It might be my rusty knowledge of async programming but I don't know why the code below is misbehaving:
it ('should allow me to create an account', function() {
return app.client
.waitUntilWindowLoaded()
.waitForExist('//a[text()="Create Free Account"]')
.click('//a[text()="Create Free Account"]')
.waitForExist('//button[text()="Create Account"]')
.setValue('#Email', "test#test.com")
.setValue('#Password', "Password1!")
.click('//button[text()="Create Account"]')
.waitForExist('//p[contains(text(),"Almost done.")]')
});
The test seems to get as far as the first click(), then it should wait for the App to request a new page, eventually displaying a "Create Account" button. However, for some reason, the app itself seems to block at this point. I know the click is occurring. When I try it manually, the app behaves properly.
Mark

I think you need to wait till the next page loads
Also chain
.pause(3*1000)
after clicking the button
(Or)
.waitUntilWindowLoaded(3*1000)

Related

React Native Detox - Local and CI have different outcomes

I am having strange issue with React Native Detox testing when being ran on local and CI environments.
Following is the piece of code being ran on both of the environments:
import { E2E_IDS } from './constants';
import {
executeBeforeEachTest,
tapById,
testAccount,
typeTextById,
waitForId,
waitForText,
} from './utils';
describe('User email sign in flow test', () => {
beforeEach(executeBeforeEachTest);
it('should login with provided user credentials successfully', async () => {
await tapById(E2E_IDS.SIGN_IN);
await waitForText('Welcome back');
await tapById(E2E_IDS.SIGN_IN_VIA_EMAIL);
await typeTextById(E2E_IDS.SIGN_IN_EMAIL, testAccount.USER);
await typeTextById(E2E_IDS.SIGN_IN_PASSWORD, testAccount.PASS);
await tapById(E2E_IDS.SIGN_IN_LOGIN_BUTTON);
await waitForText('You have no classes yet.');
});
});
On my local mac machine, e2e tests runs fine as expected.
On Github CI mac machine, e2e fails because single tap on SIGN_IN_LOGIN_BUTTON is not enough, if I do the following:
await tapById(E2E_IDS.SIGN_IN_LOGIN_BUTTON, 2);
If we tap the button twice, then it passes the test. I wonder why the first tap is not being acknowledged by the CI machine, that we had to do twice.
If anyone could help narrow down the root cause of this behaviour that would be great.
The last issue was quite tricky, it was actually a UX bug. So, when user types their email and password in the login form, the keyboard doesn't drop when we tap on the login button, because we had a keyboard overlay which is blocking the login button being tapped. To circumvent this issue, we need to add keyboardShouldPersistTaps='handled' to the top level scrollView which will trigger down the tap events to it's child which will result in closing the keyboard plus the tap to right element, all in one go.
It was strange why this didn't happen on my local simulator, perhaps, we can toggle the keyboard on/off which didn't help me to narrow down the issue at hand.
Why 2 taps?
Because, first one was to drop the keyboard (inactive state) then the next one was to tap on the login button.

How to test if Xamarin Android app closes

I am writing my first Android app, using Xamarin. I have an Exit button that, when clicked, closes the app. I want a test in Xamarin UITest that verifies clicking the button closes the app. I messed around with it for a while and finally found something that allows the test to pass.
In the app:
exitButton.Click += (o, e) =>
{
int pid = Android.OS.Process.MyPid();
Android.OS.Process.KillProcess(pid);
};
In UITest:
[Test]
public void ExitButtonClosesTheScreen()
{
try
{
app.Tap(c => c.Button("exitButton"));
Assert.Fail("App remains open.");
}
catch (System.Exception e)
{
Assert.AreEqual("The underlying connection was closed: The connection was closed unexpectedly.", e.InnerException.InnerException.InnerException.Message);
}
}
The test now passes so I guess I'm happy. My question is, is this really the best way to do this? Or is there a better way that I wasn't able to find?
Edit: Unfortunately, this is not the answer. This method allows the test to pass in VS but fails when I run it in App Center. Is there another way to run this test? Or is this something that is simply not testable with UITest? Thank you.
First of all the right code for closing the Application as per me is using finish affinity
In an Activity:
this.FinishAffinity();
In a Fragment:
this.Activity.FinishAffinity();
After doing this AppCenter should be able to figure that your app is closed.
I did a brief read up on this the other day for something similar and I am certain that the ActivityManager class would be the best way to go about this.
https://developer.xamarin.com/api/type/Android.App.ActivityManager/
There is a method within this class called RunningAppProcesses which returns a list of application processes that are running on the device - and from there I guess you can assert if your app process is on the list or not.
Hope this helps
After almost 4 years, i've encountered with the same issue.
I will do it this way in your case:
[Test]
public void ExitButtonClosesTheScreen()
{
app.Tap(c => c.Marked("exitButton"));
/** I asume exitButton click action will just exit,
no popups or alerts appear before exiting. **/
app.WaitForNoElement(q => q.Marked("exitButton"),
"Timeout waiting for element exitButton",
new TimeSpan(0, 0, 30));
AppResult[] result = app.Query();
Assert.IsTrue(result.Length == 0);
}
app.Query() returns all views visible by default, unless a query is especified by a lambda expression, as you should alredy know.
If the Application is gone, the Views visible will be 0, and as such, app.query() will return and array lenght of 0.
For WaitForNoElement's timeout I use a TimeSpan of 30 seconds, but you can use whatever timeout you prefer for this operation, i just considered 30 seconds will be ok.

IIOS IPAD No Unload,beforeunloador, paghide events

I have a MVC web database application where the records are basically documents with items.
Documents are locked, not items and they locked by code when the user looks in any of 4 or 5 different screens for any given document.
there is a 10 minute time out on the record locks. The user does not do anything with the record for 10 minutes and another can take the record. There is code that detects the lock was lost and taken by someone else. It works fine and is technically sound.
The workflow of the application relies on the lock being released when the user leaves the screen or closes the browser, or if they press the refresh button.
These are work fine on windows and android but not on ipad.
I understand there is no
beforeunload
on ios but I though there was
unload
or
pageHide
neither of these work.
Here is my code.
var isOnIOS = navigator.userAgent.match(/iPad/i)||
navigator.userAgent.match(/iPhone/i); var eventName = isOnIOS ?
"pageHide" : "beforeunload";
window.addEventListener(eventName, function (event) {
ReleaseRecordLock(); } );
This code works on all mentioned platforms except that the events don't fire on IOS.
It looks to me that this is deliberate on Apple's part so I an not thinking it will change.
So now the question.
What can I do to ensure that these records get unlocked if a user changes screens or closes the browser. If they don't no users will be able to access the document for 10 minutes which will not be acceptable.
Thanks
Edit... I don't need pop ups or notification. I just need reliable unlocking
As mentioned above none of the events that are supposed to work actually fire. pageHide and unload do nothing.
I found mentions of how to get around this problem but no details so I though I would detail it here.
This solutions works with areas and standard sites.
My solution to get around part of this was to detect if the browser is running on IOS and if so to change the link in the menu.
<li>
#{
if(Request.UserAgent.Contains("iPad") || Request.UserAgent.Contains("iPhone"))
{
<a onclick="IOSReleaseLock('controller', 'action')" href="javascript:void(0);">LinkText</a>
}
else
{
#Html.ActionLink("link Text","action","controller",new { Area = "Tasks" },null);
}
}
</li>
Every single link in the application has to have a function called IOSReleaseLock() available or the solution will not work. Not all pages lock records, only those that actually change documents. Reports, and basic website functions such as change password, log out, and the sys admin stuff do not need record locks.
At this point I have 2 versions of IOSReleaseLock()
This is the version that is used on pages that do not required unlocking.
function IOSReleaseLock(_controller, _action)
{
var url = '/__controller__/__action__/';
url = url.replace('__controller__', _controller);
url = url.replace('__action__', _action);
window.location.href = url;
}
This is the version that is placed on pages that required unlocking.
function IOSReleaseLock(_controller, _action )
{
var url = '/__controller__/__action__/';
url = url.replace('__controller__', _controller);
url = url.replace('__action__', _action);
UnloadingRecordLockRelease();
window.location.href = url;
}
Every link has a wrapper so every single page must load a version of IOSReleaseLock(). This includes your /home/index or where ever your application starts. If you miss one then once you are on that page your menu system links will not work anymore.
Pages that require the UnloadingRecordLockRelease() function load that version and the pages that do not require unlocking load the first version.
On IOS every time you click a link, IOSReleaseLock() is called. This may seem to be obvious, but for clarity, the version of IOSReleaseLock() that executes is the version that is on the current page, not the version on the page you are going to.
So as long as the user stays on the site and does not close the browser then the records are unlocked correctly.
When the user logs out all records are unlocked but I have no solution for when the browser tab is closed or when the browser is closed without the user logging out.

Testing screen tracking with UI automation on iOS

So I had this idea to test the implementation of my screen tracking (with Google Analytics) on my app using UI automation.
The original idea was to build a UI script to go through the screens while checking if the tracking events are being sent accordingly. I need this as sometimes I'm not able to compose everything out of view controllers or the events are not forwarded in the expected order. Regardless of that, I should test this aspect of my app as well and I thought that UI automation was the answer.
I have implemented a script to go through the screens using the UI automation instrument and this is working correctly. I even went so far as using tuneup js to make the code more streamlined and easier to follow.
I was expecting to have something like (in general terms, the syntax is only a simplification):
Being on screen X
Tap button A
Expect screen Y and tracking event for the screen Y
However, as far as I was able to check, testing the screen tracking is something that is not possible with the UI automation.
Or am I missing something?
I thought of creating an invisible view that stays on top of all the view hierarchy and changing its name every time a new screen is loaded to allow me to test it with UI automation but the idea sounded a little over the top...
What do you people suggest? Look for another UI automation tool? Do it with unit testing instead?
Thanks in advance for any help
You could use a UIAlertView and inspect those alerts. Instead of sending the analytics events you can pop up the alert so you can check on it in UIAutomation.
Analytics abstraction frameworks like AnalyticsKit provide an easy way to change the analytics provider. And AnalyticsKit even has an example for that (take a look at the AnalyticsKitDebugProvider class). So the changes to your production code are minimal.
You could use a build configuration where you set a build variable to control the initialization of your analytics
id<AnalyticsKitProvider> provider
#ifdef USE_UI_AUTOMATION_ANALYTICS
provider = [[TestAutomationProvider alloc] init];
#else
provider = [[RealProvider alloc] initWithApiKey:API_KEY];
#endif
[AnalyticsKit initializeLoggers:#[provider]];
In UIAutomation you can test for the alert coming up. You can utilize assertions.js out of the tuneup.js package to write a function like this
function checkForAlert()
{
var alert = null;
retry( function() {
log("wait until alert appaers");
alert = UIATarget.localTarget().frontMostApp().alert();
assertNotNull(alert, "No alert found");
assertTrue("The name you can choose for the alert" == alert.name());
}, 5, 1.0);
return alert;
};
This combines waiting for the alert and testing if it finally appear. If the alert not appears, the test will fail.
In your test you use this in the following way:
var analyticAlert = checkForAlert() // if alert appears it will be in the var, otherwise the test fails at this point.
analyticAlert.buttons()["OK"].tap(); // dismiss the alert
To make this work you also need to set an onAlert handler. Otherwise UIAutomation would try to dismiss your alert immediately. This has to be done before your tests code. Alert handling is explained in the UIAutomation docs.
function MyOnAlertHandler(alert)
{
if("The name you choose"==alert.name()) // filter all alerts created by analytics provider
{
return true; // handle alert in your test
}
return false // automaticly dismiss all other
}
UIATarget.onAlert = MyOnAlertHandler; // set the alert handler

Firefox SDK - Detecting back button in extension

I'd like to do the equivalent of chrome.tabs.onUpdated in Firefox. tabs.on('ready', function(tab){}) does not work because it does not detect the back button. How do I fire an action on every page load such that it also detects the back button using the Firefox SDK?
You'd have to use require('window-utils').WindowTracker to all windows, filter for browser windows with the require('sdk/window/utils').isBrowser(window) method, then listen to click events on the back button.
It's currently impossible, but will be possible in a future version of Firefox:
https://github.com/mozilla/addon-sdk/commit/e4ce238090a6e243c542c2b421f5906ef465acd0
A bit of a late answer, but for anyone reading this now (from 2016), it is now possible to do using the SDK!
Using the High-Level API tabs, you need to listen for the pageshow event. (More about this on MDN)
An example:
tabs.on('pageshow', function(tab) {
// Your code here
})
It is very similar to the load and ready events, the main difference being that is is also fired when a page is loaded from BFCache (which it is when the back button is pressed).
I think the following snippet gives the functionality of chrome.tabs.onUpdated
var tabs = require("sdk/tabs");
tabs.on('ready', function(tab){
console.log(tab.url);
});

Resources