- PVSM.RU - https://www.pvsm.ru -

Работа с AngularJS Protractor из C # и Java

Введение

Как лозунг на Angular.org [1] гордостью объясняет:
Angular is what HTML would have been, had it been designed for applications , что в вольном переводе звучит так: Angular является тем, чем был бы HTML — если бы он с самого начала был предназначен для создания (веб -) приложений. AngularJS был разработан с нуля, чтобы быть тестируемым. Но многие разработчиков Selenium хотят продолжать использовать свои существующие Java или C # кодовую базу и навыки но обнаруживают при переключении на тестирование AngularJS SPA и MVVM веб-приложений, что Protractor [2], лидирующий инструмент тестирования приложегий AngularJS, написан на JavaScript тоже.

К счастью, Protractor довольно легко портируется на другие языки — он использует небольшое подмножество протокола JsonWire [3] на котором основан Selenium WebDriver, а именно всего один [4] интерфейс.

За короткое время был дополнен и развит проект protractor-net [5] представляющий порт существующих методов Protractor https://github.com/angular/protractor/blob/master/lib/clientsidescripts.js [6] из Javascript на C# и затем другой проект [7], выполняющий ту же задачу из Java.
Для тестирования был выбран сайт http://www.way2automation.com [8] на котором среди прочего есть и проект для AngularJS,
http://www.way2automation.com/angularjs-protractor/banking [9].

тесты представляют собой «стандарные» действия «клиента» и «менеджера» банка «XYZ Bank» по проверке баланса, созданию учетных записей, проведения платежей и т.п. — это позволило проиллюстрировать все имеющиеся методы. Вызов тестов осуществлен из проекта на C# и из Java

Примеры кода

C#

«Клиент» заходит, выбирает счет, заносит сумму, и когда транзакция прошла, проверяет баланс (есть и тест на съем средств — тут он не показан, смотрите архив).

image


  [TestFixture]
  public class Way2AutomationTests
  {
      private StringBuilder verificationErrors = new StringBuilder();
      private IWebDriver driver;
      private NgWebDriver ngDriver;
      private WebDriverWait wait;
      private IAlert alert;
      private string alert_text;
      private Regex theReg;
      private MatchCollection theMatches;
      private Match theMatch;
      private Capture theCapture;
      private int wait_seconds = 3;
      private int highlight_timeout = 100;
      private Actions actions;
      private String base_url = "http://www.way2automation.com/angularjs-protractor/banking";

      [TestFixtureSetUp]
      public void SetUp()
      {
          driver = new FirefoxDriver();
          driver.Manage().Timeouts().SetScriptTimeout(TimeSpan.FromSeconds(60));
          ngDriver = new NgWebDriver(driver);
          wait = new WebDriverWait(driver, TimeSpan.FromSeconds(wait_seconds));
          actions = new Actions(driver);
      }

      [SetUp]
      public void NavigateToBankingExamplePage()
      {
          driver.Navigate().GoToUrl(base_url);
          ngDriver.Url = driver.Url;
      }

      [TestFixtureTearDown]
      public void TearDown()
      {
          try
          {
              driver.Close();
              driver.Quit();
          }
          catch (Exception) { } 
          Assert.IsEmpty(verificationErrors.ToString());
      }

      [Test]
      public void ShouldDeposit()
      {
          ngDriver.FindElement(NgBy.ButtonText("Customer Login")).Click();
          ReadOnlyCollection<NgWebElement> ng_customers = ngDriver.FindElement(NgBy.Model("custId")).FindElements(NgBy.Repeater("cust in Customers"));
          // select customer to log in
          ng_customers.First(cust => Regex.IsMatch(cust.Text, "Harry Potter")).Click();

          ngDriver.FindElement(NgBy.ButtonText("Login")).Click();
          ngDriver.FindElement(NgBy.Options("account for account in Accounts")).Click();


          NgWebElement ng_account_number_element = ngDriver.FindElement(NgBy.Binding("accountNo"));
          int account_id  = 0;
          int.TryParse(ng_account_number_element.Text.FindMatch(@"(?<result>d+)$"), out account_id);
          Assert.AreNotEqual(0, account_id);

          int account_amount = -1;
          int.TryParse(ngDriver.FindElement(NgBy.Binding("amount")).Text.FindMatch(@"(?<result>d+)$"), out account_amount);
          Assert.AreNotEqual(-1, account_amount);

          ngDriver.FindElement(NgBy.PartialButtonText("Deposit")).Click();

          // core Selenium
          wait.Until(ExpectedConditions.ElementExists(By.CssSelector("form[name='myForm']")));
          NgWebElement ng_form_element = new NgWebElement(ngDriver, driver.FindElement(By.CssSelector("form[name='myForm']")));


          NgWebElement ng_deposit_amount_element = ng_form_element.FindElement(NgBy.Model("amount"));
          ng_deposit_amount_element.SendKeys("100");

          NgWebElement ng_deposit_button_element = ng_form_element.FindElement(NgBy.ButtonText("Deposit"));
          ngDriver.Highlight(ng_deposit_button_element);
          ng_deposit_button_element.Click();
          
          // inspect status message
          var ng_message_element = ngDriver.FindElement(NgBy.Binding("message"));
          StringAssert.Contains("Deposit Successful", ng_message_element.Text);
          ngDriver.Highlight(ng_message_element);

          // re-read the amount
          int updated_account_amount = -1;            
          int.TryParse(ngDriver.FindElement(NgBy.Binding("amount")).Text.FindMatch(@"(?<result>d+)$"), out updated_account_amount);
          Assert.AreEqual(updated_account_amount, account_amount + 100);
      }

Java

«Клиент» заходит, выбирает счет, смотрит транзакции, умеет найти записи «Credit».

@Test
    public void testListTransactions() throws Exception {
      // customer login
      ngDriver.findElement(NgBy.buttonText("Customer Login")).click();
      // select customer/account with transactions
      assertThat(ngDriver.findElement(NgBy.input("custId")).getAttribute("id"), equalTo("userSelect"));

      Enumeration<WebElement> customers = Collections.enumeration(ngDriver.findElement(NgBy.model("custId")).findElements(NgBy.repeater("cust in Customers")));
      
      while (customers.hasMoreElements()){
        WebElement next_customer = customers.nextElement();
        if (next_customer.getText().indexOf("Hermoine Granger") >= 0 ){
          System.err.println(next_customer.getText());
          next_customer.click();
        }
      }
      NgWebElement login_element = ngDriver.findElement(NgBy.buttonText("Login"));
      assertTrue(login_element.isEnabled());
      login_element.click();

      Enumeration<WebElement> accounts = Collections.enumeration(ngDriver.findElements(NgBy.options("account for account in Accounts")));
      
      while (accounts.hasMoreElements()){
        WebElement next_account = accounts.nextElement();
        if (Integer.parseInt(next_account.getText()) == 1001){
          System.err.println(next_account.getText());
          next_account.click();
        }
      }
      // inspect transactions
      NgWebElement ng_transactions_element = ngDriver.findElement(NgBy.partialButtonText("Transactions"));
      assertThat(ng_transactions_element.getText(), equalTo("Transactions"));
      highlight(ng_transactions_element);
      ng_transactions_element.click();
      wait.until(ExpectedConditions.visibilityOf(ngDriver.findElement(NgBy.repeater("tx in transactions")).getWrappedElement()));
      Iterator<WebElement> ng_transaction_type_columns = ngDriver.findElements(NgBy.repeaterColumn("tx in transactions", "tx.type")).iterator();
      while (ng_transaction_type_columns.hasNext() ) {
        WebElement column = (WebElement) ng_transaction_type_columns.next();
        if (column.getText().isEmpty()){
          break;
        }
        if (column.getText().equalsIgnoreCase("Credit") ){
          highlight(column);
        }
      }
    }

Для интерактивного тестирования, стоит запустить Selenium-ноду и хаб локально на порт 4444

@BeforeClass
public static void setup() throws IOException {
  DesiredCapabilities capabilities =   new DesiredCapabilities("firefox", "", Platform.ANY);
  FirefoxProfile profile = new ProfilesIni().getProfile("default");
  capabilities.setCapability("firefox_profile", profile);
  seleniumDriver = new RemoteWebDriver(new URL("http://127.0.0.1:4444/wd/hub"), capabilities);
  try{
    seleniumDriver.manage().window().setSize(new Dimension(600, 800));
    seleniumDriver.manage().timeouts()
      .pageLoadTimeout(50, TimeUnit.SECONDS)
      .implicitlyWait(20, TimeUnit.SECONDS)
      .setScriptTimeout(10, TimeUnit.SECONDS);
  }  catch(Exception ex) {
    System.out.println(ex.toString());
  }
  ngDriver = new NgWebDriver(seleniumDriver);
}

Для билда используем

@BeforeClass
public static void setup() throws IOException {
  seleniumDriver = new PhantomJSDriver();
  wait = new WebDriverWait(seleniumDriver, flexible_wait_interval );
  wait.pollingEvery(wait_polling_interval,TimeUnit.MILLISECONDS);
  actions = new Actions(seleniumDriver);
  ngDriver = new NgWebDriver(seleniumDriver);
}

Полный список тестов на 01.01.2016:

  • ShouldAddCustomer
  • ShouldDeleteCustomer
  • ShouldDeposit
  • ShouldListTransactions
  • ShouldLoginCustomer
  • ShouldOpenAccount
  • ShouldSortCustomersAccounts
  • ShouldWithdraw

Это на C# — на Jave тестов пока меньше, но остаток — вопрос времени

Статья (гораздо более подробная версия) также опубликована мною на Code Project [10], туда же периодически загружаются наиболее свежие архивы проектов. Оба проекта на гитхабе полностью рабочие, коммиты практически каждый день.

Автор: sergueik

Источник [11]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/java/107810

Ссылки в тексте:

[1] Angular.org : https://angularjs.org/

[2] Protractor: https://angular.github.io/protractor/#/

[3] JsonWire: https://code.google.com/p/selenium/wiki/JsonWireProtocol

[4] один: https://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/execute

[5] protractor-net: https://github.com/sergueik/powershell_selenium/tree/master/csharp/protractor-net

[6] https://github.com/angular/protractor/blob/master/lib/clientsidescripts.js: https://github.com/angular/protractor/blob/master/lib/clientsidescripts.js

[7] проект: https://github.com/sergueik/selenium_java/tree/master/protractor

[8] http://www.way2automation.com: http://www.way2automation.com

[9] http://www.way2automation.com/angularjs-protractor/banking: http://www.way2automation.com/angularjs-protractor/banking

[10] Code Project: http://www.codeproject.com/Articles/1066968/Developing-Protractor-tests-in-Csharp-or-Java

[11] Источник: http://habrahabr.ru/post/274413/