सेलेनियम के साथ AngularJS परीक्षण




selenium c#-4.0 (8)

मेरे पास एएसपी एमवीसी + एंगुलरजेएस पर एसपीए एप्लीकेशन है और मैं यूआई का परीक्षण करना चाहता हूं। अभी के लिए मैं फैलेमजेएस और वेबकिट ड्राइवरों के साथ सेलेनियम की कोशिश कर रहा हूं।

परीक्षण पृष्ठ - एकल तत्व के साथ देखें - <li> की सूची जो सर्वर से गतिशील रूप से लोड होती है और कोणीय द्वारा बाध्य होती है।

<div id="items">
    <li>text</li>
    <li>text2</li>
</div>

मैं परीक्षा पास करने की कोशिश कर रहा हूँ

_driver.FindElements(By.TagName('li'))

समस्या यह है कि इस समय कोई तत्व लोड नहीं होता है, और _driver.PageSource में तत्व भी नहीं होते हैं।

मैं लोड की गई वस्तुओं के लिए कैसे इंतजार कर सकता हूं? कृपया थ्रेड का सुझाव न दें। नींद ()


HTML पृष्ठ के साथ मेरी विशेष समस्या के लिए iframes युक्त और AnglularJS के साथ विकसित निम्न चाल ने मुझे बहुत समय बचाया: डोम में मैंने स्पष्ट रूप से देखा कि एक आईफ्रेम है जो सभी सामग्री को लपेटता है। तो कोड को काम करने के लिए निम्नलिखित कोड:

driver.switchTo().frame(0);
waitUntilVisibleByXPath("//h2[contains(text(), 'Creative chooser')]");

लेकिन यह काम नहीं कर रहा था और मुझे कुछ कहा जैसे "फ्रेम पर स्विच नहीं कर सकता। विंडो बंद थी"। फिर मैंने कोड को संशोधित किया:

driver.switchTo().defaultContent();
driver.switchTo().frame(0);
waitUntilVisibleByXPath("//h2[contains(text(), 'Creative chooser')]");

इसके बाद सब कुछ सुचारू रूप से चला गया। तो स्पष्ट रूप से कोणीय iframes के साथ कुछ उलझ रहा था और पृष्ठ लोड करने के बाद ही जब आप उम्मीद करते हैं कि ड्राइवर डिफ़ॉल्ट सामग्री पर केंद्रित है, तो इसे पहले से ही कोणीय फ्रेम द्वारा हटा दिया गया था। उम्मीद है कि यह आप में से कुछ की मदद कर सकता है।


उपयोगी कोड स्निपेट के लिए आप मेरा प्रोटैक्टर हो सकते हैं। यह फ़ंक्शन ब्लॉक करता है जब तक कि कोणीय पृष्ठ को प्रतिपादित नहीं करता है। यह शाहजीब सलीम के जवाब का एक रूप है, सिवाय इसके कि वह इसके लिए मतदान कर रहा है और मैं कॉलबैक स्थापित कर रहा हूं।

def wait_for_angular(self, selenium):
    self.selenium.set_script_timeout(10)
    self.selenium.execute_async_script("""
        callback = arguments[arguments.length - 1];
        angular.element('html').injector().get('$browser').notifyWhenNoOutstandingRequests(callback);""")

अपने ng-app तत्व के लिए 'html' को बदलें।

यह https://github.com/angular/protractor/blob/71532f055c720b533fbf9dab2b3100b657966da6/lib/clientsidescripts.js#L51 से आता है


एडीडीक के सुझाव के अलावा। यदि आप एंगुलरजेएस ऐप का परीक्षण करते हैं, तो मैं दृढ़ता से आपको प्रोटैक्टर के बारे में सोचने का सुझाव देता हूं

प्रोटैक्टर आपको प्रतीक्षा पदार्थ (सिंक, एसिंक) को हल करने में मदद करेगा। हालांकि, कुछ नोट्स हैं

1 - आपको जावास्क्रिप्ट में अपना परीक्षण विकसित करने की आवश्यकता है

2 - प्रवाह को संभालने में कुछ अलग तंत्र हैं


मैंने निम्नलिखित कोड किया और यह मुझे एसिंक रेस हालत विफलताओं के लिए मदद की।

$window._docReady = function () {
        var phase = $scope.$root.$$phase;
        return $http.pendingRequests.length === 0 && phase !== '$apply' && phase !== '$digest';
    }

अब सेलेनियम पेजऑब्जेक्ट मॉडल में, आप प्रतीक्षा कर सकते हैं

Object result = ((RemoteWebDriver) driver).executeScript("return _docReady();");
                    return result == null ? false : (Boolean) result;

यदि आप WebDriverJS का उपयोग कर रहे हैं तो कोणीय पर प्रतीक्षा कैसे करें इसके लिए यहां एक उदाहरण दिया गया है। मूल रूप से मैंने सोचा था कि आपको कस्टम स्थिति बनाना है, लेकिन wait किसी भी समारोह को स्वीकार करती है।

// Wait for Angular to Finish
function angularReady(): any  {
  return $browser.executeScript("return (window.angular !== undefined) && (angular.element(document).injector() !== undefined) && (angular.element(document).injector().get('$http').pendingRequests.length === 0)")
     .then(function(angularIsReady) {                        
                    return angularIsReady === true;
                  });
}

$browser.wait(angularReady, 5000).then(...);

अफसोस की बात यह है कि यह सीएसपी (सामग्री-सुरक्षा-नीति) और unsafe-eval वजह से PhantomJS के साथ काम नहीं करता है। विंडोज़ पर हेडलेस क्रोम 59 के लिए इंतजार नहीं कर सकता


यदि आप AngularJS का उपयोग कर रहे हैं तो प्रोटैक्टर का उपयोग करना एक अच्छा विचार है।

यदि आप प्रोटैक्टर का उपयोग करते हैं तो आप इसका इंतजार कर सकते हैंफॉरएंगुलर () विधि जो http अनुरोधों को पूरा करने की प्रतीक्षा करेगी। तत्वों को लागू करने से पहले तत्वों को प्रदर्शित करने के लिए अभी भी अच्छा अभ्यास है, आपकी भाषा और कार्यान्वयन के आधार पर यह एक तुल्यकालिक भाषा में देख सकता है

WebDriverWait wait = new WebDriverWait(webDriver, timeoutInSeconds);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id<locator>));

या जेएस में आप प्रतीक्षा विधि का उपयोग कर सकते हैं जो एक फ़ंक्शन निष्पादित करता है जब तक कि यह सत्य न हो जाए

browser.wait(function () {
    return browser.driver.isElementPresent(elementToFind);
});

यह पेज लोड / jquery.ajax (यदि मौजूद है) और $ http कॉल, और किसी भी साथ डाइजेस्ट / रेंडर चक्र के लिए इंतजार करेगा, इसे उपयोगिता फ़ंक्शन में फेंक दें और प्रतीक्षा करें।

/* C# Example
 var pageLoadWait = new WebDriverWait(WebDriver, TimeSpan.FromSeconds(timeout));
            pageLoadWait.Until<bool>(
                (driver) =>
                {
                    return (bool)JS.ExecuteScript(
@"*/
try {
  if (document.readyState !== 'complete') {
    return false; // Page not loaded yet
  }
  if (window.jQuery) {
    if (window.jQuery.active) {
      return false;
    } else if (window.jQuery.ajax && window.jQuery.ajax.active) {
      return false;
    }
  }
  if (window.angular) {
    if (!window.qa) {
      // Used to track the render cycle finish after loading is complete
      window.qa = {
        doneRendering: false
      };
    }
    // Get the angular injector for this app (change element if necessary)
    var injector = window.angular.element('body').injector();
    // Store providers to use for these checks
    var $rootScope = injector.get('$rootScope');
    var $http = injector.get('$http');
    var $timeout = injector.get('$timeout');
    // Check if digest
    if ($rootScope.$$phase === '$apply' || $rootScope.$$phase === '$digest' || $http.pendingRequests.length !== 0) {
      window.qa.doneRendering = false;
      return false; // Angular digesting or loading data
    }
    if (!window.qa.doneRendering) {
      // Set timeout to mark angular rendering as finished
      $timeout(function() {
        window.qa.doneRendering = true;
      }, 0);
      return false;
    }
  }
  return true;
} catch (ex) {
  return false;
}
/*");
});*/

हमारे पास एक समान समस्या है जहां हमारे घर के ढांचे का उपयोग कई साइटों का परीक्षण करने के लिए किया जा रहा है, इनमें से कुछ JQuery का उपयोग कर रहे हैं और कुछ AngularJS का उपयोग कर रहे हैं (और 1 में मिश्रण भी है!)। हमारा ढांचा सी # में लिखा गया है, इसलिए यह महत्वपूर्ण था कि किसी भी जेस्क्रिप्ट को निष्पादित किया जा रहा था, न्यूनतम भाग (डीबगिंग उद्देश्यों के लिए) में किया गया था। यह वास्तव में उपर्युक्त उत्तरों में से बहुत कुछ ले गया और उन्हें एक साथ मैश किया (इसलिए क्रेडिट जहां क्रेडिट @npjohns देय है)। नीचे हमने जो किया है उसका एक स्पष्टीकरण है:

एचटीएमएल डोम लोड होने पर निम्नलिखित सत्य / गलत लौटाता है:

        public bool DomHasLoaded(IJavaScriptExecutor jsExecutor, int timeout = 5)
    {

        var hasThePageLoaded = jsExecutor.ExecuteScript("return document.readyState");
        while (hasThePageLoaded == null || ((string)hasThePageLoaded != "complete" && timeout > 0))
        {
            Thread.Sleep(100);
            timeout--;
            hasThePageLoaded = jsExecutor.ExecuteScript("return document.readyState");
            if (timeout != 0) continue;
            Console.WriteLine("The page has not loaded successfully in the time provided.");
            return false;
        }
        return true;
    }

फिर हम जांचते हैं कि JQuery का उपयोग किया जा रहा है या नहीं:

public bool IsJqueryBeingUsed(IJavaScriptExecutor jsExecutor)
    {
        var isTheSiteUsingJQuery = jsExecutor.ExecuteScript("return window.jQuery != undefined");
        return (bool)isTheSiteUsingJQuery;
    }

यदि JQuery का उपयोग किया जा रहा है तो हम जांच लें कि यह लोड हो गया है:

public bool JqueryHasLoaded(IJavaScriptExecutor jsExecutor, int timeout = 5)
        {
                var hasTheJQueryLoaded = jsExecutor.ExecuteScript("jQuery.active === 0");
                while (hasTheJQueryLoaded == null || (!(bool) hasTheJQueryLoaded && timeout > 0))
                {
                    Thread.Sleep(100);
                timeout--;
                    hasTheJQueryLoaded = jsExecutor.ExecuteScript("jQuery.active === 0");
                    if (timeout != 0) continue;
                    Console.WriteLine(
                        "JQuery is being used by the site but has failed to successfully load.");
                    return false;
                }
                return (bool) hasTheJQueryLoaded;
        }

हम फिर AngularJS के लिए भी ऐसा करते हैं:

    public bool AngularIsBeingUsed(IJavaScriptExecutor jsExecutor)
    {
        string UsingAngular = @"if (window.angular){
        return true;
        }";            
        var isTheSiteUsingAngular = jsExecutor.ExecuteScript(UsingAngular);
        return (bool) isTheSiteUsingAngular;
    }

यदि इसका उपयोग किया जा रहा है तो हम जांचते हैं कि यह लोड हो गया है:

public bool AngularHasLoaded(IJavaScriptExecutor jsExecutor, int timeout = 5)
        {
    string HasAngularLoaded =
        @"return (window.angular !== undefined) && (angular.element(document.body).injector() !== undefined) && (angular.element(document.body).injector().get('$http').pendingRequests.length === 0)";            
    var hasTheAngularLoaded = jsExecutor.ExecuteScript(HasAngularLoaded);
                while (hasTheAngularLoaded == null || (!(bool)hasTheAngularLoaded && timeout > 0))
                {
                    Thread.Sleep(100);
                    timeout--;
                    hasTheAngularLoaded = jsExecutor.ExecuteScript(HasAngularLoaded);
                    if (timeout != 0) continue;
                    Console.WriteLine(
                        "Angular is being used by the site but has failed to successfully load.");
                    return false;

                }
                return (bool)hasTheAngularLoaded;
        }

हम जांचने के बाद कि DOM सफलतापूर्वक लोड हो गया है, तो आप इन बूल मानों का उपयोग कस्टम प्रतीक्षा करने के लिए कर सकते हैं:

    var jquery = !IsJqueryBeingUsed(javascript) || wait.Until(x => JQueryHasLoaded(javascript));
    var angular = !AngularIsBeingUsed(javascript) || wait.Until(x => AngularHasLoaded(javascript));




end-to-end