Блог вебразработчика
  • ГЛАВНАЯ
  • ПОДПИСКА

Thucydides — открытие страницы

Ноя01
2012
Написал Tatyana

Для работы со страницей Thucydides предоставляет класс PageObject, от которого должны быть унаследованы все Ваши страницы в проекте. В качестве своеобразной фабрики страниц выступает класс Pages, который играет роль кеша и содержит методы для доступа и создания страниц.

Как получить страницу

Для того, чтобы получить объект страницы внутри библиотеки шагов нужно обратиться к фабрике страниц и запросить необходимый Вам класс:

LoginPage page = getPages().get(LoginPage.class);

Этот метод сам по себе всегда будет создавать новый экземпляр страницы. Возвращаемая страница при этом помещается в кеш. Для того чтобы не создавать объект страницы по-новой, если Вы итак уже находитесь на ней, можно обратиться к кешу и попытаться получить доступ к странице из него:

LoginPage page = getPages().onSamePage().get(LoginPage.class);

Если последняя созданная страница совпадает по классу с запрашиваемой, то вернется текущий объект страницы, если нет, то создаться новый.

Третий способ получения страницы позволяет не только получить экземпляр страницы, но и проверить текущий URL в браузере:

LoginPage page = getPages().currentPageAt(LoginPage.class);

Проверка URL проходит основываясь на URL паттерне определенном в аннотации @At в PageObject:

@At("http://www.site.org/login")
public class LoginPage extends PageObject {
    ...
}

@At поддерживает также использование регулярных выражений и шаблонов, игнорирует наличие параметров в URL и позволяет задать несколько url-ов для сравнения. Например,

// #HOST любой адрес сервера
// любые символы после index
@At("#HOST/catalog/index.*")
public class CatalogItemPage extends PageObject {
    ...
}
// одна страница для создания и редактирования
@At(urls = {
		"#HOST/catalog/item/create", 
		"#HOST/catalog/item/edit.*" 
		})
public class CatalogItemPage extends PageObject {
    ...
}
// одна страница для создания и редактирования
@At("#HOST/catalog/item/(create|edit.*)")
public class CatalogItemPage extends PageObject {
    ...
}

Если при проверке URL не совпадает с приведенным в аннотации, то Thucydides генерирует исключение WrongPageError и тест завершается неудачей. Аннотация @At не является обязательной и может быть опущена, тогда проверка просто не будет выполняться.

Как открыть страницу

Для того, чтобы открыть страницу в браузере используется метод open().
Объекты страниц, как правило, предназначены для работы с определенными веб-страницами. При вызове метода open() браузер будет открыт по URL-у, представленному в аннотации @DefaultUrl.

@DefaultUrl("http://www.site.org/login")
public class LoginPage extends PageObject {
    ...
}

Однако в целом, HOST-часть в @DefaultUrl всегда будет переопределяться свойством webdriver.base.url. Это позволяет установить базовый URL повсеместно для всех Ваших тестов, и упрощает запуск тестов на различных серверах простым изменением значения этого свойства. Например, в примере выше, установка webdriver.base.url в http://yandex.ru приведет к открытию страницы по адресу http://yandex.ru/login.

Пример метода в библиотеке шагов для получения объекта страницы и открытия URL только в том случае, если Вы находитесь на другой странице:

/**
 * Открыть страницу. Проверка текущей страницы:
 * если находимся на другой странице, 
 * то открываем необходимую
 * 
 * @param pageObjectClass - класс страницы PageObject
 * @return T extends {@link PageObject}
 */
public  T open(final Class pageObjectClass) {
	T page = null;
	try {
		page = getPages().onSamePage().currentPageAt(pageObjectClass);
	} catch (WrongPageError e) {
		page = getPages().get(pageObjectClass);
		page.open();
	}
	return page;
}

Страницу также можно открывать с передачей параметров с помощью метода open(final String... parameterValues), параметры в URL должны быть представлены в виде {1},{2} и т.д.

@DefaultUrl("/catalog/item/edit/{1}")
public class CatalogItemPage extends PageObject {
    ...
}

Вызов происходит следующим образом:

catalogPage.open("123374");

Вы также можете определить имена URL-адресов, которые могут быть использованы для открытия веб-страницы:

@DefaultUrl("/catalog/item/{1}")
@NamedUrls(
		  {
		    @NamedUrl(name = "create", url = "/catalog/item/create"),
		    @NamedUrl(name = "edit", url = "/catalog/item/edit/{1}"),
		  }
		)
public class CatalogItemPage extends PageObject {
    ...
}
catalogPage.open("edit", new String[] {"123374"});

Если Вам нужно, чтобы страница выполняла какие-то действия во время загрузки, например, дожидалась появления какого-либо динамического элемента, используйте аннотацию @WhenPageOpens. Методы в PageObject, помеченные этой аннотацией, будут вызваны (в произвольном порядке) после того как URL был открыт.

@DefaultUrl("/catalog/list}")
public class CatalogListPage extends PageObject {
	
	@FindBy(id="items-list");
	WebElement list;

	@WhenPageOpens
	public void waitUntilListLoaded() {
		element(list).waitUntilVisible();
	}
}
  • Нравится
  • Tweet

Опубликовано в Thucydides - Помечено Thucydides
Рассказать всем Twitter Facebook Delicious StumbleUpon E-Mail
← Параллельное выполнение JUnit тестов с помощью Maven
Selenium WebDriver: скриншот теста с помощью JUnit4 @Rule →

34 комментариев

  1. El's Gravatar El
    06.11.2012 at 04:40 | Permalink

    Добрый день,
    а установить webdriver.base.url можно только через -Dwebdriver.base.url и @ManagedPages(defaultUrl = «…») ?

    • Tatyana's Gravatar Tatyana
      06.11.2012 at 06:42 | Permalink

      можно установить напрямую через System Properties:

      System.setProperty(
      	ThucydidesSystemProperty.BASE_URL.getPropertyName(),
      	DEFAULT_BASE_URL);
      

      Также обратите внимание на методы в классах Pages и PageObject:

      public class CommonPage extends PageObject {
      
      	. . .
      
      	getPages().setDefaultBaseUrl(defaultBaseUrl);
      
      	this.setDefaultBaseUrl(defaultBaseUrl);
      
      	. . .
      
      }
      
      • Test's Gravatar Test
        28.11.2012 at 11:01 | Permalink

        Можно раскрыть тему конфигурирования сборки в jenkins (хочется использовать одну и ту же сборку, но на нескольких тестовых стендах), каким образом передать webdriver.base.url

        • Tatyana's Gravatar Tatyana
          28.11.2012 at 11:24 | Permalink

          webdriver.base.url передается в строке, где вы запускаете тесты на выполнение:
          clean integration-test -U -Dwebdriver.base.url=URL

          Думаю, что детально раскрою эту тему в следующей статье.

      • Юрий's Gravatar Юрий
        17.12.2012 at 04:54 | Permalink

        Татьяна, спасибо большое.
        А Вы не могли бы сказать, в каком классе проекта Thucydides нужно писать System.setProperty(
        ThucydidesSystemProperty.BASE_URL.getPropertyName(),
        DEFAULT_BASE_URL);
        И чему именно присваивается значение System Properties?
        Или это значение устанавливается в pom-файле? Или даже в командной строке maven?

        • Tatyana's Gravatar Tatyana
          17.12.2012 at 09:51 | Permalink

          ThucydidesSystemProperty.BASE_URL = «webdriver.base.url».

          setProperty(ThucydidesSystemProperty.BASE_URL ...
          или -Dwebdriver.base.url в командной строке — это просто два способа сделать одно и тоже, установить домен для тестов.

          В случае использования setProperty, установку лучше выполнить еще до запуска тестов, где-нибудь в @BeforeClass.

          • Юрий's Gravatar Юрий
            18.12.2012 at 06:42 | Permalink

            Спасибо, всё заработало )

          • Alert's Gravatar Alert
            06.09.2013 at 17:32 | Permalink

            если не сработал System.setProperty(ThucydidesSystemProperty.BASE_URL
            .getPropertyName(), NEW_URL);
            можно так переписать:
            pages.getConfiguration().getEnvironmentVariables()
            .setProperty(ThucydidesSystemProperty.BASE_URL
            .getPropertyName(), NEW_URL);

  2. Alex's Gravatar Alex
    19.11.2012 at 12:14 | Permalink

    Не совсем понятно, как взаимосвязаны @At и @DefaultUrl? Взаимозаменяемы ли они? Могут ли быть одновременно? Если да, для чего это может быть нужно?

    • Tatyana's Gravatar Tatyana
      19.11.2012 at 14:51 | Permalink

      Эти две аннотации никак явно не взаимосвязаны и не взаимозаменяемы. @At проверяет находитесь ли Вы на нужной странице в момент вызова getPages().currentPageAt(pageObjectClass). А @DefaultUrl используется для открытия url в браузере при вызове метода page.open(). Они могут как присутствовать на странице одновременно, так и обе отсутствовать. Связать их можно только в step-ах, например, перед открытием страницы по url проверить, может Вы уже находитесь на нужной странице, и тогда не загружать ее лишний раз. В статье есть код, в котором показано как это сделать.

  3. Test's Gravatar Test
    28.11.2012 at 10:13 | Permalink

    Татьяна, можете рассказать как прикрутить jdbc к Thucydides?

    • Tatyana's Gravatar Tatyana
      28.11.2012 at 10:39 | Permalink

      Никакой функциональности для этого Thucydides не предоставляет. В целом они никак не взаимосвязаны. Многое зависит от самой реализации работы с базой. Но независимо от того, что Вы используете (ORM или просто отдельный класс, который подключается к БД), всю работу с базой лучше вынести в отдельный класс ScenarioSteps, например, DBSteps, и осуществлять все выборки и запросы через него. Это нужно для того, чтобы Thucydides мог корректно обработать возникшие исключения. Если будете работать с базой напрямую из теста, то в случае возникновения исключения, Вы не увидите в отчете никакой информации. PageObject в свою очередь тоже не самое подходящее место для работы с БД. Поэтому на мой взгляд степы наиболее оптимальное решение для такой задачи.
      Что касается прикручивания jdbc в общем, то возможно эта статья чем-то поможет.

  4. Test's Gravatar Test
    03.12.2012 at 05:03 | Permalink

    Как можно получить имя теста находясь внутри класса ScenarioSteps?

    • Tatyana's Gravatar Tatyana
      03.12.2012 at 07:59 | Permalink

      Непосредственно с помощью Thucydides это сделать нельзя. Но можно использовать один из следующих вариантов:
      1. Определить имя теста в методе ScenarioSteps самостоятельно по каким-либо признакам:

      for (StackTraceElement ste : 
      					Thread.currentThread().getStackTrace()) {
      			System.out.println(ste);
      }
      

      2. Использовать текущую сессию Thucydides для передачи имени теста.
      В тестовом классе:

      @Before
      public void setUp() {
      	Thucydides.getCurrentSession().put("testName", 
      							this.getClass().getSimpleName());
      }
      

      В методе ScenarioSteps:

      Thucydides.getCurrentSession().get("testName");
      
  5. El's Gravatar El
    17.01.2013 at 05:16 | Permalink

    А в чем может быть проблема, если ни один из способов установки base.url не работает? По итогу открывается страница с адресом из defaultUrl. Пробовала на thucydides версии 90 и 77

    Спасибо

    • Tatyana's Gravatar Tatyana
      17.01.2013 at 08:06 | Permalink

      Установка хоста через setProperty(ThucydidesSystemProperty.BASE_URL …) или -Dwebdriver.base.url наиболее приоритетна и должна работать. В классе Pages есть метод getDefaultBaseUrl:

          public String getDefaultBaseUrl() {
      
              String baseUrl = defaultBaseUrl;
              if (isNotEmpty(getConfiguration().getBaseUrl())) {
                  baseUrl = getConfiguration().getBaseUrl();
              }
              return baseUrl;
          }
      

      Pages.defaultBaseUrl устанавливается в defaultUrl из аннотации @ManagedPages в момент инициализации. В методе видно, что defaultBaseUrl возвращается только если нет другого значения, переданного в SystemPropeties.
      Pages в свою очередь устанавливает хост для конкретной страницы во время вызова методов get, getAt, currentPageAt и т.п.
      Может не работать скорее всего по двум причинам: не правильно устанавливаете или делаете это не вовремя.

      • Test's Gravatar Test
        25.02.2014 at 14:05 | Permalink

        Таже проблема что и у El, только -Dwebdriver.base.url открывает отличную от
        @ManagedPages(defaultUrl = «http://HOST:PORT/page/»)
        Возможно не вовремя устанивниваю SystemPropeties? Он он также отрабатывает в указанном вами @BeforeClass:

        @Managed()
        public WebDriver webdriver;

        @ManagedPages(defaultUrl = "http://HOST:PORT/page/")
        public Pages pages;

        @BeforeClass
        public static void beforeClass() {
        System.setProperty(ThucydidesSystemProperty.BASE_URL.getPropertyName(), "http://newHOST:newPORT/page");
        ThucydidesSystemProperties currentSystemProperties = ThucydidesSystemProperties.getProperties();
        currentSystemProperties.setValue(ThucydidesSystemProperty.BASE_URL, "http://newHOST:newPORT/page")
        }

        Подскажите в чем может быть проблема?

        • Tatyana's Gravatar Tatyana
          26.02.2014 at 09:46 | Permalink

          Последние версии Thucydides считывают SystemPropeties во время инициализации теста, пересохраняя их в собственные объекты, поэтому дальнейшие изменения properties ни к чему уже не приводят.
          В каждом конкретном случае нужно искать что конкретно необходимо изменить, в Вашем случае:

          Injectors.getInjector()
          	.getInstance(Configuration.class)
          		.setDefaultBaseUrl("http://newHOST:newPORT/page");
          
  6. Наталья's Gravatar Наталья
    31.01.2013 at 12:00 | Permalink

    Добрый день, Татьяна!

    Спасибо огромное за Ваш предыдущий ответ по поводу формирования отчетов. Отчеты заработали и формируются.
    Я хотела спросить у Вас по поводу Ajax-запросов. Столкнулась с тем, что рекомендуемого checkThat(элемент)IsVisible не достаточно. На странице с множеством Ajax-запросов при отправке сообщения появляется алерт, который Thucydides пытается нажать (я использую alert.accept) до того как он физически появляется. Задать на алерт какие-то локаторы (и соответственно прописать его как элемент) я не могу. Ранее в аналогичном тесте, который я запускала через JUnit+Eclipse, для ожидания всех Ajax-запросов я использовала метод:
    private void waitForAllAjaxComplete() throws InterruptedException {
    Boolean ajaxIsComplete = false;

    for (int second = 0;; second++) {
    int timeout = 30;
    if (second >= timeout)
    fail(«timeout»);
    try {
    if (getDriver() instanceof JavascriptExecutor) {
    ajaxIsComplete = (Boolean) ((JavascriptExecutor) getDriver())
    .executeScript(«return jQuery.active == 0;»);
    } else {
    fail(«JavascriptExecutor»);
    }
    if (ajaxIsComplete)
    break;
    } catch (Exception e) {
    }
    Thread.sleep(1000);

    Я честно попыталась его «прикрутить» и к thucydides но не слишком успешно, вернее у меня ничего из этого не получилось 🙁

    Может быть где-то существует описание, как в thucydides работать с ajax-запросами кроме как использовать метод …IsVivsible????

    • Tatyana's Gravatar Tatyana
      31.01.2013 at 12:28 | Permalink

      Добрый день
      Вопрос с алертом в частном порядке решается следующим образом:

      protected Alert submitAlertWait() {
      	Alert alert = (new WebDriverWait(getDriver(), 60))
      	                .until(ExpectedConditions.alertIsPresent());
      	alert.accept();
      }
      

      Что касается ожидания завершения ajax-запросов, то из Вашего кода можно сделать примерно следующее:

      public void waitForAjaxComplete() {
      	waitFor(ajaxComplete());
      }
      	
      private ExpectedCondition ajaxComplete() {
      	return new ExpectedCondition() {
      		public Boolean apply(WebDriver d) {
      			return (Boolean) evaluateJavascript(
      				"return window.jQuery.active == 0");
      		}
      	};
      }
      

      К сожалению, мне не на чем проверить его работоспособность, но этот пример может помочь Вам придумать как реализовать Вашу задачу.

      В ближайшие дни постараюсь написать статью про ajax в Thucydides.

      • Наталья's Gravatar Наталья
        31.01.2013 at 13:44 | Permalink

        Буду с нетерпением ждать! А пока я решила проблему с алертом довольно топорным способом, но он единственный, который заработал (я попозже планирую подергать специалистов на работе, что они предложат и обязательно отпишу если появится что-то более элегантное)

        public void acceptAlert() {
        getDriver().findElement(By.linkText(«Отправить сообщение»)).click();
        }
        }

        Тот вариант, что Вы предложили у меня тоже не заработал, к сожалению…

  7. Natalia's Gravatar Natalia
    18.03.2013 at 10:17 | Permalink

    Добрый день!
    Я хотела уточнить один момент. Можно ли при использовании аннотации @At в один тест включать несколько подтестов.
    Например класс
    Test_Funkcional {
    @Managed (uniqueSession = true)
    @ManagedPages (defaultUrl = "default/url/")
    @Steps
    [...]
    @Test
    public void funkcional1 (){
    [...]
    }
    `@Test
    public void funkcional2(){
    [...]
    }
    @Test
    public void funkcional3(){
    [...]
    }
    }

    Ранее, без использования аннотации @At все тесты проходили у меня в одном браузере, по очереди.

    Теперь же, с аннотацией @At, успешно проходит только первый из тестов (учитывая, что они запускаются рандомно, то это может быть любой из 5 или 6 тестов, прописанных в классе) . Для всех остальных тестов выдается следующая ошибка:
    I was looking for a page compatible with class Test_Funkcional.LoginPage
    I was at the URL https://url/defauil/payments/history.bml

    Т.е. Thucydides на первом тесте успешно заходит на первую страницу, переходит на следующую, с которой уже дальше никуда не может уйти. Ни в текущем тесте (если в ходе теста требуется перейти последовательно по трем-четырем страницам). И самое главное Thucydides не позволяет последующим тестам открывать нужные им страницы и выполнять заданные действия.

    Это моя ошибка в работе с аннотацией, или она просто не работает если необходимо в рамках одного теста заходить более, чем на две страницы и не работает если несколько тестов запускаются последовательно с аннотацией (uniqueSession = true)?

    Заранее большое спасибо!

    • Tatyana's Gravatar Tatyana
      18.03.2013 at 19:46 | Permalink

      Добрый день!
      Аннотация @At может использоваться в сценариях любой сложности.
      Каким образом Вы заходите на страницы и переходите по ним?

  8. Alex's Gravatar Alex
    05.04.2013 at 13:02 | Permalink

    Татьяна, здравствуйте!
    Извините, что вопрос не совсем по теме поста.
    Я использую JBehave тесты в Thucydides. И возникает проблема: когда я пытаюсь сделать что-то с WebDriver до начала выполнения непосредственных шагов теста, поднимается лишний браузер. Например, если сделать класс AbstractPage и в нем делать driver.manage().window().maximize(). Или если использовать аннотацию @BeforeStories и там вызывать шаг из библиотеки шагов, то при выполнении @BeforeStories поднимается первый браузер, а при выполнении первого шага теста — второй.
    Не подскажете, в чем может быть дело?

    • Tatyana's Gravatar Tatyana
      05.04.2013 at 17:31 | Permalink

      К сожалению, никогда не использовала JBehave, возможно кто-то из читателей подскажет

  9. Alex's Gravatar Alex
    08.04.2013 at 05:46 | Permalink

    Татьяна, спасибо за ответ. Еще один момент мне немного непонятен. Почему в конце выполнения тестов maven пишет в консоли, что выполнено тестов больше, чем есть на самом деле? Например, у меня 3 stories, а пишется, что тестов выполнено 13. Он не может их корректно подсчитать?

    • Tatyana's Gravatar Tatyana
      08.04.2013 at 19:01 | Permalink

      Могу только предположить, что он считает количество тестовых методов, а не тестовых классов

  10. Vitalik's Gravatar Vitalik
    17.06.2013 at 13:12 | Permalink

    Подскажите пожалуйста, как сделать так чтоб браузер запускался с конкретным профайлом?
    Раньше (без фусидидиса), я делал, как описано в одной из Ваших статей, и был доволен:
    public void setUp() throws Exception {
    ProfilesIni allProfiles = new ProfilesIni();
    // PROFILE_NAME — имя профиля без указания пути, например, «default»
    FirefoxProfile profile = allProfiles.getProfile(«Vitali4ek»);
    webdriver = new FirefoxDriver(profile);
    А теперь, куда бы не приткнул, либо открывается без моего профиля, либо сначала открывается браузер с профилем, а затем без профиля. И во втором выполняется тест.
    Заранее спасибо 🙂

    • Tatyana's Gravatar Tatyana
      17.06.2013 at 15:41 | Permalink

      Для Thucydides путь к профилю можно задать только через system properties, например, при запуске из командной строки

      mvn test -Dwebdriver.firefox.profile=PATH_TO_PROFILE

      или установить программно до запуска тестов:

      System.setProperty("webdriver.firefox.profile", PATH_TO_PROFILE);

      • Vitalik's Gravatar Vitalik
        18.06.2013 at 07:39 | Permalink

        Большое спасибо!

  11. Димко's Gravatar Димко
    03.09.2013 at 09:24 | Permalink

    Татьяна, спасибо за интересную статью!

    У меня к вам небольшой вопрос:

    Есть возможность получить обект pageObjectClass например путём
    getPages().get(LoginPage.class)

    А есть ли возможность получить этот объект, для текущей страницы во время прохождения теста?

    к примеру

    loginPage.open(); — после открытия логин страницы, вызвать метод аля
    —> pageObjectClass = getPages().getCurrentPage()
    который бы вернул LoginPage.class
    loginPage.do_login(); — были введены логин, пароль, нажата кнопка логин, как результат — мы на home page
    —> pageObjectClass = getPages().getCurrentPage()
    который бы вернул HomePage.class

    Надеюсь понятно описал суть

    Заранее благодарен за ответ.

    • Tatyana's Gravatar Tatyana
      03.09.2013 at 11:12 | Permalink

      Добрый день, никакого стандартного метода для это не существует, получить класс текущей страницы динамически средствами Thucydides невозможно.
      Можно написать такой метод поиска нужного класса самим, отталкиваясь от текущего url, но задача очень нетривиальная и сильно зависит от построения url сайта.

      • Димко's Gravatar Димко
        04.09.2013 at 11:16 | Permalink

        Спасибо Татьяна!

        Я реализовал это методом кеширования текущей страницы, при каждом переходе на оную, но рассчитывал на более феншуйный подход:)

  12. Александр's Gravatar Александр
    27.05.2014 at 18:48 | Permalink

    Татьяна, здравствуйте. Подскажите пожалуйста, можно ли как-нибудь ограничить время загрузки страницы? У меня есть параметрический тест, который открывает n страниц и выполняет на них действия. Проблема заключается в том, что одна из страниц грузится очень долго, можно считать бесконечно. Собственно именно для вычисления таких страниц и был создан этот тест. Собственно, он даже не содержит PageObject, всё происходит в шагах:

    @Step
    public void startSystem(String url) {
    getDriver().manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);
    getDriver().get(url);
    }

    Для дефолтного фаерфокса работает как нужно. Проблема возникает когда я начинаю использовать HTMLUnit, задаю я его в классе теста:

    @Managed(uniqueSession = true, driver = "HTMLUnit")
    public WebDriver driver;

    он почему-то совершенно не реагирует на заданное максимальное время ожидания и не прекращает тест.

    Есть, конечно, вариант ограничить время выполнения теста установив timeout теста:

    @Test(timeout = 10000)
    public void someTest() {...}

    Но в этом случае, судя по отчету thucydides тест прогоняется n раз, где n — количество параметров, т.е. количество страниц.
    Как быть?

Свежие записи

  • WebDriver и SSL Untrusted certificate
  • Видеозапись выполнения тестов Selenium
  • Selenium WebDriver: basic авторизация
  • BrowserMob Proxy + Selenium: автоматизация сбора данных о производительности
  • Hibernate 4: UserType пользовательский тип данных (часть 2)

Поиск

Рубрики

  • Hibernate ORM
  • SEO
  • Разное
  • Тестирование
    • JUnit
    • Selenium
    • Thucydides

Метки

Actions AJAX Alert AutoIt ChromeDriver Exceptions ExpectedConditions FindElement FirefoxDriver Hibernate InternetExplorerDriver Java Javascript Jenkins JUnit4 Maven PageFactory Page Object RemoteWebDriver Select Selenium IDE Selenium Server Selenium WebDriver switchTo Thucydides WebDriverWait XPath Автоматизированное тестирование база данных заработок в сети сеть Интернет скорость продвижения сайта статейное продвижение услуги продвижения

Реклама


Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.
Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.
Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.
Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.

Блог вебразработчика
Функциональное тестирование и продвижение сайтов

Яндекс.Метрика