Need a better way to wait for ajax operation to complete

13 posts, 0 answers
  1. Ross
    Ross avatar
    3 posts
    Member since:
    Jun 2011

    Posted 22 Jun 2011 Link to this post

    Currently using a while loop to check for a variable to not be null and using thread.sleep(250) to wait after checking if it is.  Cannot find a better way to do this, does anyone have any ideas?

    [CodedStep(@"Find and click on course link")]
      public void FindAndClickOnCourseLink()
      {
                      string textContent = ((string)(System.Convert.ChangeType(Data["CourseName"], typeof(string))));       
            
                      HtmlAnchor expectedLink = null;
           
                      var attempts = 0;
           
                      while (expectedLink == null)
                      {
                          var rows = Find
                              .ById("activitiesTable")
                              .As<HtmlTable>()
                              .AllRows;
           
                          expectedLink = rows
                              .Select(row => row.Cells[0].Find.AllByContent<HtmlAnchor>(textContent).FirstOrDefault())
                              .Where(a => a != null)
                              .FirstOrDefault();
           
                          attempts++;
                           
                          //TODO: This is not very elegant but it works, needs something better.
     
                          if (attempts > 20)
                          {
                              break;
                          }
           
                          System.Threading.Thread.Sleep(250);
                      }
           
                      expectedLink.Click();
                  }
      }
  2. Cody
    Admin
    Cody avatar
    3360 posts

    Posted 27 Jun 2011 Link to this post

    Hi Ross,

    That's pretty much the best way to wait for an AJAX postback to complete. The only thing I would change is to use a System.Diagnostics.Stopwatch, adding it to your while statement instead of counting attempts.

    Kind regards,
    Cody
    the Telerik team
    Register today for a live 'What's New in Test Studio R1 2011 SP2' event on Tuesday, July 19 at 2pm EST!

    Have you looked at the new Online User Guide for Telerik Test Studio?
  3. Ross
    Ross avatar
    3 posts
    Member since:
    Jun 2011

    Posted 28 Jun 2011 Link to this post

    Hi Cody,

    Thanks for your reply, I will add the stopwatch instead.  However it is slightly disappointing, I was hoping that there was a way tell it to wait until all active connections to the web server have closed, which would signify that all AJAX operations are completed. For example in selenium I can write a waitForCondition  against "selenium.browserbot.getUserWindow().$.active == 0"  to check that all jQuery connections have closed, after which I can continue executing the test. 
    I would need to perform this kind of operation on different parts of our website many times throughout my test scripts and this is quite a lot of code to write each time, I was hoping for something similar to the above.

  4. Cody
    Admin
    Cody avatar
    3360 posts

    Posted 29 Jun 2011 Link to this post

    Hello Ross,

    Thank you very much for that tip!! I did some research on how selenium.browserbot.getUserWindow().$.active == 0 works and came up with something that does work pretty slick for AJAX. Here is the code:

    [CodedStep("Wait for AJAX")]
            public void AjaxWait()
            {
                Wait.For<int>(c => ActiveAjaxConnections() == 0, 0, 10000);
            }
     
            public int ActiveAjaxConnections()
            {
                return Actions.InvokeScript<int>("jQuery.active");
            }

    In this example I am waiting up to 10 seconds for all AJAX connections to close. Feel free to contact me again if you need additional help with this.

    Kind regards,
    Cody
    the Telerik team
    Register today for a live 'What's New in Test Studio R1 2011 SP2' event on Tuesday, July 19 at 2pm EST!

    Have you looked at the new Online User Guide for Telerik Test Studio?
  5. Ross
    Ross avatar
    3 posts
    Member since:
    Jun 2011

    Posted 30 Jun 2011 Link to this post

    Hi Cody, 

    That's just what I was looking for, thanks for your help.  I'll add it to my tests and get back to you if I have any trouble with it.

    thanks,

    Ross
  6. Steve
    Steve avatar
    35 posts
    Member since:
    Jan 2011

    Posted 15 Mar 2012 Link to this post

    When I try to use InvokeScript, VS 2010 complains 'C#: There is no such reference available here' - what am I doing wrong?  I have a reference to the Webaii.dll, version 2011.2.1413.0. I right click the word 'Actions' and select resolve, and it finds and resolves it...


    I'm thinking this solution will help me with knowing when an ajax call is finished...

    Thanks-
    Steve
  7. Cody
    Admin
    Cody avatar
    3360 posts

    Posted 16 Mar 2012 Link to this post

    Hello Steve,

    Is this the exact error message that VS2010 is reporting?
    'C#: There is no such reference available here' 

    I don't recognize that error message and do not understand what it means. Can you send me a clear screen shot of the error message? Or better yet can you send me your test project for diagnosis? I don't need to run your test, I'll just make sure it compiles correctly and send you back the necessary corrections.

    Kind regards,
    Cody
    the Telerik team
    Quickly become an expert in Test Studio, check out our new training sessions!
    Test Studio Trainings
  8. Steve
    Steve avatar
    35 posts
    Member since:
    Jan 2011

    Posted 16 Mar 2012 Link to this post

    Thanks for your response - I got it working, but it doesn't work like I had hoped - it always says there are 0 connections, so either we are doing something different, or my quad core machine is too fast.  So, I'm looking at turning on the http proxy and seeing if I can get the response back from the javascript XmlHttpRequest, and when it arrives back, I can then expect the control that's supposed to redraw has redrawn, and I can then use the telerik controls to get the contents.  But, examples for doing anything similar are sparse in the forums (always my problem) - do you have any examples of using the HTTPProxy?
  9. Cody
    Admin
    Cody avatar
    3360 posts

    Posted 16 Mar 2012 Link to this post

    Hi Steve,

    Here is a fairly complete yet simply sample:

    using System;
    using System.Text;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
     
    using ArtOfTest.WebAii.Core;
    using ArtOfTest.WebAii.ObjectModel;
    using ArtOfTest.WebAii.TestTemplates;
    using ArtOfTest.WebAii.TestAttributes;
    using ArtOfTest.WebAii.Win32.Dialogs;
    using ArtOfTest.WebAii.Controls.HtmlControls;
    using ArtOfTest.WebAii.Controls.HtmlControls.HtmlAsserts;
    using ArtOfTest.WebAii.Messaging.Http;
     
     
    namespace ProxySample
    {
        /// <summary>
        /// Summary description for WebAiiVSUnitTest1
        /// </summary>
        [TestClass]
        public class WebAiiVSUnitTest1 : BaseTest
        {
     
            #region Additional test attributes
     
            private TestContext testContextInstance = null;
            /// <summary>
            ///Gets or sets the VS test context which provides
            ///information about and functionality for the
            ///current test run.
            ///</summary>
            public TestContext TestContext
            {
                get
                {
                    return testContextInstance;
                }
                set
                {
                    testContextInstance = value;
                }
            }
     
     
            //Use ClassInitialize to run code before running the first test in the class
            [ClassInitialize()]
            public static void MyClassInitialize(TestContext testContext)
            {
            }
     
            //Use ClassCleanup to run code after all tests in a class have run
            [ClassCleanup()]
            public static void MyClassCleanup()
            {
     
            }
     
            // Use TestInitialize to run code before running each test
            [TestInitialize()]
            public void MyTestInitialize()
            {
                #region WebAii Initialization
     
                // Initializes WebAii manager to be used by the test case.
                // If a WebAii configuration section exists, settings will be
                // loaded from it. Otherwise, will create a default settings
                // object with system defaults.
                //
                // Note: We are passing in a delegate to the VisualStudio
                // testContext.WriteLine() method in addition to the Visual Studio
                // TestLogs directory as our log location. This way any logging
                // done from WebAii (i.e. Manager.Log.WriteLine()) is
                // automatically logged to the VisualStudio test log and
                // the WebAii log file is placed in the same location as VS logs.
                //
                // If you do not care about unifying the log, then you can simply
                // initialize the test by calling Initialize() with no parameters;
                // that will cause the log location to be picked up from the config
                // file if it exists or will use the default system settings (C:\WebAiiLog\)
                // You can also use Initialize(LogLocation) to set a specific log
                // location for this test.
                Initialize(this.TestContext.TestLogsDir, new TestContextWriteLine(this.TestContext.WriteLine));
     
                // If you need to override any other settings coming from the
                // config section you can comment the 'Initialize' line above and instead
                // use the following:
     
                /*
             
                // This will get a new Settings object. If a configuration
                // section exists, then settings from that section will be
                // loaded
                     
                Settings settings = GetSettings();
                     
                // Override the settings you want. For example:
                settings.DefaultBrowser = BrowserType.FireFox;
                     
                // Now call Initialize again with your updated settings object
                Initialize(settings, new TestContextWriteLine(this.TestContext.WriteLine));
                     
                */
     
                // Set the current test method. This is needed for WebAii to discover
                // its custom TestAttributes set on methods and classes.
                // This method should always exist in [TestInitialize()] method.
                SetTestMethod(this, (string)TestContext.Properties["TestName"]);
     
                #endregion
     
                //
                // Place any additional initialization here
                //
     
            }
     
            // Use TestCleanup to run code after each test has run
            [TestCleanup()]
            public void MyTestCleanup()
            {
     
                //
                // Place any additional cleanup here
                //
     
                #region WebAii CleanUp
     
                // Shuts down WebAii manager and closes all browsers currently running
                this.CleanUp();
     
                #endregion
            }
     
            #endregion
     
            private void RequestLogger(object sender, HttpRequestEventArgs e)
            {
                // TODO Implement this
                Manager.Log.WriteLine(String.Format("{0} {1} {2}", e.Request.HttpVersion, e.Request.HttpMethod, e.Request.RequestUri));
                foreach (string key in e.Request.Headers)
                {
                    Manager.Log.WriteLine(String.Format("{0}:{1}", key, e.Request.Headers[key]));
                }
            }
     
            private void ResponseLogger(object sender, HttpResponseEventArgs e)
            {
                // TODO Implement this
                Manager.Log.WriteLine(String.Format("{0} {1} {2}", e.Response.HttpVersion, e.Response.StatusCode, e.Response.StatusDescription));
                foreach (string key in e.Response.Headers)
                {
                    Manager.Log.WriteLine(String.Format("{0}:{1}", key, e.Response.Headers[key]));
                }
            }
     
            [TestMethod]
            public void TestMethod1()
            {
                //
                // Place your test code here
                //
                Manager.Settings.UseHttpProxy = true;
                Manager.LaunchNewBrowser();
                ActiveBrowser.NavigateTo("http://msdn.microsoft.com/");
                Find.ByContent<HtmlAnchor>("l:Library").Click();
                Find.ByContent<HtmlAnchor>("l:.NET Development").Click();
                RequestListenerInfo reqLI = new RequestListenerInfo(RequestLogger);
                Manager.Http.AddBeforeRequestListener(reqLI);
                ResponseListenerInfo respLI = new ResponseListenerInfo(ResponseLogger);
                Manager.Http.AddBeforeResponseListener(respLI);
                Find.ByAttributes<HtmlAnchor>("title=MSDN Library").Click();
                Manager.Http.RemoveBeforeRequestListener(reqLI);
                Manager.Http.RemoveBeforeResponseListener(respLI);
            }
     
        }
    }

    To best assist you further with this endeavor getting the part of your test code where the problem lies will speed up our investigation for you immensely. Let us know if we can be of further assistance.

    Kind regards,
    Cody
    the Telerik team
    Quickly become an expert in Test Studio, check out our new training sessions!
    Test Studio Trainings
  10. Steve
    Steve avatar
    35 posts
    Member since:
    Jan 2011

    Posted 20 Mar 2012 Link to this post

    Well, I'm making progress - I can get this to work if it's called from a test, but it does not work when called from a library method.  Is there some obvious reason why this is so? 
  11. Cody
    Admin
    Cody avatar
    3360 posts

    Posted 20 Mar 2012 Link to this post

    Hello Steve,

    "Is there some obvious reason why this is so?" - Not without some additional details about what problem you are running into, any error messages you see, what behavior you are actually getting (compared to what you expected to get). Even better would be if you can send me a sample solution that demonstrates the problem that I can run locally, reproduce the problem and investigate what's causing it.

    Greetings,
    Cody
    the Telerik team
    Quickly become an expert in Test Studio, check out our new training sessions!
    Test Studio Trainings
  12. Steve
    Steve avatar
    35 posts
    Member since:
    Jan 2011

    Posted 20 Mar 2012 Link to this post

    OK - I'm an idiot.  I basically did what you sent in the example, but added a line in the handler to set a property of the class = true when the handler was called.  Then, methods in the class would check that property and when it goes true, they know their content is loaded.  EXCEPT, I wasn't considering that the handler was async, so I was removing the response listener BEFORE checking the value, and it would never be true, because my machine is so fast, and it took the handler down before it could even set the property.  Switched those two lines of code, and voila!  Worky Good!  Gonna use this all over the place in my framework...
    Thanks for helping me think out loud...

    Steve
  13. Cody
    Admin
    Cody avatar
    3360 posts

    Posted 20 Mar 2012 Link to this post

    Hi Steve,

    That's great news!...not that you're an "idiot" but that you it's working the way you want to now and figured it out on your own.

    All the best,
    Cody
    the Telerik team
    Quickly become an expert in Test Studio, check out our new training sessions!
    Test Studio Trainings
Back to Top