How to wait for a page redirect in Selenium? - ruby

I am trying to perform a relatively simple task: to wait until a page redirect is complete. Just seen another answered question on the subject, where an advice is to wait for a particular text on the latter page to appear (IF I've got it right). If so, how about waiting till window.location will be changed? Is it better? Worse? Less applicable? Any other idea? just curious, if needed, can mark this question as a community wiki.
Thanks!

Yes I've encountered this problem many times when using Selenium. There are 2 ways I worked around this problem. First off you can actually change the implicit wait time. For example given this piece of code:
Actions builder = new Actions( driver );
builder.click( driver.findElement( By.className("lala") ) ).perform();
This code will throw an exception if at the point it's called there are no elements that could be found to match the "lala" class. You can change this implicit wait time with:
driver.manage().timeouts().implicitlyWait( 5, TimeUnit.SECONDS );
This makes the driver poll for 5 seconds instead of failing straight away. If the element still can't be located after 5 seconds then the action will fail. Of course you can change that setting. I found that this method works okay the majority of the time. Most of the time you don't care about the whole page loading, just a certain part.
I also wrote another function which is GetElementByClassAndText which will do the same as implicit wait on an element except it also checks the containing text as well to allow finer detailing of what you want:
public static void waitAndClick( WebDriver driver, By by, String text ) {
WebDriverWait wait = new WebDriverWait( driver, 10000 );
Function<WebDriver, Boolean> waitForElement = new waitForElement( by );
wait.until( waitForElement );
for( WebElement e : driver.findElements( by ) ) {
if( e.getText().equals( text ) ) {
Actions builder = new Actions( driver );
builder.click( e ).perform();
return;
}
}
}
And the corresponding Function it uses:
public class waitForElement implements Function<WebDriver, Boolean> {
private final By by;
private String text = null;
public waitForElement( By by ) {
this.by = by;
}
public waitForElement( By by, String text ) {
this.by = by;
this.text = text;
}
#Override
public Boolean apply( WebDriver from ) {
if( this.text != null ) {
for( WebElement e : from.findElements( this.by ) ) {
if( e.getText().equals( this.text ) ) {
return Boolean.TRUE;
}
}
return Boolean.FALSE;
} else {
try {
from.findElement( this.by );
} catch( Exception e ) {
return Boolean.FALSE;
}
return Boolean.TRUE;
}
}
}
I realise that you're using Selenium in Ruby but hopefully some of my code (at least conceptually) is transferable and helpful to you.

Monitoring the value, returned driver.get_location did the job perfectly to me.
Apparently, from what I've understood in my 5 mins peeping into the code was that window.location.href value is monitored under the hood.

You can use this function, it will re-load the current page ( after was redirected):
driver.getCurrentUrl();

Related

What is the purpose of getTonightFromDatabase() in the Android Kotlin Room codelabs?

I am trying to understand codelab 6.2 Coroutines and Room in Android Kotlin Fundamentals. Class SleepTrackerViewModel includes (with comments added by me):
private var tonight = MutableLiveData<SleepNight?>()
private suspend fun getTonightFromDatabase(): SleepNight? {
var night = database.getTonight() // this gets the most recent night
// Return null if this night has been completed (its end time has been set).
if (night?.endTimeMilli != night?.startTimeMilli) {
night = null
}
return night
}
fun onStartTracking() {
viewModelScope.launch {
val newNight = SleepNight()
insert(newNight)
tonight.value = getTonightFromDatabase()
}
}
fun onStopTracking() {
viewModelScope.launch {
val oldNight = tonight.value ?: return#launch
oldNight.endTimeMilli = System.currentTimeMillis()
update(oldNight)
}
}
I don't understand why the method getTonightFromDatabase(), which is called only from onStartTracking(), is needed. It seems the last statement in onStartTracking() could be replaced by:
tonight.value = newNight
I also don't understand why the conditional in getTonightFromDatabase() is needed.
One of the reasons is that the nightId in the SleepNight data class is auto generated by SQL.
If the code would do tonight.value = newNight then the nightId wouldn't be the same than the one in the database. That would cause the update call in onStopTracking to end (update) the wrong night.
Note too that the method getTonightFromDatabase is called from a later version of SleepNightViewModel:
private var tonight = MutableLiveData<SleepNight?>()
init {
initializeTonight()
}
private fun initializeTonight() {
viewModelScope.launch {
tonight.value = getTonightFromDatabase()
}
}
When the application restarts, getTonightFromDatabase is called to set the instance variable tonight (which would more accurately be called latestNight). If the most recent night was complete, the completeness check would ensure that null is returned, prevent the entry from being modified.

MVC mini profiler - manually adding step

I have lots of little actions (10-30 per page) and they're part of a recursive call, so I can't easily count them as a single step in the profiler. I get 30 short and distinct counters when I only need the total.
Is there a simple and straightforward way of manually adding a step to the mini profiler? or get it to sum up steps with the same name?
Also, is it possible to somehow put textual information there, not just timings?
I needed this as well, so I made this little thing. It works quite well.
A lot of useful properties in MiniProfiler are internal or similar, so some code is duplicated from the MiniProfiler source. Also note that since it's meant for inner loops it does not round to 1/10 millisecond.
public class GroupTiming : IDisposable
{
private Timing _timing;
private MiniProfiler _profiler;
private readonly Stopwatch _sw;
private Decimal? _previousDuration;
public GroupTiming( MiniProfiler profiler, Timing timing )
{
_timing = timing;
_previousDuration = _timing.DurationMilliseconds ?? 0;
_timing.DurationMilliseconds = null;
_profiler = profiler;
_profiler.Head = _timing;
_sw = new Stopwatch();
_sw.Start();
}
public void Dispose()
{
_timing.DurationMilliseconds = _previousDuration + ((decimal)(1000 * _sw.ElapsedTicks) / Stopwatch.Frequency);
_profiler.Head = _timing.ParentTiming;
}
}
public static class MiniProfilerExtensions
{
public static IDisposable StepGroup( this MiniProfiler profiler, string name )
{
return profiler == null ? null : profiler.StepGroupImpl( name );
}
private static IDisposable StepGroupImpl( this MiniProfiler profiler, string name )
{
Timing timing = null;
if( profiler.Head.Children != null )
{
timing = profiler.Head.Children.SingleOrDefault( _ => _.Name == name );
}
if( timing == null )
{
using( timing = new Timing( profiler, profiler.Head, name ) ) { }
}
return new GroupTiming( profiler, timing );
}
}
You want to "wrap" your recursive calls inside of a using statement. Something like this:
using (profiler.Step("Step A"))
{
// something recursive here
Thread.Sleep(100);
}
The "Step A" will be the total of your calls. Inside of that using statement you can do whatever you want. The "Step A" can be whatever information you want. You could put any string value in there and it will show up in the profiler. You can also add simple textual information by just doing a "step" without the using.
MiniProfiler.Current.Step("Some code after this");
That will just insert one line into the profiler output window. I've used that for spitting out exceptions or other debug information.

How to call delegate only once / one time with moles?

How is it possible to call a delegated Method only once / one time with moles?
MyClass.AllInstances.ResultateGet = delegate { return new ResultatInfoCollection(); };
I want to call the Method "ResultateGet" only one time because the init is quite complex the first time without a delegate.
target.UpdateResultate(); //calls delegate "ResultateGet"
//Assert some stuff
target.Verify(); //needs original function "ResultateGet" so unit test is useful
I am generally interested how to call a moles delegate one time ore a specific number of times before the original function is called and not the delegate.
Update:
I found a way, that seems a little bit cumbersome. Any better Solution?
ResultatInfoCollection x = new ResultatInfoCollection();
MolesContext.ExecuteWithoutMoles(() => x = target.Resultate);
Also, see my answer to: How to assign/opt from multiple delegates for a 'moled' method? This provides an example of gating logic inside the anonymous method.
Ooh, good question! I have encountered this, myself. What you are looking for is called a "fallthrough" behavior (execution of the original code). The anonymous method to which Moles detours must contain a switching mechanism that falls through, after the first call. Unfortunately, I don't believe a fallthrough feature is included in Moles, at this time.
Your updated workaround is exactly what you need -- calling fallthrough would do the same thing. I suggest adding a sentinel value, doFallthrough, that gates the calls:
bool doFallthrough = false;
ResultatInfoCollection x = new ResultatInfoCollection();
MyClass.AllInstances.ResultateGet = delegate {
if (!doFallthrough)
{
doFallthrough = true;
return new ResultatInfoCollection();
}
MolesContext.ExecuteWithoutMoles(() => x = target.Resultate);
};
Calling a specific number of times simply requires a change to the sentinel value type:
int doFallthrough = 0;
ResultatInfoCollection x = new ResultatInfoCollection();
MyClass.AllInstances.ResultateGet = delegate {
if (++doFallthrough < 5)
return new ResultatInfoCollection();
MolesContext.ExecuteWithoutMoles(() => x = target.Resultate);
};
Old question, but since I found it when I was searching, I'll answer it for the next person with my solution.
Using MolesContext.ExecuteWithoutMoles to call the original function works just fine in most cases, however, if you are moling any other functions or classes downstream from this call, they won't be moled, either.
Given the following class:
public class TheClass
{
public int TheFunction(int input){
return input + TheOtherFunction();
}
public int TheOtherFunction(){
return DateTime.Now.Minutes;
}
}
If you use the MolesContext.ExecuteWithoutMoles approach:
MTheClass.AllInstances.TheOtherFunctionInt = (instance) => {
return 5;
};
MTheClass.AllInstances.TheFunctionInt = (instance, input) =>
{
//do your stuff here, for example:
Debug.WriteLine(input.ToString());
var result = MolesContext.ExecuteWithoutMoles<int>(() => instance.TheFunction(input));
//do more stuff, if desired
return result;
};
Your mole for OtherFunction will not be hit, because it was (indirectly) executed within the "without moles" scope.
However, you can add and remove moles delegates at any time, so that allows you to do the following, as outlined in the Moles Documentation (p. 24)
MTheClass.AllInstances.TheOtherFunctionInt = (instance) => {
return 5;
};
MolesDelegates.Func<TheClass, int, int> molesDelegate = null;
molesDelegate = (instance, input) =>
{
//do your stuff here, for example:
Debug.WriteLine(input.ToString());
int result = 0;
try{
MTheClass.AllInstances.TheFunctionInt = null;
result = instance.TheFunction(input);
}
finally{
MTheClass.AllInstances.TheFunctionInt = molesDelegate;
}
//do more stuff, if desired
return result;
};
MTheClass.AllInstances.TheFunctionInt = molesDelegate;
The OtherFunction moles is still hit. With this method, you can remove moling just from the specific method without impacting your other moles. I've used this, and it works. The only trouble I can see is that it won't work if you have a recursive function, or possibly a multi-threaded situation.

Trying to get a DataRow[] Debugger Visualizer to work in Visual Studio 2010

I'm trying to get a DataRow[] DebuggerVisualizer working for VisualStudio 2010 and unfortunately I can't get it work work. I'm able to get the DataRow one working but not the DataRow[], I would love any please?
The meat of the code is here.
[assembly: DebuggerVisualizer(
typeof( PCHenry.DR ),
typeof( PCHenry.DRObjectSource ),
Target = typeof( DataRow[] ),
Description = "DataRow Array Debugger Visualizer (or so if you see this then it's working YAHOO!)" )]
namespace PCHenry
{
public class DR : DialogDebuggerVisualizer
{
protected override void Show( IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider )
{
StringBuilder stringToDebug = new StringBuilder();
using( Stream dataStream = objectProvider.GetData() )
{
BinaryFormatter formatter = new BinaryFormatter();
string incomingData = formatter.Deserialize( dataStream ) as string;
stringToDebug.Append( string.Format( "*!!!!{0}!!!!*", incomingData ) );
}
MessageBox.Show( stringToDebug.ToString(), "PCH String Debugger Visualizer", MessageBoxButtons.OK, MessageBoxIcon.Asterisk );
}
}
public class DRObjectSource : VisualizerObjectSource
{
public override void GetData( object target, Stream outgoingData )
{
if( target != null && target is DataRow[] )
{
DataRow[] rows = target as DataRow[];
BinaryFormatter formatter = new BinaryFormatter();
//formatter.Serialize( outgoingData, target );
formatter.Serialize( outgoingData, string.Format( "There are {0} rows of data", rows.Length ) );
}
}
}
}
As I hope you can see, I'm trying to set the Target correctly, but it's not being used by VS at runtime/debugging time. Yes, I am copying the DLLs to the correct Visualizers directory. In fact, I'm using a BuildEvent to do that work for me.
xcopy "$(SolutionDir)$(ProjectName)\$(OutDir)$(TargetFileName)" "$(USERPROFILE)\Documents\Visual Studio 2010\Visualizers" /y
When I test this, I use this.
static void Main( string[] args )
{
//String myName = "Peter Henry";
#region DataSetup, create a Habs DataTable and populate it with players
DataTable table = new DataTable( "Habs" );
table.Columns.Add( "PlayerNumber", typeof( Int32 ) );
table.Columns.Add( "PlayerName", typeof( string ) );
table.Columns.Add( "Position", typeof( string ) );
//team as current as 09-23-2010 from the Canadiens! GO HABS GO!
table.Rows.Add( new object[] { 32, "Travis Moen", "F" } );
table.Rows.Add( new object[] { 94, "Tom Pyatt", "F" } );
table.Rows.Add( new object[] { 75, "Hal Gill", "D" } );
table.Rows.Add( new object[] { 26, "Josh Gorges", "D" } );
table.Rows.Add( new object[] { 76, "P.K. Subban", "D" } );
table.Rows.Add( new object[] { 35, "Alex Auld", "G" } );
#endregion
//use this to show the debugger in two different ways
DataRow[] defencemen = table.Select( "Position = 'D'", "PlayerNumber" );
//this proves this works when told which ObjectSource to use
VisualizerDevelopmentHost host = new VisualizerDevelopmentHost(
defencemen, typeof( PCHenry.DR ),
typeof( PCHenry.DRObjectSource ) );
host.ShowVisualizer();
//but when I try to use VS debugging here, it can't seem to find the custom DebuggerVisualizer as I would expect
defencemen = table.Select( "Position = 'D'", "PlayerNumber" );
Debugger.Break();
Console.WriteLine( "FIN" );
Console.ReadLine();
}
The key here is, the VisualizerDevelopmentHost works correctly, and I can only guess cause it's told which VisualizerObjectSource to use. But when I hit the Debugger.Break(); line and try to use it like normal, I can't see the magnifying glass for the defencemen DataRow[].
I believe in the bottom of my heart this can be done. I read on MSDN DataRow couldn't be done, but I got it to work. I really do hope you can help me out there to get this working.
Thank you very much guys for your replies. You confirmed what I was thinking (well, what I was coming to realize after four nights of fighting with it!). Thanks again. I blogged about it and referenced this information. Thank you very much for your time.
Visual Studio Debugger Visualizers (Take Three)
For the most part what Spike says is true. You can write a visualizer for anything "except Object or Array": http://msdn.microsoft.com/en-us/library/e2zc529c.aspx
"Array" seems a little ambiguous; but there's lots of people with the same problem...
I haven't been able to find anything specific to this (and haven't tried it) but, what about IEnumerable? Does that work?
There's also an interesting article of getting around limitations on the types of objects a Visualizer can except here: http://joshsmithonwpf.wordpress.com/2008/01/20/the-rock-star-hack-of-2008/
Debug Visualizers don't work for arrays.
You can write a custom visualizer for
an object of any managed class except
for Object or Array.
http://msdn.microsoft.com/en-us/library/e2zc529c.aspx
The visualized type has to be attributed [Serializable] or implement ISerializable.
Arrays don't implement ISerializable and cannot be attributed. For some reason.
Lists work, though, so I sometimes make a new list<>, just for debugging purposes.

How do I read the Received Date from Outlook MSG files -without- the Outlook API?

I need to read stuff from an Outlook msg file. Currently I'm using a class from CodeProject.com project to accomplish this, since deploying VSTO and Outlook on a server is not an option.
This class gets To, From, CC, Subject, Body, and everything else I need from the msg file, except Date information (such as Received Date and Sent Date).
There is some (really, really low-level) documentation on how to get stuff out of msg files on MSDN, but it's a little beyond the scope of this project and doesn't mention dates at all.
Ideally I'd be able to have a drop-in replacement for the class I am using now (OutlookStorage.cs in the previously mentioned CodeProject) or be able to modify the existing class a bit. To modify, I would need the correct 4 character hexidecimal prop identifier for received date. For instance, Subject is listed as PR_SUBJECT = "0037" and Body is listed as PR_BOY = "1000".
If you're using OutlookStorage.cs from CodeProject, then add the following:
private const string PR_RECEIVED_DATE="007D";
private const string PR_RECEIVED_DATE_2 = "0047";
...
/// <summary>
/// Gets the date the message was received.
/// </summary>
public DateTime ReceivedDate
{
get
{
if (_dateRevieved == DateTime.MinValue)
{
string dateMess = this.GetMapiPropertyString(OutlookStorage.PR_RECEIVED_DATE);
if (String.IsNullOrEmpty(dateMess))
{
dateMess = this.GetMapiPropertyString(OutlookStorage.PR_RECEIVED_DATE_2);
}
_dateRevieved = ExtractDate(dateMess);
}
return _dateRevieved;
//return ExtractDate(dateMess);
}
}
private DateTime _dateRevieved = DateTime.MinValue;
private DateTime ExtractDate(string dateMess)
{
string matchStr = "Date:";
string[] lines = dateMess.Split(new String[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{
if (line.StartsWith(matchStr))
{
string dateStr = line.Substring(matchStr.Length);
DateTime response;
if (DateTime.TryParse(dateStr, out response))
{
return response;
}
}
}
return DateTime.MinValue;
}
I think the Aspose library will do what you want, ok it a 3rd party lib so may not be what you want. There are a few vbs scripts around that get basic infomation out of msg files that could be translated.
Got a hint from this:
string fullFileName = "c:\message.msg";
DateTime dateRevieved = new DateTime();
StreamReader sr = new StreamReader(fullFileName, Encoding.Default);
string full = sr.ReadToEnd();
string date;
int iStart;
int iLast;
string caption;
//This -should- handle all manner of screwage
//The ONLY way it would not is if someone guessed the -exact- to-the-second
//time that they send the message, put it in their subject in the right format
while (true) { //not an infinite loop, I swear!
caption = "Date:";
if (full.IndexOf("Date:") > -1) { //full shortens with each date is removed
string temp = "";
iStart = full.LastIndexOf(caption);
temp = full.Remove(0, iStart + caption.Length);
full = full.Substring(0, iStart);
iLast = temp.IndexOf("\r\n");
if (iLast < 0) {
date = temp;
} else {
date = temp.Substring(0, iLast);
}
date = date.Trim();
if (date.Contains(subject) || subject.Contains(date)) {
continue; //would only happen if someone is trying to screw me
}
try {
dateRevieved = DateTime.Parse(date); //will fail if not a date
break; //if not a date breaks out of while loop
} catch {
continue; //try with a smaller subset of the msg
}
} else {
break;
}
}
This is kind of a hack compared to the ways you can get other things from msg files using something this lovely project. Still, it's stood up to everything I have thrown against it, and as noted the -only- way to fool it is to put the exact to-the-second date in the subject line in the proper format.
to combine your two posts I would suggest the following solution:
To modify, I would need the correct 4 character hexidecimal prop identifier for recieved date. For instance, Subject is listed as PR_SUBJECT = "0037" and Body is listed as PR_BOY = "1000".
Look for "007D".
Use the method you posted in your second post on the received data to eliminate the problem when the same (date) string is inside the subject.
I have to mention that this method doesn't seem to work on internal eMails: In mails I receive from colleagues, there is no substg1.0_007Dxxxx-Property.
Here, the date seems to be hidden in substg1.0_0047xxxx.
All the best!
inno

Resources