Programmatically back out of first page of your application - silverlight

I have a login page which is shown on first launch. After the user puts in his credentials he is taken to the main page of the application. At this point, if the user presses the back key I want it to skip the login page and exit. I tried what was suggested here: Remove a page from Navigation Stack (in OnNavigatedTo, use NavigationService.GoBack()) but it throws an exception because there is nothing else in the back stack. I read some other places that not handling exceptions is basically the only way to close the app...
The problem with this method of closing the app is, well other than being a hack, it doesn't hit Application_Closing() so my state isn't saved.
Anyone know how I can skip the login page when hitting the back key, save state, and exit the application?
Thanks in advance!

Yeah, this is becoming a huge problem with Navigation in WP7 - many folks are complaining about this same type of issue. The key to remember is that Navigation mimics navigation of a website - it acts a lot less like UserForms and more like web pages and their static history.
The easiest way around this which is both transparent to your users and easy for you is to make that first login page you are reference as User Control that sits on top of your actual main page (i.e. don't use a phone:PhoneApplicationPage for your login page - just a control that is part of your main page phone:PhoneApplicationPage). Use a boolean in your OnNavigatedTo on the main page that says "if user is not logged in, display login control, otherwise, just show main page."
On saving state (i.e. tombstoning), ask another question as that's another topic.

The general best practice is to not use a page for anything you dont want in the navigation stack.
In my case i chose to use a Popup to host my Login Control. I pop it from my mainpage if they are not logged in. If they are i dont show it. This way if they are not logged in and hit back, they exit the app. However if they are logged in and also on teh main page, they see their data, and if they hit back they also exit the app (not see the login page).

For the login / home page scenario one thing you can do is on successful login rather than navigating to the home page you call "GoBack", this will take them back to the home page, but pop the login page off the navigation stack and allow the user to exit the app on the next press of the back button.

Related

Robot Framework Click Button vs Submit Form

I'm new to Robot Framework and stuck with quite simple login web page test using SeleniumLibrary:
*** Test Cases ***
Valid Login
Open Browser To Login Page
Input Username admin
Input Password test
Submit Credentials
Dashboard Page Should Be Open
[Teardown] Close Browser
Most of the keywords are irrelevant to the question, except
Submit Credentials
Click Button login-button
Dashboard Page Should Be Open
Location Should Be ${DASHBOARD URL}
Title Should Be Dashboard
If I run this test, it will fail, because Location Should Be check is executed too early, while browser is still on the original login page. I found two solutions that work, but both seems to be conceptually wrong:
Use sleep
Submit Credentials
sleep ${DELAY}
Dashboard Page Should Be Open
In this case ${DELAY} should be quite big (e.g. 10s) to be sure that page is definitely loaded or it may fail anyway. Also, I've read that best practice is to avoid sleeps. And I can't use some Wait Until Page Contains, because I don't know, whether login page will be loaded again with some error message or Dashboard page loaded in success.
Use Form Submit instead of Click Button:
Submit Credentials
Submit Form login-form
The Form Submit works fine, but it's different from actually clicking a button, because button may have some onclick handler that would prevent submitting a form.
Using Wait Until Keyword Succeeds as suggested in some other threads doesn't seem to help, as Click Button succeeds right away.
You definitely should not use sleep since it introduces artificial delays that may make your whole suite slower than it needs to be. I personally also thing Wait until keyword succeeds should almost never be used. It litters the log with messages as it retries. Plus, I think it masks problems instead of fixing them.
The answer is to use one of the wait keywords. You say you can't use Wait Until Page Contains ""because I don't know, whether login page will be loaded again with some error message or Dashboard page loaded in success". I don't understand that reasoning.
Your application should be deterministic. That is, if you enter correct login credentials than you should be guaranteed that it will go to the dashboard page, and if you enter the wrong conditions you should see an error and/or be redirected back to the login page.
The point of the test is to verify those conditions. So, for a test that verifies whether you get the dashboard page or not, you should find an element on the dashboard page and wait for it to be visible after submitting the form. If it doesn't appear in the proper amount of time, your test should throw an error.
Personally I recommend using page objects. The library I wrote [1], for example, has a mechanism to wait for a page refresh, and assertions to verify you are on the page you think you should be on. You don't need to use my library though -- the core of the code is only a couple hundred lines of code, so it's easy to write your own.
[1] https://github.com/boakley/robotframework-pageobjectlibrary

Complex url history on a Backbone Marionette application and back button

There are 2 web applications, ours and the other team. The other team's web app is http://otherteam.com and our application is http://myteam.com
On http://otherteam.com webpage, they have an href link pointing to our page which is http://myteam.com/config?lang=en. When our web application(actually Marionette AppRouter's task) receives that kind of route or path, it will parse it and set the language configuration and then we have a code to redirect the user to the final webpage which is http://myteam.com/landingpage
The code that we are using is
Backbone.history.navigate('landingpage', {replace: true});
to redirect the user to the final destination.
Unfortunately, when user clicks Back button of the browser, it doesn't go back to http://otherteam.com. It will go back to http://myteam.com/config?lang=en which is still our own application. What happens is that the Marionette app router will parse it again similar to how I described it above. The user will just be brought back to http://myteam.com/landingpage
So I changed
// Backbone.history.navigate('landingpage', {replace: true})
and now I'm using
history.replaceState({}, '', 'landingpage');
When I click Back button, the url on the top bar beocmes http://myteam.com/config?lang=en, but it doesn't reload our landingpage anymore which is good. However, nothing happens to the page until I click Back button again. After making the second click on the Back button, I'm back to http://otherteam.com which is great but I had to click the Back button twice.
The problem is you are redirecting the user from the /config?lang=en to another page, so when you click back, they land on the previous page and are then redirected back to the landing page again.
The simplest solution here would be for otherteam.com to link to your landing page and pass the params to be consumed there - http://myteam.com/landingpage?lang=en. Redirecting the user multiple time is never a good idea, and almost always unnecessary.
Once you have received the lang config param, it could be an idea to save it to local storage so it can be retrieved wherever it is needed throughout your app.

stop Angular from running the rest of the script and perform another action

I've been working on replacing alert() pop-ups in our Angular code with Angular overlay modals. I'm almost done with the exception of one problem.
I have a modal that opens when the user login has timed out. Some pages will load, fire the script properly and the overlay will be in focus, waiting for the user to click "ok" which sends them to the login page - which is what I want.
On other pages, content will partially load, then fire the overlay modal and for a split second I will see it, then the page continues to load, the modal goes away and even though they get logged out the page doesn't go to the login page.
I need some direction determining what code I should add after the overlay fires to prevent any other code from executing so the user has to interact with the overlay.
I'm sorry I can't share any code - it's proprietary - I just need some direction to go in.
This is very difficult to answer without having access to any code or fully understanding how you are managing various states/views.
A simple solution would be adding a function to the $rootScope which constantly checks if a user is authenticated (aka not timed out). And then have it perform some action if the user is no longer authenticated.
How you store the authentication indicator is completely up to you. Without knowing more about the app it would be difficult to say where the best place would be.
Example code:
$rootScope.checkAuth(){
if (!$sessionStorage.auth){
$state.go(login)
}
}
setTimeout($rootScope.checkAuth,10000)
You could also handle this by not resolving each view/state until a user has been confirmed as authenticated. Once again, how you set that up would be dependent on the structure of your app.

AngularJS routing /profile redirects to /profile/register when not logged in, browser history saves both routes

I'm facing a problem don't know how to solve. I would like to get some light here.
Given an AngularJS application that routes using the standard $routerProvider, and considering the fact that whenever an end user tries to access a private area he gets redirected to the register area, happens the following:
User just landed onto de application (didn't get logged in).
User goes to /profile
The application checks whether there is session info in the client or not.
The application redirects to /profile/register
User clicks on "Back" button of the browser and goes to /profile.
(Next step is number 3 again and again).
This happens because each time the application redirects using the $routerProvider, it pushes all routes in the browser history.
My question is, how can I jump the failed /profile access over the browser history? How can I tell the browser do not save this route under given conditions
like the user is logged in?
FAQ regarding history: https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history
Supposing you're using the $location built-in service to redirect, you can use $location.replace() to replace the current history entry:
if (notLoggedIn) {
$location.url( "/profile/register" );
$location.replace();
}
Note that this will apply to current digest only, as noted in the API docs.

Loading a separate page for this navigation instance

i have just had an app denied in the windows phone market place because i didn't adhere to the "close application on back button" rule.
currently i am doing the following:
open app
if you've never entered your details, navigate to the save details page
on arriving at this "first entry" page i cancel the use of the back button
because as you can see the first view that the user sees is my "first entry" page although i'm trying to be smart and lock the user from going back to an empty main page (because they havent entered their details) i'm really stopping them from exiting on the first screen.
as there is no way to exit using code in silverlight as per
http://blogs.msdn.com/b/ptorr/archive/2010/08/01/exiting-a-windows-phone-application.aspx
what am i supposed to do?
should i let the user navigate back and then try and capture that they have just hit back and navigate back again? (this seems like and odd way of doing it)
or is there a way for me to capture the first navigation instance and simply not store the first page actually loading into the history, so that when they hit back, it exits anyway?
I'm going to assume you mean "close app on back button rule"
I think the approach that will work for you and stick within cert reqs is to redirect the intial navigation... this will cause your initial page to not enter the backstack. Peter offers two implementations for this here.
Redirecting an initial navigation - Peter Torr's Blog

Resources