diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index 8723fbaa7..bf2cf1e51 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -2,7 +2,7 @@ name: Deploy Hugo site to Pages on: push: - branches: ["master", "design"] + branches: ["master", "multilingual"] workflow_dispatch: permissions: @@ -19,7 +19,7 @@ defaults: shell: bash jobs: - build: + build-en: runs-on: ubuntu-latest steps: - name: Setup Hugo @@ -32,13 +32,16 @@ jobs: - name: Setup Pages id: pages uses: actions/configure-pages@v5 - - name: Build with Hugo + - name: Build EN site env: HUGO_CACHEDIR: ${{ runner.temp }}/hugo_cache HUGO_ENVIRONMENT: production TZ: America/New_York run: | - hugo --minify --baseURL "${{ steps.pages.outputs.base_url }}/" + hugo --minify \ + --config hugo.toml,hugo-en.toml \ + --baseURL "${{ steps.pages.outputs.base_url }}/" \ + --destination public # Preserve /rss URL (without .xml extension) cp public/rss.xml public/rss - name: Upload artifact @@ -46,13 +49,43 @@ jobs: with: path: ./public - deploy: + deploy-en: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest - needs: build + needs: build-en steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 + + build-and-deploy-ru: + runs-on: ubuntu-latest + steps: + - name: Setup Hugo + uses: peaceiris/actions-hugo@v3 + with: + hugo-version: '0.160.1' + extended: true + - name: Checkout + uses: actions/checkout@v6 + - name: Build RU site + env: + HUGO_CACHEDIR: ${{ runner.temp }}/hugo_cache + HUGO_ENVIRONMENT: production + TZ: America/New_York + run: | + hugo --minify \ + --config hugo.toml,hugo-ru.toml \ + --destination public-ru + # Preserve /rss URL (without .xml extension) + cp public-ru/rss.xml public-ru/rss + - name: Deploy to ru.selenide.org + uses: peaceiris/actions-gh-pages@v4 + with: + personal_token: ${{ secrets.RU_SELENIDE_ORG_DEPLOY_TOKEN }} + external_repository: selenide/selenide-ru + publish_branch: gh-pages + publish_dir: ./public-ru + cname: ru.selenide.org diff --git a/.gitignore b/.gitignore index 48138616f..de7874a84 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ # Hugo build output public/* !public/javadoc +public-en/ +public-ru/ resources/_gen/ # OS files diff --git a/CLAUDE.md b/CLAUDE.md index 8145c4b49..6fb0b4b7d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,11 +2,14 @@ ## Project overview -Official website for **Selenide** (selenide.org) — a Java UI test automation framework built on Selenium WebDriver. This is a Hugo static site hosted on GitHub Pages from the `selenide/selenide.github.io` repository. +Official website for **Selenide** — a Java UI test automation framework built on Selenium WebDriver. +This single multilingual Hugo project powers both: +- `selenide.org` (English) — hosted on `selenide/selenide.github.io` +- `ru.selenide.org` (Russian) — hosted on `selenide/selenide-ru` (gh-pages branch) ## Tech stack -- **Hugo** static site generator +- **Hugo** static site generator (multilingual) - **Goldmark** for Markdown rendering (with `unsafe: true` for raw HTML in content) - **Go templates** for layouts - **jQuery 3.6.0** + jQuery UI 1.13.1 (from CDN) @@ -15,59 +18,57 @@ Official website for **Selenide** (selenide.org) — a Java UI test automation f ## Directory structure ``` -hugo.toml Main Hugo config +hugo.toml Main Hugo config (both languages) +hugo-en.toml Override for EN-only production build +hugo-ru.toml Override for RU-only production build +i18n/ + en.toml English UI strings + ru.toml Russian UI strings content/ - _index.md Homepage (content in layouts/index.html) - blog/ Blog posts (185+ files), _index.md is the blog list - documentation/ _index.md + sub-pages (page-objects, screenshots, reports, clouds, selenide-vs-selenium) - quick-start.md, faq.md, users.md, quotes.md, contacts.md, javadoc.md, thanks.md + en/ English content (homepage, blog, docs, etc.) + ru/ Russian content layouts/ _default/ baseof.html, single.html, list.html, users.html - blog/ single.html (post), list.html (blog index with year/month grouping) - partials/ donate.html, main-menu.html, documentation-menu.html, quicklinks.html, title.html, analytics.html + blog/ single.html (post), list.html (blog index) + partials/ donate.html, main-menu.html, quicklinks.html, title.html, analytics.html shortcodes/ selenide-version.html, selenium-changelog.html, documentation-menu.html - index.html Homepage template + index.html Homepage template (uses i18n) 404.html Custom 404 assets/ themes/ingmar/css/ CSS files (processed via Hugo Pipes for fingerprinting) static/ - images/ Logos, screenshots — year-based subdirs (images/2024/, etc.) - assets/themes/ingmar/js/ JavaScript files - test-page/ HTML test pages for Selenide demos + images/ Logos, screenshots — year-based subdirs + assets/themes/ingmar/js/ JavaScript CNAME, favicon.ico, robots.txt data/ users.json Companies using Selenide - user_tags.json Tags for filtering users page + user_tags.json Tags for users page ``` -## Key config (hugo.toml) - -- `params.selenideVersion = "7.16.0"` — used via `{{}}` shortcode in content -- `params.seleniumChangelog` — Selenium changelog URL, used via `{{}}` shortcode -- Blog permalinks: `/:year/:month/:day/:title/` -- Pages use `url:` in front matter for explicit URLs (e.g., `/quick-start.html`) -- `buildFuture = true` — builds future-dated posts -- `markup.goldmark.renderer.unsafe = true` — allows raw HTML in Markdown - ## Local development ```bash -# Install Hugo (macOS) brew install hugo +./start.sh # serves both languages: EN at /, RU at /ru/ +``` + +## Production builds (each language at root) + +```bash +# EN site (selenide.org) +hugo --config hugo.toml,hugo-en.toml --destination public-en -# Serve locally -./start.sh -# or manually: -hugo server --buildFuture --port 4001 +# RU site (ru.selenide.org) +hugo --config hugo.toml,hugo-ru.toml --destination public-ru ``` -Output goes to `public/` directory. +Each override toml sets `disableLanguages` and `defaultContentLanguage` so the chosen language sits at the site root. ## Creating content ### New blog post -Create `content/blog/YYYY-MM-DD-slug-name.md`: +Create under `content/en/blog/` or `content/ru/blog/` as `YYYY-MM-DD-slug.md`: ```yaml --- @@ -78,53 +79,42 @@ category: headerText: "Short tagline" tags: [] --- - -Content here... ``` ### New page -Create in `content/` with `url:` for the desired path: +Create under `content/en/` or `content/ru/` with `url:` for the path: ```yaml --- title: "Page Title" -header: "Display Header" -cssClass: my-class url: /page-name.html -headerText: "Subtitle" --- ``` ## Shortcodes -- `{{}}` — outputs current Selenide version from `hugo.toml` -- `{{}}` — outputs Selenium changelog URL -- `{{}}` — renders docs sidebar menu +- `{{}}` — current Selenide version from `hugo.toml` +- `{{}}` — Selenium changelog URL +- `{{}}` — renders docs sidebar menu (localized) -## Conventions +## Internationalization -- Blog posts are mostly Selenide release announcements, following the pattern "Released Selenide X.Y.Z" -- Posts use anchor-linked table of contents at the top for sections -- Images go in `static/images/` — use year-based subdirectories (e.g., `images/2026/`) -- Company logos for the users page go in `static/images/` -- Pages that use `layout: users` get the custom users template with data-driven content -- When releasing a new Selenide version: update `params.selenideVersion` in `hugo.toml`, create a release blog post +- UI strings live in `i18n/en.toml` and `i18n/ru.toml`, accessed via `{{ T "key" }}` +- Page content lives in language-specific `content/en/` and `content/ru/` trees +- Layouts branch on `.Site.Language.Lang` only when the structure itself differs (e.g. docs menu has extra links in RU) -## Layout hierarchy +## Conventions -``` -baseof.html (HTML shell, head, header, footer) - └── block "main" filled by: - ├── index.html (homepage) - ├── blog/single.html (blog posts) - ├── blog/list.html (blog index) - ├── _default/single.html (regular pages) - ├── _default/users.html (users page) - └── 404.html -``` +- Blog posts are mostly release announcements: "Released Selenide X.Y.Z" / "Вышла Selenide X.Y.Z" +- Release posts should be added in BOTH `content/en/blog/` and `content/ru/blog/` +- Images go in `static/images/` — use year-based subdirectories +- When releasing a new Selenide version: update `params.selenideVersion` in `hugo.toml`, create release blog posts in both languages ## Deployment -The site deploys to GitHub Pages. The `static/CNAME` file sets the custom domain `selenide.org`. -A GitHub Actions workflow runs `hugo` and deploys the `public/` directory. +GitHub Actions (`.github/workflows/hugo.yml`): +1. **EN job** — builds EN site and deploys via `actions/deploy-pages` to this repo's Pages (selenide.org) +2. **RU job** — builds RU site and pushes via `peaceiris/actions-gh-pages` to `selenide/selenide-ru` repo's `gh-pages` branch (ru.selenide.org) + +The RU cross-repo push requires a `RU_SELENIDE_ORG_DEPLOY_TOKEN` secret (PAT with push access to `selenide/selenide-ru`). diff --git a/content/_index.md b/content/en/_index.md similarity index 100% rename from content/_index.md rename to content/en/_index.md diff --git a/content/archive.md b/content/en/archive.md similarity index 81% rename from content/archive.md rename to content/en/archive.md index b69bea2cd..a45fc7c54 100644 --- a/content/archive.md +++ b/content/en/archive.md @@ -1,6 +1,6 @@ --- title: "Selenide blog" -url: /archive.html +url: archive.html --- +#{/if} +``` + +Естественно, приведённый код зависит от вашего фреймворка, приложения, проекта и т.д. +Цвет и толщина рамки - от вашего дизайна. Возможно даже, это должна быть не рамка, а что-то другое. +Главное, чтобы было видно, какой элемент был реально кликнут. + +Здесь можно посмотреть один из примеров реализации: [Highlighter](https://github.com/selenide-examples/gmail/blob/master/test/org/selenide/examples/gmail/Highlighter.java). + +## Что теперь? + +Если у вас есть мигающие тесты (а они есть у всех) - начните с этого шага, и вы хотя бы увидите, куда попал клик. +А дальше уже будем разбираться. + +
+ + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2019-12-07-advent-calendar-csrf-protection.md b/content/ru/blog/2019-12-07-advent-calendar-csrf-protection.md new file mode 100644 index 000000000..ddd26911f --- /dev/null +++ b/content/ru/blog/2019-12-07-advent-calendar-csrf-protection.md @@ -0,0 +1,201 @@ +--- +slug: "advent-calendar-csrf-protection" +date: 2019-12-07 +title: "Как протестировать защиту от CSRF атаки" +description: "" +category: +headerText: "Selenide Advent Calendar
День 7" +tags: [] +--- +Привет! + +Сегодня 7 день рождественского календаря Selenide. +И сегодня мы поговорим о тестировании безопасности. + +# Что такое CSRF? + +Одна из самых распространённых атак - это CSRF (Cross-Site Request Forgery), или подделка межсайтовых запросов. +Подробно о ней я рассказывал в видосике [WTF Security](https://www.youtube.com/watch?v=z-aEjd22BGU), а сейчас для нас +важно то, что защиту от этой атаки легко протестировать вашими обычными автотестами. + +Для того, чтобы веб-приложение было защищено от CSRF-атак, с каждым его POST-запросом должен посылаться один хитрый +параметр. Он обычно называется `authenticityToken` (хотя и не обязательно). Когда вы заходите в одной вкладке, скажем, + в свой интернет-банк, а в другой вкладке на сайт с котиками, зловредный код на этом сайте может послать POST-запрос вашему + банку для совершения платежа на счёт хакера. Хакер может послать счёт и сумму, а также все cookies из вашей вкладки, но + он не сможет послать `authenticityToken` (потому, что он уникальный для каждой сессии и не хранится в cookies). + +А типичная ошибка такая: веб-приложение либо не посылает `authenticityToken` на сервер с каким-то POST-запросом, +либо на сервере не проверяет пришедший токен. + +
+ +### Короче, как проверить защищённость? + +У вас уже есть куча автотестов, покрывающих весь критичный функционал вашего веб-приложения. +Мы убьём двух зайцев разом: во время запуска этих тестов мы будем перехватывать каждый POST-запрос и посылать точно такой +же, но с изменённым `authenticityToken`. И будем проверять, что сервер вернул ошибку. Обычно это ошибка 403 Forbidden. + +
+ +### Звучит сложно. Как это закодить? + +Не так уж сложно. +Как вы знаете, селенид может запускать свой встроенный прокси-сервер. Изначально он использовался для скачивания файлов, +но к нему можно добавлять и свои "листенеры", которые могут перехватывать все запросы между браузером и тестируемым приложением. +Это мы и сделаем. + +
+ +#### Шаг 1. Включаем селенидовский прокси-сервер + +```java +Configuration.proxyEnabled = true; +``` + +(это нужно сделать ДО открытия браузера) + +
+ +#### Шаг 2. Добавляем листенер для прокси-сервера + +```java +abstract class BaseTest { + private AuthenticityTokenChecker authenticityTokenChecker = new AuthenticityTokenChecker(); + + // и где-то сразу после open("http://..."): + getSelenideProxy().getProxy().addRequestFilter(authenticityTokenChecker); +} +``` + +На данный момент это можно сделать только ПОСЛЕ открытия браузера, что иногда не очень удобно. +Я надеюсь, в следующей версии селенида мы сможем сделать так, чтобы листенеры для прокси-сервера можно было добавлять в любой момент. + +
+ +#### Шаг 3. Реализуем AuthenticityTokenChecker + +```java +import com.codeborne.selenide.Configuration; +import io.netty.handler.codec.http.*; +import net.lightbody.bmp.filters.*; +import net.lightbody.bmp.util.*; + +public class AuthenticityTokenChecker implements RequestFilter { + private final HttpClient httpClient = HttpClient.newBuilder().build(); + + private final List unprotectedUrls = new ArrayList<>(1); + + public void reset() { + unprotectedUrls.clear(); + } + + public List getUnprotectedUrls() { + return unprotectedUrls; + } + + @Override + public HttpResponse filterRequest(HttpRequest httpRequest, HttpMessageContents contents, HttpMessageInfo httpMessageInfo) { + if (httpRequest.getMethod() != HttpMethod.POST) return null; // игнорируем не-POST запросы + if (!httpRequest.getUri().startsWith(Configuration.baseUrl)) return null; // игнорируем запросы хрома к google.com и подобным ресурсами + if (Этому урлу разрешено и без токена) return null; // некоторым post-запросам не требуется защита + + String body = contents.getTextContents(); + if (!body.contains("authenticityToken=")) { + unprotectedUrls.add("No 'authenticityToken=' found for " + httpRequest.getUri() + " in " + body); + return null; + } + + sendHackedPostRequest(httpRequest, contents); + return null; + } +} +``` + +Обратите внимание: `return null;` значит "не изменяй запрос". То есть браузер пошлёт изначальный запрос на сервер без изменений, +и нормальное течение вашего теста не будет нарушено. + +
+ +#### Шаг 4. Посылаем хакнутый POST-запрос + +```java + + private void sendHackedPostRequest(HttpRequest httpRequest, HttpMessageContents contents) throws IOException, InterruptedException { + // Над этой строчкой придётся поработать. + // Формат запроса (и даже имя параметра "authenticityToken") может зависеть от вашего приложения. + // Обратите внимание, что параметров "authenticityToken" может быть несколько (сразу кидайте ошибку, если они разные). + // Если в POST-запросе сабмитится форма, да ещё и с файлами, параметр "authenticityToken" придётся выцепить немножко по-другому. + String hackedBody = contents.getTextContents() + .replace("authenticityToken=1234567890").на("authenticityToken=hack-me-if-you-can"); + + java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder() + .uri(URI.create(httpRequest.getUri())) + .timeout(Duration.ofSeconds(1)); + + for (Map.Entry header : httpRequest.headers()) { + if (!restrictedHeaders.contains(header.getKey().toLowerCase())) { + builder.header(header.getKey(), header.getValue()); + } + } + + java.net.http.HttpRequest request = builder + .POST(java.net.http.HttpRequest.BodyPublishers.ofString(hackedBody)) + .build(); + + log.info("Sending hacked request to {}", httpRequest.getUri()); + + java.net.http.HttpResponse httpResponse = httpClient.send(request, java.net.http.HttpResponse.BodyHandlers.ofString()); + + if (httpResponse.statusCode() == 403) { + log.info("Hacked request was rejected: {} {}", httpResponse.statusCode(), httpRequest.getUri()); + } + else { + log.error("HACK SUCCEEDED {} {}", httpResponse.statusCode(), httpRequest.getUri()); + unprotectedUrls.add("Detected URL without authenticity token check: " + httpRequest.getUri()); + } + } + + private static final Set restrictedHeaders = Set.of("connection", "content-length", + "date", "expect", "from", "host", "upgrade", "via", "warning"); + +``` +Конкретно эта реализация использует `HttpClient` из Java 11, но если вы из тех бедолаг, что до сих пор сидят на Java 8, +вы можете заменить его на OkHttp, Apache Http Client или что-то подобное. + +
+ +#### Шаг 5. Валим тест, если нашлись незащищённые запросы + +```java +abstract class BaseTest { + @Before void resetChecker() { + authenticityTokenChecker.reset(); + } + + @After + public void verifyThatAllPostRequestsAreProtectedWithAuthenticityToken() { + if (!authenticityTokenChecker.getUnprotectedUrls().isEmpty()) { + fail(String.valueOf(authenticityTokenChecker.getUnprotectedUrls())); + } + } +} +``` + +
+ +## Что теперь? + +Мы убили двух зайцев и научились автоматически проверять защиту от CSRF-атак при запуске наших обычных автотестов. +Это не фантазия, мы реально так сделали на одном проекте и нашли две серьёзных уязвимости в настоящем интернет-банке. + +Хорошо, но этого мало. На свете ещё куча атак. + +Пересмотрите [WTF Security](https://www.youtube.com/watch?v=z-aEjd22BGU), почитывайте [OWASP 10](https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project) +и мыслите креативно, а как ещё можно убить третьего и четвёртого зайца вашими автотестами. + + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2019-12-09-advent-calendar-statics.md b/content/ru/blog/2019-12-09-advent-calendar-statics.md new file mode 100644 index 000000000..85d7c63af --- /dev/null +++ b/content/ru/blog/2019-12-09-advent-calendar-statics.md @@ -0,0 +1,152 @@ +--- +slug: "advent-calendar-statics" +date: 2019-12-09 +title: "Почему статики запретили, а потом разрешили?" +description: "" +category: +headerText: "Selenide Advent Calendar
День 9" +tags: [] +--- +Привет! + +9 день рождественского календаря Selenide. +Расскажу о том, что сильнее всего волнует общественность. + +# Почему статики запретили в 5.0.0, а потом снова разрешили? + +Короткий ответ: запретили случайно. Но правильно сделали.  + +А теперь подробнее.  + +### Коротко о хранении вебдрайверов в селениде + +Селенид изначально хранил вебдрайверы в ThreadLocal. +Это позволяет запускать тесты параллельно: в разных потоках - разные вебдрайверы. Код выглядит примерно так: + +```java +class WebDriverRunner { + private static final ThreadLocal webdriver = new ThreadLocal<>(); + private static final ThreadLocal proxy = new ThreadLocal<>(); +} + +``` + +Скажем, метод `$("a").click()` работает примерно так: + +```java + WebDriverRunner.webdriver.get().findElement("a").click(); +``` + +## Коротко про `SelenideDriver` + +Но ThreadLocal накладывает ограничение: ты не можешь использовать в одном потоке два вебдрайвера +(а также в двух потоках - один и тот же вебдрайвер, но до этого мы пока не дошли). + +Это мы и собирались решить в Selenide 5.0.0. Мы сделали специальный класс `SelenideDriver`, позволяющий использовать два +вебдрайвера в одном тесте: + +```java +SelenideDriver browser1 = new SelenideDriver(); +SelenideDriver browser2 = new SelenideDriver(); + +browser1.open("https://google.com"); +browser2.open("http://yandex.ru"); + +browser1.$(h1).shouldHave(text("Google")); +browser2.$(h1).shouldHave(text("Yandeks")); +``` + +Для этого пришлось сделать большой рефакторинг, так чтобы внутри самого селенида нигде не использовались старые добрые +статические методы `open()`, `$` и `$$`. Везде, где нужен вебдрайвер, селенид теперь использовал параметр `SelenideDriver`. +Да-да, пришлось его прокидывать во все методы как параметр. + + +## И вот тут главный вопрос + +А что делать со старыми добрыми статическими методами `open()`, `$` и `$$`? Они должны откуда-то взять инстанс `SelenideDriver` и передать +его дальше в кишки селенида. Откуда его взять? + + +## Selenide 5.0.0: Статикам наносят удар + +На тот момент этот вопрос решили так (как оказалось, это решение сильно повлияло на ход дел). +В класс `WebDriverRunner` добавили третий ThreadLocal: + +```java + private static final ThreadLocal selenideDriver = new ThreadLocal<>(); +``` + +Сам `SelenideDriver` - это, грубо говоря, очень простой класс с двумя полями `WebDriver` и `SelenideProxyServer`. +И в целом всё хорошо работало и решало поставленную задачу. + +Чего я не мог предусмотреть на тот момент - это того, что многие люди определяли веб-элементы в **статических** полях: + +```java +public class MyPageObject { + public static SelenideElement fname = $("#fname"); + public static SelenideElement lname = $("#lname"); +} +``` + +Да ещё и переоткрывали браузер между тестами. + + +### Важный нюанс: +в Selenide 5.0.0 мы сделали ещё одно улучшение. +Раньше селенид автоматически открывал новый браузер, если его ещё нет, что часто вызывало недоумение, ибо браузер +иногда открывался в очень неожиданные моменты (например, при попытке залогировать ошибку, произошедшую из-за закрэшившегося браузера). + +Конечно, это происходило из-за плохого кода тестов, но _мы же создали селенид, чтобы помогать людям, верно?_ +Поэтому с версии 5.0.0 селенид стал чётко говорить: "Браузера нет, работать не могу. Вызови сначала метод `open()`, тогда поговорим." + + +### И что же свалилось? + +Совпадение этих двух факторов привело к следующей проблеме: +1. Человек создаёт статическую переменную `static SelenideElement fname = $("#fname")`. +2. Этот `fname` запоминает, с каким инстансом `SelenideDriver` он был создан. +3. Человек в конце теста закрывает браузер +4. В следующем тесте человек открывает новый браузер и снова обращается к статическому полю `fname`. +5. А `fname` обращается к своему `SelenideDriver`, с которым он был изначально создан. +6. И кидает ошибку, потому что тот браузер уже закрылся. + +Больше года - с сентября 2018 до октября 2019 - я пытался объяснить всем, что статические переменные - это зло, не надо их использовать. +Сделал даже специально доклад ["Антистатик"](https://www.youtube.com/watch?v=4JJNccWtdNI). + +Но в итоге сдался из тех соображений, что слишком много людей, которым пришлось бы переписывать свои тесты. +Даже если они согласны насчёт злостности статических переменных, переписать всё - это зачастую неподъёмная задача. +_Мы же создали селенид, чтобы помогать людям, верно?_ + + +## Selenide 5.4.0: Статики победили + +Как в итоге решили эту проблему? + +Довольно просто. Мы заменили `ThreadLocal` на статическую переменную (да, вы не ослышались :)) + +```java +private static final SelenideDriver = new ThreadLocalSelenideDriver(); +``` + +Теперь наш "статический" `SelenideDriver` - один на всех. Он никогда не закрывается. Все статические поля, созданные с +ним, будут жить вечно. Но он и не хранит в себе поля `WebDriver` и `SelenideProxyServer`. Он каждый берёт их из +тредлокалов `WebDriverRunner`. + + + +### P.S. +Поэтому в версии 5.4.0 пропал метод `WebDriverRunner.getSelenideDriver()`. + +Я очень удивился, что многие люди уже успели его использовать. Люди, я вас не понимаю! _Как вы умудряетесь всё так неправильно использовать?_ +Ок, я не подумав, сделал его публичным. Моя ошибка. Но он не упомянут ни в каких пресс-релизах, ни в какой документации. +Как могла кому-то прийти в голову идея его использовать? Как эта магия вообще происходит? + +## Что теперь? + +Мы снова вернули возможность объявлять `SelenideElement` в статических полях. +Но пожалуйста, не злоупотребляйте этим. +Я всё ещё это не одобряю. :) + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2019-12-10-advent-calendar-download-files.md b/content/ru/blog/2019-12-10-advent-calendar-download-files.md new file mode 100644 index 000000000..4bd75bbe2 --- /dev/null +++ b/content/ru/blog/2019-12-10-advent-calendar-download-files.md @@ -0,0 +1,97 @@ +--- +slug: "advent-calendar-download-files" +date: 2019-12-10 +title: "Как скачать файл с помощью Selenide" +description: "" +category: +headerText: "Selenide Advent Calendar
День 10" +tags: [] +--- +Добрый вечер! + +На дворе декабрь, и в сегодняшнем посте рождественского календаря Selenide мы поговорим о том, какие возможности +для скачивания файлов есть в Selenide. + +**UPD** +Ниже описаны только два способа скачивания - [`HTTPGET`](#HTTPGET) и [`PROXY`](#PROXY). +Позже появились [третий способ `FOLDER`](/2020/07/08/selenide-5.13.0/#new-file-download-mode-folder) и [четвёртый способ `CDP`](/2024/02/07/selenide-7.1.0/#download-files-with-cdp). +Возможно, вам нужен как раз один из них, если у вашей ссылки нет атрибута `href`, и прокси у вас не заводится. + +
+ +# Как я могу скачать файл в моём тесте? + +В какой-то момент нашей карьеры каждый из нас сталкивается с необходимостью скачать какой-то файл в тесте. + +Как мы помним, в Selenium это было непросто, потому что для разных браузеров требуются разные настройки. +Например, вот так выглядит создание профиля Firefox с нужными настройками: + +```java +profile.setPreference("browser.download.dir", downloadPath); +profile.setPreference("browser.download.folderList", 2); +profile.setPreference("browser.download.manager.showWhenStarting", false); +profile.setPreference("browser.helperApps.alwaysAsk.force", false); +profile.setPreference("browser.helperApps.neverAsk.saveToDisk", mimeTypes); +profile.setPreference("browser.download.manager.focusWhenStarting",false); +profile.setPreference("browser.download.manager.useWindow", false); +profile.setPreference("browser.download.manager.showAlertOnComplete", false); +profile.setPreference("pdfjs.disabled", true); +``` + +### А в Selenide {#HTTPGET} +Проблема решается гораздо проще - методом `$.download()`. + +Чтобы скачать файл, в Selenide достаточно просто вызвать метод: + +```java +File report = element.download(); +``` + +И Selenide автоматически сделает всё, что надо. Вам не придётся возиться со всплывающим окошком, которое спрашивает, +куда сохранить файл, и потом закрывать его. + +Selenide сохранит скачанный файл в папку `build/reports/tests`. Это та же папка, где Gradle генерирует результаты прогона тестов, +так что их как раз удобно видеть вместе. + +Конечно, поменять эту папку тоже можно: + +```java +Configuration.downloadsFolder = ; +``` + +### НО: {#PROXY} +Таким образом можно скачивать файлы только со ссылкой с атрибутом "href". + +Но что, если у меня ссылки с атрибутом "href"? Так бывает, например, когда файл скачивается в результате сабмита формы. +В этом случае можно скачивать файлы с помощью встроенного в селенид прокси-сервера. + +Для начала нам нужно включить его (т.к. он по умолчанию выключен): + +```java +Configuration.proxyEnabled = true; +Configuration.fileDownload = PROXY; +``` + +После этого мы снова можем вызывать метод `$.download()`, но теперь он стал более могущественным и не требует наличия атрибута "href": + +```java +File report = element.download(); +``` + +### Хозяйке на заметку: +Не забудьте увеличить таймаут, если собираетесь скачивать файл большого размера. + +Файл будет скачан в папку по умолчанию (что-то типа `C:\downloads and settings\downloads`). +Таким образом, скачанный файл окажется в двух местах: `c:\downloads...` и `build/reports/tests`. + +Если это для вас проблема, можете в конце теста удалить ненужную папку, чтобы очистить место на диске: + +```java +FileUtils.deleteDirectory(new File(<папка, подлежащая удалению>)); +``` + +Узнать подробнее про механизмы скачивания файлов можно [тут](https://ru.selenide.org/2016/08/27/selenide-3.9.1/). + + + +Maciej Grymuza (figrym@gmail.com) diff --git a/content/ru/blog/2019-12-12-advent-calendar-actions.md b/content/ru/blog/2019-12-12-advent-calendar-actions.md new file mode 100644 index 000000000..eea37ff5e --- /dev/null +++ b/content/ru/blog/2019-12-12-advent-calendar-actions.md @@ -0,0 +1,90 @@ +--- +slug: "advent-calendar-actions" +date: 2019-12-12 +title: "Actions" +description: "" +category: +headerText: "Selenide Advent Calendar
День 12" +tags: [] +--- +Привет! + +В сегодняшнем выпуске рождественского календаря мы рассмотрим, как можно использовать "действия" (Actions) в Selenide. + +Иногда при написании автотестов мы сталкиваемся со странными проблемами. Уверен на 100%, каждый из нас испытывал или +будет испытывать необычные проблемы, которые блокируют нашу работу. +Например, у нас часто не получается кликнуть на какой-то элемент, и стандартная селениумовская/селенидовская команда типа + +```java + element.click(); +``` + +не работает. Причин, по которым клик может не срабатывать - множество. Но мы не можем сдаться просто так, мы должны +найти какое-то решение. В Selenium для таких случаев есть класс `Actions`, который позволяет выполнить клик иначе: + +```java + WebElement element = ; + Actions actions = new Actions(driver); + actions.moveToElement(element); + actions.click(); + actions.build().perform(); +``` + +Этот вариант иногда срабатывает там, где обычный клик бессилен. + +#### Но как сделать это в Selenide? + +Оказывается, в Selenide это ещё проще, чем в Selenium (как, собственно, и всё в Selenide :)). +В Selenide тоже есть `Actions`: + +```java + SelenideElement element = $(); + actions().moveToElement(element).click(element).perform(); +``` + +Здесь `actions()` - это один из тех методов, которые вы можете магически подключить волшебным импортом: + +```java + import static com.codeborne.selenide.Selenide.*; +``` + +Заметить, чтобы использовать `actions()`, не нужен webdriver! + +##### Чумачечий drag and drop + +Если вы читали документацию, вы знаете, что в Selenide по умолчанию есть два типа операций "drag and drop": + +1. `dragAndDropTo​(java.lang.String targetCssSelector);` +2. `dragAndDropTo​(org.openqa.selenium.WebElement target);` + +Первый метод перетаскивает элемент в цель по CSS локатору. Второй - в другой WebElement. + +Но что, если мы не знаем точно, в какой элемент нужно перетащить? +Допустим, у нас есть просто пустая страница, и мы хотим перетащить несколько объектов в разные места на этой странице. +И тут снова на помощь приходят `Actions`. В Selenium мы бы сделали это примерно так: + +```java + WebElement element = driver.findElement(By.some); + Actions actions = new Actions(driver); + actions.dragAndDropBy(element, xOffset, yOffset).perform(); +``` + +Где `xOffset` и `yOffset` - сдвиг по горизонтали и вертикали. + +В Selenide это выглядит чуть короче: + +```java + SelenideElement element = ; + actions().dragAndDropBy(element, xOffset, yOffset).perform(); +``` + +Таким образом мы можем перетащить элемент в любую точку, даже не зная локатора цели. + +## Что дальше? + +Конечно же, это только пара примеров использования `actions()` в Selenide, и вы можете экспериментировать и находить другие варианты. + +Наслаждайтесь `actions()`! + +Maciej Grymuza (figrym@gmail.com) + diff --git a/content/ru/blog/2019-12-15-advent-calendar-drag-and-drop.md b/content/ru/blog/2019-12-15-advent-calendar-drag-and-drop.md new file mode 100644 index 000000000..bb03678a3 --- /dev/null +++ b/content/ru/blog/2019-12-15-advent-calendar-drag-and-drop.md @@ -0,0 +1,33 @@ +--- +slug: "advent-calendar-drag-and-drop" +date: 2019-12-15 +title: "Drag and Drop" +description: "" +category: +headerText: "Selenide Advent Calendar
День 15" +tags: [] +--- +Привет! + +В сегодняшнем выпуске рождественского календаря мы посмотрим короткое, но весёлое видео о том, как перетаскивать элементы в Selenide. + +### Селенид умеет перетаскивать элементы? + +Да, в селениде есть метод Drag'n'Drop. Вот скучное описание из блога селенида: + +```java + $("#from").dragAndDropTo("#to") +``` + + +А вот весёленькое описание от Martin Škarbala: + + + +Вот это подача! + + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org + diff --git a/content/ru/blog/2019-12-16-advent-calendar-browser-logs.md b/content/ru/blog/2019-12-16-advent-calendar-browser-logs.md new file mode 100644 index 000000000..21a3f2b90 --- /dev/null +++ b/content/ru/blog/2019-12-16-advent-calendar-browser-logs.md @@ -0,0 +1,120 @@ +--- +slug: "advent-calendar-browser-logs" +date: 2019-12-16 +title: "Как получить логи браузера" +description: "" +category: +headerText: "Selenide Advent Calendar
День 16" +tags: [] +--- +Привет! + +Мы продолжаем наш рождественский календарь. +На сей раз мы посмотрим, как можно взглянуть хрому под вкладку "developer tools". +Это на случай, если вы хотите понять, какие ошибки писались и какие сетевые запросы летели из тестируемого приложения во время прогона тестов. + +> UPD Позже был реализован метод, который работает и в Firefox, и в Chromium браузерах: +> [Собираем логи браузера с помощью DevTools/BiDi](/2025/10/29/selenide-7.12.0/#browser-logs-with-bidi) + +
+
+ +Chromedriver предлагает следующий рецепт. + +### 1. Добавить щепотку строк при открытии браузера: + +```java +LoggingPreferences logPrefs = new LoggingPreferences(); +logPrefs.enable(LogType.BROWSER, Level.ALL); +logPrefs.enable(LogType.PERFORMANCE, Level.ALL); +capabilities.setCapability("goog:loggingPrefs", logPrefs); +``` + +До какой-то версии эта _капабилитя_ называлась "loggingPrefs", потом переименовали в "goog:loggingPrefs". +Не знаю, как в других браузерах. + +Кстати, помимо `BROWSER` и `PERFORMANCE`, есть и другие типы логов, но у меня они как-то нестабильно работали, да я + и пользы в них не увидел. Знаете больше? Делитесь! + + +### 2. В конце теста снять пенку с логов: + +```java +Logs logs = getWebDriver().manage().logs(); +printLog(logs.get(LogType.BROWSER)); + +void printLog(LogEntries entries) { + logger.info("{} log entries found", entries.getAll().size()); + for (LogEntry entry : entries) { + logger.info("{} {} {}", + new Date(entry.getTimestamp()), entry.getLevel(), entry.getMessage() + ); + } + } +``` + +### 3. Блюдо подаётся к отчёту примерно в таком виде: + +```java +BROWSER logs: + +Mon Dec 16 19:29:42 EET 2019 SEVERE http://localhost:9126/page/image/payment-promo-campaign-ozon.png - Failed to load resource: the server responded with a status of 404 (Not Found) +Mon Dec 16 19:49:14 EET 2019 INFO console-api 19:16 "start loading loans" +Mon Dec 16 19:49:14 EET 2019 INFO console-api 21:18 "loaded loans" +``` + +Здесь видны все логи, что есть обычно в Developer Tools -> Console. В том числе сообщения `console.log` и ошибки JavaScript. + + +### 4. Для гурманов можно подать десерт + +```json +PERFORMANCE logs: + +{"message":{"method":"Network.loadingFinished","params":{"encodedDataLength":0,"requestId":"2C9E49BC49DCD3CA6EA9644255E34DE5","shouldReportCorbBlocking":false,"timestamp":141439.076528}},"webview":"FF1A4E4EAAD7143749CD3740DF9BB95F"} +{"message":{"method":"Page.loadEventFired","params":{"timestamp":141439.234207}},"webview":"FF1A4E4EAAD7143749CD3740DF9BB95F"} +{"message":{"method":"Page.frameStoppedLoading","params":{"frameId":"FF1A4E4EAAD7143749CD3740DF9BB95F"}},"webview":"FF1A4E4EAAD7143749CD3740DF9BB95F"} +{"message":{"method":"Page.domContentEventFired","params":{"timestamp":141439.234834}},"webview":"FF1A4E4EAAD7143749CD3740DF9BB95F"} +{"message":{"method":"Page.frameResized","params":{}},"webview":"FF1A4E4EAAD7143749CD3740DF9BB95F"} +... +{"message":{"method":"Network.dataReceived","params":{"dataLength":0,"encodedDataLength":327,"requestId":"58583.71","timestamp":141474.021635}},"webview":"FF1A4E4EAAD7143749CD3740DF9BB95F"} +{"message":{"method":"Network.loadingFinished","params":{"encodedDataLength":586,"requestId":"58583.71","shouldReportCorbBlocking":false,"timestamp":141473.994219}},"webview":"FF1A4E4EAAD7143749CD3740DF9BB95F"} +``` + +### Плюс + +Каждая запись - это валидный JSON, его вполне можно парсить и анализировать прямо в тестах. + +Вот так выглядит отформатированная первая запись: + +```json +{ + "message":{ + "method":"Network.loadingFinished", + "params":{ + "encodedDataLength":0, + "requestId":"2C9E49BC49DCD3CA6EA9644255E34DE5", + "shouldReportCorbBlocking":false, + "timestamp":141439.076528 + } + }, + "webview":"FF1A4E4EAAD7143749CD3740DF9BB95F" +} +``` + +### Минус: + +* Что-то понять из этих логов сложно. Нужно строить поверх какие-то анализаторы. +* Здесь нет тела запроса. + + + +## Что теперь? + +В следующий раз вы изучим другие возможности получить логи - со статусами и телами запросов. + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2019-12-17-advent-calendar-browser-logs-with-js.md b/content/ru/blog/2019-12-17-advent-calendar-browser-logs-with-js.md new file mode 100644 index 000000000..be56e3d40 --- /dev/null +++ b/content/ru/blog/2019-12-17-advent-calendar-browser-logs-with-js.md @@ -0,0 +1,66 @@ +--- +slug: "advent-calendar-browser-logs-with-js" +date: 2019-12-17 +title: "Как получить логи браузера через JavaScript" +description: "" +category: +headerText: "Selenide Advent Calendar
День 17" +tags: [] +--- +Привет! + +В прошлом посте нашего рождественского календаря мы пробовали получить логи хрома с помощью _капабилити_ "goog:loggingPrefs". + +> UPD Позже был реализован метод, который работает и в Firefox, и в Chromium браузерах: +> [Собираем логи браузера с помощью DevTools/BiDi](/2025/10/29/selenide-7.12.0/#browser-logs-with-bidi) + +
+
+ + +А сегодня попробуем другой способ - с помощью JavaScript. + +Итак, надо всего лишь в конце теста дёрнуть такой вот JavaScript: + +```java +String js = + "var performance = window.performance || window.mozPerformance" + + " || window.msPerformance || window.webkitPerformance || {};" + + " return performance.getEntries() || {};"; +String netData = executeJavaScript(js).toString(); +logger.info("Network traffic: {}", netData); +``` + +Результат получается примерно такой: + +```json +Network traffic: [ + {name=https://selenide.org/quick-start.html, connectEnd=0, connectStart=0, decodedBodySize=32582, domComplete=724, domContentLoadedEventEnd=119, domContentLoadedEventStart=115, domInteractive=104, domainLookupEnd=0, domainLookupStart=0, duration=724, encodedBodySize=32582, entryType=navigation, fetchStart=0, initiatorType=navigation, loadEventEnd=724, loadEventStart=724, nextHopProtocol=http/1.1, redirectCount=0, redirectEnd=0, redirectStart=0, requestStart=0, responseEnd=0, responseStart=0, secureConnectionStart=0, serverTiming=[], startTime=0, transferSize=0, type=navigate, unloadEventEnd=10, unloadEventStart=9, workerStart=0}, + {name=https://selenide.org/assets/themes/ingmar/css/styles.css?001, connectEnd=12, connectStart=12, decodedBodySize=8177, domainLookupEnd=12, domainLookupStart=12, duration=29, encodedBodySize=8177, entryType=resource, fetchStart=12, initiatorType=link, nextHopProtocol=http/1.1, redirectEnd=0, redirectStart=0, requestStart=12, responseEnd=41, responseStart=21, secureConnectionStart=0, serverTiming=[], startTime=12, transferSize=0, workerStart=0}, + {name=https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js, connectEnd=13, connectStart=13, decodedBodySize=84245, domainLookupEnd=13, domainLookupStart=13, duration=28, encodedBodySize=84245, entryType=resource, fetchStart=13, initiatorType=script, nextHopProtocol=http/1.1, redirectEnd=0, redirectStart=0, requestStart=13, responseEnd=41, responseStart=21, secureConnectionStart=0, serverTiming=[], startTime=13, transferSize=0, workerStart=0} +] +``` + +### Плюсы: + +* Не нужно никак настраивать браузер. Оно работает из коробки. +* Работает во всех браузерах (кажется?) + +### Минусы: + +* Здесь всё ещё нет тела запроса. +* Это невалидный JSON. Распарсить его стандартным парсером не получится. Придётся придумывать какой-то свой обработчик. + + +Но этот способ вполне подходит, чтобы просто посмотреть глазами и прикинуть, что происходит. + + +## Что теперь? + +Наша последняя надежда - получить запросы и ответы с помощью встроенного прокси-сервера. Этот способ мы рассмотрим в следующем посте. + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2019-12-18-advent-calendar-network-logs-with-proxy.md b/content/ru/blog/2019-12-18-advent-calendar-network-logs-with-proxy.md new file mode 100644 index 000000000..2c7c8172a --- /dev/null +++ b/content/ru/blog/2019-12-18-advent-calendar-network-logs-with-proxy.md @@ -0,0 +1,81 @@ +--- +slug: "advent-calendar-network-logs-with-proxy" +date: 2019-12-18 +title: "Как получить сетевые запросы с помощью прокси" +description: "" +category: +headerText: "Selenide Advent Calendar
День 18" +tags: [] +--- +Привет! + +В предыдущих постах нашего рождественского календаря мы рассмотрели два способа получить сетевые запросы между браузером и приложением. +Оба нас расстроили тем, что не позволяют прочитать тело запроса/ответа. + +Наконец, дошла очередь до третьего способа - через встроенный прокси-сервер. + +### Перед тестом + +Как вы знаете, в селениде уже есть встроенный прокси-сервер, надо его всего лишь включить: + +```java +Configuration.proxyEnabled = true; +``` + +И ещё нужно сказать прокси-серверу, чтобы он начал отслеживать запросы: + +```java + BrowserMobProxy bmp = WebDriverRunner.getSelenideProxy().getProxy(); + + // запоминать тело запросов (по умолчанию тело не запоминается, ибо может быть большим) + bmp.setHarCaptureTypes(CaptureType.getAllContentCaptureTypes()); + + // запоминать как запросы, так и ответы + bmp.enableHarCaptureTypes(CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT); + + // начинай запись! + bmp.newHar("pofig"); +``` + +### После теста + +Теперь нужно получить HAR и анализировать все записи в нём: + +```java + List requests = bmp.getHar().getLog().getEntries(); +``` + +HAR (HTTP Archive) - это типа такой "архив" со всеми сетевыми запросами и ответами ("entries"). + +Каждая запись - это и есть запрос от тестируемого приложения к серверу. +Внутри есть все данные: URL, request, response, их http status и body. +Всё, о чём мы так давно мечтали. + +HAR entries + +### Плюсы: + +* Есть все данные, которые нам нужны +* Легко анализировать программно +* Работает во всех браузерах + +### Минусы: + +Минус только один: иногда у людей возникают сложности с запуском прокси, когда браузер и тесты бегут на разных +машинах, и с "браузерной" машины нет доступа к "тестовой" машине. +Хотя я никогда не понимал, зачем такие сложности. Запускайте тесты и браузеры на одной и той же машине - ВСЁ будет в стотыщ раз ПРОЩЕ. +Надо параллелить - параллельте тесты. +Нужен кластер - запускайте ТЕСТЫ на разных нодах кластера (а с ними запустятся и браузеры). Зачем всё усложнять? + + +## Что теперь? + +Теперь мы умеем читать сетевые запросы при прогоне тестов. +Но я вообще-то надеюсь, что обычно это вам не должно быть нужно. Ну может, в каких-то очень уж запутанных случаях. +Обычно должно быть достаточно почитать логи приложения, чтобы понять, какие запросы к нему прилетали. Будьте проще. + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2019-12-20-advent-calendar-big-wait-theory.md b/content/ru/blog/2019-12-20-advent-calendar-big-wait-theory.md new file mode 100644 index 000000000..5d6223679 --- /dev/null +++ b/content/ru/blog/2019-12-20-advent-calendar-big-wait-theory.md @@ -0,0 +1,107 @@ +--- +slug: "advent-calendar-big-wait-theory" +date: 2019-12-20 +title: "Теория большого вейта" +description: "" +category: +headerText: "Selenide Advent Calendar
День 20" +tags: [] +--- +# Теория большого вейта + +Тема ожиданий вызывает много обсуждений и споров. +Современные веб-сайты создают проблемы для _написателей_ автотестов. Возникает много ситуаций, в которых стандартные методы Selenium неэффективны. + +Если вы читали документацию Selenide, вы уже знаете, что классические явные ожидания типа + +```java +element = (new WebDriverWait(driver, )) + .until(ExpectedConditions.presenceOfElementLocated(By.cssSelector())); +``` + +или + +```java +element = (new WebDriverWait(driver, )) + .until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector())); +``` + +были заменены в Selenide более коротким конструкциями типа + +```java +element = $().should(exist); +element = $().shouldBe(visible); +``` + +**Как известно, ассерты в Selenide - это новая версия явных ожиданий, что хорошо описано в [документации](https://selenide.org/documentation.html).** + +Сегодня мы не будем рассматривать ожидания и ассерты с технической точки зрения, а подумаем, для чего можно использовать +ассерты в различных ситуациях. + + +## Современные проблемы требуют современных решений + +### 1. `Thread.sleep()` + +Это самое ужасное, что может случиться с нашими тестами на Selenium. + +В некоторых ситуациях мы были вынуждены использовать слипы. У нас просто не было другого решения, чтобы обойти проблему и двигаться дальше. +Например, слипы используют, чтобы дождаться окончания загрузки страницы. Иногда - чтобы дождаться какого-то элемента, +когда другие ожидания не помогли. Увы, таким образом мы можем терять много времени при запуске теста. + +Если поставить один слип - это ещё ничего. Вы потеряете, скажем, 4 секунды - не смертельно. +Но если вы используете слип в 150 тестах, время их выполнения увеличится заметно. +Нет смысла объяснять, почему это плохо. + +Хотя команда `sleep()` есть и в Selenide, вышеупомянутые "умные ожидания" делают слипы почти ненужными для ожидания появления чего-то либо на странице. +Смотри следующие пункты. + + +### 2. Как дождаться окончания загрузки страницы? + +Самый простой способ - выбрать какой-то элемент на странице, который редко меняется (скажем, заголовок), и использовать метод Selenide: + +```java +$(cssSelector).shouldBe(visible); +``` + +Selenide сначала попытается найти элемент, а потом проверить, что он видимый. +Если это не удалось за 4 секунды, вы можете сделать вывод, что страница не загрузилась. + +Ещё вы можете выбрать какой-то элемент на _предыдущей_ странице и дождаться, пока он исчезнет: + +```java +$(element).should(disappear); +``` + +Таким образом мы создаём двойную проверку, что мы перешли с одной страницы на другую. +И это будет работать, даже если загрузка страницы занимает значительное время. Как видите, обошлись без всяких `Thread.sleep()`. + +### 3. Изменение состояния элемента + +Иногда нам нужно проверить, что состояние элемента поменялось в результате действий пользователя. +Например, элемент может содержать текст, сигнализирующий об успешной или неуспешной загрузке файла. +Допустим, загрузка файла занимает какое-то время, потому что файл большой, или сервер должен запустить какую-то сложную обработку этого файла. + +Обычно мы в тесте загружаем файл и проверяем состояние элемента (скажем, текст "файл загружен"). +Но как узнать, _когда_ именно состояние элемента должно поменяться? Загрузка-то происходит не мгновенно. +В этой ситуации многие используют `Thread.sleep()`. + +А в Selenide у нас есть умный инструмент для "отложенной" проверки состояния элемента: + +```java +$(cssSelector).shouldHave(exactText()); +``` + +В этом случае Selenide сам дождётся, пока состояние элемента изменится, и в нём появится нужный текст. +Нам не нужно писать лишних строк для ожиданий, и мы можем быть уверены, что Selenide точно дождётся. + +### Что теперь? + +Мы рассмотрели всего лишь несколько простых идей, как можно "ждать" с помощью Selenide. +В реальности ситуаций намного больше. И здорово, что теперь у нас есть хороший инструмент, позволяющий нам обходится без слипов и не терять драгоценное время. +Используйте умные инструменты и не теряйте время - время ценно. :) + + +Maciej Grymuza (figrym@gmail.com) + diff --git a/content/ru/blog/2019-12-22-advent-calendar-defaulta-lingvo.md b/content/ru/blog/2019-12-22-advent-calendar-defaulta-lingvo.md new file mode 100644 index 000000000..62496a26a --- /dev/null +++ b/content/ru/blog/2019-12-22-advent-calendar-defaulta-lingvo.md @@ -0,0 +1,81 @@ +--- +slug: "advent-calendar-defaulta-lingvo" +date: 2019-12-22 +title: "Defaŭlta lingvo" +description: "Как определить язык по умолчанию" +category: +headerText: "Selenide Advent Calendar
День 22" +tags: [] +--- +# Defaŭlta lingvo + +Название сегодняшней темы пришло из языка Эсперанто и означает "язык по умолчанию". + +Вы могли заметить, что некоторые веб-приложения и сайты автоматически меняют свой язык в зависимости от настроек вашего браузера или вашего местоположения. + +## Проблема +В том случае, когда у вас в команде интернационал разработчиков, которые пишут и запускают тесты на разных компьютерах, вы могли обратить внимание, что иногда одни и те же тесты начинают падать из-за того, приложение запустилось не на том языке, для которого писались тесты. + +Если приложение выбирает язык в зависимости от местоположения пользователя, то писать стабильные тесты запускающиеся в разных странах будет непросто. Зато, если приложение всего лишь смотрит в браузере на язык предпочитаемый пользователем по умолчанию, задача сильно упрощается. + +## Решение + +Итак, допустим у вас есть тесты, написанные для языка, другого чем тот, который является языком вашего браузера по умолчанию. Например - ваши тесты ожидают _**немецкий**_. + +Теперь у вас есть следующие опции: + +- Поменяйте язык по умолчанию вашей системы. Теперь большинство ваших программ на компьютере заговорят по-немецки. _**Ordnung muss sein!**_ +- Поменяйте в вашем браузере порядок языков так, чтобы самым предпочитаемым стал немецкий. Сохраните профиль браузера. С помощью гугла, напильника и удачи сконфигурируйте тесты так, чтобы профиль загружался перед запуском каждого теста. Да, не забудьте удалить немецкий из топа в списке предпочитаемых языков, иначе, ну вы поняли - _**Ordnung....**_ +- Ну или - просто воспользуйтесь Chrome preference "intl.accept_languages" установив её значение на "de" (немецкий язык). + +Разумеется, вы можете легко сделать это в Selenide. +Установите значение системной переменной `chromeoptions.prefs=intl.accept_languages=de` или в коде: + +```java +System.setProperty("chromeoptions.prefs","intl.accept_languages=de"); +``` + +или, лучше, в конфигурационных файлах Maven или Gradle + +### Maven + +maven `pom.xml` +```xml + ... + + maven-surefire-plugin + 2.xx.yy + + + ... + intl.accept_languages=de + + + + ... +``` + +### Gradle + +аналогично для Gradle в `gradle.properties` (вам придётся еще добавить строчку-другую в `build.gradle` чтобы передать эти параметры в test task грэдла, но про это - в другой раз) +```properties +systemProp.chromeoptions.prefs=intl.accept_languages=de +``` + +### Командная строка + +Вы можете переопределять значения при запуске `mvn test` или `gradle test` определяя новое значение в `-Dchromeoptions.prefs=intl.accept_languages=ru` + + +## Пример + +Просто запускайте этот маленький тест с различными параметрами языка и понаблюдайте за результатом. + +```java +open("http://wikipedia.org"); +$("[data-jsl10n=slogan]").shouldHave(exactText("Die freie Enzyklopädie")); +``` + +Я желаю всем вам _**Fröhliche Weihnachten**_ и _**Guten Rutsch**_! + +**Alexei Vinogradov** diff --git a/content/ru/blog/2019-12-24-advent-calendar-javascript-tricks.md b/content/ru/blog/2019-12-24-advent-calendar-javascript-tricks.md new file mode 100644 index 000000000..95593fb80 --- /dev/null +++ b/content/ru/blog/2019-12-24-advent-calendar-javascript-tricks.md @@ -0,0 +1,276 @@ +--- +slug: "advent-calendar-javascript-tricks" +date: 2019-12-24 +title: "Трюки с JavaScript" +description: "" +category: +headerText: "Selenide Advent Calendar
День 24" +tags: [] +--- +Привет! + +На дворе 24 декабря, католическое рождество. А это значит, что Advent Calendar подошёл к концу. + +И напоследок мы поиграемся с JavaScript. + +Как язык JavaScript, конечно, дно, но он даёт большие возможности при написании автотестов. +Он позволяет залезть в такие дыры, куда с обычным вебдрайвером и не снилось. + +Приведу несколько примеров из реальных проектов. + +## Выбрать дату + +Есть масса всевозможных элементов для выбора даты - т.н. "date picker". И выбрать в них нужную дату - это вечная головная боль. + +Если реализовывать такой метод в лоб: + +```java +@Test { + setDateByName("recurrent.startDate", "16.01.2009"); +} +``` + +Придётся сделать примерно следующие шаги: +1. Тыкнуть иконку "календарик" +2. Тыкнуть год +3. Тыкнуть стрелку “месяц назад” (сколько раз?) +4. Тыкнуть день +5. Ой, фсё, сегодня 29 февраля. Тест упал. + +**Долго, сложно, ненадёжно.** + +
+ +#### А вот как этот метод можно реализовать с помощью JS: + +```java +void setDateByName(String name, String date) { + executeJavaScript( + String.format("$('[name=\"%s\"]').val('%s')", + name, date) + ); +} +``` + +**Быстро и надёжно.** + +Возможно, вам смутит, что это не совсем "честный" способ. Но об этом мы поговорим в конце. Не переключайтесь. + +## Спрятать календарик + +Допустим, календарик всё же открылся. Как его спрятать? +Решение в лоб - тыкнуть крестик в углу. Опять же, это медленно и ненадёжно: +* крестик вечно располагается в разных углах +* расположение крестика часто меняется в зависимости от дизайна, размера страницы и т.п. +* иногда календарик открывается не сразу - нужно добавить ожидание на открытие, чтобы тут же закрыть. + +Идиотская ситуация. + +
+ +#### А вот как этот метод можно реализовать с помощью JS: + +```java +executeJavaScript( + "$('.datepicker').hide();" +); +``` + +**Быстро и надёжно.** + + +## Перелистнуть перелистывалку + +Представим себе страницу, на которой есть "перелистывалка" карт. Нужно выбрать нужную карту, двигая наманикюренным пальчиком. +_Как сэмулировать это селениумом?_ +Можно, конечно. Всякие там Drag'n'Drop, Actions. Нажал, потянул, отпустил. Но всё это **медленно и нестабильно**. +Это легко может сломаться от малейших изменений дизайна, изменения размерна окна браузера, потери фокуса и т.д. + +#### А вот как можно с помощью JS: + +```java +void selectAccount(String accountId) { + executeJavaScript( + String.format("$('[data-account-id=\"%s\"]').attr('data-card-account', 'true')", accountId) + ); +} +``` + +Это нетривиально. Пришлось поизучать код этой "перелистывалки" и понять, какой JS код она дёргает при перелистывании. +И дёрнуть из теста аналогичный JS код. Придётся поработать головой, но зато это **быстро и надёжно.** + + +## Выбрать опцию в bootstrap select + +Многие UI фреймворки заменяют стандартный ``. Мы долго пытались научиться выбирать из него значения: +тыкали на один div, ждали появления следующего span, тыкали на него, искали нужный div с правильными атрибутами... Всё это работало долго и +часто падало на дженкинсе. Причин падения так до конца и не удалось понять. Хотя мы честно пытались. + +В итоге мы реализовали метод +```java +@Test { + selectBootstrap($(By.name("operationCode")), "11100"); +} +``` + +с помощью JavaScript: + +```java +void selectBootstrap(WebElement select, String value) { + executeJavaScript( + "$(arguments[0]).val(arguments[1]).trigger('change')", + select, value); +} +``` + +**Быстро и надёжно.** + +А с помощью [метода `execute`](https://ru.selenide.org/2019/09/02/selenide-5.3.0/) это можно написать ещё красивее: + +```java +$(By.name("operationCode")).execute(selectBootstrap("11100")); +``` + +## Слайдер + +На странице слайдер. Можно таскать ползунок туда-сюда от 0 до 100. +Как это сделать в тесте? + +```java +@Test { + setMaxYearlyFee(100); +} +``` + +Тут даже классический Drag'n'Drop не поможет, потому что нет целевого элемента, куда перетаскивать. +Снова Actions, снова нажал-потянул-отпустил (по координатам?), снова **медленно и нестабильно**. + +#### А можно с помощью JS: + +```java +void setMaxYearlyFee(int value) { + executeJavaScript( + "$('#sld').data('slider').value[0] = arguments[0];" + + "$('#sld').triggerHandler('slide');", + value + ); +} +``` + +Снова пришлось поковыряться в коде, чтобы узнать, какой JS код дёргает слайдер. Зато работает. Зато **быстро и надёжно.** + + +## Заигнорить чёртов confirm + +В Selenide есть удобные методы, чтобы нажать "Ok" или "Cancel" в модальном диалоге `alert`, `prompt` или `confirm`. +Но с этими модальными окошками периодически возникает проблемы. Иногда они почему-то не закрываются, и после этого +вебдрайвер не может ничего сделать с браузером, в том числе снять скриншот. Подробнее об этом я рассказывал в видео +[Flaky tests](https://www.youtube.com/watch?v=jLG3RXECQU8). + +#### И снова на помощь приходит JavaScript! +Вот так можно "типа нажать Ok" в любом `confirm` диалоге: + +```java +public void mockConfirm() { + executeJavaScript( + "window.confirm = function() {return true;};" + ); +} +``` + +## Плагины Cordova + +В одном проекте мы писали гибридное мобильное приложение с помощью фреймворка Cordova. +Он создаёт такое приложение, в котором очень маленькая нативная часть запускает браузер (т.н. WebView), а в нём уже открывает +веб-приложение. А доступ к нативным функциями мобильника (контакты, телефон, геолокация и пр.) предоставляет в виде JavaScript-плагинов. + +Это очень удобно для тестирования. Для запуска автотестов не нужны реальные мобильники, достаточно открыть урл в обычном +браузере (можно ещё и в режиме [эмуляции мобильника](https://ru.selenide.org/2019/11/29/selenide-5.5.1/) - вообще не отличишь). + +Но вот как тестировать функционал, требующий доступа к нативным функциям мобильника? + +И снова на помощь приходит JS. Мы можем эмулировать плагины Cordova, управляя из теста их поведением: + +```java +@Test { + mockContactsAPI("+79110080075"); +} + +private void mockContactsAPI(String number) { + executeJavaScript( + "window.plugins = {" + + " contactNumberPicker: { " + + " pick: function(callback) {" + + " callback({" + + " phoneNumber:\"" + number + "\"" + " });}}}"); +} +``` + +Выражение "управлять поведением" кажется диким? +Тогда посмотрите видео [Arrange, mazafaka!](https://www.youtube.com/watch?v=ePvrXUCeAr8) с конференции SeleniumCamp 2018. + +А мы имеем функцию `mockContactsAPI`, которая позволяет "типа выбрать" нужный номер из "типа адресной книги" "типа телефона". +Собственно, это единственный способ покрыть тестами все возможные случаи: и когда номер найден, и когда не найден, и когда +это дубликат, и с 100500 китайскими символами и бог знает какие ещё. **Быстро и надёжно.** + + +## Но это же не по-настоящему? + +Я знаю, у многих из вас полыхает мысль: "Это же фейк, обман, это не по-настоящему! Тесты должны делать так же, как реальный +пользователь - иначе есть риск, что тест не обнаружит реальную ошибку." + +Понимаю. + +Но возражу. + +> Быстрые и надёжные тесты +> лучше, чем +> “реалистичные” (но медленные и нестабильные) тесты. + +* Если при каждом запуске треть ваших тестов падает. +* Если каждый раз вы тратите полдня на разбор упавших тестов. +* Если заставляете ручников прогонять вручную "автоматические" сценарии, чтобы убедиться, что функционал не сломан (и это было просто случайное падение). +* Если вы заполняете эксельку с результатами упавших-не-по-настоящему тестов. +* Если в компании нет доверия к тестам. + +_То какой к чёрту прок от ваших "настоящих" тестов?_ +Один вред. + +* Лучше пусть мои тесты будут быстрыми и стабильными. +* И с лёгкостью проверять разные сложные случаи, которые "по-настоящему" повторить нереально. +* А я спокойно буду жить с пониманием того, что целью автоматизации никогда и не было _автоматизировать абсолютно всё_. + +
+ +Вы всё ещё хотите возразить: +### И всё-таки моей душе спокойнее, когда всё по-настоящему. + +Спешу вас огорчить. +* Ваши "реалистичные" тесты на Selenium WebDriver по-любому _не настоящие_. Они работают не так, как реальный пользователь. +Вебдрайвер формирует http-запрос на каждую вашу команду и даже - вот сюрприз! - запускает некую логику на JavaScript, чтобы определить видимость элементов и т.п. +* О да, в некотором смысле вызов действия через JavaScript даже "реалистичнее", чем через WebDriver. Это ближе к тому, что на самом деле делает браузер. +* И даже ваши ручные тестировщики, прокликивающие ваши сценарии - _не настоящие!_ Они работают не так, как реальный пользователь. + +Живите теперь с этим. :) + +## Что теперь? + +А всё. Это был последний пост рождественского календаря. Уффф! + +Скажу честно: я всё это затеял, чтобы набить руку и приучиться много писать. +Надеюсь, это поможет в [обновлении сайта](https://selenide.org/selenide-site-ng/) и написании документации. +А там, глядишь, и до книги дойдёт. :) + +Вот такие планы на следующий год. + +С наступающим! + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2019-12-26-selenide-5.6.0.md b/content/ru/blog/2019-12-26-selenide-5.6.0.md new file mode 100644 index 000000000..70e19e0f3 --- /dev/null +++ b/content/ru/blog/2019-12-26-selenide-5.6.0.md @@ -0,0 +1,80 @@ +--- +slug: "selenide-5.6.0" +date: 2019-12-26 +title: "Вышла Selenide 5.6.0" +description: "" +category: +headerText: "BrowserMobProxy -> BrowserUpProxy" +tags: [] +--- +Всем привет! + +Под конец года мы выпустили [Selenide 5.6.0](https://github.com/selenide/selenide/milestone/87?closed=1) с одним обновлением. + +Мы поменяли `BrowserMobProxy` (который больше не поддерживается) на его форк `BrowserUpProxy` (текущая версия 2.0.1). + +См. [issue 1019](https://github.com/selenide/selenide/issues/1019). +Спасибо [Aliaksandr Rasolka](https://github.com/rosolko) за [PR 1020](https://github.com/selenide/selenide/pull/1020). + +## Что хорошего в этом `BrowserUpProxy`? + +Он +* Поддерживает Brotli Compression (а не только gzip) +* Поддерживает HTTP/2 +* Основан на поддерживаемом форке [LittleProxy](https://github.com/mrog/LittleProxy) +* Использует какой-то улучшенный [HAR reader](https://github.com/sdstoehr/har-reader) +* Умеет фильтровать записи в HAR +* Поддерживает версионированные заголовки для JSON типа `Content-Type=application/something-v1+json` +* Имеет встроенные ассерты для сетевых запросов (что это вообще?) + +Полный список изменений `BrowserUpProxy` (по сравнению с BrowserMobProxy) есть [тут](https://github.com/browserup/browserup-proxy/blob/master/CHANGELOG.md). + +## Как нам обновиться? + +В большинстве случаев вам не придётся ничего менять. Всё работает как работало. +Изменения потребуются только в двух случаях: + +##### 1. Если вы явно импортировали BMP, то вам нужно поменять зависимость +```java +net.lightbody.bmp:browsermob-core:2.1.5 +``` + +на + +```java +com.browserup:browserup-proxy-core:2.0.1 +``` + +##### 2. Если вы определяли `RequestFilter` или `ResponseFilter`, + +то вам придётся поменять импорт + +```java +import net.lightbody.bmp.*; +``` + +на + +```java +import com.browserup.bup.*; +``` + +И всё. + +
+ +## Новости + +Завезли видео с сентябрьской конференции QA Fest: +* [Андрей Солнцев. Selenide для профи](https://www.youtube.com/watch?v=be_cTwayRQc) +* [Андрей Солнцев. Десять причин моей ненависти](https://www.youtube.com/watch?v=pln38fIbYqA&t=226s) +* И остальные [видео QA Fest 2019](https://www.youtube.com/playlist?list=PLuOBDBq7MW70q24thB9tidD2-2Tysf8FS) +* Гугловская статья про [принципы DAMP и DRY](https://testing.googleblog.com/2019/12/testing-on-toilet-tests-too-dry-make.html) +* Ещё один фреймворк на базе Selenide: [JustTestLah! (JTL)](https://www.justtestlah.qa/) - Помесь BDD, Selenide, Appium для Android, iOS и Web +* Если кто пропустил, серия постов [Selenide Advent Calendar](/blog) + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-01-14-selenide-5.6.1.md b/content/ru/blog/2020-01-14-selenide-5.6.1.md new file mode 100644 index 000000000..733eadb32 --- /dev/null +++ b/content/ru/blog/2020-01-14-selenide-5.6.1.md @@ -0,0 +1,96 @@ +--- +slug: "selenide-5.6.1" +date: 2020-01-14 +title: "Вышла Selenide 5.6.1" +description: "" +category: +headerText: "Прокси умнеет" +tags: [] +--- +Всех с Новым Годом! + +Новый год - новый релиз. Встречайте [Selenide 5.6.1](https://github.com/selenide/selenide/milestone/88?closed=1). + + +# Добавили метод `Selenide.executeAsyncScript()` + +Нет такого человека, который ни разу не запускал бы метод `Selenide.executeJavaScript()`. +JavaScript позволяет выйти [на новый уровень сумрака](/2019/12/24/advent-calendar-javascript-tricks/) в автоматизации. + +А теперь мы добавили ещё и метод `Selenide.executeAsyncScript()`. Правда, я плохо представляю, в каких случаях он +может понадобится, но если кому надо - теперь он есть. + +Обратите внимание, его использование сложнее, чем обычного `executeJavaScript()`. +После исполнения асинхронного JS кода нужно вызвать callback с результатом. А callback нужно получить из _последнего_ аргумента: + +```java +long value = (Long) Selenide.executeAsyncJavaScript( + "var callback = arguments[arguments.length - 1]; " + + "setTimeout(function() { " + + " // Вот тут любая асинхронная чертовщина: " + + " ... " + + " // и в конце возврат в селениум: " + + " callback(10);" + + "}, 5000);" + ); + assertThat(value).isEqualTo(10); +``` + +См. [issue 1030](https://github.com/selenide/selenide/issues/1030). +Спасибо [Thierry Ygé](https://github.com/tyge68) за [PR 1031](https://github.com/selenide/selenide/pull/1031). + +
+ +# Научили Selenide скачивать через прокси файлы без заголовка `Content-Disposition` + +Как вы знаете, Selenide умеет скачивать файлы через свой прокси. +Но при скачивании он перехватывал только те ответы сервера, в которых присутствует заголовок `Content-Disposition` +(чтобы узнать оттуда имя скачиваемого файлы). + +Как выяснилось, этот заголовок необязателен. Файлы могут скачиваться и без него. + +Теперь селенидовский прокси стал умнее. +1. Прежде чем скачать файл, он ждёт, пока закончатся все предыдущие запросы-ответы между браузером и сервером. +2. Кликает кнопку скачивания +3. Перехватывает ВСЕ запросы-ответы между браузером и сервером (вне зависимости от заголовков). +4. И пытается понять, какой из них больше всего похож на скачивание файла. + +А имя файла (в случае ответа без заголовка `Content-Disposition`) берётся просто из URL. + +См. [issue 1034](https://github.com/selenide/selenide/issues/1034) и [PR 1035](https://github.com/selenide/selenide/pull/1035). + +
+ +# Исправили метод `WebDriverRunner.using()` + +В октябре мы [добавили метод `using`](/2019/10/16/selenide-5.4.0/#add-method-using). +Судя по всему, вы ещё не успели его попробовать, потому что никто не пожаловался на багу: этот метод закрывал +вебдрайвер после использования (хотя не должен). Ну вот, эту багу мы исправили. + +См. [коммит 4d1b19972d](https://github.com/selenide/selenide/commit/4d1b19972d). + +
+ +# Обновились на WebDriverManager 3.8.0 + +там было исправлено несколько ошибок, в т.ч. моего авторства :) + +См. [changelog](https://github.com/bonigarcia/webdrivermanager/compare/webdrivermanager-3.8.0...master). +В частности, WDM теперь должен корректно работать без доступа в интернет. + +
+ +## Новости + +* Огонь! [Selenious](https://vitalyzinevich.visualstudio.com/_git/Selenious) - порт селенида на .NET + Ребята обещали, что проект рабочий, они его в реальном проекте используют. +* Статья от LambdaTest: [Selenide Tests With LambdaTest – Online Selenium Grid For Automated Cross Browser Testing](https://www.lambdatest.com/support/docs/selenide-tests-with-lambdatest-online-selenium-grid-for-automated-cross-browser-testing/) +* Моё видео с октябрьской конференции Cyprus Quality Conference [Threesome: Selenide for Web, Android and iOS](https://youtu.be/Y04rU7qV7Vg). + Не переживайте, в феврале я его буду рассказывать по-русски на SeleniumCamp. +* Если кто пропустил, серия постов [Selenide Advent Calendar](/blog) + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-02-07-selenide-5.7.0.md b/content/ru/blog/2020-02-07-selenide-5.7.0.md new file mode 100644 index 000000000..91e33d209 --- /dev/null +++ b/content/ru/blog/2020-02-07-selenide-5.7.0.md @@ -0,0 +1,153 @@ +--- +slug: "selenide-5.7.0" +date: 2020-02-07 +title: "Вышла Selenide 5.7.0" +description: "" +category: +headerText: "Скачивай меня нежно" +tags: [] +--- +Приветос! + +Неожиданно нас завалили пуллреквестами с кучей полезных изменений. В этом сила опенсорса! + +Мы подбили всё это в кучу и выпустили [Selenide 5.7.0](https://github.com/selenide/selenide/milestone/89?closed=1). + + +## Мы добавили новую настройку `Configuration.downloadsFolder` + +Раньше файлы скачивались в папку `build/reports` - в ту самую, где генерируются отчёты о прохождении тестов. +А людям иногда хочется разделять (и властвовать?). +Для них мы сделали отдельную настройку `Configuration.downloadsFolder` - именно туда теперь будут сохраняться файлы. + +По умолчанию это папка `build/downloads`. + +См. [issue 1025](https://github.com/selenide/selenide/issues/1025). +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1041](https://github.com/selenide/selenide/pull/1041). + +
+ +### Скачиваем файлы в `Configuration.downloadsFolder` вместо `~/Downloads` + +Со скачиваниями файлов через прокси (`Configuration.fileDownload=PROXY`) есть ещё одна особенность. +Селенид-то свои файлы скачивает в `build/reports` (а теперь в `build/downloads`), но сам-то браузер тоже скачивает свою +копию файла в папку `~/Downloads` (или что там у него по умолчанию). Во-первых, тратится лишнее место на диске, а во-вторых, +оттуда эти файлы никто автоматически не подчищает. + +Теперь селенид изначально открывает браузер с такими настройками, чтобы он сразу скачивал файлы в папку `build/downloads`. +1. Правда, пока только Chrome и Firefox. +2. И только в случае, когда селенид сам открывает браузер. + +См. [issue 1057](https://github.com/selenide/selenide/issues/1057). +Спасибо [Dmitri Korobtsov](https://github.com/dkorobtsov) за ревью [PR 1058](https://github.com/selenide/selenide/pull/1058). + + +
+ +### Добавили метод для переключения между окнами с кастомным таймаутом + +Как вы знаете, в селениде давно есть методы для переключения между вкладками/окнами: + +```java +switchTo().window(3); +``` + +И этот метод даже настолько умный, что ждёт, пока окно появится. Но для него невозможно было задать таймаут: +пресловутые 4 секунды использовались и здесь. + +Теперь мы добавили новый метод, в котором вторым аргументом можно задать таймаут для загрузки нового окна: + +```java +switchTo().window(3, Duration.ofSeconds(42)); +switchTo().window(3, Duration.ofMillis(16000)); +``` + +См. [issue 399](https://github.com/selenide/selenide/issues/399). +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1054](https://github.com/selenide/selenide/pull/1054). + +
+ +### Добавили логирование атрибута "readonly" + +См. [issue 990](https://github.com/selenide/selenide/issues/990). +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1042](https://github.com/selenide/selenide/pull/1042). + +
+ +### Исправили ошибку IndexOutOfBoundsException + +... при поиске первого/последнего элемента пустой коллекции + +См. [issue 991](https://github.com/selenide/selenide/issues/991). +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1043](https://github.com/selenide/selenide/pull/1043). + +
+ +### И целая пачка улучшений скриншотов +#### 1. Вернули потерянные скриншоты в `Screenshots.getLastScreenshot()` + +См. [issue 814](https://github.com/selenide/selenide/issues/814) и [issue 880](https://github.com/selenide/selenide/issues/880). +Спасибо [Petro Ovcharenko](https://github.com/petroOv-PDFfiller) за [PR 1052](https://github.com/selenide/selenide/pull/1052). + +
+ +#### 2. Исправили ссылки на скриншоты в Jenkins +Теперь селенид умеет читать переменную среды (env variable) `BUILD_URL`, и вам больше не нужно прописывать `BUILD_URL` в system properties в ваших билд-скриптах. + +Спасибо [GongYi](https://github.com/GongYi) за [PR 1049](https://github.com/selenide/selenide/pull/1049). + +
+ +#### 3. Исправили ссылки на скриншоты в Jenkins для мультимодульных проектов Maven +Спасибо [GongYi](https://github.com/GongYi) за [PR 1049](https://github.com/selenide/selenide/pull/1049). + +
+ +### Обновились на WebDriverManager 3.8.1 + +См. [changelog](https://github.com/bonigarcia/webdrivermanager/compare/webdrivermanager-3.8.1...master) (в т.ч. поддержка Edge 80). + +
+
+ +# Мероприятия + +### SeleniumCamp 2020 + +Приезжайте в Киев 21-22 февраля на конференцию [SeleniumCamp](https://seleniumcamp.com/program/)! +Я буду выступать с двумя докладами: +* [Flaky tests: МЕТОД](https://seleniumcamp.com/talk/flaky-tests-method/) +* [Тройничок: Selenide для Web, Android и iOS](https://seleniumcamp.com/talk/selenide-for-web-android-and-ios/) + +и ещё будет неформальная сессия BOF [про дальнейшие планы развития Селенида](https://seleniumcamp.com/talk/bof-glorious-past-and-promising-future-of-selenide/). + +### Митап про Селенид в Германии + +Какие-то черти запилили [митап про Селенид](https://stugrm.de/stugrm-meetups/) в Германии 12 февраля. +Приятно, чо. + +### Статистика + +Количество скачиваний селенида за год выросло в 2.5 раза с 40 тысяч до 110 тысяч. + +
+ +
+ +
+ +А количество уникальных айпишников перевалило за 20 тысяч: + +
+ +
+ +
+ +Мы растём! + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-02-28-selenide-5.8.0.md b/content/ru/blog/2020-02-28-selenide-5.8.0.md new file mode 100644 index 000000000..5c39c9198 --- /dev/null +++ b/content/ru/blog/2020-02-28-selenide-5.8.0.md @@ -0,0 +1,116 @@ +--- +slug: "selenide-5.8.0" +date: 2020-02-28 +title: "Вышла Selenide 5.8.0" +description: "" +category: +headerText: "Псевдо-элементы, псевдо-навигация, псевдо-условия" +tags: [] +--- +Приветос! + +Мы подбили ещё пачку пуллреквестов и выпустили [Selenide 5.8.0](https://github.com/selenide/selenide/milestone/90?closed=1). + +Какие же обновления нас ждут? + +## Упростили создание своих условий с помощью лямбд + +В классе `Condition` появился новый метод `match`, который позволяет добавлять свои проверки, не создавая подклассов `Condition`. +Ему надо просто скормить лямбду. + +См. примеры [в тестах](https://github.com/selenide/selenide/blob/master/src/test/java/integration/ConditionsTest.java): + +```java +$("#multirowTable").should(match("border=1", el -> el.getAttribute("border").equals("1"))); +``` + +Также появились похожие методы для коллекций `anyMatch`, `allMatch` и `noneMatch`. +См. примеры [в тестах](https://github.com/selenide/selenide/blob/master/src/test/java/integration/CollectionMethodsTest.java): + +```java +$$("input").shouldBe(anyMatch("value==dog", el -> el.getAttribute("value").equals("dog"))); +$$("input").shouldBe(allMatch("value==cat", el -> el.getAttribute("value").equals("cat"))); +$$("input").shouldBe(noneMatch("value==bird", el -> el.getAttribute("value").equals("bird"))); +``` + +См. [issue 662](https://github.com/selenide/selenide/issues/662). +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1059](https://github.com/selenide/selenide/pull/1059). + +
+ +## Добавили методы `$.sibling()` и `$.preceding()` + +... которые позволяют найти предшественников и последователей на том же уровне DOM. +Бывает нужно, когда удобных локаторов нет, а навигировать по дому хочется. + +См. примеры [в тестах](https://github.com/selenide/selenide/blob/master/src/test/java/integration/SiblingTest.java): + +```java +$("#multirowTableFirstRow").sibling(0).shouldHave(id("multirowTableSecondRow")); +$(".second_row").parent().preceding(0).find("td", 0).shouldHave(cssClass("first_row")); +``` + +См. [issue 845](https://github.com/selenide/selenide/issues/845). +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1064](https://github.com/selenide/selenide/pull/1064). + +
+ +## Запилили поддержку псевдо-элементов + +Как многие знают, в HTML есть такие штуковины как псевдо-элементы: ":before", ":after", ":first-letter", ":first-line", ":selection". +Они могут содержать важный текст и стили, которые иногда важно протестировать. Теперь вы можете это сделать. + +См. примеры [в тестах](https://github.com/selenide/selenide/blob/master/src/test/java/integration/PseudoTest.java): + +```java +$("h1").shouldHave(pseudo(":first-letter", "color", "rgb(255, 0, 0)")); +$("abbr").shouldHave(pseudo(":before", "content", "\"beforeContent\"")); +$("abbr").shouldHave(pseudo(":before", "\"beforeContent\"")); +``` + +А также можно спросить и `SelenideElement` значение псевдо-элемента (но мы такой способ не приветствуем): +```java +assertThat($("h1").pseudo(":first-letter", "color")).isEqualTo("rgb(255, 0, 0)"); +assertThat($("abbr").pseudo(":before")).isEqualTo("\"beforeContent\""); +``` + +См. [issue 994](https://github.com/selenide/selenide/issues/994). +Спасибо [Denys Shynkarenko](https://github.com/Denysss) за [PR 1045](https://github.com/selenide/selenide/pull/1045). + +
+ +## Исправили SoftAssertionsExtension для JUnit5 + +Если один из тестов падал, он помечал и все последующие тесты красным. Упс. + +См. [issue 1071](https://github.com/selenide/selenide/issues/1071). +Спасибо [Alexei Vinogradov](https://github.com/vinogradoff) за [исправление](https://github.com/selenide/selenide/commit/e92b250337a36a7225d6fcbdffecbf102f4592da). + +
+ +## Теперь `$.click()` кликает всегда в ЦЕНТР элемента + +В общем, история такая. Метод `$.click()` обычно кликал в центр элемента, НО +если у вас проставлена настройка `Configuration.clickViaJS=true`, он кликал в левый верхний угол. +Не то чтобы это было принципиально важно, но мало ли... Теперь он всегда кликает по центру. +На всякий случай. Чтобы всегда всё вело себя одинаково. + +См. [коммит 106c53941c718](https://github.com/selenide/selenide/commit/106c53941c7188c5a19677ad45fbdea910960c73). + +
+ +## Новости + +* Представляете, доклад Алексея Виноградова [Selenide: Брандашмыг — интерактивное путешествие по дорогам библиотеки](https://youtu.be/3J6mX98TSjk) + занял 3 место в [ТОП-10 докладов Heisenbug 2019 Moscow](https://habr.com/ru/company/jugru/blog/489310/). Это успех! + +* Ничего себе! John C. Pratt создал [экспортер в Selenide для Katalon Recorder](https://chrome.google.com/webstore/detail/selenide-exporter-for-kat/mkbfcgpbkcaieiajhllpdocjfnfcbmlm) + (работает с [Katalon Recorder](https://chrome.google.com/webstore/detail/katalon-recorder-selenium/ljdobmomdgdljniojadhoplhkpialdid)). Это дикий успех! +* Обнаружен [phpSelenide](https://github.com/razielsd/phpSelenide) - порт Селенида на PHP. Это усPHPех! +* И если кто ещё не видел, [SeleneJS](https://github.com/automician/selenejs) - порт Селенида на JS. Это уех! + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-03-10-selenide-5.9.0.md b/content/ru/blog/2020-03-10-selenide-5.9.0.md new file mode 100644 index 000000000..23657cef3 --- /dev/null +++ b/content/ru/blog/2020-03-10-selenide-5.9.0.md @@ -0,0 +1,77 @@ +--- +slug: "selenide-5.9.0" +date: 2020-03-10 +title: "Вышла Selenide 5.9.0" +description: "" +category: +headerText: "Скачай меня умно" +tags: [] +--- +Здоровендос! + +По всему миру объявлена пандемия [flaky тестов](https://www.youtube.com/watch?v=jLG3RXECQU8), и мы ищем новые лекарства для борьбы с ними. + +Сегодня мы выпустили [Selenide 5.9.0](https://github.com/selenide/selenide/milestone/92?closed=1) с одной фичей, которая может помочь справиться с моргающими тестами. + +## Добавили фильтр для скачивания файлов: `$.download(FileFilter)` + +#### Проблема +При скачивании файлов _через прокси_ селенид может иногда скачать не тот файл. +Селенид ведь как скачивает файлы: кликает на кнопку "Скачать" и перехватывает ответ сервера браузеру. + +Но иногда в этот момент между браузером и сервером могут лететь какие-нибудь левые запросы, никак не связанные со скачиванием. +Например, хром решает проверить обновления. Или ваше приложение шлёт запросы в google analytics. Или просто какие-то фоновые запросы. +Это создаёт плодотворную почву для появления [flaky тестов](https://www.youtube.com/watch?v=jLG3RXECQU8), которые у вас на машине работают, а на дженкинсе иногда падают. + +#### Решение +Чтобы избежать таких коллизий, теперь вы можете явно указать, какой файл вы ждёте. +Из коробки есть фильтры по имени и расширению файла, но вы можете создавать свои объекты [`FileFilter`](https://github.com/selenide/selenide/blob/master/src/main/java/com/codeborne/selenide/files/FileFilter.java) с какими угодно критериями. +И тогда из всех ответов сервера браузеру селенид выберет тот, который подходит под ваш фильтр. + +См. примеры [в тестах](https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/FileDownloadViaProxyTest.java): + +```java +File f1 = $("#downloadMe").download(withName("hello_world.txt")); +File f2 = $("#downloadMe").download(withNameMatching("hello_.\\w+\\.txt")); +File f3 = $("#downloadMe").download(timeout, withExtension("txt")); +``` + +См. [issue 1065](https://github.com/selenide/selenide/issues/1065) и [PR 1080](https://github.com/selenide/selenide/pull/1080). + +## Исправили ошибку при старте IE 3.150 + +См. [issue 1061](https://github.com/selenide/selenide/issues/1061). +Спасибо [Boris Osipov](https://github.com/BorisOsipov) за [PR 1075](https://github.com/selenide/selenide/pull/1075). + +## Исправили ошибку при старте Microsoft Edge + +См. [issue 1039](https://github.com/selenide/selenide/issues/1039). +Спасибо [Boris Osipov](https://github.com/BorisOsipov) за [PR 1084](https://github.com/selenide/selenide/pull/1084). + + +## Новости + +* Забавный [диалог](https://twitter.com/titusfortner/status/1234862932036608001) получился в твиттере: +контрибьютор проектов Selenium и Watir Titus Fortner признался, что видел [мой доклад про селенид на SeleniumConf](/2015/09/23/selenide-on-seleniumconf/) и спёр оттуда несколько +идей для Watir, а я признался, что некоторые вещи в селениде изначально были спёрты из Watir. + +* Хорошая статья [Modern Best Practices for Testing in Java](https://phauer.com/2019/modern-best-practices-testing-java/). Масса правильных мыслей. +* Статья [Selenide Test Automation: Using Selenoid in the Docker Container](https://hackernoon.com/selenide-in-test-automation-through-selenoid-in-the-docker-container-ttw320f) +* Статья [Parametrized UI testing with Selenide and Junit 5](https://medium.com/@neznajuskas/parametrized-ui-testing-with-selenide-and-junit-5-9aca75a8d62f) +* Некий базовый проект [qa-automation-base](https://github.com/romsper/qa-automation-base/tree/kotlin-junit5-appium), в котором намешаны Kotlin + Selenide/Appium + JUnit 5 + Allure + Allure EE + TestRail. +
+ +## Статистика + +Ну и на десерт - статистика скачиваний селенида. Растём! + +
+ +
+ +
+ + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-03-18-selenide-5.10.0.md b/content/ru/blog/2020-03-18-selenide-5.10.0.md new file mode 100644 index 000000000..05a41fe6e --- /dev/null +++ b/content/ru/blog/2020-03-18-selenide-5.10.0.md @@ -0,0 +1,198 @@ +--- +slug: "selenide-5.10.0" +date: 2020-03-18 +title: "Вышла Selenide 5.10.0" +description: "" +category: +headerText: "Шалом тебе, Shadow DOM!" +tags: [] +--- +Здоровендос! + +Шёл третий день карантина. + +Чтобы вам не было одиноко, мы выпустили [Selenide 5.10.0](https://github.com/selenide/selenide/milestone/93?closed=1) с +кучей улучшений, некоторые из которых даже окажутся капельку обратно несовместимыми. Ну, чтобы вы не скучали в своих берлогах. + + + +## Добавили поддержку Shadow DOM {#add-shadow-dom-support} + +См. примеры [в тестах](https://github.com/selenide/selenide/blob/master/src/test/java/integration/ShadowElementTest.java): + +```java +$(shadowCss("#anyButton", "#shadow-host")).click(); + +$(shadowCss("p", "#shadow-host")).shouldHave(text("Inside Shadow-DOM")); + +$(shadowCss("p", "#shadow-host", "#inner-shadow-host")).shouldHave(text("The Shadow-DOM inside another shadow tree")); +``` + +_Firefox_: Вызов `setValue("test")` / `val("text")` на input элементе выкидывает ошибку "not reachable by keyboard". +Как временное решение, можно использовать `fastSetValue=true`: + +```java +Configuration.fastSetValue = true; +$(shadowCss("input", "#shadow-host")).setValue("test"); +``` + +См. [issue 1014](https://github.com/selenide/selenide/issues/1014). +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1090](https://github.com/selenide/selenide/pull/1090). + + +## Selenide больше не тянет BrowserUpProxy по умолчанию {#exclude-bup-by-default} + +Изначально это предложил Алексей Баранцев, так что бейте его, если что. :) + +Мы сопоставили вместе два факта: +1. Селенид по умолчанию тянет за собой BrowserUpProxy и его зависимости - всего ~17 мегабайт. +2. Большинство пользователей (наверное) не использует селенидовский прокси. + +и решили обрадовать Грету Тумберг и не качать эти 17 мегабайт по умолчанию. + +### Зависимость +Те из вас, кто использует прокси, просто должны добавить в свой проект ещё одну зависимость: + +```groovy +testRuntime 'com.browserup:browserup-proxy-core:2.0.1' +``` + +(у многих из вас она и так уже есть). + +Если вы забудете добавить зависимость - не беспокойтесь, вы увидите понятное сообщение: + +```java +java.lang.IllegalStateException: Cannot initialize proxy. Probably you should add BrowserUpProxy dependency to your project. + at com.codeborne.selenide.drivercommands.CreateDriverCommand.createDriver(CreateDriverCommand.java:44) + ... + at com.codeborne.selenide.Selenide.open(Selenide.java:41) +caused by: java.lang.NoClassDefFoundError: com/browserup/bup/BrowserUpProxy +``` + +См. [issue 1021](https://github.com/selenide/selenide/issues/1021) и [PR 1094](https://github.com/selenide/selenide/pull/1094). + +**UPD 12.03.2023** +В наше время больше не нужно добавлять ту зависимость `browserup-proxy-core`. +Просто используйте `com.codeborne:selenide-proxy` вместо `com.codeborne:selenide`, и все нужные зависимости подтянутся автоматически. + +### Просто из интереса + +Кто же там сжирает эти 17 мегабайт, спросите вы? А вот кто. +Вот полный список файлов, которые должны у вас пропасть из проекта. Список впечатляет, правда? + +* animal-sniffer-annotations-1.17.jar +* barchart-udt-bundle-2.3.0.jar +* bcpkix-jdk15on-1.62.jar +* bcprov-jdk15on-1.62.jar +* browserup-proxy-core-2.0.1.jar +* browserup-proxy-mitm-2.0.1.jar +* checker-qual-2.5.2.jar +* dec-0.1.2.jar +* dnsjava-2.1.9.jar +* error_prone_annotations-2.2.0.jar +* failureaccess-1.0.1.jar +* guava-27.1-jre.jar +* jackson-annotations-2.9.9.jar +* jackson-core-2.9.9.jar +* jackson-databind-2.9.9.1.jar +* javassist-3.25.0-GA.jar +* javax.activation-api-1.2.0.jar +* jaxb-api-2.3.1.jar +* jcl-over-slf4j-1.7.28.jar +* jsr305-3.0.2.jar +* jzlib-1.1.3.jar +* listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar +* littleproxy-2.0.0-beta-5.jar +* netty-all-4.1.39.Final.jar + +Кто придумал название "animal-sniffer"? Это что вообще такое - _нюхальщик животных_? +
+ +## Поменяли Guava API на соответствующие Java API {#replace-guava} + +Мы просто поменяли +* `com.google.common.base.Predicate` из Guava +* на `java.util.function.Predicate` из Java 8 + +и выкинули Guava. Guava, ты была хороша и сделала много полезного (пока не вышла Java 8). Покойся с миром. + +Если вы реализовали свои `CollectionCondition`, вам придётся метод `apply` переименовать в `test`. Это должно быть легко. + +См. [issue 1091](https://github.com/selenide/selenide/issues/1091). +Спасибо [Wladimir Schmidt](https://github.com/wlsc) за [PR 1091](https://github.com/selenide/selenide/pull/1091). + +
+ +## Сделали селенидовский отчёт в Allure чуточку красивее {#add-quotes-to-report} + +На самом деле просто добавили кавычки вокруг селекторов. +Не представляю, зачем это может понадобиться, но теперь можно копировать селекторы из аллюровского отчёта и вставлять в +developer console браузера, и они будут работать. + + +См. [issue 1032](https://github.com/selenide/selenide/issues/1032). +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1092](https://github.com/selenide/selenide/pull/1092). + +
+ +## Добавили условие `$("img").shouldBe(image)` {#add-image-condition} + +Позволяет проверить, что картинка есть, она загрузилась и всё в порядке. + +См. примеры [в тестах](https://github.com/selenide/selenide/blob/master/src/test/java/integration/ImageTest.java): + +```java +$("#valid-image img").shouldBe(image); +$("#valid-image").shouldNotBe(image); +$("h1").shouldNotBe(image); +``` + +См. [issue 1069](https://github.com/selenide/selenide/issues/1069). +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1086](https://github.com/selenide/selenide/pull/1086). + +
+ +## Исправили поиск элементов по атрибуту, который содержит кавычки {#fix-search-by-attribute-with-quotes} + +Я не знаю, каким надо быть извращенцем, чтобы в html атрибут запихать кавычки, но такие нашлись. +А селенид оказался к этому не готов и генерировал невалидный CSS локатор. Теперь это в прошлом. + +См. [issue 1060](https://github.com/selenide/selenide/issues/1060). +Спасибо [Denys Lystopadskyy](https://github.com/denysLystopadskyy) за [PR 1062](https://github.com/selenide/selenide/pull/1062). + +
+ +## Видосики {#video} + +Немногие задумывались об этом, но возможно, SeleniumCamp 2020 - Последняя Конференция Человечества. + +Но они ещё и последние альтруисты человечества, потому что из-за карантина они досрочно выложили +[все видео с последней конференции](https://www.youtube.com/playlist?list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe) в открытый доступ. +Лечитесь, айтишники, и просвещайтесь! + +Там есть три моих доклада: +* [Flaky tests: The method](https://www.youtube.com/watch?v=6MfMtky-0q4&list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&index=35) +* [BOF: прошлое и будущее селенида](https://www.youtube.com/watch?v=RmaTYY3B-Wg&list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&index=41) +* [Тройничок: Selenide для Web, Android и iOS](https://www.youtube.com/watch?v=4vI4Z6sE7OA&list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&index=16) -- "Толерантные локаторы"! + +И ещё из того, что я успел заметить: +* Aleksei Tiurin - [Solving the problems of Espresso Android autotests](https://www.youtube.com/watch?v=uCAva5bi7IY&list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&index=32) +* Michael Bodnarchuk - [Puppeteer is a new WebDriver? Secrets of flawless testing.](https://www.youtube.com/watch?v=yETWaC91t3w&list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&index=4) +* Oleksandr Khotemskyi - [WebdriverIO + Puppeteer. Double gun – double fun](https://www.youtube.com/watch?v=UzdUu9QllK0&list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&index=2) +* Sergey Pirogov - [Test coverage myth busted](https://www.youtube.com/watch?v=lMD82Pj3Llk&list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe) +* Mikalai Alimenkou - [Static analysis tools as the best friend of QA](https://www.youtube.com/watch?v=O0-vAiqGrVk&list=PLa7q-VITePQWDxFmiDrwlBZ1E9k_nnqLe&index=14) + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-04-19-selenide-5.11.0.md b/content/ru/blog/2020-04-19-selenide-5.11.0.md new file mode 100644 index 000000000..0b13f8685 --- /dev/null +++ b/content/ru/blog/2020-04-19-selenide-5.11.0.md @@ -0,0 +1,190 @@ +--- +slug: "selenide-5.11.0" +date: 2020-04-19 +title: "Вышла Selenide 5.11.0" +description: "" +category: +headerText: "Ломаем устои" +tags: [] +--- +Всем привет! + +Мы выпустили [Selenide 5.11.0](https://github.com/selenide/selenide/milestone/94?closed=1). +Это уже второй карантинный релиз Selenide. +И чтобы вам не засохнуть от скуки, мы сделали парочку существенных изменений. + + +## Поменяли поведение `shouldNot*` проверок для несуществующего элемента + +Просто взгляните на следующую таблицу, чтобы понять, что поменялось. +Предположим, что элемент `h1` **не найден** на странице. + +Проверка | Selenide 5.10- | Selenide 5.11+ +--------------------------------------------------|----------------|---------------- +`h1.shouldNot(exist)` | ok | ok +`h1.shouldNotBe(visible)` | ok | ok +`h1.shouldBe(hidden)` | ok | ok +`h1.shouldNotHave(text("foo"))` | ok | FAIL +`h1.shouldNotHave(attribute("bar"))` | ok | FAIL +`h1.find("h2").shouldNot(exist)` | ok | ok +`h1.find("h2").shouldNotHave(text("foo"))` | ok | FAIL + +
+ +#### Старая логика +Когда-то давно в селениде было принято такое решение: проверка `h1.shouldNotHave(text("foo"))` не должна падать: +нет элемента - нет и текста. Значит, условие "should not" выполнено. + +Эту логику подкрепляло и такое соображение: проверка `h1.shouldHave(text("foo"))` валится, а "shouldNot" - её +отрицание, поэтому она валиться не должна. + +#### Новая логика + +Но победил прагматичный аргумент: старый алгоритм позволял слишком легко ошибиться: случайно написать неправильный +локатор и не заметить, что тест ложно зелёный. + +См. [issue 368](https://github.com/selenide/selenide/issues/368) и [PR 1116](https://github.com/selenide/selenide/pull/1116). + +## Теперь Селенид ругается, если SLF4J не настроен + +Если вы увидите такое сообщение: + +```java +java.lang.IllegalStateException: SLF4J is not configured. You will not see any Selenide logs. + Please add slf4j-simple.jar, slf4j-log4j12.jar or logback-classic.jar to your classpath. + See https://github.com/selenide/selenide/wiki/slf4j +``` + +то не пугайтесь - просто сделайте, что там сказано. Это очень просто. + +#### Какую проблему мы решали? + +Проблема в том, что если у вас в проекте не была подключена никакая реализация SLF4J, то вы могли не увидеть какие-то +важные логи селенида, в т.ч. "текстовой отчёт". Теперь вам придётся подключить какую-нибудь реализацию SLF4J. + +См. [issue 1114](https://github.com/selenide/selenide/issues/1114) и [PR 1115](https://github.com/selenide/selenide/pull/1115). + + +## Добавили метод для частичной проверки атрибута + +До сих пор в селениде были методы для проверки +1. наличия атрибута, и +2. точного значения атрибута: + +```java + $("#domain-container").shouldHave(attribute("class")); + $("#domain-container").shouldHave(attribute("class", "container")); +``` + +Теперь мы добавили метод `attributeMatching` для проверки _частичного_ значения атрибута. +См. примеры [в тестах](https://github.com/selenide/selenide/blob/master/src/test/java/integration/AttributeTest.java): + +```java +@Test +void canVerifyAttributeMatching() { + $("#domain-container").shouldHave(attributeMatching("class", "contain.*")); // class="container" + $("#domain-container").shouldHave(attributeMatching("class", ".*tainer")); + $("#domain-container").shouldHave(attributeMatching("class", ".+tain.+")); +} +``` + +См. [issue 996](https://github.com/selenide/selenide/issues/996). +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1100](https://github.com/selenide/selenide/pull/1100). + +## Добавили метод для получения последнего скриншота + +Добавили два новых метода: +* `Screenshots.getLastThreadScreenshot()` - возвращает последний скриншот, сделанный селенидом в текущем потоке +* `Screenshots.getThreadScreenshots()` - возвращает все скриншоты, сделанные селенидом в текущем потоке + +Обычным пользователям **эти методы ни к чему**: селенид и так добавляет информацию о скриншоте к сообщению об ошибке. +Но эти новые методы могут быть полезны тем, кто пишет какие-нибудь свои фреймворки на основе селенида или интегрирует селенид с +фреймворками типа Аллюра. + +См. [issue 1029](https://github.com/selenide/selenide/issues/1029). +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1125](https://github.com/selenide/selenide/pull/1125). + +## Добавили аннотацию `@CheckReturnValue` к большинству публичных методов селенида + +Это позволит IDE (как минимум Intellij IDEA) лучше анализировать код ваших тестов и предупреждать, +если вы вызвали какой-нибудь селенидовский метод, но забыли проверить результат: + +
+ +
+ +Спасибо [Yuriy Artamonov](https://github.com/jreznot) за [PR 1106](https://github.com/selenide/selenide/pull/1106). + +## Добавили нехватающий метод `Selectors.byTagName()` + +Просто чтобы было консистентно с `By`. + +Спасибо [Yuriy Artamonov](https://github.com/jreznot) за [PR 1104](https://github.com/selenide/selenide/pull/1104). + +## Исправили URL скриншота + +... когда проект запускается на дженкинсе, и в имени проекта есть пробел. + +См. [issue 1072](https://github.com/selenide/selenide/issues/1072). +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1098](https://github.com/selenide/selenide/pull/1098). + +## Отключили предупреждение о расширениях в Chrome + +Честно говоря, я так и не понял, при каких условиях это предупреждение появляется - лично я его не видел: + +
+ +
+ +Но некоторые товарищи жаловались. Теперь мы его отключили вот такой настройкой: + +```java +options.setExperimentalOption("excludeSwitches", new String[]{"enable-automation", "load-extension"}); +``` + +Дайте знать, если у вас это вызовет какие-то проблемы. + +См. [issue 1119](https://github.com/selenide/selenide/issues/1119) и [PR 1120](https://github.com/selenide/selenide/pull/1120). + +## Теперь можно установить `selectorMode` и `assertionMode` через системные свойства + +Никто этого не просил - просто для консистентности. + +См. [коммит 231597eb6229e](https://github.com/selenide/selenide/commit/231597eb6229e). + +## Метод `$.getWrappedElement()` больше ничего не ждёт + +Подозреваю, что большинство из вас не знали о существовании этого метода и тем более не использовали его. +Его идея была в том, чтобы дать автору теста доступ к оригинальному селениумовскому `WebElement` без всякой селенидовской +магии (ну мало ли кому-то понадобится). А [Iakiv Kramarenko](https://github.com/yashaka) заметил, что без селенидовской +магии не обошлось: метод `$.getWrappedElement()` всё-таки ждал появления элемента. + +Теперь он больше ничего не ждёт. Если элемента нет - он сразу кидает селениумовский `org.openqa.selenium.NoSuchElementException`. +Ну и легендарный `StaleElementReferenceException` вы тоже можете отхватить, конечно (ну мало ли кому-то захочется вспомнить молодость). + +См. [issue 1015](https://github.com/selenide/selenide/issues/1015) и [PR 1124](https://github.com/selenide/selenide/pull/1124). + + +## Статистика + +И моё любимое: статистика скачиваний селенида. Мы пробили потолок в 130 тысяч в месяц! + +
+ +
+ +
+ +и 23 тысячи уникальных айпишников: + +
+ +
+ +Жизнь хороша! + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-04-21-selenide-5.11.1.md b/content/ru/blog/2020-04-21-selenide-5.11.1.md new file mode 100644 index 000000000..4e481cf19 --- /dev/null +++ b/content/ru/blog/2020-04-21-selenide-5.11.1.md @@ -0,0 +1,69 @@ +--- +slug: "selenide-5.11.1" +date: 2020-04-21 +title: "Вышла Selenide 5.11.1" +description: "" +category: +headerText: "Восстанавливаем устои" +tags: [] +--- +Всем привет! + +Похоже, релиз [Selenide 5.11.0](https://github.com/selenide/selenide/milestone/94?closed=1) всё-таки сломал слишком +много устоев, и мы решили сбавить обороты. :) + +Меняем ваше возмущение на [Selenide 5.11.1](https://github.com/selenide/selenide/milestone/96?closed=1). + + +## SLF4J + +Народные массы возмутил тот факт, что в версии 5.11.0 селенид безусловно стал требовать правильной зависимости slf4j. +Народные массы не хотят настраивать slf4j и в гробу видали наши логи. :) + +Для нас это было неожиданно, но мы идём навстречу трудящимся. + +Теперь селенид требует slf4j не всегда, а только в тех редких случаях, когда без него точно никак. +А именно, если вы включите [фичу `TextReport`](/2016/09/26/selenide-3.10/). + + +## because we can! + +В Selenide 5.11.0 мы сделали одну (почти незаметную) багу, связанную с использованием `because`. А именно, + +* `$("blah").shouldNot(exist)` - не падает (это ок) +* `$("blah").shouldNot(exist.because("we can"))` - падает (а вот это не ок) + +Слово `because` оказалось несовместимым с отрицанием. Теперь мы это исправили, и обе строчки не падают. + +См. [issue 1130](https://github.com/selenide/selenide/issues/1130) и [1131](https://github.com/selenide/selenide/pull/1131). + +## Сбросили 16 мегабайт + +Оказывается, среди зависимостей селенида затесался 16-мегабайтный файл `checker.jar`. +Мы с лёгкостью от него избавились. + +Спасибо [Yuriy Artamonov](https://github.com/jreznot) за [PR 1128](https://github.com/selenide/selenide/pull/1128). + + +## Новости + +Во вторник 28 апреля я буду выступать на чешском митапе [[pro:]TEST!](https://www.meetup.com/protest_cz/events/270022839/) +Поскольку митап онлайн, участвовать будут все желающие. Можете позвать друзей, которые ещё не знают про селенид! + +* Язык: ломаный английский +* Дата: 28.04.2020, 18:00 GMT+2 +* Уровень: скорее для начинающих +* Ссылки: [Анонс](https://bit.ly/protest84invitation) / [Трансляция](https://www.youtube.com/watch?v=1d-nKyeTH2Y&feature=youtu.be) + +
+ +
+ +Добро пожаловать! + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-05-23-selenide-5.12.0.md b/content/ru/blog/2020-05-23-selenide-5.12.0.md new file mode 100644 index 000000000..be58f05f2 --- /dev/null +++ b/content/ru/blog/2020-05-23-selenide-5.12.0.md @@ -0,0 +1,119 @@ +--- +slug: "selenide-5.12.0" +date: 2020-05-23 +title: "Вышла Selenide 5.12.0" +description: "" +category: +headerText: "Утерянные капабилити" +tags: [] +--- +Всем привет! + +Ура, релиз [Selenide 5.12.0](https://github.com/selenide/selenide/milestone/95?closed=1). + +Большая часть изменений касается настроек браузеров. + +## Порешали старинную проблему с `Configuration.browserCapabilities` + +Люди давно уже жаловались на то, что часть настроек в `ChromeOptions` теряется (при некоторых условиях). +Вызвана она была [старой багой в Selenium](https://github.com/SeleniumHQ/selenium/issues/5279), которой никто особо не занимается. +И мы не хотели ввязываться. + +Но кажется, нам удалось найти простой костыль. +* Если вам помогло - делитесь. +* Если не помогло - тем более делитесь, будем докостыливать дальше. + +См. [issue 676](https://github.com/selenide/selenide/issues/676), [issue 1097](https://github.com/selenide/selenide/issues/1097) + и [PR 1155](https://github.com/selenide/selenide/pull/1155). + +Отдельное спасибо за попытки, которые не попали в релиз, но навели нас на итоговое решение: + * Спасибо [Boris Osipov](https://github.com/BorisOsipov) за [PR #1103](https://github.com/selenide/selenide/pull/1103) + * Спасибо [SeleniumTestAB](https://github.com/SeleniumTestAB) за [PR #1095](https://github.com/selenide/selenide/pull/1095) + + +## Выключили раздражающий диалог "save password?" + +См. [issue 1133](https://github.com/selenide/selenide/issues/1133) и [PR 1134](https://github.com/selenide/selenide/pull/1134). + +## Добавили режим "эмуляции мобильника" в гриде + +Как вы знаете, в Selenide 5.6.1 появилась возможность запускать хром в режиме "эмуляции мобильного браузера": +```java +java -Dchromeoptions.mobileEmulation="deviceName=Nexus 5" +``` + +Но эта опция срабатывала только при локальном запуске хрома, и не передавалась при запуске хрома в гриде. +Теперь мы это починили: в грид передаются все настройки хрома, которые используются и при локальном запуске (кроме "папки для скачивания файлов"). + +См. [issue 1109](https://github.com/selenide/selenide/issues/1109) и [PR 1163](https://github.com/selenide/selenide/pull/1163). + + +## Упростили сетап Firefox: теперь без профиля + +При открытии браузера Firefox селенид создавал ему профиль (`FirefoxProfile`) - как минимум, чтобы задать папку для скачивания файлов. +Оказалось, что использование профиля накладывает некоторые ограничения, и вообще не нужно (вроде как когда-то он был нужен для legacy firefox driver). + +Теперь мы по умолчанию обходимся без профиля: +1. Папку для скачивания файлов создаём через `firefoxOptions.addPreference("browser.download.dir")` +2. Создаём профиль, только если вы специально задали системные свойства, начинающиеся на `"firefoxprofile."`. + +См. [issue 1139](https://github.com/selenide/selenide/issues/1139) и [PR 1165](https://github.com/selenide/selenide/pull/1165). + + +## Задаём настройку `"ACCEPT_INSECURE_CERTS"` для версий Edge, построенных на движке chromium + +Начиная с какой-то версии, браузеры IE и Edge перестали поддерживать настройку `"ACCEPT_INSECURE_CERTS"` +(разрешение самоподписанных SSL сертификатов). И мы выпилили эту настройку для IE и Edge (в Selenide 5.9.0). + +Но оказалось, что более поздние версии Edge, которые построены на движке Chromium, снова начали её поддерживать. +Поэтому мы вернули настройку `"ACCEPT_INSECURE_CERTS"` для версий Edge 75 и выше. + +Важно: версию Edge селенид может узнать, только если EdgeDriver был скачан с помощью WebDriverManager (что в селениде случается по умолчанию). + +См. [issue 1093](https://github.com/selenide/selenide/issues/1093) и [PR 1167](https://github.com/selenide/selenide/pull/1167). + + +## Обновились на WebDriverManager 4.0.0 + +* Поддержка Firefox 76 +* Поддержка Edge 81, 83, 84 +* Обновили Apache HttpClient с 4.x на 5.0 + +См. [PR 1149](https://github.com/selenide/selenide/pull/1149) и [WDM Changelog](https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md). + +## Обновились на browserup-proxy-core:2.1.0 + +Ну мало ли. + + +## Исправили имя папки для скриншота 'emptyMethod' + +Проблема касалась только JUnit 5. + +Спасибо [Denis Gaievsky](https://github.com/dengayevskiy-sb) за [PR 1138](https://github.com/selenide/selenide/pull/1138) + + +## Расставили аннотации `@Nullable` и `@Nonnull` + +Это поможет IDEA (и надеюсь, другим IDE) лучше подсвечивать косяки в ваших тестах. +А также это поможет пользователям Kotlin правильно использовать nullable/non-nullable типы. + +И снова спасибо [Yuriy Artamonov](https://github.com/jreznot) за + [PR 1140](https://github.com/selenide/selenide/pull/1140) и [PR 1144](https://github.com/selenide/selenide/pull/1144)! + + + +## Новости + +* Мы опубликовали [Selenide Roadmap](https://github.com/selenide/selenide/wiki/Selenide-Roadmap). Ждём ваших отзывов! +* Видео с митапа [pro:TEST](https://www.youtube.com/watch?v=1d-nKyeTH2Y) - Чехия, 28.04.2020 +* Видео с митапа [QA meetup](https://www.youtube.com/watch?v=aFqZ6dbUJIw&feature=emb_logo) - Словакия, 12.05.2020 +* Всеволод Брекелов и Артём Ерошенко запустили шоу ["Ошибка выжившего"](https://meetup.jugru.org/qa-survival-bias-1). Я посмотрел первые 4 выпуска - годно! +* Ребята и девчонки из jug.ru запустили шоу "Тяжелое утро с Heisenbug". + Ближайший выпуск будет **со мной**, ура-ура! [27 мая 2020](https://meetup.jugru.org/qa-heisenbug-breakfast-2) + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-05-25-selenide-5.12.1.md b/content/ru/blog/2020-05-25-selenide-5.12.1.md new file mode 100644 index 000000000..23eec2f88 --- /dev/null +++ b/content/ru/blog/2020-05-25-selenide-5.12.1.md @@ -0,0 +1,46 @@ +--- +slug: "selenide-5.12.1" +date: 2020-05-25 +title: "Вышла Selenide 5.12.1" +description: "" +category: +headerText: "Горячие фиксы к 5.12.0" +tags: [] +--- +Всем привет! + +По горячим следам вы выпустили багфикс релиз [Selenide 5.12.1](https://github.com/selenide/selenide/milestone/97?closed=1) +с парочкой мелких исправлений для [Selenide 5.12.0](/2020/05/23/selenide-5.12.0/). + + +## Исправили _Concurrent modification exception_ при инициализации вебдрайвера + +См. [issue 1170](https://github.com/selenide/selenide/issues/1170) и [PR 1171](https://github.com/selenide/selenide/pull/1171). + +## Исправили мержинг настройки "excludeSwitches" разных типов + +Оказывается, настройку `excludeSwitches` можно задать и как массив, и как список: + +```java + chromeOptions.setExperimentalOption("excludeSwitches", new String[]{"enable-automation", "load-extension"}); + chromeOptions.setExperimentalOption("excludeSwitches", asList("enable-automation", "load-extension")); +``` + +Селенид 5.12.0 ломался, если задать вперемежку и так, и так. Починили. + +См. [issue 1169](https://github.com/selenide/selenide/issues/1169) и [PR 1174](https://github.com/selenide/selenide/pull/1174). + +## Новости + +* Мы опубликовали [Selenide Roadmap](https://github.com/selenide/selenide/wiki/Selenide-Roadmap). Ждём ваших отзывов! +* Видео с митапа [pro:TEST](https://www.youtube.com/watch?v=1d-nKyeTH2Y) - Чехия, 28.04.2020 +* Видео с митапа [QA meetup](https://www.youtube.com/watch?v=aFqZ6dbUJIw&feature=emb_logo) - Словакия, 12.05.2020 +* Всеволод Брекелов и Артём Ерошенко запустили шоу ["Ошибка выжившего"](https://meetup.jugru.org/qa-survival-bias-1). Я посмотрел первые 4 выпуска - годно! +* Ребята и девчонки из jug.ru запустили шоу "Тяжелое утро с Heisenbug". + Ближайший выпуск будет **со мной**, ура-ура! [27 мая 2020](https://meetup.jugru.org/qa-heisenbug-breakfast-2) + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-05-29-selenide-5.12.2.md b/content/ru/blog/2020-05-29-selenide-5.12.2.md new file mode 100644 index 000000000..66347a9cb --- /dev/null +++ b/content/ru/blog/2020-05-29-selenide-5.12.2.md @@ -0,0 +1,69 @@ +--- +slug: "selenide-5.12.2" +date: 2020-05-29 +title: "Вышла Selenide 5.12.2" +description: "" +category: +headerText: "Не тужите, котлиняги" +tags: [] +--- +Всем привет! + +Ловите ещё один мини-релиз [Selenide 5.12.2](https://github.com/selenide/selenide/milestone/99?closed=1). + + +## Подправили аннотации @Nonnull + + ... для некоторых методов `SelenideElement`. + +После обновления на Selenide 5.12.0 некоторые пользователи котлина начали жаловаться, что их проекты переставил компилироваться. +Всё дело в том, что мы пометили все методы `SelenideElement` аннотациями `@Nullable`/`@Nonnull`, а котлин к ним чуток. + +Для следующих методов мы теперь прописали `@Nonnull`, потому что дополнительная проверка показала, что они никогда не возвращают null: +* `$.getText()` +* `$.text()` +* `$.innerText()` +* `$.innerHtml()` +* `$.getSelectedText()` + +Теперь в котлине их можно по-прежнему пихать в ненулевые переменные (хоть мне и кажутся сомнительными такие конструкции в тестах). + +См. [issue 1179](https://github.com/selenide/selenide/issues/1179) и [PR 1181](https://github.com/selenide/selenide/pull/1181). + +## Исправили работу настройки `holdBrowserOpen=true` + +Эта настройка срабатывала не всегда. Уже давно. +И мы давно об этом знали, но забывали, потому что никто нам issue на гитхабе не заводил. :( + +В общем, исправили. При заданной настройке `Configuration.holdBrowserOpen=true` браузер остаётся открытым после окончания +тестов и вообще всех потоков. + +См. [issue 1172](https://github.com/selenide/selenide/issues/1172) и [PR 1176](https://github.com/selenide/selenide/pull/1176). + + +## Видосики + +* Видео [Тяжелое утро с Heisenbug #2](https://meetup.jugru.org/qa-heisenbug-breakfast-2) со мной. Вопросы, до которых обычно на конференциях не до. +* Всеволод Брекелов и Артём Ерошенко в ["Ошибке выжившего #4"](https://meetup.jugru.org/qa-survival-bias-4) в прямом эфире пишут экспорт Record&Play в Selenide. Представляете! +* Мы опубликовали [Selenide Roadmap](https://github.com/selenide/selenide/wiki/Selenide-Roadmap). Ждём ваших отзывов! + +## Новости + +Ура! + +Свершилось! + +Мы опубликовали [плагин для Selenium IDE](https://github.com/selenide/selenide-for-selenium-ide), +который умеет **экспортировать код в Selenide**. +* [для Chrome](https://chrome.google.com/webstore/detail/selenide-for-selenium-ide/nlkfobhoffngaakgdbkdnmmjcchibcba) +* [для Firefox](https://addons.mozilla.org/ru/firefox/addon/selenide-for-selenium-ide/) + +Мы скоро напишем об этом отдельную статью. + +Большое спасибо [Dmytro Stekanov](https://github.com/dstekanov) за этот исторический для селенида момент! + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-07-08-selenide-5.13.0.md b/content/ru/blog/2020-07-08-selenide-5.13.0.md new file mode 100644 index 000000000..c021027f1 --- /dev/null +++ b/content/ru/blog/2020-07-08-selenide-5.13.0.md @@ -0,0 +1,214 @@ +--- +slug: "selenide-5.13.0" +date: 2020-07-08 +title: "Вышла Selenide 5.13.0" +description: "" +category: +headerText: "Вначале была подстрока" +tags: [] +--- +Всем привет! + +Лето не повод расслабляться! Мы выпустили релиз [Selenide 5.13.0](https://github.com/selenide/selenide/milestone/98?closed=1). + +Будьте осторожны, он может сломать ваши тесты (если они были неаккуратно сделаны). + + + +## Метод `$.shouldHave(text(""))` кидает ошибку {#should-have-empty-text} + +Возможно, самый популярный метод селенида - это `$.shouldHave(text("что-то"))`. Но даже если вы используете его каждый день, +возможно, вы не подозреваете, что он проверяет _подстроку_. Т.е. проверка `$("h1").shouldHave(text("ello"))` сработает и для +элемента `

Hello World

`. + +Частный случай такой проверки - `$("h1").shouldHave(text(""))`. Такую проверку пройдёт **любой элемент**, ведь любая +строка содержит пустую подстроку. То есть такая проверка просто _бессмысленна_. + +> Если вам нужно убедиться, что текст +пустой, используйте `$("h1").shouldHave(exactText(""))` или `$("h1").shouldBe(empty)`. + +Мы хотим вам помочь избежать этой типичной проблемы и избавиться от бессмысленных проверок. Для этого теперь селенид +будет бросать ошибку, если вы попытаетесь передать в метод `text("")` пустую строку или null. + +> Я попробовал Selenide 5.13.0 на своём рабочем проекте и внезапно нашёл тестов 20-30, которые падали с этой ошибкой. +И это всё были логические ошибки в тестах! Вот какое полезное изменение вас ждёт. :) + +См. [issue 1156](https://github.com/selenide/selenide/issues/1156). +Спасибо [Roman S.A.](https://github.com/eaxdev) за [PR 1186](https://github.com/selenide/selenide/pull/1186). + +**UPD** +Позже мы добавили [настройку `FULL_TEXT`](/2022/08/04/selenide-6.7.0/#holy-whole-string), +заставляющую Selenide проверять строку целиком, а не подстроку. + +## Убрали лишние логи из аллюра {#remove-unneeded-allure-logs} + +Внимательные аллюровцы заметили, что селенид логирует одно и то же действие дважды. Например, при вызове такой строки: +```java + $(bySelector).findAll(BySelector).filter(condtion); +``` + +(на самом деле не только в аллюре, но и в обычном селенидовском `TextReport`) + +Теперь мы убрали эти двойные логи. Пришло кое-чего порефакторить, некоторые сообщения об ошибках изменились. +Но вроде бы всё стало лучше. Если заметили ухудшение - смело сообщайте. + +См. [issue 997](https://github.com/selenide/selenide/issues/997) и [PR 1193](https://github.com/selenide/selenide/pull/1193). + +## Улучшили сообщение об ошибках для коллекций {#improve-collection-error-messages} + +Ещё одна похожая история, где мы немного изменили формат ошибок при поиске элементов внутри коллекций. +По идее теперь должно быть понятнее, что внутри чего не удалось найти. + +См. [issue 967](https://github.com/selenide/selenide/issues/967) и [PR 1189](https://github.com/selenide/selenide/pull/1189). + + +## Починили загрузку файлов вне тэга `
` {#fix-upload-without-form} + +Как вы знаете, селенид позволяет загрузить одной командой несколько файлов: + +```java + $("input").uploadFile( + new File("a.txt"), + new File("b.txt"), + new File("c.txt") + ); +``` + +Для этой загрузки мы в своё время сделали в селениде хитрый JS хак. +Оказалось, что этот хак предполагал, что `` для загрузки файла должен быть внутри тэга ``. Что как бы логично. +Но оказалось, что не у всех так. + +В общем, теперь мы упростили хак и убрали зависимость от тэга ``. + +См. [issue 943](https://github.com/selenide/selenide/issues/943) и [PR 1188](https://github.com/selenide/selenide/pull/1188). + +## Научились скачивать файлы с кавычками в имени {#download-files-with-quotes} + +... и другими нехорошими символами. + +Оказывается, есть и такие чудаки, которые генерируют файлы, в имени которых есть кавычки. Линукс и Мак вполне умеют +сохранять такие файлы, а вот винда никак. Теперь селенид заменяет кавычки и другие нехорошие символы на подчёркивания +(как делают все основные браузеры). + +См. [issue 1196](https://github.com/selenide/selenide/issues/1196) и [PR 1199](https://github.com/selenide/selenide/pull/1199). + +## Научили вебдрайвер писать свои логи в файл {#write-webdriver-logs-to-file} + +До сих пор вебдрайвер, запускаемый селенидом, по умолчанию не писали никуда свои логи. +Вам нужно было включать их явно. + +Теперь же селенид включает логи вебдрайвера. Логи пишутся в файлы вида `build/reports/tests/webdriver.ts_pid_tid.log`. +Полный путь к файлу вы можете узнать из лога, который пишет селенид каждый раз при открытии браузера: + +```java +INFO Write webdriver logs to: /andrei/build/reports/tests/webdriver.1594248139109_18125_1.log +``` + +Когда в следующий раз будете изучать аномальное поведение вебдрайвера, не забудьте туда заглянуть. + +См. [issue 1206](https://github.com/selenide/selenide/issues/1206) и [PR 1207](https://github.com/selenide/selenide/pull/1207). + +## Добавили новый способ скачивания файлов `FOLDER` {#new-file-download-mode-folder} + +Как вы знаете, до сих пор в селениде было два способа скачивания файлов: `HTTPGET` и `PROXY`. +См. [пост в нашем блоге](/2019/12/10/advent-calendar-download-files/). + +* `HTTPGET` - самый простой и надёжный. Но умеет скачивать только файлы с ссылки вида ``. +* `PROXY` - универсальный и мощный способ. Но при удалённом запуске требует доступа с машины браузера к машине тестов. +Что порой вызывает сложности и поклонников Селеноида и Грида. + +Теперь появился третий способ: `FOLDER`. + +Чтобы его включить, просто пропишите в начале тестов: +```java +Configuration.fileDownload = FileDownloadMode.FOLDER; +``` + +Работает он просто: +1. Кликает элемент +2. Смотрит, какие новые файлы появились в папке `build/downloads` +3. Если таких файлов несколько, пытается угадать, какой из них подходит лучше всего. + +Рабочий пример всегда можно найти [в тестах самого селенида](https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/FileDownloadToFolderTest.java). + +
+ +P.S. Будем пока считать этот способ _экспериментальным_, поскольку есть нюансы: +1. Работает надёжно при локальном запуске в один поток +2. При параллельном запуске одновременные тесты могут скачивать файлы в одну и ту же папку, и тогда селенид не сможет определить, кому какой файл отдать. +3. При удалённом запуске этот способ вообще пока не работает. Тесты-то здесь, а папка там! +4. Поддерживаются Chrome, Firefox, Edge, Opera. Не поддерживаются IE и Safari (у в принципе +нет возможности задать папку для скачивания файлов). + +Мы будем работать над этим, а вы делитесь своими соображениями, как разрулить вышеозначенные проблемы. + +См. [issue 1212](https://github.com/selenide/selenide/issues/1212), + [PR 1213](https://github.com/selenide/selenide/pull/1213) и + [PR 1215](https://github.com/selenide/selenide/pull/1215). + +UPD Позже этот метод скачивания был доработан, и теперь его смело можно использовать в проектах. + + +## Метод `$.getWrappedElement()` снова ждёт появления элемента {#get-wrapped-element-waits-for-element} + +Вряд ли вам это интересно, но упомянуть обязан. По сути мы откатили одно недавнее изменение. + +Допустим, у вас есть такой код: + +```java +SelenideElement button = $("button"); +executeJavascript("arguments[0].click()", button); +``` + +где `button`, допустим, появляется на экране с задержкой. +Всю жизнь этот метод ждал появления кнопки, и лишь тогда кликал. В Selenide 5.11 нас укусила какая-то собака, и мы сделали +так, чтобы не ждал. Никто почему-то не жаловался, а вот в моём рабочем проекте несколько тестов упали. + +В общем, теперь мы вернули обратно старое поведение. Теперь снова ждёт. + +См. [issue 1191](https://github.com/selenide/selenide/issues/1191) и [PR 1203](https://github.com/selenide/selenide/pull/1203). + + +## Обновились до BrowserUpProxy 2.1.1 {#upgrade-to-bup-2.1.1} + +Ну вдруг. + +Обновляйтесь, пробуйте, делитесь впечатлениями! + + +## Статистика {#statistics} + +И моё любимое: статистика скачиваний селенида. +Мы пробили потолок **в 160 тысяч в месяц**! + +
+ +
+ +
+ +и **31+ тысяча уникальных айпишников**: + +
+ +
+ +Жизнь хороша! + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-08-17-selenide-5.14.0.md b/content/ru/blog/2020-08-17-selenide-5.14.0.md new file mode 100644 index 000000000..8dc10c045 --- /dev/null +++ b/content/ru/blog/2020-08-17-selenide-5.14.0.md @@ -0,0 +1,149 @@ +--- +slug: "selenide-5.14.0" +date: 2020-08-17 +title: "Вышла Selenide 5.14.0" +description: "" +category: +headerText: "Стабильный FOLDER" +tags: [] +--- +Всем привет! + +Мы выпустили релиз [Selenide 5.14.0](https://github.com/selenide/selenide/milestone/101?closed=1). + + +## Стабилизировали новый способ скачивания файлов `FOLDER` + +... который появился в [Selenide 5.13.0](/2020/07/08/selenide-5.13.0/). + +Вот что поменялось в 5.14.0: +1. Каждый раз, когда селенид открывает браузер, он создаёт для него уникальную папку для скачиваний. + Это помогает избежать ситуаций, когда параллельные тесты одновременно скачивают файлы в одну и ту же папку, и невозможно понять, где чей файл. + + См. [issue 1220](https://github.com/selenide/selenide/issues/1220) и [PR 1221](https://github.com/selenide/selenide/pull/1221). + + * Увы, это не работает для IE и Safari (которые в принципе не позволяют задать папку для скачивания файлов) + * Также это работает только для тех браузеров, которые открывает селенид. + * Если же вы сами открываете браузер и передаёте его селениду, вам нужно будет создать уникальную папку самостоятельно и передать её селениду: + * Либо с помощью нового метода `setWebDriver(driver, proxy, downloadsFolder)`, + * либо конструктора `SelenideDriver(..., downloadsFolder)`. + +2. Перед началом каждого скачивания файла селенид очищает папку -- см. [PR 1252](https://github.com/selenide/selenide/pull/1252) +3. Селенид удаляет все пустые папки для скачиваний в конце тестов -- см. [PR 1247](https://github.com/selenide/selenide/pull/1247) + + +## Добавили проверку `$$.shouldHave(itemWithText("any text"))` + +В отличие от классической `$$.shouldHave(texts("text1", "text2"))`, она означает, что в коллекции есть хотя бы один элемент с данным текстом. + +Спасибо [Luis Serna](https://github.com/LuisOsv) за [PR 1194](https://github.com/selenide/selenide/pull/1194). + +Кстати, это первый коммит в селенид аж из Боливии! + + +## Добавили поддержку браузера Safari + +Когда-то селенид поддерживал Safari, но тогда куча всего в нём не работало. +В какой-то момент нам надоело с ним мучаться, и мы поддержку выпилили. +Но сейчас попробовали новый подход. Вроде как завелось (не всё, конечно). + +Как обычно, достаточно просто прописать +1. `Configuration.browser = "safari";` либо +2. `-Dselenide.browser=safari` + +Делитесь впечатлениями. + +См. [issue 1236](https://github.com/selenide/selenide/issues/1236) и [PR 1237](https://github.com/selenide/selenide/pull/1237). + + +## Добавили метод `SelenideDriver.screenshot(fileName)` + +Полезно, если вы создаёте "нестатический" вариант драйвера (`new SelenideDriver()`) и хотите снимать скриншоты. +Теперь можно. + +См. [issue 1166](https://github.com/selenide/selenide/issues/1166) и [PR 1227](https://github.com/selenide/selenide/pull/1227). + + +## Добавили метод `SelenideDriver.screenshot(OutputType)` + +Иногда хочется получить скриншот в формате Base64. Например, этот формат хотят некоторые инструменты для сравниения скриншотов. + +Теперь их можно получить таким вызовом: + +```java +String screenshot = Selenide.screenshot(OutputType.BASE64); +byte[] decoded = Base64.getDecoder().decode(screenshot); +BufferedImage img = ImageIO.read(new ByteArrayInputStream(decoded)); +``` + +См. [issue 1224](https://github.com/selenide/selenide/issues/1224) и [PR 1231](https://github.com/selenide/selenide/pull/1231). + + +## Теперь селенид снимает скриншот в случае падения `switchTo()` + +Как вы знаете, Селенид автоматически делает скриншот в случае падения тестов. +Но мы обнаружили, что Селенид НЕ делал скриншот, если упал один из этих методов: +* `switchTo(frame)` +* `switchTo(window)` +* `switchTo(alert)` + +Теперь мы исправили эту досадную оплошность. + +См. [issue 1190](https://github.com/selenide/selenide/issues/1190) и [PR 1240](https://github.com/selenide/selenide/pull/1240). + + +## Добавили хрому опцию `--disable-dev-shm-usage` + +Мы тут вычитали, что без этой опции Chrome может крэшиться из-за out of memory error. +1. Почему никто из вас на это не жаловался? +2. Стало ли лучше после добавления это опции? + +P.S. Позже люди жаловались и на наличие этой опции. [Эпопея](https://github.com/selenide/selenide/issues/1559) пока не окончена. + +## Исправили работу Sizzle селекторов на страницах с Dojo.js, troop.js и т.п. + +См. [issue 434](https://github.com/selenide/selenide/issues/434) и [PR 1242](https://github.com/selenide/selenide/pull/1242). + + +## Сделали метод `$.toString()` безопаснее + +См. [issue 1241](https://github.com/selenide/selenide/issues/1241) и [PR 1245](https://github.com/selenide/selenide/pull/1245). + + +## Улучшили сообщение об ошибке, если элемент внезапно пропал + +См. [issue 1013](https://github.com/selenide/selenide/issues/1013) и [PR 1239](https://github.com/selenide/selenide/pull/1239). + + +## Обновились на WebDriverManager 4.1.0 + +См. [WDM Changelog](https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md). + +
+ +## Видеообзор + +Смотрите [видеообзор](https://youtu.be/x0KWgnjxsl4) данного релиза. + +## Новости + +* Ничоси! Курс на Udemy "[Selenium и Selenide для начинающих Automation QA, QC на Java](https://www.udemy.com/course/selenium-selenide-test-automation-engineer/)" +* Про селенид [на немецком](https://www.youtube.com/watch?v=WNzTuYFd8oI) +* Пример проекта [на Selenide+Selenoid+Docker](https://github.com/d3m0/automation) от [d3m0](https://github.com/d3m0) +* Ещё пример: [сравнение скриншотов с Selenide+Allure+Ashot+Screen Diff Plugin](https://github.com/Crushpowerx/JavaMavenSelenideAllureScreenDiffExample) от [Evgeniy Asovin](https://github.com/Crushpowerx/) +* Ещё пример: [Selenide + Appium + Allure + TestNG](https://github.com/qaschevychelov/giphyTest) от [qaschevychelov](https://github.com/qaschevychelov/) +* Сравнение Selenide и Selenium 2019 года: [Choosing tools for UI testing: Selenium or Selenide?](https://www.appliedtech.ru/en/web-tools-for-ui-testing-selenium-or-selenide.html) - 17.09.2019 +* Статья Jakub Skibiński в блоге компании Sonalake: [Selenide: A Powerful Testing Framework](https://sonalake.com/latest/selenide-a-powerful-testing-framework/) - 19.06.2020 +* Статья "[Почему мы перешли на Selenide, попутно написав более 200 новых автотестов](https://habr.com/ru/company/maxilect/blog/499810/)" - 30.04.2020 +* [Switch from Serenity to Selenide](https://medium.com/@maxilect_pr/selenide-our-experience-11240f9ce10c) - 22.05.2020 от [Yuri Kudryavtsev](https://medium.com/@maxilect_pr) (Maxilect company) + +И целая серия статей от [Alexander Pushkarev](https://medium.com/@alexspush): +* [Test automation framework architecture — Layered architecture example with vanilla JUnit + Selenide](https://medium.com/@alexspush/test-automation-framework-architecture-part-2-1-layered-architecture-example-62a0011d3329) +* [UI Automation for mortals: elegant Page Objects with Java and Selenide](https://medium.com/@alexspush/ui-automation-for-mortal-elegant-page-objects-with-java-and-selenide-3122b17dc473) +* [Effective test automation: subcutaneous tests as a faster alternative to Selenium-driven testing](https://medium.com/@alexspush/an-alternative-to-ubiquitous-ui-level-checking-subcutaneous-tests-8d29e8883fc2) + +
+ +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-09-26-selenide-5.15.0.md b/content/ru/blog/2020-09-26-selenide-5.15.0.md new file mode 100644 index 000000000..4b0b77054 --- /dev/null +++ b/content/ru/blog/2020-09-26-selenide-5.15.0.md @@ -0,0 +1,237 @@ +--- +slug: "selenide-5.15.0" +date: 2020-09-26 +title: "Вышла Selenide 5.15.0" +description: "" +category: +headerText: "Обкликайся и обкачайся" +tags: [] +--- +Всем привет! + +Мы выпустили релиз [Selenide 5.15.0](https://github.com/selenide/selenide/milestone/104?closed=1). + +* [Настройка `Configuration.pageLoadTimeout`](#page-load-timeout) +* [Клик с параметрами](#click-with-options) +* [Скачивание файла с параметрами](#download-with-options) +* [Работа с LocalStorage](#local-storage) +* [Текст элемента без потомков](#own-text) +* [Ускорили большие фильтрованные коллекции](#speed-up-collections) +* [Добавили проверку "href"](#href-checks) +* [Добавили опцию хрома "--no-sandbox"](#no-sandbox) +* [Новости](#news) + + +## Добавили настройку `Configuration.pageLoadTimeout`
(по умолчанию 30 секунд) {#page-load-timeout} + +Бывает так, что вебдрайвер надолго подвисает, пытаясь загрузить какую-то страницу, либо картинку на этой странице, или ещё какой-то элемент. +Теряется время, сессия обрывается по таймауту и т.д. + +В этом случае хорошо бы прервать тест пораньше, но таймаут для загрузки страницы в Selenium по умолчанию слишком большой: 5 минут. + +Поэтому мы добавили в Selenide настройку `Configuration.pageLoadTimeout`, чтобы этот таймаут было легко менять. + +Внимание! Значение по умолчанию - 30 секунд. Если ваши тесты начали падать по таймауту - знайте, какую настройку подкрутить. + + +См. [issue 1268](https://github.com/selenide/selenide/issues/1268) и [PR 1269](https://github.com/selenide/selenide/pull/1269). + + +## Добавили универсальный метод клика
с параметром `ClickOptions` {#click-with-options} + +В некотором роде это новое слово в API селенида. + +В селениде изначально был метод `$.click()`, который просто вызывал обычный селениумовский метод `WebElement.click()`. Который кликает (вроде как) в центр элемента. + +Со временем начали появляться вариации: +* Настройка `Configuration.clickViaJs`, чтобы кликать не вызовом `WebElement.click()`, а через JavaScript. Теоретически это должно сделать тесты стабильнее (а может, и быстрее) и позволит кликать то, что обычно не получается. +* Клик со сдвигом `$.click(offsetX, offsetY)`, чтобы кликать не в центр элемента + +Неудобно в этом то, что невозможно кликать то через JS, то через селениум - настройка глобальная. Пришлось бы её постоянно менять. + +Поэтому мы добавили метод, в который можно явно передавать параметр - способ клика. + +Теперь кликать можно без изменения глобальной настройки, хоть обкликайся: + +```java + $("#page").click(usingJavaScript()); + $("#page").click(usingJavaScript().offset(123, 222)); + $("#page").click(usingJavaScript().offsetY(222)); + $("#page").click(usingDefaultMethod()); +``` + +NB! Мы рекомендуем выставить настройку `Configuration.clickViaJs` в то значение, которое вам подходит в большинстве случаев, и задавать параметр `ClickOptions` точечно - только там, где он необходим. + +См. [issue 1173](https://github.com/selenide/selenide/issues/1173). +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1226](https://github.com/selenide/selenide/pull/1226). + + + +## Добавили универсальный метод скачивания файла
с параметром `DownloadOptions` {#download-with-options} + +Аналогичная история была с методом `$.download()`. Изначально он умел скачивать файлы только одним способом - через GET запрос. +Потом селенид научился скачивать файлы через прокси. Недавно мы добавили третий способ - `FOLDER`. +До сих пор способ скачивания можно было задать только через глобальную настройку `Configuration.fileDownload`. + +А теперь способ скачивания можно задавать через параметр в каждый вызов `$.download`, не меняя глобальную настройку: + +```java + File f = $("input").download(DownloadOptions.using(PROXY); + File f = $("input").download(DownloadOptions.using(PROXY).withTimeout(9999)); + File f = $("input").download(DownloadOptions.using(PROXY).withFilter(withExtension("xls")).withTimeout(9999)); + File f = $("input").download(DownloadOptions.using(FOLDER); + File f = $("input").download(DownloadOptions.using(FOLDER).withTimeout(9999)); + File f = $("input").download(DownloadOptions.using(FOLDER).withFilter(withExtension("pdf")).withTimeout(9999)); +``` + +NB! Мы рекомендуем выставить настройку `Configuration.fileDownload` в то значение, которое вам подходит в большинстве случаев, и задавать параметр `DownloadsOptions` точечно - только там, где он необходим. + +См. [issue 1259](https://github.com/selenide/selenide/issues/1259) и [PR 1260](https://github.com/selenide/selenide/pull/1260). + + +## Добавили методы для работы с LocalStorage {#local-storage} + +```java +import static com.codeborne.selenide.Selenide.localStorage; + +// Очистить всё содержимое: +localStorage().clear(); + +// Добавить значение: +localStorage().setItem("username", "john"); + +// Проверить значение: +assertThat(localStorage().getItem("username")).isEqualTo("john"); + +// Проверить количество элементов: +assertThat(localStorage().size()).isEqualTo(1); + +// удалить значение: +localStorage().removeItem("username"); +assertThat(localStorage().getItem("username")).isNull(); + +``` + +Спасибо [Dmytro Stekanov](https://github.com/dstekanov) за [PR 1274](https://github.com/selenide/selenide/pull/1274). + + + + + + +## Добавили проверки для текста элемента без потомков {#own-text} + +Классическая селенидовская проверка `$.shouldHave(text("Hello, world"))` включает и текст самого элемента, и тексты всех его потомков. +А иногда хочется проверить только текст самого элемента, без потомков. Для этого мы добавили две новых проверки: + +```java + $.shouldHave(ownText("Hello")); // Элемент должен содержать текст "Hello" + $.shouldHave(exactOwnText("Hello")); // Текст элемента должен быть "Hello" +``` + +См. [issue 1261](https://github.com/selenide/selenide/issues/1261) и [PR 1262](https://github.com/selenide/selenide/pull/1262). + + +## Ускорили работу с большими фильтрованными коллекциями {#speed-up-collections} + +В селениде есть удобные методы для работы с коллекциями элементов: их можно удобно отфильтровать, в них можно искать элементы или разом проверить, скажем, тексты всех элементов. + +Но если слишком злоупотреблять, можно написать слишком медленный тест. Например, вот так: + +```java +ElementsCollection list = $$("li").filter(visible); // На странице 100 элементов
  • +for (int i = 0; i < 10; i++) { + list.get(i).shouldBe(visible); +} +``` + +Если на странице, предположим, 100 элементов `
  • `, то такой тест может очень долго работать. +* Ведь селенид на каждом шагу должен перегрузить элемент - вдруг его состояние изменилось! +* А чтобы перегрузить N-ный элемент коллекции, нужно перегрузить всю коллекцию (в селениуме ведь нет метода `WebDriver.findElement(index)`). +* А чтобы перегрузить фильтрованную коллекцию, нужно пройтись по всем её элементам и применить фильтр для каждого (в данном примере - вызвать `WebElement.isDisplayed()`). + +
    + +Для сравнения, такой цикл работает гораздо быстрее: + +```java +ElementsCollection unfiltered = $$("li"); // Нефльтрованная коллекция +for (int i = 0; i < 10; i++) { + unfiltered.get(i).shouldBe(visible); +} +``` + +В этом релизе мы немного ускорили работу с коллекциями. Теперь Селенид фильтрует коллекцию умнее: чтобы получить `list.get(N)`, он применяет фильтр `visible` не для всех 100 элементов, а только для первых `` элементов. + +См. [issue 1266](https://github.com/selenide/selenide/issues/1266) и [PR 1270](https://github.com/selenide/selenide/pull/1270). + +
    + +P.S. Напомню, что другой вариант ускорить тесты в таких случаях - использовать метод `snapshot`: + +```java +ElementsCollection list = $$("li").filter(visible).snapshot(); // snapshot() создаёт "слепок" коллекции. Селенид не будет её перегружать каждый раз. +for (int i = 0; i < 10; i++) { + list.get(i).shouldBe(visible); +} +``` + +Но при использовании `snapshot` есть риск словить `StaleElementReferenceException`, если коллекция всё-таки обновилась во время цикла. + +> И ещё мощный способ ускорить работу с коллекциями (и вообще тесты) - это использование JavaScript. +> +> См. [Трюки с JavaScript](https://www.youtube.com/watch?v=be_cTwayRQc&ab_channel=FestGroup&t=29m57s) + +## Добавили проверку "href" {#href-checks} + +Иногда хочется в тесте проверить, что у элемента `
    ` правильное значение атрибута `href`, т.е. ссылки. +Для этого всегда можно было использовать метод `$("a").shouldHave(attribute("href", "/foo/bar/details.html")`. + +Проблема в том, что такая проверка очень неочевидно падает, потому что селениум возвращает абсолютный, а не относительный URL. +Подробнее см. в докладе Алексея Баранцева ["Заморочки в Selenium WebDriver"](http://www.youtube.com/watch?v=4dh--iD_zK8&t=57m11s) с 57:11. + +Чтобы хоть немножко облегчить эту заморочку, мы добавили проверку "should have href" для ссылок: + +```java + $("a").shouldHave(href("/foo/bar/details.html")); +``` + +См. [issue 1272](https://github.com/selenide/selenide/issues/1272) и [PR 1273](https://github.com/selenide/selenide/pull/1273). + +## Добавили опцию хрома "--no-sandbox" {#no-sandbox} + +Я где-то вычитал, что она сделает тесты на хроме стабильнее. Скрестим пальцы и будем надеяться. + +См. [commit 3293956d](https://github.com/selenide/selenide/commit/3293956d) + +## Селенид теперь явно кидает ошибку {#error-if-failed-to-create-download-folder} + +... если не удалось создать папку для скачивания файлов. + +См. [issue 1265](https://github.com/selenide/selenide/issues/1265) и commit [94ece98f](https://github.com/selenide/selenide/commit/94ece98f). + + + +## Обновились на WebDriverManager 4.2.2 {#update-webdriver-manager} + +См. [WDM Changelog](https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md). + +
    + +## Видео-обзор {#video-review} + +Смотрите [видео-обзор](https://youtu.be/txozPtQIqiE) данного релиза. + +## Новости {#news} + +Приходите 4-7 ноября 2020 на онлайн-конференцию [Heisenbug](https://heisenbug-moscow.ru/2020/msk/schedule/)! + +Я там тоже буду выступать: +* Воркшоп "Как начать свой проект автоматизации с нуля (с божьей помощью и Selenide)" - для начинающих +* Доклад "Flaky tests. Метод" - для опытных + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-11-17-why-proxy-does-not-work-in-selenoid.md b/content/ru/blog/2020-11-17-why-proxy-does-not-work-in-selenoid.md new file mode 100644 index 000000000..ec41a8eb3 --- /dev/null +++ b/content/ru/blog/2020-11-17-why-proxy-does-not-work-in-selenoid.md @@ -0,0 +1,131 @@ +--- +slug: "why-proxy-does-not-work-in-selenoid" +date: 2020-11-17 +title: "Почему прокси не работает в Selenoid?" +description: "" +category: +headerText: "Мы подсели на зависимости" +tags: [] +--- +Всем привет! + +Сегодня мы наконец-то раскроем тайну, почему у многих не работает прокси в Selenoid. + +### Задача: скачать файл +* Мы запускаем тесты, в которых браузер бежит в контейнере Selenoid (обычно также и на Selenide, но необязательно). +* В ходе теста мы хотим скачать файл. +* Метод по умолчанию `$.download()` не подходит (например, потому, что скачивание происходит не по прямой ссылке). +* Поэтому мы хотим [скачать файл через прокси](/2019/12/10/advent-calendar-download-files/). + +### Наши действия +1. Создаём проект +2. Добавляем в проект зависимость BrowserUpProxy, как указано в документации Selenide: +```kotlin +dependencies { + testRuntimeOnly("com.browserup:browserup-proxy-core:2.1.1") +} +``` +3. Копипастим типичный бойлерплейт для запуска браузера в Selenoid: +```java +Configuration.proxyHost = "192.168.0.10"; +Configuration.remote = "http://localhost:4444/wd/hub"; +DesiredCapabilities capabilities = new DesiredCapabilities(); +capabilities.setBrowserName("chrome"); +capabilities.setVersion("85.0"); +capabilities.setCapability("enableVNC", true); +capabilities.setCapability("enableVideo", true); +capabilities.setCapability("enableLog", true); +Configuration.browserCapabilities = capabilities; +Configuration.fileDownload = FileDownloadMode.PROXY; +Configuration.proxyEnabled = true; +``` + +4. Ну и пишем тест, что-то вроде +```java +open("https://the-internet.herokuapp.com/download"); +File file = $(byText("some-file.txt")).download(); +assertThat(file.getName()).isEqualTo("some-file.txt"); +``` + +### Проблема + +И получаем ошибку при открытии браузера: +```java +org.openqa.selenium.WebDriverException: unknown error: net::ERR_TUNNEL_CONNECTION_FAILED + ... + at com.codeborne.selenide.Selenide.open(Selenide.java:49) + at org.selenide.selenoid.FileDownloadTest.download(FileDownloadTest.java:45) +``` +
    + +### ААА, паника! + +На этом месте большинство людей паникует, перебирает кучу опций браузера и селенидовских настроек +и в конце концов пишет в чатик автоматизаторов. + +А ведь всего-то надо было почитать внимательно лог. +В логе чётко видна проблема: + +```java +[LittleProxy-0-ProxyToServerWorker-1] ERROR org.littleshoot.proxy.impl.ProxyToServerConnection + - (HANDSHAKING) [id: 0xc05a41d5, L:/10.10.10.145:56103 + - R:the-internet.herokuapp.com/52.1.16.137:443] + : Caught an exception on ProxyToServerConnection +java.lang.NoSuchMethodError: 'int io.netty.buffer.ByteBuf.maxFastWritableBytes()' + at io.netty.handler.codec.ByteToMessageDecoder$1.cumulate(ByteToMessageDecoder.java:86) +``` + +### Крутим зависимости + +Ошибка `NoSuchMethodError` недвусмысленно намекает на то, что у нас проблема с зависимостями: +в classpath оказались какие-то два JAR'а с несовместимыми версиями. + +Против этого уже давно придумали прививку. Удивляюсь, почему так много людей до сих пор не в курсе. + +Запускаем команду: + +* `gradle dependencies`, или +* `mvn dependency:tree` + +И вуаля! - чётко видим, какие у нас JAR'ы и каких версий. Ищем там что-то похожее на "netty". + +``` +\--- com.browserup:browserup-proxy-core:2.1.1 + +--- io.netty:netty-codec:4.1.44.Final + +--- xyz.rogfam:littleproxy:2.0.0-beta-5 + | +--- io.netty:netty-all:4.1.34.Final +``` + +Как видим, у нас есть два джарника с разными версиями: `netty-codec:4.1.44.Final` и `netty-all:4.1.34.Final`. + +### Лечим зависимости + +Чтобы исправить проблему, достаточно явно прописать в `build.gradle` или `pom.xml` более новую версию `Netty`: + +```kotlin +testRuntimeOnly("io.netty:netty-all:4.1.54.Final") +testRuntimeOnly("io.netty:netty-codec:4.1.54.Final") +``` + +(на самом деле достаточно только одной из этих строк. *Домашнее задание: какой и почему?*) + +Команда `gradle dependencies` показывает, что теперь версии совпадают: + +``` +\--- com.browserup:browserup-proxy-core:2.1.1 + +--- io.netty:netty-codec:4.1.44.Final -> 4.1.54.Final + +--- xyz.rogfam:littleproxy:2.0.0-beta-5 + | +--- io.netty:netty-all:4.1.34.Final -> 4.1.54.Final +``` + +Тест запускается, прокси работает, файл скачивается. Всем щастье. + +### Мораль + +Будьте внимательнее к логам, братьям нашим меньшим! + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-11-20-selenide-5.16.0.md b/content/ru/blog/2020-11-20-selenide-5.16.0.md new file mode 100644 index 000000000..ced2c6919 --- /dev/null +++ b/content/ru/blog/2020-11-20-selenide-5.16.0.md @@ -0,0 +1,318 @@ +--- +slug: "selenide-5.16.0" +date: 2020-11-20 +title: "Вышла Selenide 5.16.0" +description: "" +category: +headerText: "Плагины и сообщения об ошибках" +tags: [] +--- +Всем привет! + +Мы выпустили релиз [Selenide 5.16.0](https://github.com/selenide/selenide/milestone/105?closed=1). + + +## Плагины + +В начале 2020 года на конференции [SeleniumCamp](https://seleniumcamp.com/materials/) я рассказывал + про [roadmap селенида](https://seleniumcamp.com/talk/bof-glorious-past-and-promising-future-of-selenide/). + Одна из ключевых идей на этот год была создать в селениде возможность подключать сторонние плагины. + +**И вот этот день настал!** + +На данный момент доступно два плагина: +* [selenide-appium 1.5.0](https://github.com/selenide/selenide-appium) +* [selenide-selenoid 1.0.0](https://github.com/selenide/selenide-selenoid) + +Расскажем о них в отдельных постах. + +Вероятно, дальше стоит оформить в виде плагинов поддержку Allure, JUnit, TestNG, AShot. +_Накидывайте ещё идеи!_ + +См. [issue #1051](https://github.com/selenide/selenide/issues/1051) и +[PR #1264](https://github.com/selenide/selenide/pull/1264), +[PR 1317](https://github.com/selenide/selenide/pull/1317) и +[PR 1321](https://github.com/selenide/selenide/pull/1321). + + +## Сообщения об ошибках + +Одна из основных обязанностей селенида - составлять подробные сообщения об ошибках в случае падения тестов. +Иногда в эти сообщения тоже закрадываются неточности в каких-то сложных случаях. +В этом релизе мы запилили целую пачку улучшений сообщений об ошибках: + +### Улучшили описание проверок AND и NOT + +Нормальный способ устроить негативную проверку в селениде - метод `shouldNotHave`. +А проверить несколько условий подряд - просто через запятую: +```java +$("#username").shouldNotHave(text("admin")); +$("#username").shouldHave(text("____"), attribute("data-masked")); +``` + +Но есть ещё методы `Condition.not` и `Condition.and` для особых случаев: +например, с их помощью можно определять составные условия, таким образом составляя целый DSL для ваших тестов. + +```java +public class MyConditions { + private static final Condition NONADMIN = not(text("admin")); + private static final Condition MASKED = and("MASKED", text("___"), attribute("data-masked")); +} + +public class MyTest { + $("#username").shouldBe(MASKED); + $("#username").shouldBe(NONADMIN); +} +``` + +Оказалось, что оба эти методы выводили в отчёте неполную информацию: + +```java + | #username |should be(MASKED) |PASS | + | #username |should have(not text) |PASS | +``` + +Проблема в том, что в нём не виден ожидаемый текст ("admin") и другие условия. + +Теперь мы эту проблему исправили, и при падении проверки вы увидите сообщение с текстом: + +```java + | #username |should be(MASKED: text '___' and attribute data-masked) |PASS | + | #username |should have(not text 'admin') |PASS | +``` + +Спасибо [Pavel Fokin](https://github.com/fokinp) за [PR 1306](https://github.com/selenide/selenide/pull/1306) +и [PR 1306](https://github.com/selenide/selenide/pull/1300). + +
    + + +### Добавили информацию о предках + +Селенид позволяет искать элементы внутри других элементов. Например, так: +```java + $("#user-table").$("thead").$("trrrr-chah-chah").shouldHave(text("Age")); +``` +Но если такая проверка падает, в сообщении был виден только локатор дочернего элемента: +```java + Element not found {trrrr-chah-chah} +``` + +А теперь мы также добавили информацию и о родителях: +```java + Element not found {#user-table/thead/trrrr-chah-chah} +``` + +Спасибо [Petro Ovcharenko](https://github.com/petroOv-PDFfiller) за [PR 1312](https://github.com/selenide/selenide/pull/1312). + +
    +
    + + +### Добавили актуальный текст для проверок `ownText` и `exactOwnText` +Как вы помните, в Selenide 5.15.0 мы добавили проверки `ownText` и `exactOwnText`: + +```java + $("#child_div1").shouldHave(ownText("Sonar")); +``` +Но и тут оказалось, что при падении такой проверки в сообщении не выводился, а какой же "свой текст" был на самом деле. +Выводился только текст элемента с детьми: + +```java + Element should have own text 'Sonar' {#child_div1} + Element: '
    Son
    ' +``` + +Теперь мы добавили строчку "Actual value" с собственным текстом элемента: +```java + Element should have own text 'Sonar' {#child_div1} + Element: '
    Son
    ' + Actual value: Son +``` + +См. [issue 1261](https://github.com/selenide/selenide/issues/1261) и [PR 1294](https://github.com/selenide/selenide/pull/1294). + +
    +
    + +### Кидаем правильную ошибку при загрузке несуществующего файла +Если вы пытались загрузить несуществующий файл: +```java + $("input[type='file']").uploadFile(new File("/foo/bar/xyz.pdf")); +``` + +То получали некорректную ошибку: +```java + Element not found {input[type='file']} + ... + Caused by: InvalidArgumentException: invalid argument: File not found : /foo/bar/xyz.pdf +``` + +Казалось бы, мелочь, но иногда это сбивало с толку. + +Теперь мы это исправили, и вы получите сразу + +```java + InvalidArgumentException: invalid argument: File not found : /foo/bar/xyz.pdf +``` + +См. [issue 987](https://github.com/selenide/selenide/issues/987) и [PR 1301](https://github.com/selenide/selenide/pull/1301). + +
    + +> Корень проблемы в том, что в селенум не хватает отдельных классов ошибок для всех возможных нестандартных ситуаций, и +> простой `WebDriverException` может говорить как о ненайденном элементе, так и неверной кодировке в вводимой строке. +> См., например, [issues 1293](https://github.com/selenide/selenide/issues/1293). +> +> Плюс некоторые реализации вебдрайвера могут кидать какие-то нелогичные ошибки - например, IEDriver когда-то кидал +> `Throwable` вместо `ElementNotFound`. +> +> Поэтому в своё время в селениде была принята консервативная стратегия: если не удалось определить тип ошибки точнее, +> по умолчанию считаем, что элемент не найден. А в "caused by" будут видны подробности. + +
    +
    + + +### Адекватно показываем ClickOptions в отчёте +Как вы помните, в Selenide 5.15.0 мы добавили удобные методы для клика со всевозможными опциями: +```java + $("#page").click(usingJavaScript().offset(123, 222)); +``` + +И снова оказалось, что в отчёте такая строка выглядит некрасиво: +```java + | #page | click(com.codeborne.selenide.ClickOptions@33617539) | PASS | +``` + +Мы и это исправили, теперь строчка стала _окейнее_: +```java + | #page | click(method: JS, offsetX: 123, offsetY: 222) | PASS | +``` +См. [issue 1302](https://github.com/selenide/selenide/issues/1302) и [PR 1303](https://github.com/selenide/selenide/pull/1303). + +
    + + +## Другое + +### Добавили проверку `$$.shouldHave(exactTextsCaseSensitiveInAnyOrder(...))` + +В селениде уже давно есть проверки для коллекций: +```java + $$(".employee").shouldHave(texts("вася", "петя", "катя")); // case-insensitive, substring + $$(".employee").shouldHave(textsInAnyOrder("вася", "катя", "петя")); // case-insensitive, substring, any order + $$(".employee").shouldHave(exactTexts("вася", "петя", "катя")); // case-insensitive, full string match +``` + +И теперь к ним добавилась ещё одна - менее толерантная: +```java + // case-sensitive, full string match, any order + $$(".employee").shouldHave(exactTextsCaseSensitiveInAnyOrder("Вася", "Петя", "Катя")); +``` + +Спасибо [Vitali Plagov](https://github.com/plagov) за [PR 1286](https://github.com/selenide/selenide/pull/1286). + +
    + +### Исправили проверку `href` со спец.символами + +Как вы помните, в Selenide 5.15.0 мы добавили проверку `href`. +Оказалось, что она неправильно работала, если в `href` затесались экранированные символы, как во второй строке: + +```java + $("a").shouldHave(href("/foo/bar/details.html")); // works + $("a").shouldHave(href("/files/some%20file.pdf")); // fails +``` + +Проблема исправлена. + +См. [issue 1298](https://github.com/selenide/selenide/issues/1298). +Спасибо [rerednaw](https://github.com/rerednaw) за [PR 1299](https://github.com/selenide/selenide/pull/1299). + +
    + + + +### Разрешаем хрому скачивать несколько файлов + +Бывают такие хитрые ссылки, по клику на которые браузер начинает скачивать не один, а сразу два или больше файлов. +Оказалось, что в этом случае браузер Chrome показывает диалог "Уверены, что хотите скачать все файлы?" - и этот диалог +не даёт ничего дальше сделать, пока пользователь не нажмёт кнопку. И ваш тест падает. + +> Самое противное в этой проблеме то, что её очень сложно повторить руками: браузер показывает диалог только в первый раз, так что +при локальном запуске скорее всего вы его не увидите, и тест будет зелёным. + +Чтобы вылечить эту проблему, мы добавили при запуске хрома специальный ключик `profile.default_content_setting_values.automatic_downloads=1`, +который сразу разрешает хрому качать сколько угодно файлов без всяких диалогов. + +См. [issue 1307](https://github.com/selenide/selenide/issues/1307). +Спасибо [Alexei Vinogradov](https://github.com/vinogradoff) за [PR 1308](https://github.com/selenide/selenide/pull/1308). + +
    + + +### Разрешили скачивать файлы со слэшем в названии + +Метод `download` не разрешает скачивать файл, если в его названии есть неразрешённые символы, в числе которых был и слэш: + +```java + File report = $("#report").download(); + + --> IllegalArgumentException("File name cannot contain slash: 11/08/2020_-_day_transactions.pdf") +``` + +Нам казалось это логичным, ведь такие файлы тупо не разрешает создавать файловая система. +Но оказалось, что иногда слэш вполне логичен - например, как разделитель в датах. И хром вполне скачивает такие файлы, +просто заменяя слэш на подчёркивание. + +Теперь и селенид так делает. + +См. [issue 1322](https://github.com/selenide/selenide/issues/1322) и [PR 1323](https://github.com/selenide/selenide/pull/1323). + +
    + +### Зафиксировали версию Guava 30.0-jre + +Ох уж эта гуава! + +В коде самого селенида Guava не используется, нам она не нужна. +Но с ней вечные проблемы: от неё зависят многие другие библиотеки (Selenium, LittleProxy, BrowserUpProxy, Checkstyle), +и все от разных версий. А ещё ведь у неё есть специальная версия для android... + +В общем, слишком часто так случалось, что Maven или Gradle подтягивал не ту версию Guava, и селенид в итоге не работал. +Нам это надоело, и теперь в селениде явно прописана свежая версия Guava `30.0-jre`. Надеемся, это поможет избежать всех +этих бесконечных конфликтов завиимостей. + +
    + + +### Перешли на Github Actions + +Как в любом приличном проекте, в Selenide есть свой набор автотестов (юнит- и интеграционных), и они запускаются +автоматически для всех веток на CI сервере. Раньше мы использовали Travis CI, который предоставляет бесплатный сервис +для опен-сорс проектов. Спасибо им большое за годы совместной работы. :) + +Но в этом году гитхаб выкатил свой CI сервис под названием "Github actions". +> Смотри обзор от Артём Ерошенко и Севы Брекелова в [выпуске №3 Шоу "Ошибка выжившего"](http://www.youtube.com/watch?v=dxGGZQiuD6Q&t=60m10s). + +И казалось логичным использовать его. + +Ура, этот день настал! Теперь все билды селенида видны [прямо на гитхабе](https://github.com/selenide/selenide/actions). + +Спасибо [Boris Osipov](https://github.com/BorisOsipov) за [PR 1319](https://github.com/selenide/selenide/pull/1319). + +
    + + +## Уффф. + +Многабукаф, но вы осилили. Все молодцы! + +Как обычно - обновляйтесь, пробуйте, смело сообщайте о проблемах и делитесь идеями. + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-11-25-selenide-5.16.2.md b/content/ru/blog/2020-11-25-selenide-5.16.2.md new file mode 100644 index 000000000..f16f04e35 --- /dev/null +++ b/content/ru/blog/2020-11-25-selenide-5.16.2.md @@ -0,0 +1,53 @@ +--- +slug: "selenide-5.16.2" +date: 2020-11-25 +title: "Вышла Selenide 5.16.2" +description: "" +category: +headerText: "Багфиксы с антресолей" +tags: [] +--- +Всем привет! + +Мы выпустили релиз [Selenide 5.16.2](https://github.com/selenide/selenide/milestone/109?closed=1). + +Нет, вы не подумайте, что в недавнем крупном релизе [Selenide 5.16.0](/2020/11/20/selenide-5.16.0/) была куча багов. +Вовсе нет. + +Данный релиз 5.16.2 - это исправление кучи старых мелких бажочков, просто сейчас дошли до них руки. + +Итак, коротко: + +## Релиз [5.16.2](https://github.com/selenide/selenide/milestone/109?closed=1) (вышел 25.11.2020) {#selenide-5.16.2} +* [#1332](https://github.com/selenide/selenide/issues/1332) return old click(int, int) command logic -- thanks to Petro Ovcharenko for PR [#1333](https://github.com/selenide/selenide/pull/1333) +* make SoftAssertsExtension thread-safe -- thanks to @dtuchs for PR [#1334](https://github.com/selenide/selenide/pull/1334) +* [#1258](https://github.com/selenide/selenide/issues/1258) fix soft asserts with ParameterizedTest in jUnit5 -- see PR [#1328](https://github.com/selenide/selenide/pull/1328) +* [#1293](https://github.com/selenide/selenide/issues/1293) don't report "Element not found" in case of other errors -- see PR [#1326](https://github.com/selenide/selenide/pull/1326) +* [#1290](https://github.com/selenide/selenide/issues/1290) don't show unused page object fields in report -- see PR [#1327](https://github.com/selenide/selenide/pull/1327) +* upgrade to littleproxy:2.0.1 -- see PR [#1325](https://github.com/selenide/selenide/pull/1325) + +## Релиз [5.16.1](https://github.com/selenide/selenide/milestone/106?closed=1) (вышел 23.11.2020) {#selenide-5.16.1} + +Тут было два исправления, чтобы хром можно было запускать с расширениями. +* [#1314](https://github.com/selenide/selenide/issues/1314) do not exclude "load-extension" switch if Chrome is opened with extensions -- see PR [#1324](https://github.com/selenide/selenide/pull/1324) +* [#1315](https://github.com/selenide/selenide/issues/1315) support custom DriverFactory for running remote browsers -- see PR [#1324](https://github.com/selenide/selenide/pull/1324) + + +## Новости {#news} + +Раз осталось место, поделюсь новенькими ссылками: +* Пример от LambdaTest: [selenide-testng-sample](https://github.com/LambdaTest/selenide-testng-sample) +* Видосик про Селенид на португальском: [Testes de Aceitação em Java com Selenide, Adriano Magalhães](https://www.youtube.com/watch?v=yOfrqZUsFuU&feature=youtu.be&ab_channel=BluesoftLabs) +* Курс по Селениду где-то в Бразилии: [Automação Web Descomplicada Com Selenide](https://inoveteste.com.br/automacao-web-descomplicada-com-selenide/) +* Визуальное тестирование: [Applitools+Selenide](https://medium.com/automated-visual-testing-with-applitools/getting-started-with-the-applitools-sdk-653f2cd1ad48) +* Пример проекта: [Getting started with applitools](https://github.com/bmurmistro/applitools) + +
    + +Selenide 5.17.0 уже не за горами, не переключайтесь! + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-12-26-selenide-5.17.0.md b/content/ru/blog/2020-12-26-selenide-5.17.0.md new file mode 100644 index 000000000..6474b03fc --- /dev/null +++ b/content/ru/blog/2020-12-26-selenide-5.17.0.md @@ -0,0 +1,166 @@ +--- +slug: "selenide-5.17.0" +date: 2020-12-26 +title: "Вышла Selenide 5.17.0" +description: "" +category: +headerText: "Ho-ho-ho, Page Objects!" +tags: [] +--- +Доброй ночи! + +Я трепетно отношусь к Католическому Рождеству. +Потому, что именно в Рождество террористы захватили небоскрёб Накатоми, и Брюс замочил Ханса Грубера. +А потом взорвал самолёт зажигалкой. + +Поэтому ловите рождественский релиз [Selenide 5.17.0](https://github.com/selenide/selenide/milestone/108?closed=1). + +
    + +# Добавили метод $.as("name") + +Чувствую, что открываю ящик пандоры, но что уж поделаешь... + +В общем, мы добавили метод `as`, позволяющий давать элементам читаемые имена. + +Чтобы продемонстрировать эффект, давайте сравним эти две строки в тесте: + +```java + $(By.xpath("/long/ugly/xpath[1][2][3]")).shouldNot(exist); + $(By.xpath("/long/ugly/xpath[1][2][3]")).as("Login button").shouldNot(exist); +``` + +Результат в отчёте будет таким: +``` + +---------------------------------------+--------------------+----------+----------+ + |Element |Subject |Status |ms. | + +---------------------------------------+--------------------+----------+----------+ + |By.xpath: /long/ugly/xpath[1][2][3] |should not(exist) |PASS |13 | + |Login button |should not(exist) |PASS |38 | + +---------------------------------------+--------------------+----------+----------+ +``` + +В последней строке вместо длинного нечитабельного xpath мы видим понятное имя "Login button". + +NB! Не торопитесь использовать эту возможность. Лично я воспринимаю её как "хак последней надежды". +В отчёте всегда лучше видеть настоящий локатор, чем кем-то придуманное имя, которое всегда может оказаться: +* Обманчивым +* Устаревшим +* Вводящим в заблуждение + +Лучше инвестируйте свои усилия в то, чтобы использовать читаемые локаторы. Ну и грамотно называть переменные и методы. Вот где сила, брат! + +См. [issue 1200](https://github.com/selenide/selenide/issues/1200) и [PR 1353](https://github.com/selenide/selenide/pull/1353). + +
    + + +# Добавили настроек нашему headless chrome + +Мы взяли и добавили нашему безголовому хрому те же настройки, [что и в puppeteer](https://github.com/puppeteer/puppeteer/blob/7a2a41f2087b07e8ef1feaf3881bdcc3fd4922ca/src/Launcher.js#L261). +Ребята из puppeteer же не дураки, знают, что делают. Мы как они. + +Спасибо [Aliaksandr Rasolka](https://github.com/rosolko) за [PR 1329](https://github.com/selenide/selenide/pull/1329). + +P.S. Интересно, если ребята из puppeteer решать с крыши спрыгнуть, мы тоже спрыгнем? + +
    + + +# Починили `ByShadowCss.findElements` + +Оказалось, в одном хитром случае он возвращал не все элементы: когда в DOM было несколько _inner shadow hosts_ +(как это по-православному, бог ты мой?) + +Теперь возвращает все. + +См. [issue 1346](https://github.com/selenide/selenide/issues/1346). +Спасибо [Daniel H. Peger](https://github.com/dpeger) за [PR 1347](https://github.com/selenide/selenide/pull/1347). + +
    + + +# Добавили метод $.should* с кастомным таймаутом + +Как вы все знаете, в Селениде есть две основных группы методов: +1. `$.shouldHave` / `$.shouldBe` / `$.should` -- используют таймаут по умолчанию +2. `$.waitUntil` / `$.waitWhile` -- используют заданный таймаут + +Методы `$.wait*` полезны для ожидания явно долгих действий, которые точно длятся дольше обычного таймаута (который 4 секунды по умолчанию). + +Проблема с `$.wait*` методами чисто грамматическая: встроенные селенидовские проверки не звучат по-английски корректно с глаголом "wait": +1. `element should have text` - звучит +2. `element wait until text` - не звучит + +Не смертельно, но ухо режет (как говорил Ван Гог, гы-гы). + +Поэтому теперь вы можете заменить `$.waitUntil(hasText("bob"), 18_000)` на `$.shouldHave(text("bob"), Duration.ofSeconds(18))`. + +См. [issue 1136](https://github.com/selenide/selenide/issues/1136), +[issue 1338](https://github.com/selenide/selenide/issues/1338) и +[PR 1340](https://github.com/selenide/selenide/pull/1340). + + +
    + +# Пэдж обжекты +Следующий блок улучшений касается пэдж обжектов. +Как вы знаете, в селениде есть возможность объявлять свои пэдж обжекты, +* а в них объявлять поля с аннотациями `@FindBy`, +* а поля эти могут быть как стандартные селениумовские `WebElement`, +* так и наши `SelenideElement`, +* и даже переиспользуемые компоненты `ElementsContainer`, из которых можно собирать пэдж обжекты, как из кирпичиков. + +И работает всё это в лучших традициях селенида: ленивая загрузка и перезагрузка элементов, вот это всё. + +
    + +В общем, в этих `@FindBy` уже давно были шероховатости: +1. не работала ленивая загрузка для полей ПО с типом `List` (см. issue [282](https://github.com/selenide/selenide/issues/282) и [482](https://github.com/selenide/selenide/issues/482)) +2. не поддерживались поля ПО с дженериками (см. [issue 694](https://github.com/selenide/selenide/issues/694)) + +И это было сложно исправить. Пришлось погрузиться в этот (старый) код и серьёзно его порефакторить. +Пришлось напрячь мозги и применить все свои остатки былого абстрактного мышления. + +Так что эти два пулреквеста - предмет моей гордости: +* [support page object fields of generic types](https://github.com/selenide/selenide/pull/1351) +* [enable lazy loading for Page Object fields of type `List`](https://github.com/selenide/selenide/pull/1354) + + +
    + +# И напоследок пачка технологических улучшений: +* разбили проект на подпроекты - см. [PR 1348](https://github.com/selenide/selenide/pull/1348) +* исправили тесты селенида, зависящие от ОС - См. [issue 1344](https://github.com/selenide/selenide/issues/1344) и + [PR 1345](https://github.com/selenide/selenide/pull/1345), спасибо [Daniel H. Peger](https://github.com/dpeger) +* подчистили код `Plugins` -- спасибо [Yuri Orlov](https://github.com/yorlov) за [PR 1343](https://github.com/selenide/selenide/pull/1343) +* Обновились до browserup-proxy:2.1.2 и guava:30.1-jre +* Добавили поддержку chrome 88, edge 89, opera 73 + +
    + +### Известные проблемы: +* файл [selenide-5.17.0-javadoc.jar](https://search.maven.org/remotecontent?filepath=com/codeborne/selenide/5.17.0/selenide-5.17.0-javadoc.jar) + получился неполным: он содержит javadoc не для всех классов. Надеемся, никто не обидится. Исправим в версии 5.17.1. + +
    + +# Итоги +В общем, заканчиваем год на позитивной ноте: +провели серьёзный рефакторинг и исправили несколько старых болячек. +В новый год мы переходим всего с одним экраном в [github issues](https://github.com/selenide/selenide/issues) вместо прежних двух. + +И количество скачиваний селенида выросло за год с 102 до 167 тысяч. + +
    + +
    + +
    + +С наступающим! +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2020-12-30-selenide-5.17.2.md b/content/ru/blog/2020-12-30-selenide-5.17.2.md new file mode 100644 index 000000000..f3614940e --- /dev/null +++ b/content/ru/blog/2020-12-30-selenide-5.17.2.md @@ -0,0 +1,58 @@ +--- +slug: "selenide-5.17.2" +date: 2020-12-30 +title: "Вышла Selenide 5.17.2" +description: "" +category: +headerText: "Последний подарочек" +tags: [] +--- +Доброе утро! +Гномики всё никак не успокоятся. Завтра утром они принесут в ваши носочки последний подарочек: +релиз [Selenide 5.17.2](https://github.com/selenide/selenide/milestone/110?closed=1). + +
    + +# Теперь `Commands` возвращают `SelenideElement` вместо `WebElement` + +Это даёт возможность _чейнить_ вызовы методов `$.execute(Command)` с другими селенидовскими метода, делая ваши тесты +ещё лаконичнее и экспрессивнее: + +```java +$(".lupa").execute(new ScrollToCenter()).$(".pupa").click(); +``` + +Спасибо [Boris Osipov](https://github.com/BorisOsipov) за [PR 1355](https://github.com/selenide/selenide/pull/1355). + +
    + + +# Починили метод `$.setValue(null)` + +См. [issue 1356](https://github.com/selenide/selenide/issues/1356). +Спасибо [Dmitriy Zemlyanitsyn](https://github.com/dzem) за [PR 1357](https://github.com/selenide/selenide/pull/1357). + +
    + +# Включили soft asserts в методах @BeforeAll и @AfterAll (в JUnit 5) + +См. [issue 981](https://github.com/selenide/selenide/issues/981), +[issue 1070](https://github.com/selenide/selenide/issues/1070) и +[PR 1359](https://github.com/selenide/selenide/pull/1359). + +
    + +# Починили файл [selenide-5.17.2-javadoc.jar](https://search.maven.org/remotecontent?filepath=com/codeborne/selenide/5.17.2/selenide-5.17.2-javadoc.jar) + теперь он содержит javadoc для всех классов. + +
    + + +
    + +Ещё раз с наступающим! +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2021-01-23-selenide-5.18.0.md b/content/ru/blog/2021-01-23-selenide-5.18.0.md new file mode 100644 index 000000000..d31842ead --- /dev/null +++ b/content/ru/blog/2021-01-23-selenide-5.18.0.md @@ -0,0 +1,172 @@ +--- +slug: "selenide-5.18.0" +date: 2021-01-23 +title: "Вышла Selenide 5.18.0" +description: "" +category: +headerText: "Несанкционированный релиз" +tags: [] +--- +Ура, товарищи! + +На дворе 23 января. + +Несанкционированные релизы сейчас запрещены, поэтому сегодня у нас просто негативное падение номера версии. +Обновляйтесь: [Selenide 5.18.0](https://github.com/selenide/selenide/milestone/113?closed=1). + +Приглашаю вас на маленькую виртуальную экскурсию по изменениям в 5.18.0. +Устраивайтесь поудобнее. + +
    + +# Выключили логи вебдрайвера по умолчанию + +Начиная с версии 5.13.0, Selenide писал логи вебдрайвера в файлы `build/reports/tests/webdriver.uuid.log`. +Тогда это казалось полезным, но оказалось, что логи эти занимают довольно много места и особо никого не интересуют. +Поэтому мы всё-таки решили не включать их по умолчанию. + +_Логи вебдрайвера отправляются в комнату для мусора._ + +Если надо, вы всегда можете включить эти логи настройкой +`Configuration.webdriverLogsEnabled = true`. + +См. [issue 1365](https://github.com/selenide/selenide/issues/1365) и [PR 1379](https://github.com/selenide/selenide/pull/1379). + +
    + +# Заменили тип параметра "timeout" с Long на Duration + +... в методах коллекций. Теперь вместо +```java +$$.shouldHave(texts(...), 5000); +``` + +модно будет писать +```java +$$.shouldHave(texts(...), Duration.ofSeconds(5)); +``` + +См. [issue 1377](https://github.com/selenide/selenide/issues/1377). +Спасибо [Ostap Oleksyn](https://github.com/ostap-oleksyn) за [PR 1377](https://github.com/selenide/selenide/pull/1377). + +
    + +# Ускорили поиск вложенных элементов в shadow dom + +Одна из фич, которые есть Selenide, но нет в Selenium webdriver - это [_shadow dom_](/2020/03/18/selenide-5.10.0/): + +```java +$(shadowCss("p", "#shadow-host", "#inner-shadow-host")) + .shouldHave(text("The Shadow-DOM inside another shadow tree")); +``` + +В дереве DOM может быть сколько угодно _shadow root_ внутри других _shadow root_. + +Чтобы найти все элементы внутри всех вложенных shadow root, метод `$(shadowCss())` вызывал в цикле +хитрый JavaScript код для каждого shadow root по отдельности. +И это может быть медленно, потому что каждый вызов webdriver занимает время. + +Теперь `$(shadowCss())` дёргает [ещё более хитрый рекурсивный JavaScript](https://github.com/selenide/selenide/blob/master/src/main/resources/find-in-shadow-roots.js), +который находит все элементы во всех shadow dom за один вызов. + +См. [PR 1373](https://github.com/selenide/selenide/pull/1373). + +Отдельное спасибо [sakamoto66](https://github.com/sakamoto66) за +[issue 1246](https://github.com/selenide/selenide/issues/1246) и +[PR 1233](https://github.com/selenide/selenide/pull/1233). +К сожалению, он не был влит, но дал нам пищу для размышлений. + +
    + +# Исправили проверки `$.shouldNot(and(...))` и `$.shouldNot(or(...))` + +Пользователь [pavelpp](https://github.com/pavelpp) обнаружил в селениде багу, комбинируя `not` с условиями `and` и `or`: + +```java +$(".lolkek").shouldNotBe(visible, ofSeconds(5)); // работает +$(".lolkek").shouldNotBe(and("foo", visible)); // падает +$(".lolkek").shouldNotBe(or("foo", visible)); // падает +``` + +Не отвертишься. Пришлось чинить. + +См. [issue 1369](https://github.com/selenide/selenide/issues/1369) и [PR 1370](https://github.com/selenide/selenide/pull/1370). + +Кстати, мы запретили `and` и `or` только с одним условием. +То есть теперь строка `or("foo", visible)` не скомпилируется. +Придётся написать как минимум два условия: `or("foo", visible, enabled)`. + +Согласитесь, это логично. _Зачем нам выбор из одного?_ + + +
    + +# Обнаруживаем конфликт в настройке "browserName" + +Так уж вышло, что для задания браузера есть две разных настройки: +1. Главная - `Configuration.browser` +2. Другая - `Configuration.browserCapabilities["browserName"]` (не знаю, зачем она вообще нужна) + +И у вас может открыться неожиданный браузер, если вы не задали первую, но задали вторую. +В общем, теперь селенид обнаруживает такой конфликт и сразу кидает ошибку, чтобы всем всё стало понятно: + +```java +IllegalArgumentException: Conflicting browser name: 'chrome' vs. 'firefox' +``` + +Подчёркиваю: настройки `Configuration.browser` должно хватать во всех случаях, поэтому вторую не надо никуда пихать. + +См. [issue 1366](https://github.com/selenide/selenide/issues/1366) и [PR 1374](https://github.com/selenide/selenide/pull/1374). + +
    + +# Починили показ таймаута в отчёте + +Недавно мы добавили в методы `$.should*` параметр `timeout` с типом `Duration`. +А потом оказалось, что он непонятно отображался в отчётах. +Например, строка `$("h1").shouldBe(visible, Duration.ofSeconds(1))` в отчёте выглядела так: + +```java +$("h1") should be([visible, PT1M]) +``` + +И хотя эта "PT1M" на самом деле отвечает стандарту ISO и означает "time period 1 minute", мы всё же заменили её на более +понятные "300 ms", "1s", "1.500 s." и т.п. + + +См. [issue 1376](https://github.com/selenide/selenide/issues/1376) и [PR 1378](https://github.com/selenide/selenide/pull/1378). + +
    + +# Обновились на WebDriverManager 4.3.1 + +Как обычно, изменения описаны [здесь](https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md). + +
    + +Вот и всё на сегодня. Обновляйтесь и делитесь впечатлениями. +Заводите баги [на гитхабе](https://github.com/selenide/selenide/issues/new), жалуйтесь [в чатиках](https://softwaretesters.slack.com/messages/selenide_ru), +материтесь [в твиттере](https://twitter.com/selenide). + +
    + +## Читальня + +На хабре вышла расшифровка доклада ["Как законтрибьютить в опенсорс, чтобы не сгореть со стыда"](https://habr.com/ru/company/jugru/blog/537166/) +со смачной картинкой Мастера Йоды. Этот доклад мы с Артёмом Ерошенко делали на фестивале TechTrain осенью 2020. + +По ссылке и текст, и видео: кому что больше нравится. +
    + +
    + +Буду счастлив, если пользователи Селенида его посмотрят. Вы же хотите приобщиться к таинству опен-сорса? + +
    + +Всем щастья! +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2021-02-11-selenide-5.18.1.md b/content/ru/blog/2021-02-11-selenide-5.18.1.md new file mode 100644 index 000000000..37fdcecaf --- /dev/null +++ b/content/ru/blog/2021-02-11-selenide-5.18.1.md @@ -0,0 +1,114 @@ +--- +slug: "selenide-5.18.1" +date: 2021-02-11 +title: "Вышла Selenide 5.18.1" +description: "" +category: +headerText: "Локалхост - нежная штучка!" +tags: [] +--- +Всем привет! + +Как сказал бы рэпер Гнойный, "релизай, а не накапливай!" +Вот и мы релизнули небольшое обновление [Selenide 5.18.1](https://github.com/selenide/selenide/milestone/115?closed=1). + +Давайте заглянем туда с фонариком: + +
    + +# Добавили метод `Selenide.getSessionStorage()` + +по аналогии с `Selenide.getLocalStorage()`, который появился ранее в версии 5.15.0. + +У них одинаковый набор методов: `getItem`, `setItem`, `removeItem`, `clear` и т.д. + +> Иногда полезно положить `sessionStorage` или `localStorage`, скажем, хитрый флаг, чтобы эмулировать какое-нибудь +действие пользователя или включить-выключить какие-то фичи или настройки. + +Спасибо [Dmitriy Budim](https://github.com/dbudim) за [PR 1400](https://github.com/selenide/selenide/pull/1400). + +P.S. Для справки, [разница между localStorage и sessionStorage](https://itchief.ru/javascript/localstorage-and-sessionstorage). + +
    + +# Исправили сообщение об ошибке для `$$.filterBy(and(..))` + +Как вы знаете, селенид предоставляет богатые возможности для фильтрации и проверки коллекций. + +Но пользователь [Pavel Fokin](https://github.com/fokinp) обнаружил, что сообщение об ошибке может выглядеть +непонятно, когда коллекция фильтруется по `and` условию, т.е. комбинации нескольких разных условий: + +```java +$$(".sofa").filterBy(and("shining", text("Jorshik"), text("Zoloto"))).shouldHave(size(2)); +``` +
    + +Результат был не совсем логичный (он содержал лишь последнее проверенное условие): +```java +... collection: .sofa.filter(text Jorshik) +``` + +А теперь результат более корректный (он содержит все условия): +```java +... collection: .sofa.filter(shining: text 'Jorshik' and text 'Zoloto') +``` + +См. [issue 1392](https://github.com/selenide/selenide/issues/1392). +Спасибо [Pavel Fokin](https://github.com/fokinp) за [PR 1393](https://github.com/selenide/selenide/pull/1393). + +
    + +# Передаём настройку "noproxy" от внешнего прокси селенидовскому + +Бывает, что селенид запускается и со своим собственным прокси, и с прокси пользователя. + +У прокси есть одна особенная настройка "noproxy", и туда часто пихают "localhost". Это значит, что через прокси должны +ходить все запросы, кроме "http://localhost:*". Так вот, в случае с "двойным" прокси эта настройка терялась, и +селенид не мог выполнить запросы на localhost. + +_Напрямую, а не через прокси._ + +_Локалхост - нежная штучка!_ + +Спасибо [Boris Osipov](https://github.com/BorisOsipov) за [PR 1390](https://github.com/selenide/selenide/pull/1390). + +
    + +# Обновились на Netty 4.1.59.Final и LittleProxy 2.0.2 + +Вряд ли вы будете читать, но вот релизноутсы +[Netty 4.1.59.Final](https://netty.io/news/2021/02/08/4-1-59-Final.html) и +[LittleProxy 2.0.2](https://github.com/mrog/LittleProxy/blob/master/RELEASE_NOTES.md). +Как минимум там исправили какие-то утечки памяти и дыру в безопасности. + +## Читальня + +Организаторы Гейзенбага выложили видосики с осеннего Heisenbug Moscow 2020. +Из того, что я успел заметить: + +* [Flaky tests. Порядок имеет значение](https://www.youtube.com/watch?list=PLsVTVVvrKX9tBV0_LSkAoSZge3C8qb0ec&v=fFe3reCoeBQ&feature=emb_logo&ab_channel=Heisenbug) + / Андрей Солнцев +* Воркшоп "Как начать свой проект автоматизации с нуля": + [часть 1](https://www.youtube.com/watch?v=1aq4gYflEho&feature=youtu.be&utm_campaign=Heisenbug_2020_Piter_Announce_NoParticipants_211220&utm_medium=email&utm_source=newsletter&ab_channel=Heisenbug), + [часть 2](https://www.youtube.com/watch?utm_campaign=Heisenbug_2020_Piter_Announce_NoParticipants_211220&utm_medium=email&utm_source=newsletter&v=pbvJ8rmh7Ws&feature=youtu.be&ab_channel=Heisenbug) + / Андрей Солнцев, Юрий Артамонов +* [Серверный античит: Панацея или рудимент?](https://www.youtube.com/watch?v=4yq37nxkguM&list=PLsVTVVvrKX9tBV0_LSkAoSZge3C8qb0ec&index=12&ab_channel=Heisenbug) / Евгений Ченцов, Евгений Крутских +* [Типы автоматического тестирования в IntelliJ IDEA](https://www.youtube.com/watch?v=8gOkdFk2JZ8&list=PLsVTVVvrKX9tBV0_LSkAoSZge3C8qb0ec&index=3&ab_channel=Heisenbug) / Юрий Артамонов +* [Тест-кейсы как код](https://www.youtube.com/watch?v=Prm2-c_5mYs&list=PLsVTVVvrKX9tBV0_LSkAoSZge3C8qb0ec&index=18&ab_channel=Heisenbug) / Артем Ерошенко + + +
    + +Вот и всё на сегодня. Обновляйтесь и делитесь впечатлениями. +Заводите баги [на гитхабе](https://github.com/selenide/selenide/issues/new), жалуйтесь [в чатиках](https://softwaretesters.slack.com/messages/selenide_ru), +материтесь [в твиттере](https://twitter.com/selenide). + +
    + +_Опенсорс сильнее багов!_ + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2021-02-24-selenide-5.19.0.md b/content/ru/blog/2021-02-24-selenide-5.19.0.md new file mode 100644 index 000000000..4ec6b378d --- /dev/null +++ b/content/ru/blog/2021-02-24-selenide-5.19.0.md @@ -0,0 +1,167 @@ +--- +slug: "selenide-5.19.0" +date: 2021-02-24 +title: "Вышла Selenide 5.19.0" +description: "" +category: +headerText: "День независимости" +tags: [] +--- +Всем привет! + +Вы, наверное, не знали, но сегодня, 24 февраля, в Эстонии чуть ли не главный праздник - +[День Независимости](https://ru.wikipedia.org/wiki/%D0%94%D0%B5%D0%BD%D1%8C_%D0%BD%D0%B5%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D0%B8_%D0%AD%D1%81%D1%82%D0%BE%D0%BD%D0%B8%D0%B8). +Ровно 103 года назад Эстония была провозглашена независимым демократическим государством. + +А спустя 93 года в Эстонии, в казематах компании [Codeborne](https://codeborne.com/) родилась библиотека Selenide. Это ли не чудо? + +Дню независимости мы и посвящаем наш новый релиз [Selenide 5.19.0](https://github.com/selenide/selenide/milestone/116?closed=1). + + +
    + +# Наконец-таки починили drag'and'drop + +В селениде уже давно есть метод `$.dragAndDropTo()`, но он фактически не работает. Под капотом он использует +селениумовский механизм `Actions`, и что-то там явно сломано. Ну не тащит элемент и всё. + +А теперь мы запилили альтернативную реализацию с помощью JavaScript. И она, похоже, работает во всех браузерах. +Поэтому мы даже включили её по умолчанию. + +```java + +// Рабочий вариант: +$("#drag1").dragAndDropTo("#div2"); +$("#drag1").dragAndDropTo("#div2", usingJavaScript()); + +// Нерабочий вариант через Actions (ну вдруг он у вас почему-то работает): +$("#drag1").dragAndDropTo("#div2", usingActions()); + +``` + + +См. [issue 1110](https://github.com/selenide/selenide/issues/1110). + +Спасибо [Dmitriy Budim](https://github.com/dbudim) за [PR 1412](https://github.com/selenide/selenide/pull/1412). + +
    + + +# Поддержка Appium + +Заодно мы выпустили и обновление библиотеки `selenide-appium:1.6.2`, в которой метод `$.dragAndDropTo()`, +теперь переопределён, так что он работает и на мобильниках. +См. [PR #53](https://github.com/selenide/selenide-appium/pull/53/files). + +
    + +# Починили метод `$.click(usingJavascript())` в Internet Explorer + + +См. [issue 1406](https://github.com/selenide/selenide/issues/1406) и +[PR 1419](https://github.com/selenide/selenide/pull/1419). + +
    + +# Улучшили описание коллекции `$$.snapshot()` + +У селенидовских коллекций есть один хитрый метод `$$.snapshot()`. +Он запоминает текущее состоние коллекции, и при дальнейших обращениях не загружает её заново из браузера. +Это полезно для ускорения тестов, когда коллекция большая, и вы уверены, что её элементы уже точно не изменятся. + +С ними была только маленькая проблемка: в отчётах выглядело не слишком красиво. Например, такая строка: +```java +$$("#root li").snapshot().shouldHave(size(3)) +``` + +при падении в отчёте выглядела как +> List size mismatch: expected: = 3, actual: 2, collection: $$(2 elements) + +Как видите, в описании нет селектора оригинальной коллекции, только `(2 elements)`. + +Теперь виден и селектор: +> List size mismatch: expected: = 3, actual: 2, collection: #root li.snapshot(2 elements) + + +Спасибо [Pavel Fokin](https://github.com/fokinp) за [PR 1402](https://github.com/selenide/selenide/pull/1402). + +
    + + +# Добавили метод `$.getAlias()` + +Он возвращает то, что вы сами же задали с помощью `$.as("login button")`. +В обычных тестах этот метод не должен быть нужен. Но может понадобиться, если вы пилите какой-то свой хитрый отчёт. +Ну мало ли, убийцу Аллюра... + +Спасибо [pavelpp](https://github.com/pavelpp) за [PR 1415](https://github.com/selenide/selenide/pull/1415). + +
    + + +# Добавили события "refresh" и т.п. в селенидовский лог + +В селениде есть целый ряд методов, которые не связаны явно в веб-элементами (`refresh()`, `back()` и т.п.) +И мы в какой-то момент обнаружили, что некоторые из них не отображались в отчёта Selenide или Allure. +Несмертельно, конечно, но всё-таки зачем-то ведь эти отчёты кому-то нужны... + +Теперь мы исправили эту оплошность, и следующие методы будут исправно красоваться в отчётах: +* `refresh` +* `back` +* `forward` +* `updateHash` +* `confirm` +* `dismiss` +* `prompt` +* `clearCookies` + +См. [issue 1383](https://github.com/selenide/selenide/issues/1383) и +[PR 1404](https://github.com/selenide/selenide/pull/1404). + +
    + + +# Добавили аннотаций `@Nullable` методам класса `WebDriverRunner` + +Самым важным, по-видимому, тут является метод `WebDriverRunner.getSelenideProxy()` - не было очевидно, +что он может возвращать `null`, если прокси не запущен. + +Теперь такая ошибка будет подсвечиваться в IDE жёлтеньким. + +См. [коммит](https://github.com/selenide/selenide/commit/9b4723d090442c). + +
    + +# Починили тесты селенида на не-англоязычных машинах + +Оказалось, что парочка собственных тестов селенида падали, если их запустить на +машине, на которой системным языком был выбран не английский, а скажем, французкий или испанский. +Оказывается, в этих странах иначе форматируют Duration. + +Теперь тесты исправлены, и по идее такое больше не может повториться. + +Спасибо [Vicente Rossello Jaume](https://github.com/vrossellotravelc) за [PR 1408](https://github.com/selenide/selenide/pull/1408). + +
    + +# Статистика + +Свежая статистика по скачкам Селенида: + +
    + +
    + +
    + +# Традиции + +Ну вот и всё на сегодня. + +Вы обновляйтесь, а я пока пойду найду стопки водки и бутерброд с килькой. Традиция, ничего не поделаешь. + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2021-03-23-selenide-5.20.1.md b/content/ru/blog/2021-03-23-selenide-5.20.1.md new file mode 100644 index 000000000..e06136991 --- /dev/null +++ b/content/ru/blog/2021-03-23-selenide-5.20.1.md @@ -0,0 +1,152 @@ +--- +slug: "selenide-5.20.1" +date: 2021-03-23 +title: "Вышла Selenide 5.20.1" +description: "" +category: +headerText: "Ммм, хмм, да, киллер-фича!" +tags: [] +--- +Добрый вечер! + +Джо Байдена спросили, считает ли он `$$.as` киллер-фичей. «Ммм, хмм, да», — ответил Байден. + +Это сдвоенный обзор на релиз [Selenide 5.20.0](https://github.com/selenide/selenide/milestone/118?closed=1) и +[Selenide 5.20.1](https://github.com/selenide/selenide/milestone/119?closed=1). + + +
    + +# Добавили методы для операций с буфером обмена + +* `Selenide.clipboard().setText("111");` +* `assertEquals("Hello World", Selenide.clipboard().getText());` + +Имейте в виду, что на линуксе буфер обмена не будет работать без иксов. Либо запускайте xvfb, либо ещё как-то выкручивайтесь. + +Спасибо [Dmitriy Budim](https://github.com/dbudim) за [PR 1409](https://github.com/selenide/selenide/pull/1409). + +NB! Эти методы переопределены в плагине [selenide-selenoid](https://github.com/selenide/selenide-selenoid), так что они корректно +работают с селеноидом. Для него мы тоже выпустили версию [1.1.0](https://github.com/selenide/selenide-selenoid/releases/tag/v1.1.0). + +
    + +# Добавили режим headless для браузера Microsoft Edge + +Раньше настройка `Configuration.headless` срабатывала только для Chrome и Firefox, а теперь ещё и для Edge. + +(Браузеры IE, Opera и Safari, насколько я знаю, до сих пор не поддерживают headless режим.) + +См. [issue 1422](https://github.com/selenide/selenide/issues/1422) +и [PR 1424](https://github.com/selenide/selenide/pull/1424). + +
    + +# Добавили метод $$.as() для задания алиаса коллекциям + +Как вы помните, в Selenide 5.17.0 мы добавили возможность задавать единичным элементам "понятное" имя. +Теперь имя можно задавать и коллекциям: + +```java +$(By.xpath("/long/ugly/xpath[1][2][3]")).as("Login button").shouldBe(visible); +$$(By.xpath("/long/ugly/xpath[1][2][3]")).as("Login buttons").shouldHave(size(2)); +``` + +См. [issue 1389](https://github.com/selenide/selenide/issues/1389) +и [PR 1431](https://github.com/selenide/selenide/pull/1431). + +NB! Не торопитесь использовать эту возможность. Лично я воспринимаю её как "хак последней надежды". +В отчёте всегда лучше видеть настоящий локатор, чем кем-то придуманное имя, которое всегда может оказаться: +* Обманчивым +* Устаревшим +* Вводящим в заблуждение + +Лучше инвестируйте свои усилия в то, чтобы использовать читаемые локаторы. Ну и грамотно называть переменные и методы. Вот где сила, брат! + + +
    + +# Добавили проверку для коллекций `containExactTextsCaseSensitive` + +Существующий метод `$$.shouldHave(texts("a", "b", "c"))` проверяет, что в коллекции ровно эти элементы и никаких больше. А иногда хочется менее строгой проверки. Например, нужно проверить, что в списке торгуемых валют точно +есть RUB, EUR, USD - и какие угодно ещё. + +Теперь для этого есть метод: + +```java + $$.should(containTexts("RUB", "EUR", "USD")); +``` + +Спасибо [Oleg Berezhnoy](https://github.com/bereg2k) за [PR 1426](https://github.com/selenide/selenide/pull/1426). + +**UPD** В оперативно вышедшей Selenide 5.20.1 его переименовали в + +```java + $$.should(containExactTextsCaseSensitive("RUB", "EUR", "USD")); +``` + +Спасибо [Oleg Berezhnoy](https://github.com/bereg2k) за [PR 1438](https://github.com/selenide/selenide/pull/1438) и [PR 1439](https://github.com/selenide/selenide/pull/1439). + + +
    + +# Починили утерянные опции FirefoxOptions + +В некоторых ситуации некоторые настройки Firefox терялись, теперь не теряются. Опции нашлись. + +См. [issue 1436](https://github.com/selenide/selenide/issues/1436). +Спасибо [Dmitriy Budim](https://github.com/dbudim) за [PR 1437](https://github.com/selenide/selenide/pull/1437). + +
    + +# Убрали логирование "поисковых" методов + +В SelenideElement есть несколько методов для поиска других элементов: +* `$.findAll()` +* `$.parent()` +* `$.sibling()` +* `$.preceding()` +* `$.lastChild()` +* `$.closest()` + +Такие методы оказывались в отчёте дважды: сначала при их вызове, а потом - при вызове любого метода на найденном элементе. Теперь мы это дублирование убрали. + +Спасибо [Pavel Fokin](https://github.com/fokinp) за [PR 1428](https://github.com/selenide/selenide/pull/1428). + +
    + + +
    + +### Доска объявлений + +Ура, новый сезон конференций открыт! +Буквально через неделю-две начинается: +* У кого нет денег на Heisenbug и JPoint - приходите 27 марта на бесплатный [фестиваль TechTrain](https://techtrain.ru/2021/spring/schedule/), программа там очень многообещающая. + * Я, например, планирую послушать "[Что мобильным разработчикам в IT-индустрии неведомо](https://techtrain.ru/2021/spring/talks/4vehn9kwvjg7uzjjbp0nl4/)" + * и "[Ловушки коллективного владения кодом](https://techtrain.ru/2021/spring/talks/1vtaygqjny9w3folebliqv/)". + * И конечно, "[Какие тулы ты бы взял на удаленку](https://techtrain.ru/2021/spring/talks/74akccvzvqirxg2jbh4t3m/)" от ведущих "Ошибки выжившего" Севы и Артёма обещает стать хитом. +* А 6-9 апреля грядёт наш любимый [Heisenbug](https://heisenbug-piter.ru/2021/spb/schedule/). + + У меня там будет заключительный доклад эпопеи про флейки тесты + "[Flaky tests. Метод](https://heisenbug-piter.ru/2021/spb/talks/4wcc3dephlxuzc87wgwkk7/)" + и продолжение мастер-класса "[Как начать свой проект автоматизации с нуля](https://heisenbug-piter.ru/2021/spb/talks/8p4qtsit5rqgga8yuxz5a/)". + + А послушать я хочу как минимум мастер-класс гуру юзабилити Виталия Фридмана "[От birthday selector до inline validation: Всё, что нужно знать о веб-формах](https://heisenbug-piter.ru/2021/spb/talks/5lxiyz5rdanigu1wuaujtt/)" и много чего ещё вкусненького. + +* А 13-17 апреля пройдёт конференция [JPoint](https://jpoint.ru/2021/schedule/) + + Она скорее для разработчиков, и на ней я тоже успею засветиться в [мастер-классе по парному программированию](https://jpoint.ru/2021/talks/5gmcsxserjfhlzgt9dpfq3/). + +* А ещё 29 мая будет новосибирский [Codefest](https://11.codefest.ru/) + + Там у меня будет доклад про "[Трюки с javascript в автотестах](https://11.codefest.ru/lecture/1751)". + + +Приходите, всё равно ж делать нечего на карантине! + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2021-05-15-selenide-5.21.0.md b/content/ru/blog/2021-05-15-selenide-5.21.0.md new file mode 100644 index 000000000..9c3c7f705 --- /dev/null +++ b/content/ru/blog/2021-05-15-selenide-5.21.0.md @@ -0,0 +1,150 @@ +--- +slug: "selenide-5.21.0" +date: 2021-05-15 +title: "Вышла Selenide 5.21.0" +description: "" +category: +headerText: "Долой дубликаты!" +tags: [] +--- +Добрый вечер! + +За окошком месяц май, а на экране релиз [Selenide 5.21.0](https://github.com/selenide/selenide/milestone/123?closed=1). + + +
    + +# Убрали повторные скриншоты и шаги в отчёте для цепочи локаторов + +Большинство методов Селенида устроены так, что их можно вызвать несколько штук подряд, в одну строку. +Это позволяет писать лаконичные тесты. + +Что-то вроде + +```java + $("table#id").$("tbody", 2).$("tr.active").$("td", 5) + .shouldHave(text("Ну вот")) + .click(); +``` + +Правда, с ними была одна проблема. При падении такой проверки Селенид делал несколько скриншотов, а +в отчёт (в т.ч. числе в аллюровский отчёт) добавлялось несколько шагов (один для `"table#id"`, второй для `"tbody"` и т.д.), +хотя по сути это один шаг. + +Хоть это и некритично, мы эту неприятность убрали. Теперь селенид будет делать один скриншот, а в аллюр отчёте будет одна строка. + +См. [issue 1055](https://github.com/selenide/selenide/issues/1055) и [PR 1465](https://github.com/selenide/selenide/pull/1465). + +NB! Для этого пришлось сделать приличный рефакторинг, и не исключено даже, что что-то могло сломаться. Сообщайте, будем реагировать! + +
    + +# Добавили BrowserPerTestStrategyExtension +... для перезапуска браузер после каждого теста. + +По умолчанию Селенид переиспользует браузер между тестами (в рамках одного потока). Это сделано для скорости. +Мы предполагаем, что вы сами в начале теста позаботитьесь о том, чтобы обновить страницу, почистить данные и т.п. - ведь это зависит от каждого приложения. + +Если же вы очень хотите в каждом тесте использовать новый браузер, есть и такая возможность. +В Селениде из коробки есть поддерджка для JUnit 4, JUnit 5 и TestNG. + +Но для JUnit5 у нас был только экстеншн для перезапуска браузера для каждого тестового класса (`@ExtendWith({BrowserStrategyExtension.class}`), но не тестового метода. + +А теперь появился экстенш, заполнивший эту нишу. Если прописать в ваших тестах `@ExtendWith({BrowserPerTestStrategyExtension.class}`, то в каждом тестовом методе будет использоваться новый браузер. + +Это сделает ваши тесты значительно медленнее, но иногда по-другому никак. + +См. [issue 1448](https://github.com/selenide/selenide/issues/1448) +Спасибо [Anton Aftakhov](https://github.com/simple-elf) за [PR 1450](https://github.com/selenide/selenide/pull/1450). + +
    + +# Добавили метод $.hover() со сдвигом + +В селениде давно есть метод `$("div#123").hover()` для наведения курсора мыши на нужный элемент. +Этот метод двигает курсор к центру элемента, и на это не было возможности повлиять. + +Теперь же у нас появился метод `$.hover()` с параметром, позволяющим указать, на сколько пикселей от центра нужно сдвинуть курсор: + +```java + $("div#123").hover(withOffset(123, 122)); +``` + +P.S. Кажется, этот сдвиг не всегда оказывается точным. У меня иногда курсор оказывался _примерно_ в этой позиции плюс-минус 30 пикселей. +Делитесь, как у вас? + +См. [issue 1447](https://github.com/selenide/selenide/issues/1447) и [PR 1461](https://github.com/selenide/selenide/pull/1461). + +
    + +# Обновились на WebDriverManager 4.4.3 + +Спасибо [Anil Kumar Reddy Gaddam](https://github.com/anilreddy) +за [PR 1464](https://github.com/selenide/selenide/pull/1464) + и [PR 1469](https://github.com/selenide/selenide/pull/1469). + +
    + +# Обновились javadoc многих селенидовских методов +... касающийся ленивой загрузки и фразы "not recommended". + +Теперь javadoc ведёт на эти две статьи в вики: +* [Lazy loading](https://github.com/selenide/selenide/wiki/Lazy-loading) +* [Not recommended](https://github.com/selenide/selenide/wiki/Do-not-use-getters-in-tests) + +Внимание, неоднозначный контент. +Возможно, вы захотите подискутировать. +Так давайте подискутируем! + +См. [PR 1430](https://github.com/selenide/selenide/pull/1430) + +
    + +# selenide-selenoid 1.1.2 + +Мы выпустили обновление [`selenide-selenoid:1.1.2`](https://github.com/selenide/selenide-selenoid/blob/main/CHANGELOG.md), в котором добавили поддержку BasicAuth при скачивании файлов из контейнера Selenoid. +См. [issue 8](https://github.com/selenide/selenide-selenoid/issues/8) и [PR 9](https://github.com/selenide/selenide-selenoid/pull/9). + + +
    + +# selenide-appium 1.6.5 + +Мы выпустили обновление [`selenide-appium:1.6.5`](https://github.com/selenide/selenide-appium/blob/master/CHANGELOG), в котором улучшили сообщения об ошибках пр падении тестов в iOS. +См. [issue 54](https://github.com/selenide/selenide-appium/issues/54). + + +
    + +# Ссылки + +Что новенького мы нарыли на просторах сети: + +* Открытые видеокурсы [Дневник тестировщика](https://www.youtube.com/channel/UCVE8_r0VkxUYjGd094sKc4g) - там и про селенид есть несколько выпусков. +* [Как e2e автотесты на Selenide помогают QA-команде при частых релизах](https://habr.com/ru/company/croc/blog/546430/) +* годный тред [как слезть с ЛКФ на Селенид](https://twitter.com/arthicl/status/1366598485252964360?s=20) (ЛКФ = локальный кривой фреймворк) +* Пост [Write Concise Web Tests With Selenide for Java Projects](https://rieckpil.de/write-concise-web-tests-with-selenide-for-java-projects/) за авторством [Philip Riecks](https://github.com/rieckpil). +* Видео [Введение в Selenide](https://www.youtube.com/watch?v=T9xns1iMbPI) от него же +* Маленький видеоурок [Create Screenshots With Selenide](https://www.youtube.com/watch?v=XPUPirH1yMs) от него же +* Пример [Selenide+Serenity+JBehave](https://github.com/senpay/layered-test-framework-example-serenity-jbehave) +* Пример [Selenide+TestNG+ExtentReports](https://github.com/sergiomartins8/test-automation-bootstrap/tree/master/ui-tests) +* курс [Selenium и Selenide для начинающих](https://slifki.info/threads/sergei-semenov-selenium-i-selenide-dlja-nachinajuschix-automation-qa-qc-na-java-2020.85098/) (прикольно же!) + +
    + +## Немного статистики + +Статистика скачиваний Selenide за апрель 2021: +
    + +
    + +Чуть-чуть не дотянули до 200 тысяч. + +
    + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2021-06-08-selenide-5.22.0.md b/content/ru/blog/2021-06-08-selenide-5.22.0.md new file mode 100644 index 000000000..464017135 --- /dev/null +++ b/content/ru/blog/2021-06-08-selenide-5.22.0.md @@ -0,0 +1,165 @@ +--- +slug: "selenide-5.22.0" +date: 2021-06-08 +title: "Вышла Selenide 5.22.0" +description: "" +category: +headerText: "Проснитесь, у нас снова релиз!" +tags: [] +--- +Добрый вечер! + +Лучший подарок - сделанный своими коммитами. +В мой день 40 рождения мы выпустили юбилейный релиз [Selenide 5.22.0](https://github.com/selenide/selenide/milestone/124?closed=1). + +Развернём упаковку? + + +
    + +# Теперь можно закрыть алерт перед скачиванием файла + +В Селениде есть метод `$.download()`, который работает по простому принципу: +1. Кликни. +2. Подожди, пока в папке появится нужный файл. + +Проблема в том, что на некоторых сайтах после клика появляется алерт, который нужно закрыть, чтобы началось скачивание. +Ну или вообще, нужно совершить ещё какое-то действие после или вместо клика, чтобы запустить скачивание файла. + +Теперь можно будет [закрыть алерт](https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/FileDownloadToFolderTest.java): +```java +File downloadedFile = $(byText("Download me with alert")).download( + using(FOLDER).withAction( + clickAndConfirm("Are you sure to download it?") + ) + ); +``` + +или вообще совершить [любое нужное действие](https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/FileDownloadViaProxyTest.java): +```java +File downloadedFile = $(byText("Download me with alert")).download( + using(PROXY).withAction((driver, link) -> { + // add cookies + link.click(); + // driver.switchTo().window(); + // alert.dismiss(); + // send http request + // call api + })); +``` + +См. [issue 1479](https://github.com/selenide/selenide/issues/1479) и [PR 1481](https://github.com/selenide/selenide/pull/1481). + +
    +
    + +# Доработали проверку `Condition.textCaseSensitive` + +... чтобы она поддерживала выбранные опции в `` и `` можно использовать старый добрые методы +`$.selectOptionByValue()` и `$.selectRadio()`. + + +Спасибо [Boris Osipov](https://github.com/BorisOsipov) за [PR 1619](https://github.com/selenide/selenide/pull/1619). + +
    + +# Починили метод `Selenide.sleep(N)` + +Казалось бы, разве такой просто однострочный метод может быть сломан? А вот может. +Оказывается, стандартный джавовый метод `Thread.sleep(N)` не обязательно спит именно N мс, он может проснуться и раньше. +И это может привести к моргающим тестам, если ваш тест рассчитывал именно на определённую паузу. +Век живи - век учись. + +Теперь метод `Selenide.sleep(N)` гарантированно спит заданное количество миллисекунд. + +См. [реализацию](https://github.com/selenide/selenide/blob/b05d53dfb794ee02e795587867c6ec8022171040/statics/src/main/java/com/codeborne/selenide/Selenide.java#L258). + + +
    + +# Добавили метод для добавления и удаления `WebDriverListener` + +Раньше в селениде можно было добавлять `WebDriverEventListener`, но этот класс был заменён на `WebDriverListener` в Selenium 4. +Ну вот, пришлось поддерживать оба. + +
    + +См. [issue 1615](https://github.com/selenide/selenide/issues/1615) и [PR 1616](https://github.com/selenide/selenide/pull/1616). + + +
    + +# Поменяли сигнатуру метода `Condition.apply` +Если вы не писали свои Conditions, то вас это не касается. + +А если успели наваять, то придётся их немножко дополнить. + +Итак, +раньше в классе `Condition` был метод `apply`, который возвращал boolean: +```java +public boolean apply(Driver driver, WebElement element) +``` + +Теперь его нужно переименовать в `check`, и возвращать он должен не просто boolean, а `CheckResult`: +```java +public CheckResult check(Driver driver, WebElement element) +``` + +А этот `CheckResult` содержит не только признак "проверка прошла / не прошла", но и какое значение было у элемента в тот момент. +Это позволить формировать более точное сообщение об ошибке в случае падения теста. + +P.S. Впрочем, старый метод `apply` всё ещё остался как deprecated, поэтому какое-то время вы можете сидеть на старых кондишинах. +Просто при падении теста строчка "Actual value: " не будет добавляться к сообщению об ошибке. Но это и не всегда критично. + +См. [issue 217](https://github.com/selenide/selenide/issues/217), +[PR 1586](https://github.com/selenide/selenide/pull/1586) и +[PR 1618](https://github.com/selenide/selenide/pull/1618). + +
    + +# selenide-selenoid 2.0.1 + +Мы выпустили [`selenide-selenoid:2.0.0`](https://github.com/selenide/selenide-selenoid/releases/tag/v2.0.0) с обновлением на Selenide 6.0.1 + + +
    + +# selenide-appium + +Кажется, пока что Appium не поддерживает Selenium 4, так что `selenide-appium` пока обновить не можем. Будет следить за ситуацией. + +
    + +# UPD Selenide 6.0.2 + +Обнаружилась проблемка с проектами на TestNG, по-быстрому выпустили хотфикс 6.0.2. + +См. [issue 1623](https://github.com/selenide/selenide/issues/1623) + +
    + +# UPD Selenide 6.0.3 + +Оказалось, что Maven может подтягивать старый `selenium-api-3*.jar`, если он найден в дереве зависимостей +(обычно у BrowserUpProxy или Allure). + +Мне давно кажется, что тут Maven мог бы быть чуточку поумнее и выбирать всё-таки более свежую версию. +Но поскольку люди довольно часто наступают на эти грабли, мы решили запилить костыль в селениде. + +См. [костыль 1625](https://github.com/selenide/selenide/pull/1625) + + +
    + +# Что почитать про Selenium 4 + +* [What’s New In Selenium 4?](https://applitools.com/blog/selenium-4/) by Applitools +* [Selenium 4: Understanding Key Features](https://www.browserstack.com/guide/selenium-4-features) by BrowserStack +* [A comprehensive guide to Selenium 4](https://saucelabs.com/selenium-4) by SauceLabs +* [What Is New In Selenium 4 And What Is Deprecated In It?](https://www.lambdatest.com/blog/what-is-deprecated-in-selenium4/) by LambdaTest +* [Обновлённый сайт Selenium](https://www.selenium.dev/documentation/) + +
    + +# Другие новости +* внезапный [выпуск Heisenbug Show](https://youtu.be/mK-6-k5EwQM), посвящённый 10-летию Селенида. +* Первый [TestOps Hackathon](https://www.eventbrite.com/e/propeller-testops-hackathon-registration-194333114577) от PropellerAds и Qameta Software - с 12 по 16 ноября. Регистрируйтесь! +* Ребята из Aerokube выпустили [альтернативный клиент WebDriver](https://github.com/aerokube/lightning-java). Теоретически теперь селенид может работать на нём вместо Selenium Webdriver. Звучит заманчиво? +* [Koncerns: Почему я не тороплюсь на Котлин](https://www.youtube.com/watch?v=ch5sxsQJzW4) +* Я пока не разбирался, но люди вроде хвалят: [какие-то образы Docker для Selenium](https://github.com/markhobson/docker-maven-chrome) + +
    + +# Статистика использования Селенида +
    + +
    + +
    + +Перевалили за **255 тысяч скачиваний** в месяц. + +Что нас ждёт впереди? + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2021-11-23-selenide-6.1.0.md b/content/ru/blog/2021-11-23-selenide-6.1.0.md new file mode 100644 index 000000000..3dec27324 --- /dev/null +++ b/content/ru/blog/2021-11-23-selenide-6.1.0.md @@ -0,0 +1,113 @@ +--- +slug: "selenide-6.1.0" +date: 2021-11-23 +title: "Вышла Selenide 6.1.0" +description: "" +category: +headerText: "Больше настроек богу настроек!" +tags: [] +--- +
    + +# TERE! + +
    + +Мы зарелизили [Selenide 6.1.0](https://github.com/selenide/selenide/milestone/137?closed=1). + + +
    + +# Добавили поддержку `selenide.properties` + +Теперь Селенид умеет читать настройки из отдельного файлика `selenide.properties`, если таковой найдётся в classpath. + +NB! Лично я всё ещё не вижу пользы от этого, ведь проще задать настройки +1. прямо в коде: `Configuration.timeout = 8000;` +2. или через system properties: `-Dselenide.timeout=8000`. + +Прошу, не надо резко ломиться генерировать эти файлики. Используйте `selenide.properties`, только если у вас есть хорошие причины для этого, а не просто потому, что теперь это модно или "так красиво". + +Спасибо [Petro Ovcharenko](https://github.com/petroOv-PDFfiller) за +[PR 1601](https://github.com/selenide/selenide/pull/1601). + +
    + +# Добавили возможность тонкой настройки прокси + +Как вы знаете, Селенид умеет запускать свой прокси-сервер, который даёт нам некоторые дополнительные возможности. Но возможности для настройки прокси до сих пор были ограниченные. Только `Configuration.proxyHost` и `Configuration.proxyPort`. + +Теперь же можно будет получить инстанс BrowserModProxy и настроить его как угодно до запуска браузера. + +NB! Пожалуйста, не переусердствуйте с этим. Тут очень легко выстрелить себе в ногу. + +И если ваши настройки действительно помогли вам, то возможно, они помогут и другим. Расскажите нам, что вы там такого настроили - может, стоит сделать это в селениде по умолчанию? + +См. [issue 1561](https://github.com/selenide/selenide/issues/1561). +Спасибо [Boris Osipov](https://github.com/BorisOsipov) за +[PR 1620](https://github.com/selenide/selenide/pull/1620). + + +
    + +# Добавили костыль для избежания случайных `NoClassDefFoundError` в `WebDriverException`. + +В Селениум есть [бага](https://github.com/SeleniumHQ/selenium/issues/9784), которая полностью до сих пор не исправлена. Но вы её больше не увидите, потому что теперь в селениде есть костыль против неё. :) + +См. [костыль](https://github.com/selenide/selenide/commit/2eff0307e3a). + + +
    + +# Поменяли тип параметра `SelenideConfig.browserCapabilities()` + +... с `DesiredCapabilities` на `MutableCapabilities`. + +Это позволяет упростить ваш код и не заворачивать `ChromeOptions` в `DesiredCapabilities`. +Больше об упрощении капабилитей этом будет в следующем релизе `Selenide 6.1.1`. + +См. [PR 1637](https://github.com/selenide/selenide/pull/1637). + + +
    + +# Обновились на Selenium Webdriver 4.1.0 + +Спасибо [Boris Osipov](https://github.com/BorisOsipov) за [PR 1638](https://github.com/selenide/selenide/pull/1638). + +
    + +# Удалили метод `$.shadowRoot()` + +Этот метод сломался после обновления на Chrome 96, и вероятно, вскоре сломается и в остальных браузерах. Починить его муторно, и при этом [пользы от этого метода немного](https://github.com/selenide/selenide/issues/1515#issuecomment-894476289), ведь для поиска элементов внутри Shadow DOM есть [более удобные и быстрые методы](/2020/03/18/selenide-5.10.0/). + +См. [issue 1640](https://github.com/selenide/selenide/issues/1640) и +[PR 1641](https://github.com/selenide/selenide/pull/1641). + + +
    + +# Новости +* Первый [TestOps Hackathon](https://www.eventbrite.com/e/propeller-testops-hackathon-registration-194333114577) от PropellerAds и Qameta Software перенесли на 1-6 декабря. Регистрируйтесь! +* [Как использовать Selenide с сервисом Lambdatest](https://www.lambdatest.com/selenium-automation-testing-with-selenide-framework) +* Пост [Selenide - Create a Custom WebDriver](https://mbbaig.blog/selenide-webdriverfactory/) от Boris Bay +* Оказывается, [LinkedIn проводит курсы по Селениду](https://www.linkedin.com/feed/update/urn:li:activity:6867477909766979584/) и даже выдаёт красивенькие дипломы. + +
    + +# Статистика использования Селенида +
    + +
    + +
    + +В октябре мы сделали мощный скачок и перевалили за **280 тысяч скачиваний** в месяц. Эгегей! + +_Больше скачиваний богу скачиваний!_ + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2021-11-24-selenide-6.1.1.md b/content/ru/blog/2021-11-24-selenide-6.1.1.md new file mode 100644 index 000000000..bdeaaec6e --- /dev/null +++ b/content/ru/blog/2021-11-24-selenide-6.1.1.md @@ -0,0 +1,110 @@ +--- +slug: "selenide-6.1.1" +date: 2021-11-24 +title: "Вышла Selenide 6.1.1" +description: "" +category: +headerText: "Капабилятити" +tags: [] +--- +
    + +# TERE HOMMIKUST! + +
    + +Мы зарелизили [Selenide 6.1.1](https://github.com/selenide/selenide/milestone/141?closed=1). + +В этом маленьком релизе мы исправили сразу пачку проблем с настройками браузеров. +Они все всплыли после обновления на Selenium 4, в котором `ChromeOptions` и другие `Capabilities` были серьёзно переработаны. + +Ну вот, теперь мы погрузились в тему и разом все проблемы исправили. + + +
    + +# Раннее обнаружение конфликтов {#early-conflicts-detection} +Если вы попытаетесь открыть хром с настройками файерфокса: +```java +Configuration.browser = "chrome"; +Configuration.browserCapabilities.setCapability(FIREFOX_OPTIONS, new FirefoxOptions()); +``` +то Селенид версии 5.x ругался, а Селенид 6.0.x перестал ругаться. +Теперь мы ругань восстановили, и вы снова увидите старое доброе +> IllegalArgumentException: Conflicting browser name: 'chrome' vs. 'firefox' + +См. [issue 1591](https://github.com/selenide/selenide/issues/1591) и [PR 1642](https://github.com/selenide/selenide/pull/1642). + +
    + +# Слияние аргументов хрома {#merging-chrome-arguments} + +Если вы попытаетесь задать хрому, например, полноэкранный режим или язык: +```java +ChromeOptions options = new ChromeOptions(); +options.addArguments("--start-fullscreen", "--start-incognito"); +options.setExperimentalOption("prefs", Map.of("intl.accept_languages", "de_DE")); +Configuration.browserCapabilities = chromeOptions; +open("https://codeborne.com";) +``` + +то эти настройки терялись в Selenide 6.0.x +Теперь мы их восстановили. + + +См. [issue 1626](https://github.com/selenide/selenide/issues/1626), +[issue 1630](https://github.com/selenide/selenide/issues/1630) и +[issue 1631](https://github.com/selenide/selenide/issues/1631). + +Исправление в [PR 1642](https://github.com/selenide/selenide/pull/1642). + + +
    + +# ВАЖНО {#wrapping-browser-capabilities} + +Если вы использовали `Configuration.browserCapabilities`, то с большой вероятностью заворачивали +их в `DesiredCapabilities`: + +```java +ChromeOptions options = new ChromeOptions(); +options.addArguments(...); + +DesiredCapabilities caps = new DesiredCapabilities(); +caps.setCapability(ChromeOptions.CAPABILITY, options); +Configuration.browserCapabilities = caps; +``` + +Так вот, теперь этот **код нужно упростить**, чтобы настройки больше не терялись: +```java +ChromeOptions options = new ChromeOptions(); +options.addArguments(...); +Configuration.browserCapabilities = options; +``` + +
    + +# Поменяли тип параметра в `WebDriverProvider` {#webdriver-provider-parameter-type} + +... с `DesiredCapabilities` на просто `Capabilities`. + +Для вас почти ничего не меняется. Если вы используете в своих тестах `WebDriverProvider`, просто +поменяйте `DesiredCapabilities` на `Capabilities`, и всё будет по-старому. + +См. [PR 1642](https://github.com/selenide/selenide/pull/1642). + +
    + +_Больше капабилитей богу капабилитей!_ + +
    + +# UPD Selenide 6.1.2 {#upd-selenide-6.1.2} + +Мы выпустили Selenide 6.1.2 с обновлением на Selenium 4.1.1 - эта версия содержит несколько заметных исправлений. + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2022-01-10-selenide-6.2.0.md b/content/ru/blog/2022-01-10-selenide-6.2.0.md new file mode 100644 index 000000000..d46ea6183 --- /dev/null +++ b/content/ru/blog/2022-01-10-selenide-6.2.0.md @@ -0,0 +1,157 @@ +--- +slug: "selenide-6.2.0" +date: 2022-01-10 +title: "Вышла Selenide 6.2.0" +description: "" +category: +headerText: "Мягкие ассерты, твёрдые итераторы" +tags: [] +--- +
    + +# С новым годом! + +
    + +Мы зарелизили [Selenide 6.2.0](https://github.com/selenide/selenide/milestone/140?closed=1). + +Давайте посмотрим, что нам приготовил первый релиз в новом году. + +Наливайте чай и погнали! +
    + +# Добавили ссылку "<Click to see difference>" для большинства селенидовских ошибок + +Как вы помните, в [Selenide 5.25.0](/2021/09/28/selenide-5.25.0/) мы добавили поддержку OpenTest4J, в результате чего у +селенидовских ошибок в IDE появилась ссылочка "<Click to see difference>", позволяющая удобно посмотреть различия +между ожидаемым и актуальным значением. + +Но тогда мы всё порефакторить не успели, и ссылочка появилась не у всех типов ошибок. +А теперь должна появиться у всех. + +См. [issue 1589](https://github.com/selenide/selenide/issues/1589) и [PR 1676](https://github.com/selenide/selenide/pull/1676). + +
    + +# Заменили `$$.iterator()` на `$$.asDynamicIterable()` и `$$.asFixedIterable()` + +> _Ух какую старую болячку мы исправили!_ +> _Ну молодцы же!_ + +Есть в селениде метод `$$` для коллекции элементов. Возвращает он объект класса `ElementsCollection`. +Изначально у него должен был быть только один метод `$$.shouldHave(<условие>)`. Хочешь проверить коллекцию элементов на +соответствие какому-то условию - передай нужное условие. Не нашёл готового условия - напиши своё, благо это легко. + +### The ошибка +Но в те давние времена случилось так, что я наследовал класс `ElementsCollection` от `AbstractList`. +Об этом решении я неоднократно жалел впоследствии. + +Что же случилось, спросите вы? А случилось то, что люди начали абьюзить коллекции как не в себя. +* Например, начали итерировать все элементы в коллекции (это _случайно_ стало +возможным благодаря наследованию от `AbstractList`). +* И ещё люди ожидают, что элементы в коллекции будут постоянно обновляться, ведь до сих пор селенид автоматически обновлял любые веб-элементы. +* Помимо сомнительного тест-дизайна, это вызвало ещё и проблемы с производительностью, ведь на каждом шаге итерации селенид +должен загрузить заново всю коллекцию элементов. А это может быть медленно, особенно есть элементов много или коллекция +фильтруется: `$$("div").filter(visible).filterBy(text("Hello"))`. + +### The дилемма + +Получилась дилемма: +* одним хотелось, чтобы селенид при итерировании перегружал элементы каждый раз, ведь это позволяет не получать `StaleElementException`, когда элементы на странице исчезают и появляются; +* а другим хотелось, наоборот, чтобы селенид не перегружал элементы при итерировании, ведь это ускоряет тест на больших коллекциях. + +Какой вариант ни выберешь - всем не угодишь. + +### The решение + +И наконец мы придумали, как решить эту дилемму. Случайно унаследованные от `AbstractList` методы типа `$$.iterator()` мы +пометили как `@Deprecated`. Вместо них предлагаем вам два метода, из которых вы сами сможете выбрать согласно вашим потребностям: +* `$$.asDynamicIterable()` - перегружает элементы коллекции при итерировании. Может быть медленным на больших коллекциях. +* `$$.asFixedIterable()` - не перегружает элементы при итерировании. Он быстрее, но не получает обновлений, +если элементы удаляются или добавляются во время итерирования. + +### The совет + +Какой из них я вам советую? + +НИКАКОЙ! :) + +Напоминаю, что в хорошем тесте, скорее всего, не должно быть циклов, условий и т.п. +Вы должны точно знать, сколько элементов ожидается на странице, и какие свойства должны быть у каждого из них! _Просто проверьте эти свойства._ + +Вместо итерирования всегда лучше написать [свой `CollectionCondition`](https://github.com/selenide/selenide/blob/master/statics/src/test/java/integration/CustomCollectionConditionTest.java). Благо это легко. + +См. [issue 797](https://github.com/selenide/selenide/issues/797) и [PR 1688](https://github.com/selenide/selenide/pull/1688). + +
    + +# Исправили SoftAssert, чтобы он не валил тест + +в довольно редкой ситуации: +1. если софт ассерт listener/rule/extension добавлен к тесту, но +2. софт ассерты **выключены**, и +3. внутри теста кидается и тут же ловится ошибка (try/catch). + +Вообще в такой ситуации надо исправлять сам тест. :( + +И всё же. До сих пор селенидовский софт ассерт валил тест, потому что в ходе теста была ошибка, и листенер это заметил. +А теперь листенер стал чуть умнее и тест не валит. + +> _Уф, ну и проблемки вы иногда подкидываете, дорогие пользователи... :)_ + +См. [issue 1646](https://github.com/selenide/selenide/issues/1646) и [PR 1680](https://github.com/selenide/selenide/pull/1680). + +
    + +# Исправили софт ассерты, чтобы они включали все падения +Ещё одна редкая проблема с софт ассертами. Представьте ситуацию: +1. Софт ассерты включены; +2. В ходе теста случились какие-то селенидовские ошибки (пойманы софт ассерт листенером); +3. А также в ходе теста случилась какая-то другая ошибка (банальный `NPE` или `assertEquals(2, 3)`). + +В этом случае селенидовский софт ассерт листенер валил тест (что правильно), но показывал только селенидовские ошибки (п. 2) и +терял "другую" ошибку (п.3). + +Теперь листенер стал умнее, и показывает все ошибки. + +См. [issue 1661](https://github.com/selenide/selenide/issues/1661) и [PR 1679](https://github.com/selenide/selenide/pull/1679). + +
    + +# Добавили локаторы к некоторым селенидовским ошибкам + +Мелочь, но стоит упомянуть. + +Мы добавили селектор к некоторым селенидовским ошибкам. +Например, там, где селенид раньше кидал такую ошибку: +> "Invalid element state: Cannot change invisible element" + +Теперь он будет кидать такую: +> "Invalid element state [.btn.btn-primary]: Cannot change invisible element" + +
    + +# Обновили BrowserUpProxy с 2.1.2 на 2.1.3 + +Важно отметить, что версия 2.1.3 - это форк оригинального BrowserUpProxy. +Автор объявил о прекращении поддержки, добровольцы переняли инициативу и зарелизили версию 2.1.3 [из форка](https://github.com/browserup/browserup-proxy/issues/388#issuecomment-1004097733). + +Будем следить за ситуацией. В идеале хорошо бы перейти с BrowserUpProxy на mitmproxy. Есть добровольцы? + +См. [PR 1678](https://github.com/selenide/selenide/pull/1678). + +
    + +# Обновили TestNG с 7.4.0 на 7.5 +Список изменений [внушительный](https://github.com/cbeust/testng/blob/7.5/CHANGES.txt). + +См. [PR 1682](https://github.com/selenide/selenide/pull/1682). + +
    + +С Новым Годом, друзья! +Стабильных тестов вам и красивых отчётиков! + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2022-02-07-selenide-6.3.0.md b/content/ru/blog/2022-02-07-selenide-6.3.0.md new file mode 100644 index 000000000..7f922f7d0 --- /dev/null +++ b/content/ru/blog/2022-02-07-selenide-6.3.0.md @@ -0,0 +1,213 @@ +--- +slug: "selenide-6.3.0" +date: 2022-02-07 +title: "Вышла Selenide 6.3.0" +description: "" +category: +headerText: "Начало прекрасной дружбы" +tags: [] +--- +
    + +# Здравствуйте, друзья! + +
    + +Мы зарелизили [Selenide 6.3.0](https://github.com/selenide/selenide/milestone/143?closed=1). + +Приготовьте бутеры и погнали! + +
    + +# Добавили метод `switchTo().frame(timeout)` с кастомным таймаутом + +В селениде есть метод `switchTo().frame(name)` для переключения между фреймами. Как всегда, со встроенной ожидалкой и другими плюшками. +Но что, если фрейм грузится дольше, чем таймаут по умолчанию (4 секунды)? + +Теперь вы можете передать дополнительный параметр `Duration` - таймаут для переключения во фрейм: + +```java + switchTo().frame("ifrm"); // по умолчанию ждёт до 4 секунд + switchTo().frame("ifrm", Duration.ofSeconds(6)); // а вот теперь до 6 секунд +``` + +Спасибо [@donesvad](https://github.com/donesvad) за [PR 1722](https://github.com/selenide/selenide/pull/1722). + +
    + +# Добавили селекторы `byTagAndText` и `withTagAndText` + +До сих пор в селениде были методы для поиска элементов по тексту: +```java + import static com.codeborne.selenide.Selectors.*; + + $(byText("Hello world")).shouldHave(text("Hello World")); + $(withText("Hello")).shouldHave(text("Hello World")); +``` + +Иногда этого мало: когда элементов с таким текстом несколько, и хочется из них выбрать только один - с нужным тэгом. + +Теперь и для этого есть методы: + +```java + import static com.codeborne.selenide.Selectors.*; + + $(byTagAndText("h1", "Hello world")).shouldHave(text("Hello World")); + $(withTagAndText("h1", "Hello")).shouldHave(text("Hello World")); +``` + +Спасибо [Maurizio Lattuada](https://github.com/maurizio-lattuada ) за [issue 1650](https://github.com/selenide/selenide/issues/1650) и [PR 1651](https://github.com/selenide/selenide/pull/1651). + +
    + +# Исправили ошибку в `byTextCaseInsensitive` + +Теперь этот селектор игнорирует множественные пробелы и переводы строк в начале и конце текста (как и каноничный `byText`). + +См. [issue 1723](https://github.com/selenide/selenide/issues/1723) и [PR 1724](https://github.com/selenide/selenide/pull/1724). + +
    + +# Добавили записи "webdriver create" в "webdriver close" в отчёт + +Если вы используете селенидовский `TextReport` или плагин `AllureSelenide`, вы привыкли в конце каждого теста +видеть отчёт, в котором видны все действия: открыли страничку - нашли элемент - кликнули и т.д. + +Теперь там добавилась запись, когда был запущен сам вебдрайвер. И когда закрыт. Иногда эта информация может быть +полезна при отладке различных проблем с тестами. + +Спасибо [Petro Ovcharenko](https://github.com/petroOv-PDFfiller) за [PR 1715](https://github.com/selenide/selenide/pull/1715). + +
    + +# Исправили переопределение селениумовского таймаута + +В [Selenide 5.22.0](/2021/06/08/selenide-5.22.0/) мы сделали хак, который менял дефалтовый селениумовский таймаут для общения с вебдрайвером с дичайших 3 часов до 2 минут. + +Однако выяснилось, что при обновлении на Selenium 4 этот хак сломался (как и положено всем хакам). +Теперь мы его реанимировали. + +Напоминаю, теперь при общении между тестами и вебдрайвером таймаут такой: +* таймаут на соединение - 10 секунд +* таймаут на чтение - 1.5 минуты + +См. [commit cf02da5](https://github.com/selenide/selenide/commit/cf02da5). + +
    + +# Убрали двойное заворачивание ошибок "Element not found" друг в друга + +См. [issue 1705](https://github.com/selenide/selenide/issues/1705) и [PR 1706](https://github.com/selenide/selenide/pull/1706). + +
    + +# Добавили поддержку типа аутентификации `BEARER` + +В селениде давно уже есть способ аутентификации с разными типами: +```java +open("/basic-auth/hello", BASIC, "scott", "tiger"); +``` + +но точно правильно работал только тип `BASIC`. Остальные особо никто не проверял. :) + +Оказалось, что тип `BEARER` не работал. Теперь вот работает (а остальные по-прежнему никто не проверял :)). + +Использовать так: + +```java + open("/bearer-token-auth/hello", BEARER, new BearerTokenCredentials("token-123")); +``` + +См. [PR 1714](https://github.com/selenide/selenide/pull/1714). + +
    + +# Теперь пустые настройки типа `selenide.remote` считаются незаданными + +Это должно чутка упростить жизнь девопсам. +При настройках всяких там джобов и пайплайнов на CI сервере, часто приходится использовать переменные для задания настроек селенида: + +``` +-Dselenide.remote=${env.GRID_URL} +``` + +И если в какой-нибудь среде переменной `GRID_URL` не окажется, то селенид грохнется, т.к. попытается использовать пустой урл для `selenide.remote`. + +Так было раньше. А теперь селенид будет считать, что `selenide.remote` просто не задан, и продолжить работать как обычно. + +См. [Alexei Vinogradov](https://github.com/vinogradoff) за [issue 1656](https://github.com/selenide/selenide/issues/1656) и [Boris Osipov](https://github.com/BorisOsipov) за [PR 1663](https://github.com/selenide/selenide/pull/1663). + +
    + + +# Обновились на Selenium 4.1.2 + +После обновления на Selenium 4.1.2 у многих слетела версия Guava. Селенид явно определяет нужную версию Guava, так что +вас эта проблема затронуть не должна. Но если что, убедитесь, что в вашем проекте никакой там градловский или мавеновский плагин не переопределяет версию Guava. Старый добрый [пост про зависимости](/2020/11/17/why-proxy-does-not-work-in-selenoid/) в помощь. + +См. [ченджлог Selenium](https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG) и [PR 1719](https://github.com/selenide/selenide/pull/1719). + +
    + +# UPD Selenide 6.3.1 +Небольшое обновление [Selenide 6.3.1](https://github.com/selenide/selenide/milestone/146?closed=1): +* [#1731](https://github.com/selenide/selenide/issues/1731) вернули возможность использовать софт ассерты в TestNG в методах `@Before*` и `@After*` (ранее мы их случайно запретили в Selenide 6.2.0) - см. [PR #1732](https://github.com/selenide/selenide/pull/1732) +* [#1729](https://github.com/selenide/selenide/pull/1729) Обновились с Netty 4.1.73.Final на 4.1.74.Final + + +
    + +# UPD Selenide 6.3.2 +Ещё обновление [Selenide 6.3.2](https://github.com/selenide/selenide/milestone/147?closed=1): +* [#1733](https://github.com/selenide/selenide/pull/1733) Запилили костыль для баги селениума [10345](https://github.com/SeleniumHQ/selenium/issues/10345), из-за которой метод `FirefoxDriver.close()` валится после обновления на Firefox 97. +* [#1736](https://github.com/selenide/selenide/pull/1736) Обновились с BrowserUpProxy 2.1.3 на 2.1.4 +* [#1611](https://github.com/selenide/selenide/pull/1611) Обновили версию Java с 8 до 17. + +А вот тут давайте остановимся поподробнее. Теперь проект Selenide собирается на Java 17, но бинарники `selenide-*.jar` +по-прежнему собираются для Java 8. Поэтому +* разработчики селенида могут использовать все последние фичи языка Java, а +* пользователи селенида могут по-прежнему запускать свои тесты на Java 8 (хоть мы и советуем обновить джавушку, конечно). + +А стало это возможным благодаря инструменту [Jabel](https://github.com/bsideup/jabel) и лично [ +Sergei Egorov](https://github.com/bsideup), придумавшему этот изящный хак +(а ещё причастному к [TestContainers](https://github.com/testcontainers/testcontainers-java) и [AtomicJar](https://www.atomicjar.com/)). + +
    + +# UPD Selenide 6.3.3 +Ещё обновление [Selenide 6.3.3](https://github.com/selenide/selenide/milestone/148?closed=1): +* #1737 позволили переопределять настройки Firefox для скачивания файлов +* #1740 обновились на WebDriverManager 5.1.0 + +
    + +# UPD Selenide 6.3.4 +Ещё обновление [Selenide 6.3.4](https://github.com/selenide/selenide/milestone/149?closed=1): +* #1746 показываем ожидаемый атрибут при падении `$.shouldHave(attribute(...))`. +* #1748 исправили имя модуля в сгенерированных бинарниках селенида + +
    + +# UPD Selenide 6.3.5 +Ещё обновление [Selenide 6.3.5](https://github.com/selenide/selenide/milestone/150?closed=1): +* [#1755](https://github.com/selenide/selenide/issues/1755) починили скачивание файлов через прокси, если ответ сервера закодирован - см. [PR #1756](https://github.com/selenide/selenide/pull/1756) + +
    + +# Новости +* Мы создали группу в LinkedIn [Selenide User Group](https://www.linkedin.com/groups/9154550/)! +* Пост от Miklós Szeles [Selenium or Selenide?](https://www.linkedin.com/pulse/selenium-selenide-mikl%25C3%25B3s-szeles/) +* Селенид попал в подборку [5 Testing Automation Tools](https://qameta.io/blog/5-testing-automation-tools/) в блоге компании Qameta Software (это которая Allure Report) +* Селенид попал в подборку [Top Java Libraries for Automation Testing in 2022](https://hackernoon.com/top-java-libraries-for-automation-testing-in-2022) +* Пост [про Селенид](https://blog.knoldus.com/selenide-concise-ui-test-in-java/) в блоге компании Knoldus +* Пост [The software that doesn’t need documentation](https://medium.com/@gaveen0513/selenide-the-software-that-doesnt-need-documentation-cda8535cb7e6) от Gaveen Nayanajith +* Пост [начало прекрасной дружбы](https://mszeles.com/selenide-i-think-this-is-the-beginning-of-a-beautiful-friendship) от Miklós Szeles + +
    + +#### Я думаю, это начало прекрасной дружбы! + + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2022-04-07-selenide-6.4.0.md b/content/ru/blog/2022-04-07-selenide-6.4.0.md new file mode 100644 index 000000000..8e337287c --- /dev/null +++ b/content/ru/blog/2022-04-07-selenide-6.4.0.md @@ -0,0 +1,122 @@ +--- +slug: "selenide-6.4.0" +date: 2022-04-07 +title: "Вышла Selenide 6.4.0" +description: "" +category: +headerText: "Отчёты пустое место" +tags: [] +--- +
    + +# Здравствуйте, друзья! + +
    + +Мы выпустили релиз [Selenide 6.4.0](https://github.com/selenide/selenide/milestone/145?closed=1). + +### Показываем и алиас, и локатор при падении тестов + +Как вы знаете, в Селениде с помощью метода `as` можно задавать элементам "алиас", или понятное имя. +Это полезно в тех случаях, когда нет хорошего локатора, и приходится писать какой-нибудь длинный сложный xpath, который +потом в отчётах сложно читать. + +Например: +```java +$x("/long/ugly/xpath/div[2]/span[3]/li[4]").as("Login button").click(); +``` + +И у нас всегда была дилемма: нужно ли +1. показывать только алиас (плюс: легко читается, минус: не видно селектора - вдруг он нужен?) +2. показывать и алиас, и селектор (плюс: видно селектор, минус: трудно читается). + +
    + +И вот наконец мы поняли, как правильно. +Начиная с версии 6.4.0, селенид будет: +1. В отчётах на каждом шаге показывать только алиас (коротко, легко читается) +2. А вот при падении теста в сообщение об ошибке добавлять и алиас, и локатор +(длинно, зато будет вся необходимая информация для изучения падения). + +Например, вышеупомянутая строка в отчётах будет выглядеть вот так: +``` ++----------------------+--------------------+------------+------------+ +| Element | Subject | Status | ms. | ++----------------------+--------------------+------------+------------+ +| Login button | click() | FAIL | 206 | ++----------------------+--------------------+------------+------------+ +``` + +А сообщение об ошибке - так: +```java +Element "Login button" not found {By.xpath: /long/ugly/xpath[1][2][3]} +Expected: exist +Screenshot: ... +``` +См. [issue 1765](https://github.com/selenide/selenide/issues/1765) и [PR 1766](https://github.com/selenide/selenide/pull/1766). + +
    + +### Добавили пробелы в селенидовском отчёте + +Например, вышеупомянутый отчёт раньше выглядел так: + +``` ++---------------------+-------------------+------------+------------+ +|Element |Subject | Status | ms. | ++---------------------+-------------------+------------+------------+ +|open |https://google.com/some-long-url.html?q=selenide|PASS |1285 | +|---|---------------------|------------------------------------------------|-----------|-----------|---| +|Login button |click() | FAIL | 206 | ++---------------------+-------------------+------------+------------+ +``` + +Проблема была как минимум в том, что вокруг URL слева и справа вплотную прилегают символы `|`, так что его +невозможно быстро выделить двойным кликом. Теперь вокруг URL и других значений будут пробелы. +Заодно отчёт и покрасивее стал. + +См. [issue 1764](https://github.com/selenide/selenide/issues/1764) и [PR 1767](https://github.com/selenide/selenide/pull/1767). + +
    + +### Обновились на Selenium 4.1.3 + +См. [ченджлог Selenium](https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG) и [PR 1759](https://github.com/selenide/selenide/pull/1759). + +
    + +
    + +# ВАЖНО + +Меня зовут Андрей Солнцев, я 10 лет делаю библиотеку Selenide и делюсь опытом на конференциях. +Просто так, бесплатно. Я у вас никогда ничего за это не просил. + +А теперь я прошу всего лишь услышать меня. Вот как вижу ситуацию я - в целом неглупый человек, мнение которого, надеюсь, +стало для многих из вас авторитетным за эти 10 лет. + +
    + +Россия начала **войну в Украине**. Бессмысленную и бесчеловечную. + +Там сейчас под бомбёжками, под обстрелами сидят мирные люди, которые никому ничего плохого не сделали. +В том числе и пользователи селенида. +* Те, перед которыми я многократно выступал на конференциях. +* Те, которых я слушал и учился. +* Те, которые помогали развивать селенид, и результатами работы которых пользуются люди во всём мире, в том числе +и России. Пользуетесь лично вы. + +Это тяжело признать, об этом тяжело думать, от этого ужаса хочется спрятаться - но такова реальность. + +
    + +Я не знаю, как это остановить. +Но я прошу вас хотя бы *не поддерживать это*. +Я призываю вас не верить этой *чудовищной лжи* про нацистов, расширение НАТО, фейки и т.п. +Я прошу вас оставаться людьми. + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2022-05-17-selenide-6.5.0.md b/content/ru/blog/2022-05-17-selenide-6.5.0.md new file mode 100644 index 000000000..8441f073c --- /dev/null +++ b/content/ru/blog/2022-05-17-selenide-6.5.0.md @@ -0,0 +1,222 @@ +--- +slug: "selenide-6.5.0" +date: 2022-05-17 +title: "Вышла Selenide 6.5.0" +description: "" +category: +headerText: "ремастеринг setValue" +tags: [] +--- +
    + +# Здравствуйте, друзья! + +
    + +Мы выпустили релиз [Selenide 6.5.0](https://github.com/selenide/selenide/milestone/151?closed=1). + +### Теперь можно маскировать пароли в отчётах + +Иногда в автотестах приходится вбивать в поля пароли и другие секретные данные. И некоторые люди +переживают, что эти данные потом видны в отчётах (Allure или TextReport). И просят их как-нибудь скрыть. + +Лично я не понимаю, почему кого-то должен волновать пароль от тестовой среды. +(Вы же не используете одни и те же пароли во всех средах? Вы же не гоняете тесты на продакшине?) + +Но мы пошли навстречу пожеланиям переживающих, и теперь вы можете маскировать или заменять секретные данные: + +```java + $("#password").setValue(withText("admin").sensitive()); + // заменяет на звёздочки + + $("#username").setValue(withText("john").withDisplayedText("J* username")); + // заменяет на "J* username" +``` + +См. [issue 1768](https://github.com/selenide/selenide/issues/1768) и [PR 1770](https://github.com/selenide/selenide/pull/1770). + +
    + +### Теперь можно легко выбрать дату в `` + +Оказалось, что выбрать дату в селениуме не так-то просто. +Если в вашем приложении есть элемент вида ``, то при клике в него разные браузеры +открывают разные календарики, и при этом используют разные форматы даты. По идее они должны использовать +формат из настроек пользователя, но на деле каждый браузер играет в свою игру. + +Всё это приводят к флейки тестам, которые могут работать на одном компьютере, но внезапно упасть на другом. + +В результате моего исследования я пришёл к выводу, что единственный надёжный способ выбрать дату - это установить +значение в фиксированном формате `yyyy-mm-dd` через JavaScript. Похоже, это работает одинаково во всех ОС и браузерах. + +И теперь Селенид предоставляет такую возможность с помощью нового метода `withDate`: + +```java + LocalDate birthday = LocalDate.parse("1979-12-31"); + $("#birthday").setValue(withDate(birthday)); +``` + +См. [issue 1753](https://github.com/selenide/selenide/issues/1753) и [PR 1770](https://github.com/selenide/selenide/pull/1770). + +
    + +### Теперь метод `$.setValue("")` поддерживает React, Vue.js и т.п. + +Давно замечено, что стандартный селениумовский метод `WebElement.clean()` (в частности, использующийся в селенидовском +`$.setValue()`) не всегда правильно работает, когда имеют дело не с обычным ``, а с обёрнутыми/обвязанными +модными конструкциями, генерируемыми всякими современными JS-фреймворками типа React, Vue.js и прочей хипстоты. + +По идее мы это починили, ждём ваших отзывов. + +Теперь следующие методы реализованы не через стандартный селениумовский `WebElement.clear()`, а через +нажатия комбинации клавиш: + +#### 1. Method `$.clear()`: +```java +input.sendKeys(HOME, chord(SHIFT, END), BACK_SPACE); +``` + +#### 2. Method `$.setValue("")`: +```java +input.sendKeys(HOME, chord(SHIFT, END), BACK_SPACE, TAB); +``` + +Такой способ, похоже, работает во всех ОС и браузерах. + +См. [issue 1497](https://github.com/selenide/selenide/issues/1497) и [PR 1787](https://github.com/selenide/selenide/pull/1787). + +Спасибо [Alexei Vinogradov](https://github.com/vinogradoff) за исследование проблемы в [PR 1499](https://github.com/selenide/selenide/pull/1499). + +
    + +### Убрали двойное событие `blur` и `change` +Из предыдущего изменения автоматически следует, что метод `$.setValue("blah")` вызывает события `blur` и `change` только единожды. + +А раньше метод `$.setValue("blah")` работал в два шага и вызывал их дважды: +* Шаг 1. `$.clear()` // вызывало `blur` и `change` +* Шаг 2. `$.sendKeys("blah")` // ещё раз вызывало `blur` и `change` + +И события на первом шаге иногда приводили к неожиданным эффектам - например, исчезанию самого поля. +См. [issue 960](https://github.com/selenide/selenide/issues/960). + +
    + +### Вызываем событие `blur` на предыдущем элементе +В предыдущем пулреквесте заодно сделали так, что метод `$.setValue("blah")` вызывает событие `blur` на предыдущем +активном элементе. Как минимум это помогло исправить некоторые наши флейки тесты. Надеемся, поможет и вам. + +См. [issue 1784](https://github.com/selenide/selenide/issues/1784) и [commit 593e6fc9005](https://github.com/selenide/selenide/commit/593e6fc900500d9). + +
    + +### Теперь методы `$.setValue()` и `$.append()` проверяют, что элемент не выключен + +Точнее, что элемент не находится в состоянии "disabled" или "readonly". + +См. [issue 1523](https://github.com/selenide/selenide/issues/1523) и [PR 1787](https://github.com/selenide/selenide/pull/1787). + +
    + +### Добавили новые проверки "interactable" и "editable" + +Эти проверки уже существовали и использовались раньше внутри Селенида, но не торчали наружу. +А теперь и вы сможете их использовать: + +```java +$("input[type=file]").shouldBe(interactable); + // interactable = visible OR "opacity: 0" + +$("input").shouldBe(editable); + // editable = interactable AND enabled AND !readonly +``` + +См. [issue 1523](https://github.com/selenide/selenide/issues/1523) и [PR 1787](https://github.com/selenide/selenide/pull/1787). + +
    + +### Метод `$.download(FOLDER)` дожидается полной загрузки файла + +Британские учёные обнаружили, что иногда флейки тесты вызваны тем, что файл скачивается довольно медленно, и селенид +успевает обнаружить и скопировать к себе файл, который уже появился в `C:\Downloads`, +но ещё не полностью загружен. + +Теперь селенид ждёт, пока в `C:\Downloads` исчезнут все файлы "*.crdownload" (для хрома) и "*.part" (для фаерфокса). +Это временный файл, создаваемый браузером на короткий период, пока скачивается файл. + +См. [issue 1779](https://github.com/selenide/selenide/issues/1779), +[PR 1804](https://github.com/selenide/selenide/pull/1804) и [PR 1769](https://github.com/selenide/selenide/pull/1769). + +
    + +### Добавили метод `stream()` для коллекций + +Точнее, метод `$$.stream()` существовал и раньше, но в версии [6.2.0](/2022/01/10/selenide-6.2.0/) был помечен как deprecated. +Теперь вместо него есть на выбор два не-deprecated метода: +* `$$.asFixedIterable().stream()` +* `$$.asDynamicIterable().stream()` + +См. [issue 1773](https://github.com/selenide/selenide/issues/1773) и [PR 1774](https://github.com/selenide/selenide/pull/1774). + +
    + +### Удалили встроенную селениумовскую телеметрию (OpenTelemetry) + +Я так понимаю, эта телеметрия появилась в Selenium 4. +Не знаю, зачем она вообще нужна, но кому-то мешала (потому, что у него уже была какая-то своя телеметрия). +Ну и нам было проще её удалить, чем поддерживать обе. + +Спасибо [Petro Ovcharenko](https://github.com/zzz) и [Aliaksandr Rasolka](https://github.com/zzz) +за [PR 1763](https://github.com/selenide/selenide/pull/1763). + +
    + +### Обновили зависимости + +* Selenium [4.1.3 -> 4.1.4](https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG). +* WebDriverManager [5.1.0 -> 5.1.1](https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md) +* Netty [4.1.75.Final -> 4.1.76.Final](https://netty.io/news/2022/04/12/4-1-76-Final.html) +* Netty [4.1.76.Final -> 4.1.77.Final](https://netty.io/news/2022/05/06/2-1-77-Final.html) +* LittleProxy [2.0.7 -> 2.0.9](https://github.com/LittleProxy/LittleProxy/releases) + +Кстати, проект LittleProxy переехал в отдельную [организацию на гитхабе](https://github.com/LittleProxy/LittleProxy), и +теперь я его главный мейнтейнер. Не то, чтобы я был фанатом проксей, но он используется в селениде, и +поддерживать его как-то надо... + +
    + +# UPD Selenide 6.5.1 +Небольшое обновление [Selenide 6.5.1](https://github.com/selenide/selenide/milestone/153?closed=1): +* [#1808](https://github.com/selenide/selenide/issues/1808) Починили `$.clear()`, чтобы он не жмякал таб - см. [PR #1809](https://github.com/selenide/selenide/pull/1809) +* [#1806](https://github.com/selenide/selenide/pull/1806) Обновились с browserup-proxy-core 2.1.4 на 2.1.5 + + +
    + +# UPD Selenide 6.5.2 +[#1497](https://github.com/selenide/selenide/issues/1497) Починили `$.clear()` на свежем фаерфоксе: теперь жмякаем "Ctrl+A -> Delete" вместо "Home -> Shift+A -> Delete". +См. [PR #1838](https://github.com/selenide/selenide/pull/1838). + +
    + +### Новости + +Отдельный привет всем, кто ждал, что же тут будет в конце пресс-релиза. ;) + +А будет моя презентация с последнего фестиваля TechTrain. + + + +
    + +Видео с TechTrain будет через несколько месяцев, а пока можете посмотреть похожее
    видео из девклуба. +Оно немного другое, ибо ориентировано на другую аудиторию, но общее представление получить можно. + +
    + +Не переключайтесь! + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2022-06-08-selenide-6.6.0.md b/content/ru/blog/2022-06-08-selenide-6.6.0.md new file mode 100644 index 000000000..fcf257e1e --- /dev/null +++ b/content/ru/blog/2022-06-08-selenide-6.6.0.md @@ -0,0 +1,167 @@ +--- +slug: "selenide-6.6.0" +date: 2022-06-08 +title: "Вышла Selenide 6.6.0" +description: "" +category: +headerText: "Дешорткатификация $.clear" +tags: [] +--- +
    + +# Здравствуйте, друзья! + +
    + +Мы выпустили релиз [Selenide 6.6.0](https://github.com/selenide/selenide/milestone/152?closed=1). + + +### Появился новый плагин `selenide-clear-with-shortcut` {#selenide-clear-with-shortcut} + +В Selenide 6.5.0 мы поменяли реализацию `$.clear()` со стандартной селениумовской на шорткат ("Выделить всё" - Удалить). +Оказалось, что этот шорткат не работал достаточно стабильно во всех браузерах, пришлось его доработать. Вроде +стабилизировался, но стал медленнее, чем просто `WebElement.clear()`. А поскольку это не всем нужно, решили в конце концов +в Селениде оставить старую добрую селениумовскую реализацию. + +А кому нужна очистка шорткатом - может подключить себе наш новый плагин: +```groovy + testImplementation('com.codeborne:selenide:6.6.0') + testImplementation('com.codeborne:selenide-clear-with-shortcut:6.6.0') +``` + +Зависимость `com.codeborne:selenide-clear-with-shortcut` переопределит метод `$.clear()` - а соответственно, и `$.setValue()`. + +См. [issue 1497](https://github.com/selenide/selenide/issues/1497), [PR 1847](https://github.com/selenide/selenide/pull/1847) и [PR 1838](https://github.com/selenide/selenide/pull/1838). + +
    + +### Исправили метод `$.clear()` в Safari {#fix-clear-in-safari} + +Внезапно выяснилось, что новый `$.clear()` не работал в Safari (кто его вообще использует?). +Вроде починили. Делитесь опытом, как у вас, починилось? + +См. [issue 1819](https://github.com/selenide/selenide/issues/1819), [PR 1820](https://github.com/selenide/selenide/pull/1820). + +
    + +### Новые проверки для текста элемента {#new-own-test-checks} + +Добавили две новых проверки для "своего текста" (own text) элемента: + +* `$("#child_div1").shouldHave(ownTextCaseSensitive("Son"));` +* `$("#child_div1").shouldHave(exactOwnTextCaseSensitive("Son"))` + +Спасибо [Kachurin Alexandr](https://github.com/kachurinaa) за +[PR 1811](https://github.com/selenide/selenide/pull/1811) и [PR 1812](https://github.com/selenide/selenide/pull/1812). + +
    + +### Добавили метод `$.click()` с таймаутом {#click-timeout} + +По умолчанию у метода `$.click()` стандартный селенидовский таймаут (который по умолчанию 4 секунды). +Иногда этого недостаточно - например, +1. Когда клик по ссылке ведёт на следующую страницу, которая грузится дольше 4 секунд. +2. Когда элемент, по которому нужно кликнуть, ещё не появился на экране - и появляется больше, чем через 4 секунды. + +В этом релизе мы добавили таймаут методу `$.click()`: + +```java + $("#slow-link").click(usingDefaultMethod().timeout(ofSeconds(8))); + $("#slow-link").click(usingJavaScript().timeout(ofSeconds(8))); +``` + +Правда, этот параметр решает пока только первую проблему, но не вторую. В следующем релизе займёмся и второй. :) + +См. [issue 1572](https://github.com/selenide/selenide/issues/1572) и [PR 1845](https://github.com/selenide/selenide/pull/1845). + +
    + +### Добавили таймаут методам `confirm()`, `dismiss()` и `prompt()` {#modal-timeout} + +Издревле эти три метода позволяют работать с модальными джаваскриптовскими окошками (`alert`, `confirm`, `prompt`). +Например, +```java +confirm(); +confirm("Are you sure you want to delete all files?"); +``` + +Но не было варианта с таймаутом - на тот случай, если алерт появляется не сразу, а больше, чем через 4 секунды. +Теперь можно задать таймаут: +```java +confirm(withTimeout(ofSeconds(2))); +confirm(withExpectedText("Are you sure?").timeout(ofSeconds(2))); +``` +См. [issue 1721](https://github.com/selenide/selenide/issues/1721) и [PR 1846](https://github.com/selenide/selenide/pull/1846). + +
    + +### Подправили метод `Driver.executeJavaScript()` {#fix-execute-javascript} + +...чтобы он работал и с "завёрнутым" вебдрайвером (т.е. когда на вебдрайвер навешаны листенеры). + +См. [PR 1848](https://github.com/selenide/selenide/pull/1848). + +
    + +### Подправили формулировку некоторых проверок {#fix-checks-wording} +... чтобы он звучали корректно по-английски. А именно: + +| В тесте | В отчёте было | В отчёте стало | +|-----------------------|---------------------------|-----------------------------| +| `$.should(appear)` | "Element should visible" | "Element should be visible" | +| `$.should(disappear)` | "Element should hidden" | "Element should be hidden" | + + +См. [PR 1840](https://github.com/selenide/selenide/pull/1840). + +
    + +### Добавили опции для Safari {#restore-safari-options} + +Выяснилось, что при открытии браузера Safari селенид терял почти все его настройки. Сломалось при переходе на Selenium 4. +Починить это оказалось легко, но почему никто до сих пор не жаловался? + +Похоже, Safari всё-таки никто не использует. :) + +См. [issue 1836](https://github.com/selenide/selenide/issues/1836) и [PR 1841](https://github.com/selenide/selenide/pull/1841). + +
    + +### Починили софт ассерты на TestNG {#fix-testng-soft-asserts} + +После обновления на TestNG 7.5 перестали правильно работать селенидовские софт ассерты. Если какая-то проверка падала, +тест по-прежнему оставался зелёным. + +Пришлось откатиться до TestNG 7.4.0 и ждать исправления на той стороне. + +См. [issue 1834](https://github.com/selenide/selenide/issues/1834) и [PR 1843](https://github.com/selenide/selenide/pull/1843). + +
    + + +### Обновили зависимости {#update-dependencies} + +* Selenium [4.1.4 -> 4.2.1](https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG). +* WebDriverManager [5.1.1 -> 5.2.0](https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md) + +
    + +### Статистика {#statistics} + +Давно мы не публиковали статистика скачиваний Селенида + +
    + +
    + +Мы почти вернулись к рекордному показателю: 324 тысяч скачек за май. + +
    + +Не переключайтесь! + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2022-06-12-selenide-6.6.3.md b/content/ru/blog/2022-06-12-selenide-6.6.3.md new file mode 100644 index 000000000..386c93045 --- /dev/null +++ b/content/ru/blog/2022-06-12-selenide-6.6.3.md @@ -0,0 +1,54 @@ +--- +slug: "selenide-6.6.3" +date: 2022-06-12 +title: "Вышла Selenide 6.6.3" +description: "" +category: +headerText: "Зарелизил и точка!" +tags: [] +--- +
    + +# Здравствуйте, друзья! + +
    + +Мы выпустили мини-релиз [Selenide 6.6.3](https://github.com/selenide/selenide/milestone/157?closed=1). + + +### Доработали таймаут для клика {#improve-click-timeout} + +В версии 6.6.0 мы добавили опциональный параметр - таймаут для метода `$.click()`. +Но оказалось, что тот параметр решал [лишь половину проблемы](/2022/06/08/selenide-6.6.0/#click-timeout). + +Теперь мы исправили и вторую половину: вызов +```java +$("#slow-link").click(usingDefaultMethod().timeout(ofSeconds(8))); +``` + +ждёт до 8 секунд как появления элемента `#slow-link`, так и последующей загрузки страницы. + +См. [issue 1572](https://github.com/selenide/selenide/issues/1572) и [PR 1853](https://github.com/selenide/selenide/pull/1853). + +
    + +### Selenide 6.6.2 {#selenide-6.6.2} + +А чуть раньше мы выпустили мини-релиз [Selenide 6.6.2](https://github.com/selenide/selenide/milestone/156?closed=1) с обновлением на Selenium 4.2.2 + +См. [PR 1851](https://github.com/selenide/selenide/pull/1851). + +
    + +### Selenide 6.6.1 {#selenide-6.6.1} + +А чуть раньше мы выпустили мини-релиз [Selenide 6.6.1](https://github.com/selenide/selenide/milestone/155?closed=1) +с исправлением старой [issue 1850](https://github.com/selenide/selenide/issues/1850). +Там мы вернули зависимость `byte-buddy`, без которой не работало добавление листенеров для вебдрайвера. + +
    + + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2022-06-20-selenide-6.6.4.md b/content/ru/blog/2022-06-20-selenide-6.6.4.md new file mode 100644 index 000000000..2e24dc5d3 --- /dev/null +++ b/content/ru/blog/2022-06-20-selenide-6.6.4.md @@ -0,0 +1,81 @@ +--- +slug: "selenide-6.6.4" +date: 2022-06-20 +title: "Вышла Selenide 6.6.4" +description: "" +category: +headerText: "Квазирелиз" +tags: [] +--- +
    + +# Приветос! + +
    + +У нас вышел ещё один мини-релиз [Selenide 6.6.4](https://github.com/selenide/selenide/milestone/158?closed=1). + + +### Добавили условие `exactTextsCaseSensitive` для коллекций {#exact-texts-case-sensitive} + +В селениде есть несколько проверок для текстов коллекций: +```java +$$("li").shouldHave(texts("foo", "bar", "baz")); +$$("li").shouldHave(textsInAnyOrder("foo", "bar", "baz")); +$$("li").shouldHave(exactTexts("foo", "bar", "baz")); +// и др. +``` + +Теперь к ним добавилась ещё одна: +```java +$$("li").shouldHave(exactTextsCaseSensitive("foo", "bar", "baz")); +``` + +Спасибо [Ben Heap](https://github.com/ben-nc2) за [PR 1861](https://github.com/selenide/selenide/pull/1861). + +
    + +### Сделали метод `$.getSelectedOption()` ленивым {#selected-option-lazy-loaded} + +По задумке, (почти) все методы Селенида [должны быть ленивыми](https://github.com/selenide/selenide/wiki/Lazy-loading). + +Например, просто вызов `$("#nope")` не должен падать, если элемента нет. Это позволяет писать отрицательные условия: +```java +$("#nope").shouldNot(exist); +``` + +Оказалось, что метод `$("select").getSelectedOption()` не был ленивым и падал сразу, если селект ещё не успел подгрузиться и т.д. +То есть вы в принципе не могли написать такую проверку: +```java + var option = $("select#gender").getSelectedOption(); // падало на этом шаге + option.shouldNot(exist); +``` + +Теперь мы исправили это недоразумение. _Лень победила!_ +См. [issue 1581](https://github.com/selenide/selenide/issues/1581) и [PR 1864](https://github.com/selenide/selenide/pull/1864). + +
    + +### Обновили зависимости {#update-dependencies} + +* Netty [с 4.1.77.Final на 4.1.78.Final](https://github.com/selenide/selenide/pull/1857). +* BrowserUp proxy [с 2.1.5 на 2.2.0](https://github.com/selenide/selenide/pull/1860). + +
    + +### UPD Выпустили Selenide 6.6.5 {#release-selenide-6.6.5} + +И ещё мини-релиз [Selenide 6.6.5](https://github.com/selenide/selenide/milestone/159?closed=1). + +Обновили Selenium с 4.2.2 на 4.3.0. + +
    +
    + +_Это наш откровенный респонс на ваш откровенный реквест._ + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2022-07-01-selenide-6.6.6.md b/content/ru/blog/2022-07-01-selenide-6.6.6.md new file mode 100644 index 000000000..531668016 --- /dev/null +++ b/content/ru/blog/2022-07-01-selenide-6.6.6.md @@ -0,0 +1,101 @@ +--- +slug: "selenide-6.6.6" +date: 2022-07-01 +title: "Вышла Selenide 6.6.6" +description: "" +category: +headerText: "Шаг злой воли" +tags: [] +--- +
    + +# Добър вечер! + +
    + +У нас вышел ещё один мини-релиз [Selenide 6.6.6](https://github.com/selenide/selenide/milestone/160?closed=1) + +### Удалили старые капабилити {#remove-deprecated-capabilities} + +Некоторые настройки вебдрайвера (которые селенид проставлял с испокон веков) были помечены как устаревшие, а с недавних +пор селениум начал ругаться на нах в логах. + +Теперь селенид их больше не проставляет: `acceptSslCerts`, `handlesAlerts`, `javascriptEnabled`, `takesScreenshot`. +Мы не забудем вас, друзья! Вы служили нам верой и правдой больше 10 лет. + +См. [issue 1862](https://github.com/selenide/selenide/issues/1862), [issue 1866](https://github.com/selenide/selenide/issues/1866) +и [PR 1870](https://github.com/selenide/selenide/pull/1870). + +
    + +### Исправили ClearWithShortcut {#fix-clear-with-shortcut} + +... при работе с вебдрайвером, завёрнутым в листенеры. Редкая ситуация, не заморачивайтесь. + +Спасибо [Petro Ovcharenko](https://github.com/petroOv-PDFfiller) за [PR 1856](https://github.com/selenide/selenide/pull/1856). + +
    + +### Добавили короткие варианты для вызова `$.click` {#shorter-syntax-for-click} + +Раньше, чтобы кликнуть со сдвигом или с кастомным таймаутом, приходилось писать довольно длинную строку: +```java +$.click(withDefaultMethod().offset(123, 222)); +$.click(withDefaultMethod().timeout(...)); +``` + +Теперь же можно написать короче: +```java +$.click(withOffset(123, 222)); +$.click(withTimeout(...)); +``` + +См. [PR 1875](https://github.com/selenide/selenide/pull/1875). + +
    + +### Добавили поддержку мобилок при проверке, жив ли вебдрайвер {#support-mobile-apps-in-webdriver-health-checker} + +Мелкое исправление для `selenide-appium`. +Чтобы проверить, а жив ли браузер, селенид периодически дёргает метод `WebDriver.getTitle()` (если вы переиспользуете +один вебдрайвер между разными тестами). + +А тут обнаружилось, что метод `getTitle()` не поддерживается в Appium. Пришлось учесть. + +См. [issue 1878](https://github.com/selenide/selenide/issues/1878) и [PR 1879](https://github.com/selenide/selenide/pull/1879). + +
    + +### Исправили логику настройки `reopenBrowserOnFail` {#fix-reopen-browser-on-fail} + +Ещё одно исправление для улучшения поддержки мобилок. + +См. [issue 1880](https://github.com/selenide/selenide/issues/1880) и [PR 1881](https://github.com/selenide/selenide/pull/1881). + +
    + + +### Обновили зависимости {#update-dependencies} + +* WebDriverManager [с 5.2.0 на 5.2.1](https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md). +* byteBuddyVersion [с 1.12.11 на 1.12.12](https://github.com/selenide/selenide/pull/1872). + +
    + +### Выпустили selenide-appium 2.1.0 {#release-selenide-appium-2.1.0} + +Немного улучшили там поддержку тестов на iOS. + +См. [selenide-appium](https://github.com/selenide/selenide-appium/blob/master/CHANGELOG). + +
    + +_Этим релизом мы решили продемонстрировать мировому сообществу, что не препятствуем созданию автоматических тестов для мобильных приложений._ + +_Теперь слово за автоматизаторами._ + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2022-08-04-selenide-6.7.0.md b/content/ru/blog/2022-08-04-selenide-6.7.0.md new file mode 100644 index 000000000..abd611db3 --- /dev/null +++ b/content/ru/blog/2022-08-04-selenide-6.7.0.md @@ -0,0 +1,187 @@ +--- +slug: "selenide-6.7.0" +date: 2022-08-04 +title: "Вышла Selenide 6.7.0" +description: "" +category: +headerText: "Полные тексты, полные скриншоты" +tags: [] +--- +
    + +# Привет! + +
    + +У нас случился толстенький релиз [Selenide 6.7.0](https://github.com/selenide/selenide/milestone/154?closed=1) + +### Теперь `$.shouldHave(text)` может проверять текст целиком {#holy-whole-string} + +Испокон веков команда `$.shouldHave(text)` проверяла не текст целиком, а только подстроку: + +```html +
    Britney Spears
    +``` + +```java + $("#freedom-to").shouldHave(text("Brit")); // was OK +``` + +Когда-то это показалось удачной идеей, потому что веб-страничка часто содержит всякие левые символы +(переводы строк, символы табуляции, непереносимые пробелы, множественные пробелы и т.п.). + +Но похоже, это всё-таки была неудачная идея, т.к. новички по умолчанию предполагают, что текст проверяется целиком, и +выхватывают свою порцию WTF, когда обнаруживают, что все их проверки проверяли немного не то. :) + +А левые символы селенид научился правильно игнорировать (например, несколько пробелов/табов/переводов подряд эквивалентны одному пробелу). + +NB! Поскольку это изменение слишком уж кардинальное и наверняка сломает кучу ваших тестов, мы пока оставили по умолчанию +старое поведение. А новое можно включить такой настройкой: +```java + Configuration.textCheck = FULL_TEXT; +``` + +А когда вам нужно проверить именно подстроку, можете использовать новую проверку `partialText`: +```java + $("#freedom-to").shouldHave(partialText("ey Spear")) +``` +Возможно, мы включим этот режим по умолчанию в следующей мажорной версии Selenide 7.0.0 - а до тех пор +**вы можете поиграться и дать нам обратную связь**. + +См. [issue 1780](https://github.com/selenide/selenide/issues/1780) и [PR 1783](https://github.com/selenide/selenide/pull/1783). + +
    + +### Научили Селенид делать большие скриншоты {#full-size-screenshots} + +Ну наконец-то! + +Как вы знаете, при падении теста селенид автоматически делает снимок экрана (скриншот), чтобы помочь вам понять, почему тест упал. +По умолчанию вебдрайвер умеет снимать не всё окно браузера, а только видимую его часть. А самое важно часто оказывается +за пределами экрана - тест валит какая-нибудь неактивная кнопка внизу экрана или всплывшее уведомление где-нибудь в углу. + +Теперь вы можете одной строчкой подключить плагин, который снимает скриншот с полным содержимым веб-странички: + +```groovy +testImplementation "com.codeborne:selenide-full-screenshot:6.7.0" +``` + +P.S. Фича работает только для браузеров, поддерживающих CDP (Chrome, Edge и т.д.) и Firefox. +Для остальных будут по-прежнему обычные скриншоты. + +См. [issue 1799](https://github.com/selenide/selenide/issues/1799) и [PR 1858](https://github.com/selenide/selenide/pull/1858). +Спасибо [Aliaksandr Rasolka](https://github.com/rosolko) за [PR 1800](https://github.com/selenide/selenide/pull/1800). + +
    + +### Добавили кэширование элементов в пэдж обжектах {#cache-lookup-annotation} + +Как вы знаете, селенид поддерживает обычные селениумовские пэдж-обжекты с аннотациями `@FindBy`. +Но вот аннотацию `@CacheLookup` селенид до сих пор не поддерживал - нам это казалось ненужной оптимизацией, ведь в +тестах большая часть времени теряется вовсе не на поиск элементов. + +Но теперь вот поддерживаем, почему бы нет. Вдруг у кого-то всё настолько оптимизировано, что именно поиск элементов +стал узким горлышком. Хотел бы я посмотреть на такой проект. :) + +Спасибо [Ilya Koshaleu](https://github.com/groov1kk) за [PR 1894](https://github.com/selenide/selenide/pull/1894). + +P.S. Встаёт вопрос, а не надо ли добавить кэширование и для обычных `$` и `$$`. А как это оформить - параметром, настройкой? Новым методом? + +**Предлагайте ваши идеи!** + +
    + +### Отменили аннотацию `@Report` {#cancel-report-testng-annotation} + +Вот культура отмены добралась и до аннотаций! + +Это изменение касается любителей TestNG, которые использовали селенидовский отчёт. Для этого им надо было повесить на +тесты две аннотации: + +```java + @Listeners({TextReport.class}) + @Report + class MyTest {...} +``` + +Почему так сделали - это долгая история про корявые принципы работы листенеров в TestNG +(вкратце: добавление аннотации листенера одному классу внезапно влияет на все остальные классы). +Но теперь мы поняли, что систему можно упростить: аннотация `@Report` больше не нужна. + +А отчёт будет генерироваться для всех тестов, помеченных аннотацией `@Listeners({TextReport.class}` **и их потомков**. + +См. [issue 1891](https://github.com/selenide/selenide/issues/1891) и [PR 1909](https://github.com/selenide/selenide/pull/1909). + +
    + +### Декодируем имя скачанного файла {#decode-downloaded-file-name} + +Оказалось, что при скачивании файла имя файла в ответе сервера иногда бывает закодировано в Base64. +А селенид считывал имя файла как есть. Теперь вот умеет расшифровывать и Base64. + +См. [issue 1886](https://github.com/selenide/selenide/issues/1886) и [PR 1889](https://github.com/selenide/selenide/pull/1889). + +
    + +### Починили `$.setValue()` в IE {#restore-ie-support-set-value} + +Оказалось, мы недавно сломали метод `$.setValue()` в Internet Explorer. +Не то чтобы случайно: IE ведь официально отдал концы. Но жалобы были, и мы его вернули. + +См. [PR 1907](https://github.com/selenide/selenide/pull/1907). + +
    + +### Сделали публичным `HttpClientTimeouts` {#made-http-client-timeouts-public} + +Но лишний раз туда лучше не лазать. + +См. [PR 1902](https://github.com/selenide/selenide/pull/1902). + +
    + +### Вернули тип параметра `String` для `$.setValue()` {#restore-set-value-string} + +Лично у меня подгорает от того, что такая проблема вообще возникла. + +Подробности в [issue 1885](https://github.com/selenide/selenide/issues/1885) и [PR 1888](https://github.com/selenide/selenide/pull/1888). + +
    + +### Добавили валидацию расширения файла {#validate-file-extension} + +См. [PR 1887](https://github.com/selenide/selenide/pull/1887). + +
    + +### Обновили зависимости {#update-dependencies} + +* JUnit [from 5.8.2 to 5.9.0](https://github.com/selenide/selenide/pull/1900) +* WebDriverManager [from 5.2.1 to 5.2.3](https://github.com/selenide/selenide/pull/1901) +* Netty [from 4.1.78.Final to 4.1.79.Final](https://github.com/selenide/selenide/pull/1892) +* BrowserUpProxy [from 2.2.0 to 2.2.1](https://github.com/selenide/selenide/pull/1895) +* LittleProxy [from 2.0.9 to 2.0.10](https://github.com/selenide/selenide/pull/1896) +* ByteBuddy [from 1.12.12 to 1.12.13](https://github.com/selenide/selenide/pull/1904) + +
    + +### UPD Selenide 6.7.1 {#selenide-6.7.1} + +* вернули параметр `Driver` в метод `SelenidePageFactory.findSelector()` - он используется в `selenide-appium`. + +
    + +### Новости {#news} + +* [Opinionated reporting framework for Selenide](https://github.com/iSYS-Software/SelenideReporter) от Ulrich Mayring +* Новая версия [Пацан накодил - пацан протестил](https://www.youtube.com/watch?v=C8MIGAjgVqE&ab_channel=KVHigh-TechClub) - Career Day, Минск, 04.06.2022 +* [Extending open-source libraries: Selenide & Selenium](https://www.youtube.com/watch?v=-KGtZoFVzr8&list=PL9Z-JgiTsOYRfoG_mcRBlTUIFPIknhQ6S) - Selenium Conf, 30.07.2022 +* [Автоматизація з Selenide, ввідне заняття](https://www.youtube.com/watch?v=SqiYAJfpQwY&list=PLULFH3b6unlcUrwT9hJycTvAWPFqXZO4m&ab_channel=QAClubLviv) by Роман Маринский +* [Flaky Tests](https://www.youtube.com/watch?v=-c5XT2v5gRY&ab_channel=DEVCLUB.EE) - devclub.ee, Tallinn, 05.07.2022 +* Оффтопик: моё выступление на типа открытом микрофоне [про поездки на конференции в Киев](https://youtu.be/AOBEqZ0T51c) - "Твой выход", 23.07.2022, Таллинн + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2022-08-14-selenide-6.7.2.md b/content/ru/blog/2022-08-14-selenide-6.7.2.md new file mode 100644 index 000000000..ad0044b59 --- /dev/null +++ b/content/ru/blog/2022-08-14-selenide-6.7.2.md @@ -0,0 +1,98 @@ +--- +slug: "selenide-6.7.2" +date: 2022-08-14 +title: "Вышла Selenide 6.7.2" +description: "" +category: +headerText: "Памятное головотяпство" +tags: [] +--- +
    + +# Привет! + +
    + +Мы выпустили мини-релиз [Selenide 6.7.2](https://github.com/selenide/selenide/milestone/162?closed=1) с исправлением +утечек памяти. + +Да-да, мы серьёзные ребята, у нас тоже бывают утечки. + +Но не пугайтесь, они некритические. Вряд ли кто-то из вас их вообще замечал. + +### Исправили утечки с shutdown hooks в Selenide {#fix-selenide-memory-leak} + +Если в тесте много-много раз открывать и закрывать вебдрайвер +```java +for (int i = 0; i < 1000; i++) { + open("about:blank"); + closeWebDriver(); +} +``` + +то расход памяти потихоньку растёт: + +Memory consumption: before + +_Красная линия, ты где?_ + +А вот что случилось на самом деле. + +Это просто сдетонировало несколько shutdown хуков, которые селенид складировал для каждого открытого вебдрайвера. + +См. [issue 1917](https://github.com/selenide/selenide/issues/1917) +и [PR 1919](https://github.com/selenide/selenide/pull/1919). + +После обновления на версию 6.7.2 память больше не растёт: + +Memory consumption: after + +_Обновляемся на Selenide 6.7.2, выдыхаем и идём на пляж._ + +
    + +### Исправили утечку в LittleProxy {#fix-little-proxy-memory-leak} + +Мы обновились на версию LittleProxy 2.0.11, в которой была исправлена ещё одна утечка памяти. + +См. [PR 1918](https://github.com/selenide/selenide/pull/1918) +и [PR 141](https://github.com/LittleProxy/LittleProxy/pull/141) + +
    + +### Обновились на Selenium 4.4.0 {#upgrade-to-selenium-4.4.0} + +в котором даже есть одно лично моё исправление, так-то! Которое, кстати, помогло нам исправить и следующую проблему. + +См. [PR 1913](https://github.com/selenide/selenide/pull/1913) +и [Selenium changelog](https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG) + +
    + +### Исправили плагин `full-size-screenshot` {#fix-full-size-screenshot} + +В нашем новом плагине `full-size-screenshot` была одна известная проблема (на самом деле вызванная багой в селениуме): +если вы запускаете браузер удалённо и открываете несколько вкладок или окон, то селенид мог взять скриншот не с того окна. + +Эта ошибка была исправлена в Selenium 4.4.0, и соответственно, у нас она теперь тоже исправится. + +См. [PR 1920](https://github.com/selenide/selenide/pull/1920) и [PR 10811](https://github.com/SeleniumHQ/selenium/pull/10811). + +
    + + +### Ссылки {#news} + +* Статья [Working Efficiently with Selenide](https://blogs.perficient.com/2022/06/22/working-efficiently-with-selenide-the-subset-of-selenium-webdriver/) by Zainab Firdos, 22.06.2022 +* Серия руководств [Selenide Tutorial Series](https://dev.to/automationbro/selenide-tutorial-series-58p5) by Dilpreet Johal, 13.06.2022 +* Видео-руководство [Selenide Java Tutorial Series](https://www.youtube.com/watch?v=0vlV8_4EDAg&t=318s&ab_channel=AutomationBro-DilpreetJohal) by Automation Bro, 13.06.2022 +* Статья [How to Start Your Friendship with Selenide](https://hackernoon.com/how-to-start-your-friendship-with-selenide) by Miki Szeles, 30.03.2022 +* Оффтопик: моё выступление на типа открытом микрофоне [про поездки на конференции в Киев](https://youtu.be/AOBEqZ0T51c) - "Твой выход", 23.07.2022, Таллинн + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2022-08-22-selenide-puzzler.md b/content/ru/blog/2022-08-22-selenide-puzzler.md new file mode 100644 index 000000000..5ff4d203a --- /dev/null +++ b/content/ru/blog/2022-08-22-selenide-puzzler.md @@ -0,0 +1,94 @@ +--- +slug: "selenide-puzzler" +date: 2022-08-22 +title: "Selenide puzzler" +description: "" +category: +headerText: "Логическое И или ИЛИ?" +tags: [] +--- +
    + +# Привет! + +Вы любите пазлеры? +Соскучались по пазлерам? +В последний раз мы показывали пазлеры аж в 2017 году, кто не смотрел - [смотрим](https://www.youtube.com/watch?v=y-ZyxTWHH08&ab_channel=Heisenbug)! + +И вот наконец мы [опубликовали в твиттере](https://twitter.com/selenide/status/1560192824536088580) новый пазлер: + +> Одинаково ли работают эти строки? Или есть какая-то разница? + +```java +1. $(".btn").shouldBe(visible, enabled); +2. $(".btn").shouldBe(visible).shouldBe(enabled); +``` + +### Варианты ответов + +Люди в твиттере и чатиках накидали разных вариантов: +* обе строчки работают одинаково (самый популярный ответ) +* первый случай: логическое or, второй: логический and +* Второй работает на %ожидание по умолчанию% дольше. +* Первый должен отработать с одним тайм-аутом, второй должен с двумя тайм-аутами +* в первом случае упадёт, если отсутствует любое из условий, во втором - если не visible, но enabled. + +### Правильный ответ + +В большинстве случаев оба варианта работают одинаково. + +Оба варианта - это логическое AND. В обоих вариантах селенид проверит, что элемент соответствует обоим условиям. + +| | **enabled** | **disabled** | +|---|-------------|--------------|---| +| **видимый** | ok | nok | +| **невидимый** | nok | nok | + +
    + +Но есть нюанс. + +### Нюанс + +Разница проявится в том случае, если элемент соответствует условиям не сразу, а через какое-то время. +Причём первому условию меньше, чем за 4 секунды, а второму - больше. +(Допустим, visible он становится через 3.5 секунды, а enabled - ещё через 3.5 секунды). + +> Всё дело в том, что таймаут (по умолчанию 4 секунды) есть у метода `shouldHave`, а у проверок +(`visible`, `enabled`, `cssClass`, `text`) никакого таймаута нет - они просто умеют проверить, да или нет. + +### Пример + +Откроем для примера [Светофор](https://selenide.org/traffic-light.html). +Светофор становится зелёным через 3.5 секунды, а текст на нём появляется ещё через 3.5 секунды. + +Первый вариант проверяет, что светофор удовлетворит обоим условиям в течение 4 секунд: + +```java + $("#light").shouldHave(cssClass("green"), text("GO!")); // таймаут 4 секунды +``` + +И эта проверка упадёт, т.к. таймаут на эту проверку - 4 секунды, но элемент не приобретёт и цвет, и текст в течение 4 секунд. + +А второй вариант не упадёт: +```java +$("#light") + .shouldHave(cssClass("green")) // таймаут 4 секунды + .shouldHave(text("GO!")); // и плюс ещё 4 секунды +``` + +Первая проверка дождётся, пока элемент станет зелёным (и он станет в течение 4 секунд). +После этого запустится вторая проверка и запустит новый таймаут с целью дождаться, пока у элемента появится текст. +И он дождётся. + +Видимо, наиболее близкий к правильному был ответ "Первый должен отработать с одним тайм-аутом, второй должен с двумя тайм-аутами". + +### Ваши пазлеры + +Есть ли у вас свои пазлеры? +Присылайте их нам, давайте будем отгадывать вместе! + + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2022-08-27-selenide-6.7.3.md b/content/ru/blog/2022-08-27-selenide-6.7.3.md new file mode 100644 index 000000000..32ddf9e79 --- /dev/null +++ b/content/ru/blog/2022-08-27-selenide-6.7.3.md @@ -0,0 +1,92 @@ +--- +slug: "selenide-6.7.3" +date: 2022-08-27 +title: "Вышла Selenide 6.7.3" +description: "" +category: +headerText: "Душевно, по-домашнему" +tags: [] +--- +
    + +# Привет! + +
    + +Вы читаете пресс-релиз [Selenide 6.7.3](https://github.com/selenide/selenide/milestone/163?closed=1) в пиратском переводе. + +А что делать, _все хотят кушать_... + +
    + +### Добавили условие `partialValue` {#condition-partial-value} + +По аналогии с `$.shouldHave(partialText("Добрый ко"))` теперь появилась и `$.shouldHave(partialValue("cola"))`. + +Это если вы установили настройку `Configuration.textCheck = FULL_TEXT`, но хотите проверить значение какого-то инпута +или textarea частично, а не полностью. + +См. [issue 1923](https://github.com/selenide/selenide/issues/1923) и [PR 1924](https://github.com/selenide/selenide/pull/1924). + +
    + +### Добавили условие `tagName` {#condition-tag-name} + +Наверное, оно нечасто нужно, т.к. мы часто ищем элемент по тэгу, и уж потом проверяем другие атрибуты. +Да и вообще, тэг - это внутренности, которые пользователь не видит, поэтому, может, и проверять его не нужно. + +Тем не менее, теперь вы можете проверять тэг: + +`$(".btn-primary").shouldHave(tagName("button"));` + +Или фильтровать коллекцию по тэгу: + +`$$(byText("Submit!")).filterBy(tagName("button"));` + +См. [issue 1928](https://github.com/selenide/selenide/issues/1928) и [PR 1929](https://github.com/selenide/selenide/pull/1929). + +
    + +### Проверяем, что элемент - `` через JavaScript {#select-options-using-javascript} + +Это должно сделать работу с селектами быстрее. И теперь селенид выкидывает более подробную ошибку, если ` + + + + +``` + +Попытка выбрать `disabled` опцию: +```java +$("#region").selectOption("Kherson"); +``` + +выдаст понятную ошибку с подробным объяснением: +```java +Invalid element state [#region/option[text:Kherson]]: Cannot select a disabled option +``` + +Раньше эта ошибка была не такой подробной: +```java +java.lang.UnsupportedOperationException: You may not select a disabled option +``` + +(а ещё раньше такой тест вообще не падал, но и опцию не выбирал) + +См. [issue 1553](https://github.com/selenide/selenide/issues/1553) и [PR 1876](https://github.com/selenide/selenide/pull/1876). + +> Отдельное спасибо [Oleg Berezhnoy](https://github.com/bereg2k) за [PR 1553](https://github.com/selenide/selenide/pull/1553), +> который хоть и не попал в селенид, но инициировал целую дискуссию и в селениде, и в самом селениуме, в т.ч. о том, за +> что должен или не должен отвечать селениум, и что такое "просто фреймворк" и "опионейтед фреймворк". + +
    + +### Сделали `$.click(options)` "чейнебл" {#make-click-chainable} + +Люди часто жалуются, что метод `$.click()` имеет тип `void`, то есть его нельзя чейнить: +```java + $(".btn").click().should(disappear); +``` + +Увы, это мы исправить не можем, т.к. класс `SelenideElement` наследует метод `void click()` из селениумовского `WebElement`. + +Но мы сделали "чейнебл" другой `click` метод, который с параметрами (т.н. "оверлоадед"). +Теперь хотя бы его можно "чейнить": +```java + $(".btn") + .click(usingDefaultMethod()) + .should(disappear); + + $(".btn") + .click(usingDefaultMethod().withOffset(42, 42)) + .shouldHave(cssClass("alert")); +``` + +См. [issue 2007](https://github.com/selenide/selenide/issues/2007) и [PR 2008](https://github.com/selenide/selenide/pull/2008). + +
    + +### Исправили размер окна для новых вкладок {#fix-size-for-new-tabs} + +Спасибо [Boris Osipov](https://github.com/BorisOsipov) за [PR 2017](https://github.com/selenide/selenide/pull/2017). + +P.S. Исправили ещё раз в [Selenide 6.10.1](https://github.com/selenide/selenide/milestone/170?closed=1) + +
    + +### Поддерживаем логин/пароль BasicAuth со спецсимволами {#encode-basic-auth-credentials-in-url} + +Selenide умеет открывать сайты, защищённые паролем (т.н. BasicAuth): +```java +open("/basic-auth/hello", BASIC, + new BasicAuthCredentials("", "Královec", "is Czechia /:)")); +``` + +Эти логин-пароль добавляются либо в http заголовок `Authorization` (если прокси включён), либо в URL (если прокси выключен). + +Недавно я обнаружил, что второй способ работает некорректно, если логин или пароль содержат спецсимволы. +При добавлении в URL эти символы не экранировались, и получался невалидный URL: +``` +https://Královec:is Czechia /:)@127.0.0.1:4405/basic-auth/hello +``` +и браузер не мог открыть страницу. + +> Мне по-настоящему неловко, что я как-то не увидел этой страницы. Надеюсь, вы меня простите. + +В общем, теперь такие хитрые пароли тоже должны работать. +Селенид экранирует все спецсимволы и генерирует корректный URL: +``` +https://Kr%C3%A1lovec:is+Czechia+%2F%3A%29@127.0.0.1:27663/basic-auth/hello +``` +См. [issue 2020](https://github.com/selenide/selenide/issues/2020) и [PR 2021](https://github.com/selenide/selenide/pull/2021). + +
    + + +### Обновили зависимости {#update-dependencies} + +* Selenium from 4.5.0 to 4.6.0, см. [ченджлог](https://www.selenium.dev/blog/2022/selenium-4-6-0-released/) +* WebDriverManager from 5.3.0 to 5.3.1, см. [ченджлог](https://github.com/bonigarcia/webdrivermanager/blob/master/CHANGELOG.md#531---2022-11-04) +* BrowserUpProxy from 2.2.3 to 2.2.5, см. [ченджлог](https://github.com/valfirst/browserup-proxy/blob/master/CHANGELOG.md) +* Netty from 4.1.82.Final to 4.1.85.Final +* LittleProxy from 2.0.13 to 2.0.14, см. [ченджлог](https://github.com/LittleProxy/LittleProxy/milestone/19?closed=1) +* #2014 Bump httpclient5 from 5.1.3 to 5.2, см. [PR 2014](https://github.com/selenide/selenide/pull/2014) +* #2025 bump slf4j from 2.0.3 to 2.0.4, см. [PR 2025](https://github.com/selenide/selenide/pull/2025) + +
    + +### Дочерние проекты + +Также зарелизили наши дочерние проекты: +* [selenide-appium 2.3.0](https://github.com/selenide/selenide-appium/releases/tag/v2.3.0) +* [selenide-selenoid 2.3.2](https://github.com/selenide/selenide-selenoid/releases/tag/v2.3.2) + +
    + +### Новости {#news} + +* JetBrains выпустила AQUA - новую [IDE для автотестов](https://www.jetbrains.com/aqua/)! Клёвое лого! +* В Selenium появился свой встроенный [аналог WebDriverManager](https://www.selenium.dev/blog/2022/introducing-selenium-manager/). Кто-то уже попробовал? +* Новый фреймворк [Selenide Pages](https://gitlab.com/brewcode/selenide-pages) на базе Selenide от Maxim Kochetkov. Клёвое лого! + +### Мои свежие видосы {#my-videos} + +Появилось видео моих осенних докладов из таллиннского девклуба: +* [Как законтрибьютить в опенсорс, чтобы не сгореть со стыда](https://www.youtube.com/watch?v=VtX7IpCHMS8&ab_channel=DEVCLUB.EU) +* [WTF Thread Pools](https://www.youtube.com/watch?v=JKxzELiwO_o&ab_channel=DEVCLUB.EU) - как накосячить с потоками в Java (с зубодробительными примерами из Selenium) + +### Видосы и читосы {#videos} + +* Видос [Чтение логов из браузера через Selenide](https://www.youtube.com/watch?v=_X0rL1eUMK0&ab_channel=OlehPendrak) от Oleh Pendrak +* Пост [All About Selenide](https://www.linkedin.com/pulse/all-selenide-muhammad-naeem/) от Muhammad Naeem +* Видос [Working with web elements using Selenide](https://morioh.com/p/018678871de9) от Automation Bro +* Пост [Page Object Model](https://dev.to/automationbro/page-object-model-selenide-tutorial-series-g3g) из серии "Selenide Tutorial Series" от Automation Bro +* Пост [Как кастомизировать UI артефакты для Selenide + Selenoid + Allure (with TestOPS)](https://habr.com/ru/company/innotech/blog/696140/) на Хабре + +
    + +### Статистика {#statistics} + +* Наша [группа в LinkedIn](https://www.linkedin.com/groups/9154550/) насчитывает уже 176 участников. Присоединяйтесь! +* Подъехала свежая статистика скачиваний Селенида. Перевалили за 470 тыщ! + +
    + +
    + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2022-12-08-selenide-6.10.2.md b/content/ru/blog/2022-12-08-selenide-6.10.2.md new file mode 100644 index 000000000..5097cf441 --- /dev/null +++ b/content/ru/blog/2022-12-08-selenide-6.10.2.md @@ -0,0 +1,120 @@ +--- +slug: "selenide-6.10.2" +date: 2022-12-08 +title: "Вышла Selenide 6.10.2" +description: "" +category: +headerText: "Ну ивенты и ивенты, чего бухтеть-то" +tags: [] +--- +
    + +# Всем привет! + +У нас вышел новый мини-релиз [Selenide 6.10.2](https://github.com/selenide/selenide/milestone/171?closed=1). + + + + +### Добавили метод `$.press()` {#added-method-press} + +По сути это то же самое, что `sendKeys()`, только он не `void`. То есть его можно _чейнить_ с другими методами: +```java +$("#username") + .press("x") + .press(TAB, CONTROL, ALT, ENTER) + .should(disappear); +``` + +Спасибо [Amuthan Sakthivel](https://github.com/amuthansakthivel) за [PR 2032](https://github.com/selenide/selenide/pull/2032). + +
    + +### Генерируем события `change` в методах `$.select*` {#trigger-change-events-by-select-methods} + +Как вы помните, в предыдущем релизе мы [переделали работу с селектами на JavaScript](/2022/11/21/selenide-6.10.0/#select-options-using-javascript). +Но при этом забыли, что надо ещё и генерировать события `focus`, `click`, `change`. Теперь генерируем. + +См. [issue 2050](https://github.com/selenide/selenide/issues/2050). +Спасибо [Vicente Rossello Jaume](https://github.com/cocorossello) за [PR 2051](https://github.com/selenide/selenide/pull/2051). + +UPD. Исправили ещё раз в [Selenide 6.10.3](https://github.com/selenide/selenide/milestone/172?closed=1). + +
    + +### Показываем `$.selectOption()` в отчётах по-человечески {#friendly-select-option-in-reports} + +Ещё один косячок, вылезший после предыдущего рефакторинга селектов: в отчётах выскочили нечитаемые параметры. +Это всё потому, что в Java у массивов нет стандартного метода `toString()`, приходится изобретать велосипед. + +Было: +``` +| #blockChannel | select option([Канал Дождь, [Ljava.lang.String;@6732726]) | PASS | 487 | +``` + +Стало: +``` +| #blockChannel | select option(Канал Дождь) | PASS | 487 | +``` + +См. [issue 2047](https://github.com/selenide/selenide/issues/2047) и [PR 2052](https://github.com/selenide/selenide/pull/2052). + +
    + +### Показываем `localStorage` в отчётах по-человечески {#friendly-local-storage-in-reports} + +Почти такая же проблема: операции с `sessionStorage` и `localStorage` выглядели в отчётах нечитабельно. + +Было: +``` +| com.codeborne.selenide.LocalStorage@138a952f | set item(['Бут', 9125]) | +| com.codeborne.selenide.SessionStorage@549w123gg | set item(['Грайнер', 3285]) | +``` + +Стало: +``` +| localStorage | set item(['Бут', 9125]) | +| sessionStorage | set item(['Грайнер', 3285]) | +``` + +См. [issue 2045](https://github.com/selenide/selenide/issues/2045) и [PR 2046](https://github.com/selenide/selenide/pull/2046). + +
    + + +### Обновили зависимости {#update-dependencies} + +* #2044 #2057 bump Selenium from 4.6.0 to 4.7.1 +* #2036 bump browserup-proxy-core from 2.2.5 to 2.2.6 +* #2058 bump httpclient5 from 5.2 to 5.2.1 +* bump slf4j from 2.0.4 to 2.0.5 + +
    + +### Дочерние проекты + +Также зарелизили наши дочерние проекты: +* [selenide-appium 2.4.0](https://github.com/selenide/selenide-appium/releases/tag/v2.4.0) +* [selenide-selenoid 2.3.3](https://github.com/selenide/selenide-selenoid/releases/tag/v2.3.3) + +
    + +### Новости {#news} + +* Selenide Tutorial: [Replacement for Selenium?](https://www.youtube.com/watch?v=5vrYMfsxkGY&list=PL9ok7C7Yn9A9YyRISFrxHdaxb5qqrxp_i&index=4&ab_channel=TestingMiniBytes) на канале Testing Mini Bytes +* [Test automation framework for UI testing with java](https://oleksandr-podoliako.medium.com/test-automation-framework-for-ui-testing-with-java-fddd1e3fd75b) от Oleksandr Podoliako + +
    + + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2023-01-03-selenide-6.11.0.md b/content/ru/blog/2023-01-03-selenide-6.11.0.md new file mode 100644 index 000000000..5c73c445d --- /dev/null +++ b/content/ru/blog/2023-01-03-selenide-6.11.0.md @@ -0,0 +1,241 @@ +--- +slug: "selenide-6.11.0" +date: 2023-01-03 +title: "Вышла Selenide 6.11.0" +description: "" +category: +headerText: "Итоги 2022 года" +tags: [] +--- +
    + +
    + +
    + +# С Новым Годом, друзья! + +Дедушка Мороз принёс нам новый релиз [Selenide 6.11.0](https://github.com/selenide/selenide/milestone/169?closed=1). + + + + +### Добавили методы для копирования текста {#added-copy-paste-methods} + +Мы добавили два новых метода: +* `Selenide.copy()` - копирует выделенный текст в буфер обмена, и +* `$.paste()` вставляет текст из буфера обмена в поле ввода. + +```java +open("https://best-propaganda-quotes.ru"); +$("#solovjov").doubleClick(); // select the quote text +Selenide.copy(); +$("[name=q]").paste(); +$("[name=q]").shouldHave(text("Обсираться мелкими алмазами на берегу озера Комо")); +``` + +Известные ограничения: пока что эти методы не работают на серверных линуксах (без графического окружения). +Но запуск xvfb должен помочь. + +См. [issue 1817](https://github.com/selenide/selenide/issues/1817). +Спасибо [Evgenii Plugatar](https://github.com/evpl) за [PR 2027](https://github.com/selenide/selenide/pull/2027). + +
    + + +### Исправили метод `Selenide.download(url)` {#fix-download-with-credentials} + +...для случая, когда url содержит логин/пароль (т.е. ресурс защищён BasicAuth). + +Например, такой код раньше работал, но сломался после обновления Apache Http client: + +```java +File f = Selenide.download("https://admin:tiger@the-internet.herokuapp.com/basic_auth"); +``` + +Оказалось, что в Apache Http client усилили валидацию URL, и часть с логином и паролем больше не разрешена +(это типа небезопасная практика). + +Ну а селенид теперь вырезает эту часть и посылает с запросом в заголовке `Authorization`. + +См. [issue 2037](https://github.com/selenide/selenide/issues/2037) +и [PR 2102](https://github.com/selenide/selenide/pull/2102). + +
    + + +### Позволяем скачивать большие файлы через прокси {#download-large-files-via-proxy} + +Если вы скачиваете файлы методом `PROXY`, то размер файла не мог превышать 64 мегабайта. +Изначально это казалось разумным ограничением: зачем кому-то нужно нагружать тестовый стенд, скачивая гигантские файлы? +(64 и то многовато, по умолчанию в BrowserUpProxy вообще было 2 мегабайта; мы увеличили лимит до 64 в селениде) + +Но оказалось, что иногда люди хотят тестировать именно скачивание больших файлов. +После долгих споров мы решили просто убрать это ограничение. Вам виднее, качайте сколько хотите. + +```java +File favoriteMovie = $("#topMovie").download(); +assertThat(favoriteMovie) + .hasName("BadSanta.avi") + .as("2 GB").hasSize(2147483648L); +``` + +P.S. Но имейте в виду, со слишком большими файлами, скорее всего, прокси всё равно не справится (либо будет скачивать слишком долго). +И BrowserUpProxy по-прежнему имеет встроенное техническое ограничение в 2 гигабайта (потому, что тип данных - Integer). + +Но хотя бы файлы по 200 мегабайтов вы вполне сможете скачивать. + + +См. [issue 2082](https://github.com/selenide/selenide/issues/2082) +и [PR 2098](https://github.com/selenide/selenide/pull/2098). + +
    + + + +### Можно обрабатывать неожиданные алерты {#can-handle-unexpected-alerts} + +По умолчанию, селенид игнорирует неожиданные алерты в браузере +(точнее, запускает вебдрайвер с опцией `capabilities.setCapability(UNHANDLED_PROMPT_BEHAVIOUR, ACCEPT)`). + +С одной стороны, это удобно, чтобы тесты не ломались от внезапно всплывающих реклам и других бесполезных сообщений. +С другой стороны, иногда эти алерты могут содержать полезную информацию - в частности, ценное сообщение об ошибке. + +Если это ваш случай, теперь вы можете переопределить эту настройку: +```java +import static org.openqa.selenium.remote.CapabilityType.UNHANDLED_PROMPT_BEHAVIOUR; +import static org.openqa.selenium.UnexpectedAlertBehaviour.ACCEPT_AND_NOTIFY; + +Configuration.browserCapabilities.setCapability(UNHANDLED_PROMPT_BEHAVIOUR, ACCEPT_AND_NOTIFY); +``` + +И тогда при возникновении нежданных алертов вы узнаете, какой текст в них был: +```java +UnhandledAlertException: unexpected alert open: {Alert text : Как жопа, рогозин?} // chrome +UnhandledAlertException: Accepted user prompt dialog: Маршрут через мост недоступен. Чот бахнуло. // firefox +UnhandledAlertException: unexpected alert open: {Alert text : Обнаружены боевые комары-убийцы} // edge +UnhandledAlertException: : Обнаружена грязная бомба // safari +``` + +См. [issue 2054](https://github.com/selenide/selenide/issues/2054) +и [PR 2095](https://github.com/selenide/selenide/pull/2095). + +
    + + + +### Исправили пермиссии файла скриншота {#fix-screenshot-file-permission} + +Как вы знаете, при падении теста селенид автоматически сохраняет скриншот и создаёт два файла: `*.png` и `*.html`. +Так вот выяснилось, что селенид создаёт эти два файла с разными пермиссиями: + +``` +-rw------- 1 root root 300295 Dec 19 10:24 1671441847908.0.png +-rw-r--r-- 1 root root 185070 Dec 19 10:24 1671441847908.0.html +``` + +И кое-кому это помешало писать сложносочинённые CI скрипты, выполняющие команды из-под разных юзеров. +_Чем бы девопс не тешился... :)_ + +В общем, теперь у обоих будет "обычные" пермиссии `-rw-r--r--`. + +См. [issue 2081](https://github.com/selenide/selenide/issues/2081) +и [PR 2084](https://github.com/selenide/selenide/pull/2084). + +
    + +### Поддержка аннотации `@As` для полей без `@FindBy` {#support-as-annotation} + +В селениде уже давно можно задавать удобные имена элементам пэдж обжекты (т.н. "алиасы") с помощью метода `as`: + +```java +class LoginPage { + SelenideElement loginButton = $(By.xpath("/long/ugly/xpath[3]")).as("Login button"); +} +``` + +Но кому-то показалось, что удобно было бы повесить имя элемента в начало строки, а то справа от длинного селектора оно +визуально теряется. + +В общем, теперь алиас можно задать и с помощью аннотации `@As`: + +```java +class LoginPage { + @As("Login button") + SelenideElement loginButton = $(By.xpath("/long/ugly/xpath[3]")); +} +``` + +Но естественно, аннотация сработает, только если вы инициализируете пэдж обжект с помощью метода `Selenide.page()` или `Selenide.open()` + +См. [issue 2087](https://github.com/selenide/selenide/issues/2087) +и [PR 2088](https://github.com/selenide/selenide/pull/2088). + +
    + +### Метод для последнего сохранённого исходника страницы {#last-page-source} + +Редко когда это нужно, так что не заморачивайтесь. +По сути добавили методы `ScreenShotLaboratory`: +`threadScreenshots()`, `contextScreenshots()`, `lastThreadScreenshot()`, `lastContextScreenshot()`. + +Спасибо [Arman Ayvazyan](https://github.com/armanayvazyan) за [PR 2065](https://github.com/selenide/selenide/pull/2065). + +
    + +### Теперь можно добавлять URL страницы в сообщение об ошибке {#page-url-in-error-message} + +Кому-то это полезно, кому-то вредно. После долгих споров сделали эту возможность опциональной (в виде плагина). + +Пусть пока побудет в статусе экспериментальной возможности. +Вероятно, с форматами сообщений об ошибках мы ещё будем играться. + +См. [issue 980](https://github.com/selenide/selenide/issues/980) и [PR 2097](https://github.com/selenide/selenide/pull/2097). + +
    + +### Итоги года {#year-summary} + +Подведём итоги 2022 года? За этот год Selenide был упомянут в нескольких топах: + +* [5 Testing Automation Tools](https://qameta.io/blog/5-testing-automation-tools/) в блоге компании Qameta Software +* [Top Java Libraries for Automation Testing in 2022](https://hackernoon.com/top-java-libraries-for-automation-testing-in-2022) +* [Top Java Frameworks to Use in 2022](https://aglowiditsolutions.com/blog/top-java-frameworks/) + +И наконец, +* Selenide упомянут на [официальном сайте Selenium](https://www.selenium.dev/ecosystem/) в разделе "Экосистема". + +Количество скачиваний селенида выросло аж **в полтора раза**: +> с 302 тысяч в январе до 469 тысяч в ноябре. + +### И всё-таки {#new-year-wishes} +Это был ужасный год. Но я рад, что я смог использовать накопленный багаж в виде сайта selenide.org и его +аудитории, чтобы распространять антивоенную позицию. Кажется, здесь собрались люди, которые эту позицию разделяют. +Чему я тоже очень рад. + +Надеюсь, в наступившем году война закончится, виновные будут наказаны, граждане угнетённых стран сбросят наконец своих +тиранов. А сомневающиеся вытащат наконец голову из жопы. + +А прекрасная свободная страна Украина отстроится и будет цвести пуще прежнего. + +> И через год мы с вами увидимся в Киеве на замечательной [конференции SeleniumCamp](https://seleniumcamp.com/). + +Героям слава! + +
    + + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2023-01-20-selenide-6.11.1.md b/content/ru/blog/2023-01-20-selenide-6.11.1.md new file mode 100644 index 000000000..04d91c3d5 --- /dev/null +++ b/content/ru/blog/2023-01-20-selenide-6.11.1.md @@ -0,0 +1,95 @@ +--- +slug: "selenide-6.11.1" +date: 2023-01-20 +title: "Вышла Selenide 6.11.1" +description: "" +category: +headerText: "Качаем-обрезаем" +tags: [] +--- +Хаюшки! + +Одна моя знакомая из Италии рассказала, что вышел новый +релиз [Selenide 6.11.1](https://github.com/selenide/selenide/milestone/174?closed=1). + + + + +### Обрезаем только сообщения `WebDriverException` {#truncate-webdriver-exception-message} + +В довольно редких ситуациях - если вы +* используете кастомное действие (custom command), +* и из него кидаете какую-то свою ошибку (assertion error), +* и текст этой ошибки содержит несколько строк, + +то Селенид обрезает этот текст, оставляя лишь первую строку. +Изначально планировалось обрезать только текст `WebDriverException`, потому что он объективно содержит многострочный мусор: +> The element could not be found (WARNING: The server did not provide any stacktrace information) +> Command duration or timeout: 21 milliseconds +> For documentation on this error ... +> Build info: version: '2.29.1', ... +> System info: os.name: 'Linux', ... +> Session ID: 610138404f5c18... +> Driver info: org.openqa.selenium.chrome.ChromeDriver + +Но как-то так вышло, что селенид обрезал текст не только `WebDriverException`, а вообще всех ошибок. +Теперь подправили, и свой многострочный текст вы увидите целиком. + +См. [PR 2131](https://github.com/selenide/selenide/pull/2131). + +
    + +### Чутка подправили `$.download(FOLDER)` {#fix-download-to-folder} +Это очень редко случай, так что вы наверняка этого не замечали. + +Но наши тесты изредка моргали, и я покопал-покопал, да и раскопал парочку редких багов в методе `$.download(FOLDER)`. +Иногда он мог кинуть ошибку, что файл не скачался (хоть он на самом деле скачался), в двух случаях: + +* [#2116](https://github.com/selenide/selenide/pull/2116) Если время изменения оказалось в предыдущей секунде от начала скачивания +(такое бывает, т.к. разные файловые системы выдают время изменения файла с погрешностью до секунды, и иногда оно может даже оказаться в прошлом) + +* [#2119](https://github.com/selenide/selenide/pull/2119) Если ОС вернула время последнего изменения файла "0" +(оказываете, и такое бывает - если файловая система почему-то решила, что имя файла некорректное) + +Теперь должно качаться как намасленное. + +
    + +### Обновили зависимости {#update-dependencies} + +* bump WebdriverManager from 5.3.1 to 5.3.2 +* bump Netty from 4.1.86.Final to 4.1.87.Final, см. [PR 2126](https://github.com/selenide/selenide/pull/2126). + +
    + +### News {#news} + +* Пост от Amuthan Sakthivel [Почему мы выбрали Селенид, а не Селениум](https://creatingvalue.substack.com/p/why-we-chose-selenide-over-selenium) +* Свежая статья на хабре [Как написать UI-автотесты, если не умеешь программировать?](https://habr.com/ru/company/rostelecom/blog/707710/) +* Мой доклад в девклубе [Как законтрибьютить в опенсорс, чтобы не сгореть со стыда](https://www.youtube.com/watch?v=VtX7IpCHMS8&ab_channel=DEVCLUB.EU) +* Мой доклад в девклубе [WTF Thread Pools](https://www.youtube.com/watch?v=JKxzELiwO_o&ab_channel=DEVCLUB.EU) + +
    + +### Статистика {#statistics} + +Количество ежемесячных скачиваний Селенида перевалило за 490 тыщ! + +
    + +
    + +Поднажмём... + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2023-02-24-selenide-6.12.0.md b/content/ru/blog/2023-02-24-selenide-6.12.0.md new file mode 100644 index 000000000..e947b4ea9 --- /dev/null +++ b/content/ru/blog/2023-02-24-selenide-6.12.0.md @@ -0,0 +1,126 @@ +--- +slug: "selenide-6.12.0" +date: 2023-02-24 +title: "Вышла Selenide 6.12.0" +description: "" +category: +headerText: "Новый безбашенный" +tags: [] +--- +Привет! + +В этот трагичный и одновременно праздничный день мы выпустили +релиз [Selenide 6.12.0](https://github.com/selenide/selenide/milestone/173?closed=1). + +В нём почти нет фич, но есть новый режим, который может сильно повлиять на ваши тесты. + + + +
    + +### Новый безбашенный режим {#new-headless-mode} + +В Chromium-браузерах появился новый безголовый (headless) режим. +Подробнее о нём [в их блоге](https://developer.chrome.com/articles/new-headless/). + +Если вкратце, этот новый режим внутри использует тот же код, что и обычный headful, и поэтому должен вылечить все +болячки headless режима. А вот старый headless режим по сути был отдельным браузером со своими особенностями и багами. + +В теории вы всё ещё можете переключаться между старым и новым headless режимом. Но на практике вам придётся переключиться на новый, т.к. +при обновлении Chrome и Edge перестало работать скачивание файлов в старом headless режиме. + +В общем, в Selenide 6.12.0 новый headless режим будет включаться по умолчанию. + +См. [issue 2104](https://github.com/selenide/selenide/issues/2104). +Спасибо [Boris Osipov](https://github.com/BorisOsipov) за [PR 2105](https://github.com/selenide/selenide/pull/2105) +и [PR 2169](https://github.com/selenide/selenide/pull/2169). + +
    + +### Улучшили логирование при скачивании файлов {#improve-logs-when-downloading-file} +Если скачивание файла падает (особенно методом `FOLDER`), иногда бывает сложно понять, почему именно. +Мы немного доработали логирование внутри метода `$.download()`, так что теперь должно стать полегче. + +См. [PR 2167](https://github.com/selenide/selenide/pull/2167). + +
    + +### Улучшили скачивание файлов в Edge под Windows {#improve-download-in-edge} + +До сих пор селенид отслеживал только временные файлы "*.crdownload", которые хромиум использует при скачивании файлов. +Но оказалось, что на Windows браузер Edge создаёт ещё и временные файлы "*.tmp". Теперь селенид отслеживает и их. + +См. [PR 2167](https://github.com/selenide/selenide/pull/2167). + +
    + +### Обновили зависимости {#update-dependencies} + +* bump Selenium from 4.8.0 to 4.8.1, см. [PR 2161](https://github.com/selenide/selenide/pull/2161) и [ченджлог Selenium](https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG). +* Bump nettyVersion from 4.1.87.Final to 4.1.89.Final, см. [PR 2158](https://github.com/selenide/selenide/pull/2158). + +
    + +### Переименовали ветку `master` в `main` {#rename-master-to-main} + +Да-да, это отголоски того самого BLM. Один умный человек убедил меня, что стоит это сделать. :) + +
    + +### News {#news} + +* Пост [Test automation framework for UI testing with java](https://oleksandr-podoliako.medium.com/test-automation-framework-for-ui-testing-with-java-fddd1e3fd75b) by Oleksandr Podoliako +* Пост [Running test automation with Selenide on GitLab](https://pradappandiyan.medium.com/running-test-automation-with-selenide-on-gitlab-fb13c0a0dddf) by Pradap Pandiyan +* Моё видео с Continuous Testing Meetup: [Selenide UI tests in java](https://www.youtube.com/watch?v=5qiuRoUcICs&t=48m02s), 23.01.2023 +* Видео [Автотесты с нуля для начинающих Java + Selenide + TestNG + Maven](https://www.youtube.com/watch?v=G7iYLr_IgGA&ab_channel=FullStackQA) на канале FullStackQA + +
    + +Ну а почему же я назвал этот день праздничным? +Да потому, что 24 февраля вообще-то День Независимости Эстонии. +105 лет назад эстонские войска напихали оркам в панамку и провозгласили новое независимое государство. + +
    + +
    + +> Если бы не те бравые ребята на бронепоезде, не было бы сейчас Селенида. :) + +
    + +# UPD Вышла Selenide 6.12.1 + +Исправили старинную багу в методе `using`. + +См. [changelog](https://github.com/selenide/selenide/milestone/176?closed=1) + +
    + +# UPD Вышла Selenide 6.12.2 + +По-быстрому залепили костыль для баги в Chromedriver 111: +`Invalid Status code=403 text=Forbidden` + +См. [changelog](https://github.com/selenide/selenide/milestone/178?closed=1) + +
    + +# UPD Вышла Selenide 6.12.3 + +Исправили одну старую багу в методе `$.download(FOLDER)`, если его вызвать после `using`. + +См. [changelog](https://github.com/selenide/selenide/milestone/179?closed=1) + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2023-03-09-selenide-6.12.2.md b/content/ru/blog/2023-03-09-selenide-6.12.2.md new file mode 100644 index 000000000..8a10928af --- /dev/null +++ b/content/ru/blog/2023-03-09-selenide-6.12.2.md @@ -0,0 +1,49 @@ +--- +slug: "selenide-6.12.2" +date: 2023-03-09 +title: "Вышла Selenide 6.12.2" +description: "" +category: +headerText: "Костыль для Хрома" +tags: [] +--- +Привет! + +Срочно обновляйтесь на [Selenide 6.12.2](https://github.com/selenide/selenide/milestone/178?closed=1). + +Он содержит один важный костыль для баги в Chromedriver 111. + +> Invalid Status code=403 text=Forbidden + +### В чём проблема? + +Недавно вышла новая версия Chrome и Chromedriver 111. +И у всех, кто на неё обновился, резко посыпались тесты. +Браузер открывался, но при этом тест получал от вебдрайвера ошибку и дальше не мог ничего +сделать, в том числе закрыть этот самый браузер. + +В логах было видно такое вот красноречивое сообщение: + +```java +Starting ChromeDriver 111.0.5563.64 on port 31021 +org.openqa.selenium.remote.http.WebSocket$Listener onError +WARNING: Invalid Status code=403 text=Forbidden +java.io.IOException: Invalid Status code=403 text=Forbidden +... +``` + +И хотя это [бага хромдрайвера]( https://bugs.chromium.org/p/chromedriver/issues/detail?id=4361), +для неё нашёлся один простой костыль, и мы его по-быстрому запилили в Селениде. + +См. [issue 2192](https://github.com/selenide/selenide/issues/2192) и +[PR 2194](https://github.com/selenide/selenide/pull/2194). + +> А вообще, обновляйтесь на [HttpClient](/2023/03/22/selenide-6.12.4/#support-jdk-http-client). +Он требует Java11+, но зато таких багов там не будет. + +
    + + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2023-03-23-selenide-6.12.4.md b/content/ru/blog/2023-03-23-selenide-6.12.4.md new file mode 100644 index 000000000..0b74dd263 --- /dev/null +++ b/content/ru/blog/2023-03-23-selenide-6.12.4.md @@ -0,0 +1,121 @@ +--- +slug: "selenide-6.12.4" +date: 2023-03-23 +title: "Вышла Selenide 6.12.4" +description: "" +category: +headerText: "Точка отсчёта" +tags: [] +--- +Привет! + +А вы следили за новостями 23 марта? +Молодцы! + +Сегодня у нас _Точка Отсчёта_ - релиз [Selenide 6.12.4](https://github.com/selenide/selenide/milestone/180?closed=1). + + +
    + +### Костыль для Хрома {#workaround-for-chromedriver-bug} +Напоминание: если вы всё ещё роете интернет в поисках лекарства против +> Invalid Status code=403 text=Forbidden + +то лекарство уже было выпущено в [Selenide 6.12.2](/2023/03/09/selenide-6.12.2/). + +
    + +### Добавили поддержку `jdk-http-client` вместо `netty-client` {#support-jdk-http-client} + +По умолчанию по-прежнему используется `netty-client`, но если +вы хотите [перейти на jdk-http-client](https://www.selenium.dev/blog/2022/using-java11-httpclient/), +то можете это легко сделать: +1. Добавить зависимость +`org.seleniumhq.selenium:selenium-http-jdk-client:$seleniumVersion` +2. Добавить пропертю перед открытием браузера: +`System.setProperty("webdriver.http.factory", "jdk-http-client");` + +См. [issue 2215](https://github.com/selenide/selenide/issues/2215) +и [PR 2216](https://github.com/selenide/selenide/pull/2216). + +
    + +### Исправили работу прокси после метода `using` {#restore-proxy-after-using} + +Это почти такая же проблема, как в [issue 2202](https://github.com/selenide/selenide/issues/2202), +но только с прокси. + +В общем, стоило вам разочек использовать метод `using`, +как у вас сразу пропадал прокси. И дальнейшее скачивание файлов (или для чего ещё вы +использовали прокси) больше не работало. + +Но судя по всему, про этот [супер-удобный метод `using`](/2019/10/16/selenide-5.4.0/#add-method-using) +мало кто знает, потому что жалоба была всего одна. :) + +Ну вот, теперь и `using` починили, и про него узнает больше народу. :) + +См. [PR 2208](https://github.com/selenide/selenide/pull/2208) и +[PR 2209](https://github.com/selenide/selenide/pull/2209). + +
    + +### Исправили `$.clear()` при пропадании элемента {#fix-clear-when-element-disappears} + +Как вы знаете, в селениде есть метод `$("input").clear()`, который очищает поле ввода. +Оказалось, что метод мог упасть в одной редкой ситуации. +А именно, если в результате очистки элемент пропадает. +В этот момент метод `$.clear()` пытался сгенерировать событие `on change` на этом элементе - и падал. + +См. [issue 2207](https://github.com/selenide/selenide/issues/2207) и +[PR 2221](https://github.com/selenide/selenide/pull/2221). + +
    + +### Обновили зависимости {#update-dependencies} + +* #2210 Bump nettyVersion from 4.1.89.Final to 4.1.90.Final +* #2218 Bump slf4jVersion from 2.0.6 to 2.0.7 + +
    + +### Выпустили `selenide-appium:2.7.0` {#release-selenide-appium} + +* Добавили скролл вверх-вниз для мобильников (#139) +* Исправили функцию `terminateApp` (#146) +* Обновились на Selenide 6.12.4 (#143) + +См. [release notes](https://github.com/selenide/selenide-appium/releases/tag/v2.7.0). + +
    + +### Выпустили `selenide-selenoid:2.3.6` {#release-selenide-selenoid} + +* Обновились на Selenide 6.12.4 + +См. [release notes](https://github.com/selenide/selenide-selenoid/releases/tag/v2.3.6). + +
    + +### News {#news} + +* Я запилил первый видос после 9-летнего перерыва :) +[Как скачать файл в Selenide: спросим у ChatGPT](https://youtu.be/k0A8HFWV_iE) +* Наконец-то у меня появился [доклад про Flaky tests на английском](https://www.youtube.com/watch?v=18J2_4a4Cl4&ab_channel=Jfokus) - конференция JFokus, Стокгольм, 8.02.2023 +* Видос [Selenide: як тестувати веб-елементи](https://www.youtube.com/watch?v=9S6xaAvJc9M&t=4226s&ab_channel=HillelITSchool) от Hillel IT School + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2023-04-01-selenide-6.13.0.md b/content/ru/blog/2023-04-01-selenide-6.13.0.md new file mode 100644 index 000000000..19ed738ac --- /dev/null +++ b/content/ru/blog/2023-04-01-selenide-6.13.0.md @@ -0,0 +1,118 @@ +--- +slug: "selenide-6.13.0" +date: 2023-04-01 +title: "Вышла Selenide 6.13.0" +description: "" +category: +headerText: "Навстречу баннерам" +tags: [] +--- +Всем привет! + + +Ура, сегодня у нас новый релиз **Selenide 6.13.0** + + +
    + +### Поддержка баннеров {#banners-support} + +#### Проблема +Очень часто люди спрашивают: "А что делать, если посреди теста на экране может выскочить баннер или какой-то ещё неожиданный элемент?" + +Ведь он может перекрыть другие элементы, закрыть важную кнопку и т.п. - и таким образом сломать тест. + +> [Я всегда на это люто ругался](https://ru.selenide.org/2019/12/02/advent-calendar-how-to-abuse-selenide/) +и настоятельно советовал взять тестовую среду под контроль и самому из теста регулировать, когда баннеры должны появляться, а когда нет. + +Алексей Виноградов сделал выступление на эту тему: [Spinner-driven-development](https://www.youtube.com/watch?v=MLxf9q9qXu4&ab_channel=%D0%A2%D0%B5%D1%85%D0%BD%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D0%B8%D0%B2%D0%9A%D0%BE%D0%BD%D1%82%D1%83%D1%80%D0%B5). + +
    + +#### Стадия принятия +Но слишком уж это распространённая проблема. В конце концов, Селенид задуман для того, чтобы помогать людям решать проблемы, а не читать нотации. + +Мы решили пойти людям навстречу и создать решение для проблемы баннеров. +Теперь в начале теста вы можете вызвать метод `Selenide.onBanner()`: + +```java +onBanner("#pizzaAds", CLOSE, ".btn-close"); +``` + +
    + +#### Как это работает +По умолчанию, этот метод добавит вебдрайверу листенер, который будет перед каждым кликом или проверкой проверять, не +появился ли элемент с данным селектором `"#pizzaAds"`. Если появился, селенид попытается закрыть его, нажав на кнопку закрытия `".btn-close"`. + +Этот метод называется `POLL`. Он самый простой и надёжный, но и самый медленный. +Ведь селенид должен будет кучу раз спрашивать у браузера, не появился ли баннер. Каждый такой запрос занимает некоторое время. + +
    + +#### Альтернативные методы +Поэтому мы добавили ещё два альтернативных метода, которыми селенид может проверять, а не появился ли баннер. +Их можно включить либо глобально настройкой: + +```java +Configuration.bannerCloseMode = POLL; // по умолчанию + +// Слушает события по изменению DOM через CDP: +Configuration.bannerCloseMode = CDP; // Работает только в Chromium-браузерах + +// Скармливает html текущей страницы ChatGPT и спрашивает, нет ли там баннера: +Configuration.bannerCloseMode = CHATGPT; +``` + +Либо вы можете задать его параметром с помощью `using`: + +```java +onBanner(using(CDP) + .withBannerSelector("#pizzaAds") + .withCloseButtonSelector(".btn-close") + .withAction(CLOSE) +); +``` + +#### Кастомный обработчик +Есть также более общий вариант, в котором вы сможете залямбдашить свою специфическую логику обработки баннера. +Вы же не всегда хотите сразу закрыть баннер - иногда сначала нужно из него прочитать какую-то информацию. + +```java +onBanner(using(CHATGPT) + .withBannerSelector("#pizzaAds") + .withCloseButtonSelector(".btn-close") + .withAction((banner, closeButton) -> { + banner.find(".title").shouldHave(text("Ваш пароль изменён.")); + String newPassword = banner.find(".new-password").text(); + closeButton.doubleClick(); + }) +); +``` + +
    + +Пробуйте, пишите, заводите тикеты на гитхабе. Предлагайте свои алгоритмы для обнаружения баннеров. + +_Хватит примерять на себя белые пальто и ссориться из-за дурацких принципов._ + +> Давайте объединимся против баннеров! + + +### News {#news} + +Сегодня у нас три видоса про Селенид +* на русском: [ChatGPT: Как скачать файл в Selenide](https://youtu.be/k0A8HFWV_iE) +* на английском: [ChatGPT: How to download file in Selenide](https://www.youtube.com/watch?v=GwHG550moGc) +* [Ускоряем UI Автотесты с помощью подстановки Cookies](https://www.youtube.com/watch?v=SohZfPKicZQ&ab_channel=OlehPendrak) by Oleh Pendrak + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2023-04-04-selenide-6.13.0.md b/content/ru/blog/2023-04-04-selenide-6.13.0.md new file mode 100644 index 000000000..9625caca9 --- /dev/null +++ b/content/ru/blog/2023-04-04-selenide-6.13.0.md @@ -0,0 +1,231 @@ +--- +slug: "selenide-6.13.0" +date: 2023-04-04 +title: "Вышла Selenide 6.13.0" +description: "" +category: +headerText: "В жопу баннеры!" +tags: [] +--- +Привет! + +Сегодня у нас большой мажорный релиз [Selenide 6.13.0](https://github.com/selenide/selenide/milestone/177?closed=1). + + +
    + +### Добавили метод `$.cached()` {#add-method-cached} + +Иногда приходится воротить довольно сложный код для поиска элемента. +И он может работать **медленно**, особенно если элемент ищется из какой-то большой коллекции с применением сложной фильтрации. +Что-то вроде такого: + +```java +ElementsCollection subscriptions = $$("div.subs-expands") + .filter(childExactText( + By.xpath(".//div[contains(@class,'data')]//div[contains(@class,'heading')]"), + orderNumber) + ); + +SelenideElement target = subscriptions + .filter(childAttributeValue(...)) + .find(childExactText(....)); +``` + +Каждое обращение к `target` заметно притормаживает. + +Теперь такие тесты можно ускорить, закэшировав значение `target`: +```java +SelenideElement target = subscriptions + .filter(..) + .find(..) + .cached(); +``` + +Естественно, это можно сделать только в том случае, если вы уверены, что этот элемент не меняется, не перегружается и т.д. +Если он всё-таки перегрузится, то вы словите тот самый легендарный `StaleElementReferenceException`. + +См. [issue 2171](https://github.com/selenide/selenide/issues/2171), +[issue 1927](https://github.com/selenide/selenide/issues/1927) +и [PR 2189](https://github.com/selenide/selenide/pull/2189). + +
    + +### Добавили http статус при моке ответа сервера {#mock-response-with-http-status} +В селениде есть методы, чтобы замокать ответ сервера: + +```java +getSelenideProxy().responseMocker().mockText("login-mock", + urlContains(POST, "/login"), () -> "{role: admin}"); +``` + +Раньше можно было мокать только тело ответа, но статус всегда оставался 200 ("OK"). +Теперь можно задать и другой статус: +```java +getSelenideProxy().responseMocker().mockText("login-mock", + urlContains(POST, "/login"), 403, () -> "{role: looser}"); +``` + +См. [issue 2227](https://github.com/selenide/selenide/issues/2227) и [PR 2234](https://github.com/selenide/selenide/pull/2234). + +
    + +### Новый метод `inNewBrowser` для запуска куска кода в новом браузере {#add-method-in-new-browser} + +Иногда вам хочется посреди теста запустить кусок кода в новом браузере. +> Если что, я это осуждаю: такие вспомогательные действия надо делать не через UI +> (который мы тестируем, а потому не доверяем), а каким-то контролируем способом: через API, прямой запрос в базу и т.п. + +Уже давно для этого есть [метод `using`](/2019/10/16/selenide-5.4.0/#add-method-using). Но он требует, чтобы вы открыли +новый браузер с какими-то своими настройками. А что, если вам подходят обычные селенидовские настройки? То есть вам +нужен точно такой же браузер, только новый? + +Теперь для этого есть метод `inNewBrowser`: +```java +open("https://site.com/login/as/user/bob"); + +inNewBrowser(() -> { + open("https://site.com/login/as/admin"); + $(by("value", "bob")).find("[name=is_admin]").setEnabled(); +}); + +$("h1").shouldHave(text("Hello, chat admin!")); +``` + +См. [issue 2213](https://github.com/selenide/selenide/issues/2213) и [PR 2236](https://github.com/selenide/selenide/pull/2236). + +
    + +### Добавили метод `$.doubleClick(options)` {#add-method-doubleclick-with-options} + +Раньше был просто метод `$.doubleClick()`, который мог кликать только по центру элемента. +Теперь же у него появился продвинутый тёзка с параметром `options`. Опции такие же, как и у обычного клика: + +```java +$(".btn").doubleClick(usingDefaultMethod()); +$(".btn").doubleClick(usingJavaScript()); +$(".btn").doubleClick(usingDefaultMethod().offset(66, 33)); +$(".btn").doubleClick(usingJavaScript().offset(66, 33).withTimeout(ofSeconds(9))); +``` + +См. [issue 2133](https://github.com/selenide/selenide/issues/2133). +Спасибо [aakachurin](https://github.com/aakachurin) за [PR 2135](https://github.com/selenide/selenide/pull/2135). + +
    + +### Добавили условие `$.shouldHave(innerText())` {#add-condition-inner-text} + +Оно позволит проверять текст невидимых элементов. +> Скорее всего это плохая идея: раз пользователь не видит элемента, значит, и проверять его не надо. + +Но если всё-таки очень хочется, то можно: +```java +$("#theHiddenElement") + .shouldHave(innerText("Видишь суслика? И я не вижу. А он есть!")); + // Обычный $("#theHiddenElement").text() выдаёт здесь пустую строку ""; +``` +См. [issue 2220](https://github.com/selenide/selenide/issues/2220) и [PR 2223](https://github.com/selenide/selenide/pull/2223). + +
    + +### Добавили условие для коллекций `$$.shouldHave(attributes(...))` {#add-condition-attributes} + +```java +$$("#numbers option").shouldHave(attributes("value", + "one", "two", "three", "four", "five")); +``` + +См. [issue 2091](https://github.com/selenide/selenide/issues/2091). +Спасибо [Alexey Lakovych](https://github.com/AlexLAA) за [PR 2091](https://github.com/selenide/selenide/pull/2091). +Также см. [PR 2230](https://github.com/selenide/selenide/pull/2230). + +
    + +### Ясное сообщение об ошибки в методах `$.select*()` {#clear-error-message-in-select} + +В селениде есть методы для работы с выпадающими списками: +```java +$("select#gender").selectOptionContainingText("Female"); +``` + +Недавно мы [переделали их реализацию на JavaScript](/2022/11/21/selenide-6.10.0/#select-options-using-javascript) - так быстрее и надёжнее. + +Но оказалось, что если по ошибке вызвать такой метода для не-селекта, вылетала очень непонятная ошибка: +```java +$("ul").selectOptionContainingText("Kelly Snyder"); +--> JavascriptException: + javascript error: + undefined is not iterable (cannot read property Symbol(Symbol.iterator)) +``` + +Теперь сообщение будет понятное: +```java +IllegalArgumentException: Cannot select option from a non-select element +``` + +См. [issue 2231](https://github.com/selenide/selenide/issues/2231) и [PR 2233](https://github.com/selenide/selenide/pull/2233). + +### Исправили ошибку в методе `$$.subList()` {#fix-method-sublist} + +Как вы знаете, в селениде есть удобные методы для проверки разом целой коллекции элементов: + +```java + $$("#numbers").shouldHave(texts("One", "Two", "Three", "Four", "Five")); +``` + +Но метод `$$` возвращает объект `ElementsCollection`, который, к сожалению, наследуется от `AbstractList`. +А потому случайно (так не задумывалось!) наследует от него некоторые методы, на которые мы не рассчитывали. + +Один из таких методов - `subList`: + +```java + $$(".user").subList(1, 4).iterator(); +``` + +Приведённый выше итератор возвращает не три, а всего два элемента. Обрезает последний. Ошибочка. `¯\_(ツ)_/¯` + +Теперь она оперативно исправлена. + +См. [issue 2239](https://github.com/selenide/selenide/issues/2239) и [PR 2240](https://github.com/selenide/selenide/pull/2240). + +
    + +### Обновили зависимости {#update-dependencies} + +* bump Selenium from 4.8.1 to 4.8.3 -- см. [CHANGELOG](https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG) +* bump LittleProxy from 2.0.16 to 2.0.17 +* bump BrowserUpProxy from 2.2.8 to 2.2.9 +* bump nettyVersion from 4.1.90.Final to 4.1.91.Final + +
    + + +### Новости {#news} + +Сегодня у нас подборка видосов про Селенид +* на русском: [ChatGPT: Как скачать файл в Selenide](https://youtu.be/k0A8HFWV_iE) +* на английском: [ChatGPT: How to download file in Selenide](https://www.youtube.com/watch?v=GwHG550moGc) +* [Flaky tests на английском](https://www.youtube.com/watch?v=18J2_4a4Cl4&ab_channel=Jfokus) +* [Ускоряем UI Автотесты с помощью подстановки Cookies](https://www.youtube.com/watch?v=SohZfPKicZQ&ab_channel=OlehPendrak) by Oleh Pendrak +* [Канал про селенид](https://www.youtube.com/watch?v=wN45Qla66-o&list=PLFGoYjJG_fqrvWt1FfHqKoREQmSPxazBq&ab_channel=NaveenAutomationLabs) от NaveenAutomationLabs +* [Selenide: як тестувати веб-елементи](https://www.youtube.com/watch?v=9S6xaAvJc9M&t=4226s&ab_channel=HillelITSchool) + + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2023-05-08-selenide-6.14.0.md b/content/ru/blog/2023-05-08-selenide-6.14.0.md new file mode 100644 index 000000000..1268bee1f --- /dev/null +++ b/content/ru/blog/2023-05-08-selenide-6.14.0.md @@ -0,0 +1,184 @@ +--- +slug: "selenide-6.14.0" +date: 2023-05-08 +title: "Вышла Selenide 6.14.0" +description: "" +category: +headerText: "Полный вперёд!" +tags: [] +--- +Привет! + +Пока не начался контрнаступ, давайте-ка обновимся на [Selenide 6.14.0](https://github.com/selenide/selenide/milestone/181?closed=1) - а то потом будет не до него. + +В нём есть несколько изменений, которые как будто не очень большие, но могут чего-нибудь сломать. +_Поэтому очень советую не оттягивать и **обновиться сейчас**._ + + +
    + +### Ускорили дебаг {#speedup-debug} + +Когда дебажишь свой тест и останавливаешься на брейкпойнте, иногда можно заметить, что IDE очень долго отображаешь +значения полей в пэджобжекте. Вот в таком состоянии IDE может подвиснуть надолго: + +Selenide. debug. slow. + +Причина в том, что для отображения каждого поля Selenide обращается к вебдрайверу, +чтобы получить имя тэга, актуальный текст и атрибуты элемента. Зато через некоторое время вы могли увидеть актуальную картинку: + +Selenide. debug. slow. result. + +Теперь этот процесс должен сильно ускориться. Селенид больше не будет обращаться к вебдрайверу, а просто покажет локатор элемента: + +Selenide. debug. slow. result. + +Но и формат метода `$.toString()` / `$$.toString()` тоже изменился. Будьте готовы. + +См. [issue 2253](https://github.com/selenide/selenide/issues/2253). +и [PR 2269](https://github.com/selenide/selenide/pull/2269). + +> Но не переживайте, это всё касается только дебага. +> При падении теста вы по-прежнему будете получать полную информацию об элементе с блекджектом и скриншотами. +
    + +### Убрали флажок хрома `--no-sandbox` {#remove-flag--no-sandbox} + +История с этим флажком мутная. Лично я не вижу никакой разницы, запускать хром с ним или без него. + +Но +1. Некоторые пользователи говорят, что без флажка `--no-sandbox` хром не запускается в докере +2. А другие пользователи говорят, что с флажком `--no-sandbox` процесс хрома остаётся висеть в фоне и пожирает весь CPU. Но это вроде только на винде (?) + +В общем, мы убрали этот флажок, потому что пользователям №1 +* легко обнаружить проблему (хром тупо не запускается) +* легко добавить его самостоятельно: +```java +Configuration.browserCapabilities = + new ChromeOptions().addArguments("--no-sandbox"); +``` + +См. [issue 2270](https://github.com/selenide/selenide/issues/2270) и [PR 2271](https://github.com/selenide/selenide/pull/2271). + +
    + +### Добавили метод `step` для отчётиков {#add-step-method} + +Если вы используете селенидовский встроенный отчёт (`TextReport`), то теперь можете группировать действия в "шаги" +с помощью нового метода `step`: + +```java +@Test +void authentication() { + step("login",()->{ + open("/login.asp"); + $("#username").val("u"); + $("#password").val("p"); + }); + + step("logout",()->{ + $("#logout").click(); + $("#goodBye").shouldHave(text("Good bye looser!")); + }); +} +``` + +В отчёте шаги будут визуально выделяться. +```text ++---------------+-----------------------------------------------+-------+------+ +| Element |Subject |Status | ms. | ++---------------+-----------------------------------------------+-------+------+ +| login | |PASS | 4000 | +|---|---------------|-------|------|---| +| open | http://127.0.0.1:8080/my_account/account.html |PASS | 2662 | +| #username | val "u" |PASS | 300 | +| #password | val "p" |PASS | 400 | +| logout | |PASS | 1023 | +| #logout | click |PASS | 923 | +| #goodBye | should have text "Good bye looser!" |PASS | 100 | ++---------------+-----------------------------------------------+-------+------+ +``` + +Кстати, шаги могут быть вложенными друг в друга. + +См. [issue 2172](https://github.com/selenide/selenide/issues/2172). +Спасибо [Maksim @Au6ojlut](https://github.com/Au6ojlut) за [PR 2250](https://github.com/selenide/selenide/pull/2250). + +
    + +### Добавили метод `$.dragAndDrop(DragAndDropOptions)` {#drag-and-drop-with-options} + +Теперь метод `$.dragAndDrop` приобрёл более логичное звучание: сначала "что", потом "куда" и наконец, "как". + +```java +$("#drag1").dragAndDrop(to("#div2")); +$("#drag1").dragAndDrop(to("#div2").usingJS()); +``` + +Спасибо [Maksim @Au6ojlut](https://github.com/Au6ojlut) за [PR 2245](https://github.com/selenide/selenide/pull/2245). + +
    + +### Разрешили двигать браузер за экран {#allow-negative-browser-position} + +Исправили мелкую багу, из-за которой нельзя было проставить негативные значения в позиции браузера: + +```java +Configuration.browserPosition = "-1900x-450"; +``` + +Слабо себе представляю, зачем это может быть полезно, но исправили. + +См. [issue 2258](https://github.com/selenide/selenide/issues/2258) и [PR 2259](https://github.com/selenide/selenide/pull/2259). + +
    + +### Путь к бинарнику Edge {#support-edge-binary-location} + +В селениде есть настройка `Configuration.browserBinary`, позволяющая задать путь к бинарнику браузера. +(на всякий случай: в большинстве случаев её _не нужно_ задавать). + +Раньше эта настройка не поддерживалась для браузера Edge, а теперь поддерживается. Ура. + +Спасибо [Vladislav Velichko](https://github.com/vlad8x8) за [PR 2267](https://github.com/selenide/selenide/pull/2267). + +
    + +### Обновили зависимости {#update-dependencies} + +* [Selenium 4.9.1](https://github.com/selenide/selenide/pull/2277) - см. [ченджлог](https://github.com/SeleniumHQ/selenium/blob/trunk/java/CHANGELOG) +* [Netty 4.1.92.Final](https://github.com/selenide/selenide/pull/2263) + +
    + +### Новости {#news} + +* Серия уроков [Selenide Java with Cucumber](https://www.youtube.com/playlist?list=PLFGzDEkV3ACu0i-Gd_whXsspqDlmP3ymP) от [TechPro Education](https://www.youtube.com/@TechProEducationUS) +* Обзор [Jetbrains Aqua для автоматизации тестирования](https://www.youtube.com/watch?v=vUTQyr2UF0M&ab_channel=OlehPendrak) от [Oleh Pendrak](https://www.youtube.com/@threadqa) + +
    + +### Статистика {#statistics} + +Количество ежемесячных скачиваний Селенида перевалило за 600 тыщ! + +
    + +
    + +
    + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2023-05-29-selenide-6.15.0.md b/content/ru/blog/2023-05-29-selenide-6.15.0.md new file mode 100644 index 000000000..bd9ef8fc0 --- /dev/null +++ b/content/ru/blog/2023-05-29-selenide-6.15.0.md @@ -0,0 +1,258 @@ +--- +slug: "selenide-6.15.0" +date: 2023-05-29 +title: "Вышла Selenide 6.15.0" +description: "" +category: +headerText: "Нештатный сход фичeприпаса" +tags: [] +--- +Доброй ночи! + +> Есть люди, которые постоянно деплоят, а есть люди, которые один раз в жизни где-то выучили, что должен быть РЕЛИЗ — и копят, копят, копят фичи для этого релиза. +> А счастливый дедушка-мейнтейнер думает, что ему хорошо. +> И как использовать опенсорс-проект, если вдруг случайно окажется, что этот дедушка — законченный мудак? + + +Как вы поняли, мы выпустили новую версию [Selenide 6.15.0](https://github.com/selenide/selenide/milestone/184?closed=1) +с серьёзными такими внутренними переделками. + +
    + +### Влили проект `selenide-selenoid` в `selenide` {#merge-selenide-selenoid-to-selenide} + +Это позволит нам легче менять и релизить эти проекты. +Для вас поменяется объявление зависимости. +Вместо +```groovy + testImplementation("org.selenide:selenide-selenoid:2.3.7") +``` + +Теперь нужно будет прописать: +```groovy + testImplementation("com.codeborne:selenide-selenoid:6.15.0") +``` + +См. [PR 2292](https://github.com/selenide/selenide/pull/2292). + +
    + +### Влили проект `selenide-appium` в `selenide` {#merge-selenide-appium-to-selenide} + +Это позволит нам легче менять и релизить эти проекты. +Вам всего лишь нужно будет обновить версию `selenide-appium` с `2.8.1` на `6.15.0` + +См. [PR 2291](https://github.com/selenide/selenide/pull/2291). + +
    + +### Клик теперь проверяет, что элемент не disabled {#clicking-disable-element-fails} + +Как вы знаете, метод `$.click()` требует, чтобы элемент был видимым (более точно: либо элемент должен быть видимый, +либо иметь css свойство `opacity: 0`). + +НО до сих пор Селенид не проверял, что элемент enabled. Другими словами, + +> Селенид разрешал кликать на `disabled` элементы. + +1. **В пользу** этого решения был такой аргумент: а вдруг автор теста и хочет кликнуть на задизейбленый элемент и убедиться, что ничего не произошло? +2. **Против** этого решения был другой аргумент: такое поведение может спровоцировать нестабильные тесты: + * тест кликает на кнопку, не дожидаясь, пока она станет enabled + * по факту клик не случится (но и никаких ошибок не возникнет) + * и позже тест упадёт из-за не случившегося клика (и будет очень сложно понять, что произошло) + * или ещё хуже: тест может остаться ложно позитивным. + +В общем, теперь **аргумент №2 победил**. Теперь метод `$.click()` дождётся, пока элемент станет enabled. +А если не станет - клик упадёт. + +Теперь вы можете смело сократить все свои тесты: +> `$.shouldBe(enabled).click()` заменить на `$.click()`. + +P.S. Если вы из лагеря аргумента №1, то можете вместо клика использовать `$.shouldBe(disabled)`. + +См. [issue 2288](https://github.com/selenide/selenide/issues/2288). +Спасибо [Maksim @Au6ojlut](https://github.com/Au6ojlut) за [PR 2290](https://github.com/selenide/selenide/pull/2290). + +
    + +### Маскируем переводы строк в отчёте {#escape-newlines-in-report} + +Если вы пробовали использовать в тесте многострочную строку: + +```java +$.shouldHave(text("Если\n дедушка\n законченный\n мудак"); +``` + +То могли заметить, что в отчёте эта строка выглядела коряво и ломала всю таблицу. + +А теперь будет красиво. + +См. [issue 2283](https://github.com/selenide/selenide/issues/2283). +Спасибо [Maksim @Au6ojlut](https://github.com/Au6ojlut) за [PR 2284](https://github.com/selenide/selenide/pull/2284). + +
    + + +### Комбинированные селекторы для мобилок {#combined-selectors-for-mobile-apps} + +При тестировании мобильных приложений удобно задать в одной проверке два селектора: отдельно для Android и iOS. +Раньше приходилось придумывать вспомогательные методы или городить ифы. + +Теперь же можно объявить "комбинированный" селектор с помощью `CombinedBy`: +```java +import static com.codeborne.selenide.appium.selector.CombinedBy.android; +import static com.codeborne.selenide.appium.AppiumSelectors.byTagAndName; + +$(android(byText("Бибер")).ios(byText("Долик"))) + .shouldHave(text("Бибер")); +``` + +
    + + +### Новые проверки для мобилок {#conditions-for-mobile-apps} + +Аналогичное решение для проверок: теперь можно одной строкой задать "комбинированную" проверку и для Android, и для iOS +с помощью класса `CombinedAttribute`: +```java +import static com.codeborne.selenide.appium.conditions.CombinedAttribute.android; +import static com.codeborne.selenide.appium.AppiumCondition.attribute; +import static io.appium.java_client.AppiumBy.accessibilityId; + +// Проверка элемента: +$.shouldHave(attribute( + android("content-desc").ios("name"), + "Гойду, Жерасимов, где, сука, ебоприпасы?" +)); + +// Проверка коллекции: +$$.shouldHave(attributes(android("text"), + "Бздила картонный", + "Болтун безмозглый", + "Вазелиновая коррекция", + "Зять-«у*бок»", + "Сын-отморозок" +)); +``` + +
    + +### Новые селекторы для мобилок {#new-selectors-for-mobile-apps} + +Для кучи, нас появилась пачка новых селекторов для поиска элементов по тэгу, тексту, подстроке и т.п.: +```java +import static com.codeborne.selenide.appium.AppiumSelectors.*; + +$(byAttribute("content-desc", "Hello")).click(); +$(byContentDescription("Hello")).click(); +$(byTagAndAtttribute("android.widget.TextView", "Не")).click(); +$(byTagAndName("XCUIElementTypeStaticText", "вы е")).click(); +$(withTagAndName("XCUIElementTypeText", "бываться на красной площади")).click(); +``` + +См. [issue 2300](https://github.com/selenide/selenide/issues/2300). +Спасибо [Amuthan Sakthivel](https://github.com/amuthansakthivel) за [PR 135](https://github.com/selenide/selenide-appium/pull/135). +Также см. [PR 2315](https://github.com/selenide/selenide/pull/2315). + +
    + + +### Переключение контекста в мобилках {#switch-context-in-mobile-apps} +Зачастую мобильные приложения открывают какой-то контент во встроенном браузере (WebView). А то и полностью построены на WebView. +При тестировании таких приложений требуется переключаться между "нативным" и "веб" контекстом. + +Теперь для переключения есть удобные методы: + +```java +// Тут мы в "нативном" контексте +open(); +$(accessibilityId("URL input field")).setValue("www.google.com"); +$(accessibilityId("Go To Site button")).click(); + +// Опа, и мы уже в "веб" контексте: +switchTo().context("WEBVIEW_com.saucelabs.mydemoapp.rn"); +$("#i-am-not-a-robot").click(); + +assertThat(getContextHandles()).hasSize(2) +``` + +См. [PR 2308](https://github.com/selenide/selenide/pull/2308). +Спасибо [Amuthan Sakthivel](https://github.com/amuthansakthivel) за [PR 149](https://github.com/selenide/selenide-appium/pull/149). + +
    + + +### Переколбас CollectionCondition {#refactor-collection-conditions} +Мы поменяли внутреннее устройство условий для коллекций (класс `CollectionCondition`). + +Раньше, если вы хотели создать [кастомную проверку для коллекций](https://github.com/selenide/selenide/blob/main/src/test/java/integration/collections/CustomCollectionConditionTest.java), +вы должны были реализовать метод `test(elements)`: +```java +var allTextsStartingWithZ = new CollectionCondition() { + public boolean test(List webElements) { + return webElements.stream() + .map(webElement -> webElement.getText().startsWith("Z")) + .reduce(true, (x, y) -> x && y); + } +} +$$(".mudak").shouldHave(allTextsStartingWithZ) +``` + +Этот метод останется ещё на какое-то время (для сохранения обратной совместимости), +но **рекомендуемый метод** теперь будет `check(CollectionSource collection)`: + +```java +var allTextsStartingWithZ = new CollectionCondition() { + public CheckResult check(CollectionSource collection) { + List elements = collection.getElements(); + List actualTexts = ElementsCollection.texts(elements); + + boolean allMatched = webElements.stream() + .map(webElement -> webElement.getText().startsWith("Z")) + .reduce(true, (x, y) -> x && y); + return new CheckResult(allMatched, actualTexts); + } +} +$$(".mudak").shouldHave(allTextsStartingWithZ) +``` + +### Что нам это даёт? +В будущем это откроет нам возможности для улучшений проверок коллекций: +1. Можно будет сильно ускорить проверки: например, быстро получить тексты всех элементов коллекции за один вызов JavaScript кода. +2. В сообщении об ошибке писать не "актуальные тексты на момент составления сообщения", а "актуальные тексты на момент последней проверки". +Как в [этой проблеме](/2021/09/28/selenide-5.25.0/#actual-value-at-the-moment-of-last-check), только с коллекциями. + +См. [PR 2312](https://github.com/selenide/selenide/pull/2312) и [PR 2307](https://github.com/selenide/selenide/pull/2307). + +
    + +### Новости {#news} + +* Исторический момент: [первый мем про селенид](https://pikabu.ru/story/selenium_selenide_i_selenoid_8376039) +* Моё выступление на новогоднем девклубе: [Думай как пиарщик](https://www.youtube.com/watch?v=jyPQzygMpoo&ab_channel=DEVCLUB.EU) +* Видос [Тестируем Spring с помощью Selenide](https://www.youtube.com/watch?v=M--_ziTZPQQ&ab_channel=kanezi) от kanezi +* Серия видосов на Testing Mini Bytes: [Selenide + Allure = Beautiful HTML Reports](https://www.youtube.com/watch?v=UQWQJ3dhgVI&ab_channel=TestingMiniBytes) +* Пост [Why we chose Selenide over Selenium](https://creatingvalue.substack.com/p/why-we-chose-selenide-over-selenium) от Amuthan Sakthivel + +
    + Selenide meme +
    +
    + + +[Андрей Солнцев](http://asolntsev.github.io/) + +ru.selenide.org diff --git a/content/ru/blog/2023-07-02-selenide-6.16.0.md b/content/ru/blog/2023-07-02-selenide-6.16.0.md new file mode 100644 index 000000000..e681d404d --- /dev/null +++ b/content/ru/blog/2023-07-02-selenide-6.16.0.md @@ -0,0 +1,239 @@ +--- +slug: "selenide-6.16.0" +date: 2023-07-02 +title: "Вышла Selenide 6.16.0" +description: "" +category: +headerText: "Фарш справедливости" +tags: [] +--- +Доброй ночи! + +> У меня к вам предложение, от которого лучше не отказываться. + +Обновляйтесь на [Selenide 6.16.0](https://github.com/selenide/selenide/milestone/185?closed=1)! + + +
    + +### Ускорили проверки коллекций {#speedup-collection-checks} + +Вот это крутизна! + +Как вы знаете, одна из базовых возможностей в Селениде - это проверки коллекций. Одной строчкой можно проверить сразу кучу элементов: + +```java +$$("option").shouldHave(texts("Шмякино", "Шебекино", "Шелебякино", "Шлёпкино")) +``` + +Однако **такая проверка занимает время**, если коллекция достаточно большая. + +Например, если на странице 1000 элементов `
  • a
  • c
  • ` вернет массив вида ["a", "", "c"] + +

    +Методы выборки внутренних элементов +

    + +* filterBy(Condition) возвращает коллекцию (как ElementsCollection) из только тех элементов оригинальной коллекции, которые удовлетворяют условию - например `$$("#multirowTable tr").filterBy(text("Norris"))` +* excludeWith(Condition) - например `$$("#multirowTable tr").excludeWith(text("Chuck"))` +* get(int) - возвращает n-ый элемент как `SelenideElement` +* findBy(Condition) - возвращает элемент коллекции как `SelenideElement` который удовлетворяет условию + +Более подробная информация доступна в [Selenide gitbook](https://selenide.gitbooks.io/user-guide/content/ru/selenide-api/elements-collection.html) + +

    com.codeborne.selenide.CollectionCondition + [src] + [javadoc] +

    + +Условия используются в конструкциях shouldBe / shouldHave для коллекции - объекта ElementsCollection. Рекомендуется статически импортировать используемые условия, чтобы получить все преимущества читаемого кода. + +* empty // e.g. $$("#list li").shouldBe(empty) +* size(int) // e.g. $$("#list li").shouldHave(size(10)) +* sizeGreaterThan(int) +* sizeGreaterThanOrEqual(int) +* sizeLessThan(int) +* sizeLessThanOrEqual(int) +* sizeNotEqual(int) +* texts(String... substrings) +* exactTexts(String... wholeTexts) + +Более подробная информация доступна в [Selenide gitbook](https://selenide.gitbooks.io/user-guide/content/ru/selenide-api/collection-condition.html) + + +

    com.codeborne.selenide.WebDriverRunner + [src] + [javadoc] +

    + +Этот класс содержит некоторые функции, относящиеся к браузеру: + +* isChrome() +* isFirefox() +* isHeadless() +* url() - возвращает текущий url +* source() - возвращает исходный HTML текущего окна +* getWebDriver() - возвращает обьект WebDriver (созданный Selenide автоматически или установленный пользователем), таким образом отдавая "чистый" интерфейс к Selenium, если нужно +* setWebDriver(WebDriver) - указывает Selenide использовать драйвер, созданный пользователем. С этого момента пользователь сам ответственен за закрытие драйвера. + + +Более подробная информация доступна в [Selenide gitbook](https://selenide.gitbooks.io/user-guide/content/ru/selenide-api/webdriver-runner.html) + +

    com.codeborne.selenide.Configuration + [src] + [javadoc] +

    + +Этот класс содержит конфигурации для запуска тестов, например: + +* timeout - время ожидания в миллисекундах, которое используется в явных (should/shouldNot) и неявных ожиданиях для SelenideElement, может быть изменено во время исполнения, e.g. `Configuration.timeout = 6000;` +* browser (e.g. `"chrome"`, `"ie"`, `"firefox"`) +* baseUrl +* reportsFolder +* ... + +Также можно передать конфигурационные параметры как system properties для использования в CI (continuous integration) задачах (например `-Dselenide.baseUrl=http://staging-server.com/start`) + +Более подробная информация доступна в [Selenide gitbook](https://selenide.gitbooks.io/user-guide/content/ru/selenide-api/configuration.html) + +Оставайся на связи! diff --git a/content/ru/documentation/clouds.md b/content/ru/documentation/clouds.md new file mode 100644 index 000000000..f2eb11dfc --- /dev/null +++ b/content/ru/documentation/clouds.md @@ -0,0 +1,216 @@ +--- +url: documentation/clouds.html +title : +header : Облака +cssClass: docs +headerText: > +

    Документация

    + + Облака +--- +{{< documentation-menu >}} + +
    + +#### [> Selenium Grid](#selenium-grid) +#### [> TestContainers](#testcontainers) +#### [> TestMu AI (ex. LambdaTest)](#testmu-ai) +#### [> BrowserStack](#browserstack) +#### [> Saucelabs](#saucelabs) +#### [> Moon](#moon) +#### [> Selenoid](#selenoid) +#### [> Другие облачные провайдеры](#other) + +
    +
    + +Самый простой, быстрый и надёжный способ - запускать браузер рядом с тестом (т.н. "локальный" запуск). +В крайнем случае - в докере на той же машине. + +Но люди не ищут простых путей. Иногда им хочется запускать браузер в облаках. +В теории это может дать вам некоторые плюсы: бесконечное масштабирование и запуск разных версий разных браузеров. +Но конечно, есть и свои сложности и ограничения. Смотрите сами. + +Селенид это позволяет сделать довольно легко. +Чтобы запустить браузер удалённо, в общем случае нужно задать настройку `remote`: + +```java +Configuration.remote = "https://your-cloud-provider.com/wd/hub"; +``` + + +## Selenium Grid + +Написан на Java командой Selenium. + +### Как использовать: +```xml + + com.codeborne + selenide-grid + {{< selenide-version >}} + +``` + +### Плюсы +* Работает без докера. Поддерживает все браузеры (для которых есть вебдрайвер) любых версий. +* Скалируется: можете запускать много нодов на разных ОС с разными версиями браузеров. +* Можете запускать на своих серверах и локально + +### Минусы +* Не поддерживает операции с буфером обмена + + +## TestContainers + +Позволяет одной аннотацией запускать браузер на той же машине, но внутри докера. + +Рабочий пример: [selenide-examples/testcontainers](https://github.com/selenide-examples/testcontainers/). + +Плюсы: +1. Позволяет запускать разные версии браузеров +2. Умеет записывать видео с тестов (и ещё куча фич TestContainers) +3. Большинство фич селенида продолжают работать (скриншоты, прокси, CDP и т.д.) + +Минусы: +1. Некоторые фичи селенида могут не работать (clipboard) +2. Поддерживаются только те браузеры, что в принципе способны работать в докере (Internet Explorer точно нет, насчёт Safari не уверен) + +
    + + +## TestMu AI (ex. LambdaTest) + +Рабочий пример: [selenide-examples/selenide-lambdatest](https://github.com/selenide-examples/selenide-lambdatest). +Сайт: [testmu.ai](https://www.testmu.ai/blog/selenium-testing-with-selenide-using-intellij-maven/?utm_source=selenide&utm_medium=partnered). + +Это рабочий пример тестов на селениде, которые запускают браузер на серверах TestMu AI (ex. LambdaTest). +Как видно, настройка там минимальная: + +```java + Configuration.remote = "https://hub.lambdatest.com/wd/hub"; + Configuration.browserCapabilities.setCapability("LT:Options", Map.of( + "user", "unclebob", + "accessKey", "0123456789001234567890" + )); +``` + +Плюсы: +1. Позволяет запускать разные версии браузеров + +Минусы: +1. Некоторые фичи селенида могут не работать (clipboard, прокси) + +
    + + +## BrowserStack + +Рабочий пример: [selenide-examples/selenide-browserstack](https://github.com/selenide-examples/selenide-browserstack). +Сайт: [BrowserStack.com](https://www.browserstack.com/?utm_source=selenide&utm_medium=partnered) + +Это рабочий пример тестов на селениде, которые запускают браузер на серверах BrowserStack. +Как видно, настройка там минимальная: + +```java + Configuration.remote = "https://hub-cloud.browserstack.com/wd/hub"; + Configuration.browserCapabilities.setCapability("bstack:options", Map.of( + "userName", "unclebob", + "accessKey", "0123456789001234567890" + )); +``` + +Плюсы: +1. Позволяет запускать разные версии браузеров + +Минусы: +1. Некоторые фичи селенида могут не работать (clipboard, прокси) + +
    + + +## Saucelabs + +Компания Saucelabs тоже предлагает запуск браузеров и мобильников на их серверах. + +Рабочий пример: [selenide-examples/selenide-saucelabs](https://github.com/selenide-examples/selenide-saucelabs). +Сайт: [saucelabs.com](https://saucelabs.com/) + +Плюсы: +1. Позволяет запускать разные версии браузеров + +Минусы: +1. Некоторые фичи селенида могут не работать (clipboard, прокси) + +
    + + +## Moon + +Как Selenium Grid, но в докере. И написано на Go, поэтому работает быстро и потребляет мало памяти. + +### Как использовать: +```xml + + com.codeborne + selenide-moon + {{< selenide-version >}} + +``` + +* Исходники: [на гитхабе](https://github.com/selenide/selenide/tree/main/modules/moon). +* Рабочий пример: [на гитхабе](https://github.com/selenide/selenide/tree/main/modules/moon/src/test/java/it/moon) + +### Плюсы: +1. Поддерживается Селенидом напрямую +2. Поддерживает скачивание файлов, операции с буфером обмена (фичи, которые не обязательно работают в других облаках). +3. Позволяет запускать разные версии браузеров +4. Умеет записывать видео с тестов + +### Минусы: +1. Поддерживаются только те браузеры, что в принципе способны работать в докере (Internet Explorer точно нет, насчёт Safari не уверен) + +
    + + +## Selenoid + +Как Selenium Grid, но в докере. И написано на Go, поэтому работает быстро и потребляет мало памяти. + +### Как использовать: +```xml + + com.codeborne + selenide-selenoid + {{< selenide-version >}} + +``` + +* Исходники: [на гитхабе](https://github.com/selenide/selenide/tree/main/modules/selenoid/). +* Рабочий пример: [на гитхабе](https://github.com/selenide/selenide/tree/main/modules/selenoid/src/test/java/it/selenoid) + + +### Плюсы: +1. Поддерживается Селенидом напрямую +2. Поддерживает скачивание файлов, операции с буфером обмена (фичи, которые не обязательно работают в других облаках). +3. Позволяет запускать разные версии браузеров +4. Умеет записывать видео с тестов + +### Минусы: +1. Поддерживаются только те браузеры, что в принципе способны работать в докере (Internet Explorer точно нет, насчёт Safari не уверен) + +
    + + +## Другие облачные провайдеры + +Теоретически остальные облачные провайдеры должны интегрироваться так же легко. + +Какие ещё провайдеры пробовали вы? Плюсы, минусы, подводные камни? +Расскажите, поделитесь кодом. + +И самое главное, _стоило ли оно того_? +Расскажите, какие такие проблемы решает удалённый запуск браузер, ради чего стоило поступиться скоростью, удобством и некоторыми фичами? + +
    +
    diff --git a/content/ru/documentation/page-objects.md b/content/ru/documentation/page-objects.md new file mode 100644 index 000000000..0a49eed80 --- /dev/null +++ b/content/ru/documentation/page-objects.md @@ -0,0 +1,112 @@ +--- +url: documentation/page-objects.html +title : +header : Page Objects +cssClass: docs +headerText: > +

    Документация

    + + Page Objects +--- +{{< documentation-menu >}} + +## Page Objects - это просто! + +В мире тестирования очень популярен шаблон [Page Objects](https://github.com/SeleniumHQ/selenium/wiki/PageFactory). +Суть его в том, что для каждой страницы тестируемого приложения создаётся отдельный объект, методы которого инкапсулируют логику работы с отдельными элементами. +Считается, что Page Object позволяет избежать дублирования локаторов в тестах. + +А Selenide позволяет писать более короткие и читаемые Page Objects. + +Вот как выглядит Page Object с Selenide. + +```java +public class GoogleSearchPage { + public GoogleResultsPage search(String query) { + $(By.name("q")).setValue(query).pressEnter(); + return page(GoogleResultsPage.class); + } +} + +public class GoogleResultsPage { + public ElementsCollection results() { + return $$("#ires li.g"); + } +} +``` + +Как видите, никаких ```PageFactory```, никаких ```initElements``` и прочего мусора. Ваш Page Object содержит +только вашу логику. + +А как же выглядит тест с использованием этих Page Objects? А вот так: + +```java + GoogleSearchPage searchPage = open("/login", GoogleSearchPage.class); + GoogleResultsPage resultsPage = searchPage.search("selenide"); + resultsPage.results().shouldHave(size(10)); + resultsPage.results().get(0).shouldHave(text("Selenide: Concise UI Tests in Java")); +``` + +Кто скажет, что это не просто? + +## Классический вариант Page Object + +Многим полюбился шаблон написания тестов, согласно которому на каждый веб-элемент создаётся поле в page object. +У этого подхода есть недостатки, но Selenide позволяет делать и так: + +```java +public class GoogleSearchPage { + @FindBy(how = How.NAME, using = "q") + private SelenideElement searchBox; + + public GoogleResultsPage search(String query) { + searchBox.setValue(query).pressEnter(); + return page(GoogleResultsPage.class); + } +} + +public class GoogleResultsPage { + @FindBy(how = How.CSS, using = "#ires li.g") + public ElementsCollection results; +} +``` + +### Какие такие недостатки? +Один из недостатков "классического" варианта - это недостаточно динамичный. + +Представьте, что вы пишете автотест для страницы, на которой есть английский алфавит из 26 букв. +Вы действительно хотите определить **26 полей** в классе `AlphabetPage` с аннотациями `@FindBy`? + +```java +class AlphabetPage { + @Find(By.xpath("//*[@letter='A']")) + WebElement a; + + @Find(By.xpath("//*[@letter='B']")) + WebElement b; + + // 24 more elements ... +} +``` + +И что если пользователь может менять язык, а в разных языках разное количество букв? +Или погодите, не собираетесь ли вы создать 7164 разных пэдж обжектов (под одному на каждый язык)? :) +Ах да, есть же кодогенерация, Lombok, процессинг аннотаций. Давайте, пусть ваше CV разбухнет. +Ещё AI попросите написать эти тысячи пэдж обжектов... + +**Или вы всё-таки предпочитаете написать один короткий метод?** + +```java +public void pickLetter(char letter) { + $(by("letter", letter)).click(); +} +``` + +## И напоследок про ООП +Хочу напомнить, что изначальный смысл Page Objects состоял в том, чтобы инкапсулировать (то есть прятать!) +логику работы с элементами. Тесты не должны ничего знать о веб-элементах, не должны оперировать напрямую с +XPath или другими селекторами. Тесты должны использовать публичные методы пэдж объекта. + +То есть если уж вы объявляете поля для элементов, то пусть они будут приватными, а все операции с ними пусть осуществляются через публичные методы. + +Иначе зачем весь этот ООП? diff --git a/content/ru/documentation/reports.md b/content/ru/documentation/reports.md new file mode 100644 index 000000000..fe38ad8dd --- /dev/null +++ b/content/ru/documentation/reports.md @@ -0,0 +1,143 @@ +--- +url: documentation/reports.html +title : +header : Отчёты +cssClass: docs +headerText: > +

    Документация

    + + Отчёты +--- +{{< documentation-menu >}} + +
    + +#### [> YAGNI](#yagni) +#### [> Text report](#text-report) +#### [> Allure report](#allure-report) + + +## YAGNI + +Для начала хочу предупредить, что возможно, вам вовсе не нужны никакие отчёты. + +И Maven, и Gradle генерируют достаточно хороший отчёт о прохождении тестов, в который включены все ошибки. +При падении теста Селенид генерирует подробное сообщение об ошибке (включая [скриншот](/documentation/screenshots.html) и html страницы). +Как правило, этого достаточно, чтобы понять, почему тест упал: + +``` +Element should be hidden {#gameWin} +Element: '' + +Screenshot: file:/.../hangman/build/reports/tests/1510751914648.0.png +Page source: file:/.../hangman/build/reports/tests/1510751914648.0.html +Timeout: 4 s. +``` + +
    + +Но если вы всё-таки очень хотите отчёты, можем предложить вам два варианта: "Text report" и "Allure report". + + +## 1. Text report + +Это встроенный в Селенид отчёт, который в простом текстовом виде показывает все шаги, сделанные в ходе теста: + +``` ++----------------------+---------------------------------------------+--------+----------+ +|Element |Subject |Status |ms. | ++----------------------+---------------------------------------------+--------+----------+ +|open |http://localhost:2070/ |PASSED |4669 | +|open |http://localhost:2070/fakeLogin?username=bob |PASSED |1324 | +|By.linkText: Quicky |click() |PASSED |793 | +|#btn-message-reply |click() |PASSED |1002 | +|By.name: message.text |should be(focused) |PASSED |57 | +|By.name: message.text |should have(text 'long thread') |PASSED |47 | +|By.name: message.text |set value(Hello world!) |PASSED |69 | +|#send-button |click() |PASSED |1051 | +|.alert-success |should be(visible) |PASSED |71 | ++--------------------+-----------------------------------------------+--------+----------+ +``` + +Выглядит просто, но он содержит всю необходимую информацию. +Чтобы включить такой отчёт, нужно +1. [Настроить в своём проекте slf4j](https://github.com/selenide/selenide/wiki/slf4j) (де-факто стандартный инструмент логирования в Java). +2. Добавить экстенш/рул/листенер, как показано ниже. + +#### Для JUnit 5: + +```java + import com.codeborne.selenide.junit5.TextReportExtension; + + @ExtendWith({TextReportExtension.class}) + public class MyTest { + // ... + } +``` + +#### Для JUnit 4: + +```java +import com.codeborne.selenide.junit.TextReport; + +public class MyTest { + @Rule + public TextReport textReport = new TextReport(); + + // ... +} +``` + +#### Для TestNG: + +```java +import com.codeborne.selenide.testng.TextReport; + +@Listeners({ TextReport.class}) +public class MyTest { + // ... +} +``` + + + +## 2. Allure report + +Часто автоматизаторы зачем-то хотят генерировать "красивые" отчёты. Говорят, для менеджмента. Хотя я уверен, что +это лишнее, и менеджмент эти отчёты не читает. + +Но если вы всё-таки очень хотите "красивые" отчёты, можете настроить Allure. Это популярная бесплатная библиотека от +компании [Qameta Software](https://qameta.io/), которая имеет встроенную интеграцию с Селенидом. И да, она генерирует действительно +красивые отчёты. + +Для этого вам нужно: +1. Добавить в проект зависимость `io.qameta.allure:allure-selenide:2.21.0` (или выше). +2. Добавить одну строчку в начале тестов: + +```java + @BeforeAll + static void setupAllureReports() { + SelenideLogger.addListener("AllureSelenide", new AllureSelenide()); + + // либо для тонкой настройки: + SelenideLogger.addListener("AllureSelenide", new AllureSelenide() + .screenshots(false) + .savePageSource(true) + ); + } +``` + +См. пример проекта [Selenide+Allure](https://github.com/selenide-examples/selenide-allure-junit) + +NB! Метод `SelenideLogger.addListener` должен быть вызван в том же потоке, в котором и сам тест. +Некоторые тестовые фреймворки могут вызывать методы `@BeforeAll` и `@Test` в разных потоках - тогда ваш листенер не будет ловить события из теста. +В таких случаях, возможно, стоит перенести вышеуказанный блок в метод `@Before` или даже `@Test`. + +
    +
    + +P.S. Умоляю, только не берите BDD ради красивых отчётов! +[BDD вообще не для этого](https://www.youtube.com/watch?v=JnoZbbYZeeI&ab_channel=MikalaiAlimenkou). +Только огребёте новых проблем, а свою не решите. + +
    diff --git a/content/ru/documentation/screenshots.md b/content/ru/documentation/screenshots.md new file mode 100644 index 000000000..8df7b193e --- /dev/null +++ b/content/ru/documentation/screenshots.md @@ -0,0 +1,138 @@ +--- +url: documentation/screenshots.html +title : +header : Скриншоты +cssClass: docs +headerText: > +

    Документация

    + + Скриншоты +--- +{{< documentation-menu >}} + +## Как сделать скриншот в тесте? + +Обычно это не нужно, так как **Selenide автоматически делает скриншоты** при падении тестов. Это очень удобно для анализа ошибки. + +По умолчанию Selenide складывает скриншоты в папку `build/reports/tests`. + + +### Можно ли сказать Selenide сохранять скриншоты в другую папку? + +Да. Для этого используйте ключик `-Dselenide.reportsFolder=test-result/reports` и укажите путь к нужной папке. +Для версии 4 и ниже используйте `-Dselenide.reports=test-result/reports` +Альтернативный вариант - установить путь к скриншотам прямо в своём коде: + +```java +Configuration.reportsFolder = "test-result/reports"; +``` + + +## Поддержка JUnit и TestNG + +Для пользователей JUnit и TestNG мы сделали дополнительную поддержку. + +Повторюсь: в большинстве случаев вам не надо ничего делать, т.к. Селенид сам делает скриншоты в случае падения +проверок типа `$.shouldBe(..)`. + +А вот если вы хотите делать скриншоты +1. и в случае успешных тестов, или +2. при падении не-селенидовских проверок (какой-нибудь `assertEquals` или `assertThat`), + +то придётся добавить пару строк. + +### Для JUnit 4: + +Чтобы автоматически делать скриншот после каждого упавшего теста: + +```java +import com.codeborne.selenide.junit.ScreenShooter; + +public class MyTest { + @Rule + public ScreenShooter makeScreenshotOnFailure = ScreenShooter.failedTests(); + + // ... +} +``` + +Чтобы автоматически делать скриншот после вообще каждого теста (в т.ч. зелёного): + +```java +@Rule +public ScreenShooter makeScreenshotOnFailure = ScreenShooter.failedTests().succeededTests(); +``` + +### Для TestNG: + +```java +import com.codeborne.selenide.testng.ScreenShooter; + +@Listeners({ ScreenShooter.class}) +public class MyTest { + // ... +} +``` + +Чтобы делать скриншоты после зелёных тестов, нужно вызвать такую команду перед запуском тестов: +```java +ScreenShooter.captureSuccessfulTests = true; +``` + +### Для JUnit 5: + +#### Как использовать в Java: + +```java + @ExtendWith({ScreenShooterExtension.class}) + public class MyTest { + // ... + } +``` + +Как использовать в Java (с тонкими настройками): +```java + public class MyTest { + @RegisterExtension + static ScreenShooterExtension screenshotEmAll = new ScreenShooterExtension(true).to("target/screenshots"); + } +``` + +#### Как использовать в Kotlin: +```kotlin + @ExtendWith(ScreenShooterExtension::class) + class MyTest { + // ... + } +``` + +Как использовать в Kotlin (с тонкими настройками): + +```kotlin + class MyTest { + companion object { + @JvmField + @RegisterExtension + val screenshotEmAll: ScreenShooterExtension = ScreenShooterExtension(true).to("target/screenshots"); + } + } +``` + +### В любом месте +Вы также можете сделать скриншот в любом месте теста одной строчкой: + +```java +import static com.codeborne.selenide.Selenide.screenshot; + +String pngFileName = screenshot("my_file_name"); +``` + +При этом Selenide создаст два файла: `my_file_name.png` и `my_file_name.html` + +Позже появился альтернативный метод, возвращающий скриншот в желаемом формате (т.е. `BASE64`, `BYTES` или `FILE`): + +```java +String screenshotAsBase64 = Selenide.screenshot(OutputType.BASE64); +byte[] decoded = Base64.getDecoder().decode(screenshotAsBase64); +``` + diff --git a/content/ru/documentation/selenide-vs-selenium.md b/content/ru/documentation/selenide-vs-selenium.md new file mode 100644 index 000000000..abfb8aaf3 --- /dev/null +++ b/content/ru/documentation/selenide-vs-selenium.md @@ -0,0 +1,106 @@ +--- +url: documentation/selenide-vs-selenium.html +title : +header : +cssClass: docs +headerText:

    Сравнение Selenide и Selenium

    + + Почему обычного Selenium webdriver недостаточно? + +--- +{{< documentation-menu >}} + +## Мотивация + +Selenium WebDriver - отличный инструмент. Но это не инструмент для тестирования. Это инструмент для управления браузером. + +А Selenide - удобный инструмент для автоматических тестов, построенный на базе Selenium WebDriver. + +### Почему понадобился ещё один враппер для Selenium? + +Да, есть и другие "обёртки" для Selenium webdriver. Но нам кажется, что все они не решают главные проблемы UI тестов. +А именно, нестабильность тестов, веб-приложения с динамическим контентом, JavaScript, Ajax, таймауты и т.д. +Selenide был создан для решения этих проблем. + +А ещё Selenide очень простой для изучения. С ним каждый может начать писать автоматические тесты буквально за 5 минут, +даже те, кто не имеет никакого опыта в тестировании. И даже разработчики! + +## Какие преимущества даёт Selenide по сравнению с голым Selenium WebDriver? + +Прежде всего, Selenide помогает вам делать стабильные тесты, решая (почти) все проблемы с таймаутами и аяксом. + +Selenide предлагает лаконичный API для использования Selenium WebDriver в UI тестах: + +* Умные ожидания +* Автоматическое управление браузером (открытие, закрытие - вам больше не придётся об этом думать) +* Удобные методы +* Поддержка Ajax +* Автоматические скриншоты + +Подробности ниже. + +### Автоматическое управление браузером +Вам больше не надо явно открывать браузер и думать о том, где его хранить и когда закрывать. +Selenide сам откроет браузер, когда он впервые понадобится, и закроет, когда он больше не будет нужен. + +### Удобные методы +Selenide предлагает лаконичный и мощный API, который поможет вам писать короткие и хорошо читаемые тесты. +Selenide есть масса удобных методов для заполнения полей, выбора чекбоксов, выпадающих списков, поиска элементов по тексту и т.д. + +```java +@Test +public void canFillComplexForm() { + open("/client/registration"); + $(By.name("user.name")).val("johny"); + $(By.name("user.gender")).selectRadio("male"); + $("#user.preferredLayout").selectOption("plain"); + $("#user.securityQuestion").selectOptionByText("What is my first car?"); +} +``` + +### Поддержка Ajax +При тестировании современных динамичных приложений, полных аякса и яваскрипта, нам часто нужно подождать, пока + изменится состояние какого-либо элемента. Selenide делает это из коробки. Автоматически. Вам даже не нужно задумываться + о том, требуется ли ожидание в том или ином месте. + +Все нижеследующие методы могут немножко подождать, если условие не выполнено сразу (по умолчанию до 4 секунд): + +```java + $("#topic").should(appear); + $("#topic").shouldBe(visible); + + $("#topic").should(disappear); + $("h1").shouldHave(text("Hello")); + $(".message").shouldNotHave(text("Wait for loading...")); + $(".password").shouldNotHave(cssClass("errorField")); + + $(".error").should(disappear); +``` + +### Автоматические скриншоты + +Когда тест падает, Selenide автоматически делает скриншот. Вам ничего не нужно для этого делать. + +## Больше преимуществ! + +Это лишь краткий обзор. Есть ещё +* Тесты для мобилок +* Работа с облаками (Grid/Selenoid/Moon/BrowserStack/LambdaTest/TestMu AI/...) +* Скачивание файлов +* Запись видео +* и т.д. и т.п. + +В этом видео можно узнать больше о преимуществах Selenide: + +
    + +
    + +
    + +
    + +
    + + + diff --git a/content/ru/faq.md b/content/ru/faq.md new file mode 100644 index 000000000..b6917441d --- /dev/null +++ b/content/ru/faq.md @@ -0,0 +1,205 @@ +--- +title: "ЧАВО" +header: "Часто задаваемые вопросы" +cssClass: faq +url: faq.html +headerText: "Часто задаваемые вопросы" +--- + +## Мотивация + +> Почему недостаточно Selenium webdriver + +> Зачем понадобилась ещё одна обёртка над Selenium? + +Вкратце: короче код, лучше читается, не надо переизобретать велосипед. + +И куча дополнительных фич для тестирования. +И автоматические скриншоты и отчёты. +И запись видео. +И тесты для мобилок. +И много чего ещё... + +Подробный ответ [здесь](/documentation/selenide-vs-selenium.html) + + +## Page Objects +> Можно ли использовать Пэдж Обжекты с Selenide? + +Да! Вы можете использовать Пэдж Обжекты с Selenide. + +Более того, с Selenide ваши page objects станут **короче и читабельнее**. [Тут подробности](/documentation/page-objects.html). + +## Настройки +> Где я могу найти все доступные настройки Selenide? + +Описание всех настроек и значений по умолчанию можно найти в [javadoc](https://selenide.org/javadoc/current/com/codeborne/selenide/Configuration.html). + +> Как задать настройки Selenide? + +Selenide имеет очень разумные настройки по умолчанию, которые должны быть +удобны для большинства "нормальных" проектов. + +Но если всё-таки захочется запустить тесты с другими настройками, это можно сделать либо через System property: + +``` +-Dselenide.timeout=6000 +``` + +либо программно, прямо в тестах: + +```java +public void setUp() { + Configuration.timeout = 6000; +} +``` + +Ещё можно создать файл "selenide.properties" в classpath +(в типовом проекте это значит создать файл `src/test/resources/selenide.properties`): + +```java +> cat src/test/resources/selenide.properties +selenide.timeout=6000 +selenide.browser=edge +selenide.remote=https://hub.lambdatest.com/wd/hub +selenide.textCheck=FULL_TEXT +``` + +Настройки браузера можно задавать не глобально, а каждый раз при открытии браузера: +```java +Config config = new SelenideConfig().browser("firefox").browserSize("800x600"); +open("/one", config); +``` + +[Используйте вдумчиво!](/2024/09/15/selenide-7.5.0/#new-configuration-for-every-browser) + + +## Браузеры +>Можно ли запустить тесты Selenide на Internet Explorer? А headless-браузере? + +Да. +Selenide можно запускать с любым браузером, для которого существует webdriver. Самые популярные браузеры +поддерживаются из коробки (chrome, firefox, edge, ie, safari, opera). + +Некоторые менее популярные тоже поддерживаются, но требуют пары строк конфигурации (например, htmlunit). +См. [Wiki](https://github.com/selenide/selenide/wiki/How-Selenide-creates-WebDriver). + +Другие браузеры тоже можно использовать, передав имя класса вебдрайвера (или фабрики). + +
    + +Например, чтобы запустить тесты с браузером Firefox: +```-Dselenide.browser=firefox``` + +
    + +>Как сказать Selenide использовать браузер с моим кастомным профайлом? + +Вы можете подсунуть Selenide любой экземпляр webdriver, который вы можете создать с какими угодно параметрами. +Смотри примеры на [Wiki](https://github.com/selenide/selenide/wiki/How-Selenide-creates-WebDriver). + +
    + +>Можно ли использовать Selenide в связке с Selenium Grid? + +Да, Selenide поддерживает Selenium Grid. Просто добавьте настройку при запуске тестов: +> -Dselenide.remote=https://your.grid.com:5678/wd/hub + +Большинство функционала заработает автоматически. +Но для некоторых фич (в частности, скачивания файлов) потребуется добавить зависимость `com.codeborne:selenide-grid`. + +См. [плагин selenide-grid](/2024/02/27/selenide-7.2.0/#download-files-to-folder-in-selenium-grid) + +>Можно ли использовать Selenide в связке с Selenoid? + +Да, Selenide поддерживает Selenoid. Просто добавьте настройку при запуске тестов: +> -Dselenide.remote=https://your.selenoid.com:5678/wd/hub + +Но для некоторых фич (в частности, скачивания файлов) потребуется добавить зависимость `com.codeborne:selenide-selenoid`. + +См. [плагин selenide-selenoid](https://github.com/selenide/selenide/tree/main/modules/selenoid). + +
    + +>Можно ли использовать Selenide в связке с Selenoid/Moon/BrowserStack/LambdaTest/TestMu AI/TestContainers или другими облачными провайдерами? + +Да. См. [доку](/documentation/clouds.html) + +>Можно ли использовать Selenide для тестирования мобильных приложений? + +Да, Selenide поддерживает тестирование мобильных приложений с помощью библиотеки Appium. + +Вот что вам нужно сделать: +1. Добавить в зависимости селенидовский плагин [selenide-appium](https://github.com/selenide/selenide/tree/main/modules/appium). +2. Найти рабочие примеры [на гитхабе](https://github.com/selenide-examples/selenide-appium) +3. Посмотреть презентацию [Selenide для мобилок](https://seleniumcamp.com/talk/selenide-for-web-android-and-ios/) + + +## Билд-скрипты + +>Как запустить тесты Selenide на CI - сервере непрерывной интеграции? + +Для этого нужно написать билд-скрипт. Скорее всего он у вас уже есть. +На [Wiki page](https://github.com/selenide/selenide/wiki/Build-script/) есть несколько примеров на Maven, Gradle и Ant. + + +## Скриншоты (снимок экрана) + +> Как сделать скриншот в тесте? + +См. [документация](/documentation.html) -> [Скриншоты](/documentation/screenshots.html) + +> Как сказать Selenide сохранять скриншоты в другую папку? + +См. [документация](/documentation.html) -> [Скриншоты](/documentation/screenshots.html) + + +## Вкладки/окна браузера + +> Как переключаться между разными окошками / вкладками браузера? + +Для этого можно использовать API самого Selenium WebDriver. + + * `getWebDriver().getWindowHandles()` - возвращает множество всех вкладок или окон + * `getWebDriver().getWindowHandle()` - возвращает уникальный идентификатор активной вкладки или окна. + +## Исходный код Selenide + +> Могу ли я посмотреть исходный код Selenide? + +Да. Исходный код Selenide выложен [на гитхабе](https://github.com/selenide/selenide/). + +> Могу ли я вносить изменения в Selenide? + +Конечно! На то он и open source. +* Если умеете кодить сами, смело создавайте [Pull Request](https://github.com/selenide/selenide/pulls), +* если нет - оформляйте свои пожелалки в виде [issue](https://github.com/selenide/selenide/issues). + +[Руководствуйтесь](https://github.com/selenide/selenide/blob/main/CONTRIBUTING.md) и + +Мотивируйтесь: +[Как законтрибьютить в опенсорс, чтобы не сгореть со стыда](https://www.youtube.com/watch?v=VtX7IpCHMS8&ab_channel=DEVCLUB.EU). + +## Лицензия + +> Сколько стоит Selenide? + +> Если наш заказчик потребует исходный код тестов, позволяет ли лицензия Selenide ему их передать? + +Selenide - __бесплатный__ продукт с __открытым исходным кодом__, распространяемый [по лицензии MIT](https://github.com/selenide/selenide/blob/master/LICENSE). +Проще говоря, это значит, что вы можете делать с ним всё что угодно. + +> А точно вы не сделаете Selenide платным? + +Точно. Selenide всегда будет бесплатным. + +* Во-первых, потому, что мы верим в open-source. +* Во-вторых, потому, что мы не верим, что на этом можно заработать. :) + +## Полезно почитать + +- Если у вас **Gradle**, **JUnit5**, **Allure** и **Selenide**, то вам стоит почитать [статью](https://medium.com/@rosolko/simple-allure-2-configuration-for-gradle-8cd3810658dd), где описан минимальный набор шагов и конфигураций для получения базового тестового окружения, так же можно посмотреть исходный код на [гитхабе](https://github.com/rosolko/allure-gradle-configuration). +- Так же советуем почитать [статью](https://medium.com/@rosolko/boost-you-autotests-with-fast-authorization-b3eee52ecc19) о том, как можно с помощью одного простого действия значительно ускорить ваши тесты. +- Тот же метод, только с [другой](https://medium.com/@rosolko/fast-authorization-level-local-storage-6c84e9b3cef1) реализацией. +- Хороший обзор [что лучше, явные или неявные ожидания](https://seleniumcamp.com/talk/deep-dive-into-selenium-waits/) (спойлер: плохи и те, и те - используйте селенидовские) +- Вечно полезная статья [как прочитать много данных с веб-страницы?](http://barancev.github.io/read-data-from-web-page/) (спойлер: через JavaScript) diff --git a/content/ru/javadoc.md b/content/ru/javadoc.md new file mode 100644 index 000000000..cf1f80b23 --- /dev/null +++ b/content/ru/javadoc.md @@ -0,0 +1,8 @@ +--- +title: "javadoc" +header: "javadoc" +url: javadoc.html +layout: javadoc +--- + + diff --git a/content/ru/quick-start.md b/content/ru/quick-start.md new file mode 100644 index 000000000..a24d8f71d --- /dev/null +++ b/content/ru/quick-start.md @@ -0,0 +1,86 @@ +--- +title: "С чего начать?" +header: "С чего начать?" +cssClass: howto +url: quick-start.html +headerText: > +

    Начать использовать Selenide очень просто. Не нужно читать тонны документации. Не нужно покупать тренинг.

    + + Просто добавь в проект зависимость Selenide и начинай писать тест.
    + +--- + + Как написать UI тест за 10 минут + + +### Для пользователей Maven: + +Добавь в файл pom.xml: + +```xml + + com.codeborne + selenide + {{< selenide-version >}} + test + +``` + +### Для пользователей Gradle: + +Добавь в файл build.gradle: + +```groovy +dependencies { + testImplementation 'com.codeborne:selenide:{{< selenide-version >}}' +} +``` + +## Начинай писать тест + +Вот так просто! Больше никакой волокиты, начинай писать тест. + +Импортируй нужный класс: + +```java +import static com.codeborne.selenide.Selenide.*; +import static com.codeborne.selenide.Condition.*; +``` + +и пиши тест: + +```java +@Test +public void userCanLoginByUsername() { + open("/login"); + $(By.name("user.name")).setValue("johny"); + $("#submit").click(); + $(".loading_progress").should(disappear); // Само подождёт, пока элемент исчезнет + $("#username").shouldHave(text("Hello, Johny!")); // Само подождёт, пока у элемента появится нужный текст +} +``` + +И готово! + +Можно использовать любой фреймворк по вкусу: JUnit, TestNG, Cucumber, ScalaTest, JBehave - что душа пожелает. + +Запускать как обычные юнит-тесты. Можно из IDE, можно ANT скриптом, можно "mvn test". + +### Хотите увидеть работающий пример? + +Мы создали группу [Selenide examples](https://github.com/selenide-examples) на гитхабе, в которой будут различные примеры использования Selenide: + +* для тестирования [почтовика Gmail](https://github.com/selenide-examples/gmail/tree/master/test/org/selenide/examples/gmail), +* для тестирования [поиска Google](https://github.com/selenide-examples/google/blob/master/test/org/selenide/examples/google/selenide_page_object/GoogleTest.java). +* для тестирования настоящего [интернет-банка](https://github.com/selenide-examples/selenide-allure-junit/blob/master/src/test/java/org/selenide/examples/InternetBankTest.java) +* [игра Виселица](https://github.com/selenide-examples/hangman/blob/main/test/uitest/selenide/HangmanSpec.java) - эталонный open-source проект, в котором используется Selenide + +и т.д. + +### Поделитесь с нами своими примерами! + +Если у вас есть свои примеры использования Selenide, смело присылайте их нам! +Нам было бы очень интересно на них взглянуть. + +### Видеоурок +

    Как написать UI тест за 10 минут from Selenide on Vimeo.

    Туториал по Selenide

    diff --git a/content/ru/quotes.md b/content/ru/quotes.md new file mode 100644 index 000000000..99a4ab27d --- /dev/null +++ b/content/ru/quotes.md @@ -0,0 +1,133 @@ +--- +title: "Что говорят о Selenide" +header: "Что говорят о Selenide" +cssClass: quotes +url: quotes.html +headerText: +--- + +
    + +
    +

    + "I use Selenide for 4 years already and I can't stop praising it. It's much simpler and clearer, adds syntactic sugar, I don't need to reinvent the wheel and create custom methods. I'm very grateful to those who contribute to Selenide!" +

    + Lana Petrenko
    + Senior Software Engineer In Test at Aledade, Inc. +
    + +[source] +
    + +
    + +
    +

    + "Selenide is an open-source library that can make a huge impact on and accelerate software delivery by introducing a concise API, shorter expressions, and many other capabilities. It is a wrapper around Selenium WebDriver and is designed to solve problems that Selenium cannot address." +

    + Hima Bindu Peteti, Senior SDET at Fannie Mae
    + a former developer who moved to test automation to focus on her passion. + +
    + +[source] +
    + +
    + +
    +

    + "Андрей, спасибо за селенид, это просто бомба!!" +

    + Aleksey Bobrutskov
    + QA engineer +
    + +
    + +
    +

    + "С Selenide я смог сделать очень приличную автоматизацию UI + даже с моими ограниченными познаниями в Java." +

    + Jari Heikkilä
    + Финляндия +
    + +
    + +
    +

    + "Selenide похож на подарок от близкого чуткого друга: надёжный, полезный и удобный. + Сразу видно, что его создали настоящие профессионалы, знакомые с предметом. + У нас ОЧЕНЬ много автоматизации и динамичный темп разработки. + Selenide помогает держать скорость на каждом этапе - от проектирования до обслуживания." +

    + Александр Седых
    + Отдел контроля качества Infotech Group +
    + +
    + +

    "Парни, это здорово! Жаль что раньше не попробовал Selenide. Это то что нужно в любом проекте!"

    Илья Слабый
    + +
    + +

    "Волшебный враппер для повышения продуктивности"

    kazuki-ma
    + +
    + +

    Наконец-то приличный фреймворк для вебдрайвера.

    Philippe Cambien
    + +
    + + + +
    + +![Spock and Selenide are really awesome together](/images/2013/07/spock_and_selenide_tweet.png) +![Spock and Selenide example](/images/2013/07/spock_and_selenide.jpg) + +
    + + + +
    + + + +
    + + + +
    + + + +
    + + + +
    + +
    +

    Супер полезная вещь. Очень сильно облегчает написание понятных, коротких и чётких тестов.

    +
    + + +
    + +
    +

    "Selenide - мощный инструмент для написания функциональных тестов. Рекомендую."

    +
    +
    KAUR MÄTAS,
    Инженер LiveRebel в ZeroTurnaround
    + +
    + +
    +
    +
    + + +
    +
    diff --git a/content/ru/thanks.md b/content/ru/thanks.md new file mode 100644 index 000000000..8e10b6778 --- /dev/null +++ b/content/ru/thanks.md @@ -0,0 +1,11 @@ +--- +title: "Мы говорим СПАСИБО" +header: "Thanks" +cssClass: testimonials +url: thanks.html +headerText: +--- + + diff --git a/content/ru/users.md b/content/ru/users.md new file mode 100644 index 000000000..b0c83c351 --- /dev/null +++ b/content/ru/users.md @@ -0,0 +1,8 @@ +--- +title: "Кто использует Selenide" +header: "Кто использует Selenide" +cssClass: testimonials +url: users.html +layout: users +headerText: +--- diff --git a/data/users.json b/data/users/en.json similarity index 100% rename from data/users.json rename to data/users/en.json diff --git a/data/users/ru.json b/data/users/ru.json new file mode 100644 index 000000000..100b8db82 --- /dev/null +++ b/data/users/ru.json @@ -0,0 +1,2636 @@ +[ + { + "name": "", + "id": "", + "link": "", + "logo": "", + "logoWidth": "px", + "description": "", + "source": "", + "tags": [ + ] + }, + { + "name": "Amazon", + "id": "amazon", + "link": "https://www.amazon.com/", + "logo": "logo-amazon.svg", + "logoWidth": "200px", + "description": "American multinational technology company engaged in e-commerce, cloud computing, online advertising, digital streaming, and artificial intelligence.", + "source": "https://www.linkedin.com/in/anatolii-hanziuk/", + "tags": [ + "usa", + "global", + "logistics", + "it" + ] + }, + { + "name": "Dell Technologies", + "id": "dell", + "link": "https://www.dell.com/", + "logo": "logo-dell.svg.png", + "logoWidth": "96px", + "description": "один из крупнейших в мире производителей вычислительной техники (США)", + "tags": [ + "usa", + "it" + ] + }, + { + "name": "MasterCard", + "id": "mastercard", + "link": "https://www.mastercard.us/", + "logo": "logo-mastercard.svg", + "logoWidth": "160px", + "description": "ведущая глобальная платёжная и технологическая компания, объединяющая потребителей, предприятия, торговцев, эмитентов и правительства по всему миру.", + "tags": [ + "usa", + "finances" + ] + }, + { + "name": "Paysera", + "id": "paysera", + "link": "https://paysera.com", + "logo": "logo-paysera.png", + "logoWidth": "180px", + "description": "Credit Cards & Transaction Services", + "source": "https://www.cvmarket.lt/qa-automation-engineer-kaunas-paysera-lt-uab-1141529", + "tags": [ + "finances", + "lithuania", + "europe" + ] + }, + { + "name": "IBM", + "id": "ibm", + "link": "https://www.ibm.com/us-en/", + "logo": "ibm-logo.jpeg", + "logoWidth": "140px", + "description": "\"Голубой гигант\" - один из крупнейших в мире производителей и поставщиков аппаратного и программного обеспечения, а также IТ-сервисов и консалтинговых услуг.", + "tags": [ + "usa", + "it" + ] + }, + { + "name": "General Electric", + "id": "general-electric", + "link": "https://www.ge.com/", + "logo": "logo-general-electric.png", + "logoWidth": "160px", + "description": "Американская многоотраслевая инжиниринговая корпорация (авиация, энергетика, возобновляемые источники энергии, цифровая промышленность)", + "source": "https://career.habr.com/kochetkov-ma", + "tags": [ + "usa", + "resources" + ] + }, + { + "name": "Google", + "id": "google", + "link": "https://en.wikipedia.org/wiki/Google", + "logo": "logo-google.png", + "description": "an American multinational technology company that focuses on artificial intelligence, search engine, online advertising, cloud computing etc.", + "source": "https://github.com/search?q=org%3Agoogle+selenide&type=code", + "tags": [ + "usa", + "it" + ] + }, + { + "name": "BlaBlaCar", + "id": "bla-bla-car", + "link": "https://www.blablacar.com/", + "logo": "logo-blablacar.png", + "logoWidth": "120px", + "description": "крупнейший в мире международный онлайн-сервис поиска автомобильных попутчиков", + "source": "https://app.theirstack.com/home?search-company=BlaBlaCar", + "tags": [ + "france", + "europe", + "global", + "taxi" + ] + }, + { + "name": "Gett", + "id": "gett", + "link": "http://gett.com/", + "logo": "logo-gett.png", + "logoWidth": "100px", + "description": "Gett is one of the leading taxi booking platforms operating in Israel and the United Kingdom", + "source": "https://www.linkedin.com/in/ovodenko/details/experience/", + "tags": [ + "israel", + "britain", + "taxi" + ] + }, + { + "name": "Embention", + "id": "embention", + "link": "https://embention.com/", + "logo": "logo-embention.jpeg", + "logoWidth": "220px", + "description": "производитель автопилотов и компонентов авионики для БПЛА", + "source": "https://app.theirstack.com/home?search-company=Embention", + "tags": [ + "spain", + "europe", + "military", + "manufacturing" + ] + }, + { + "name": "Inrad Optics", + "id": "inrad-optics", + "link": "https://www.inradoptics.com/", + "logo": "logo-inrad-optics.jpeg", + "logoWidth": "190px", + "description": "Advanced optical materials / Defense and Space Manufacturing", + "source": "https://app.theirstack.com/home?search-company=Inrad%20Optics", + "tags": [ + "usa", + "technology", + "military", + "manufacturing" + ] + }, + { + "name": "OpenText", + "id": "opentext", + "link": "https://www.opentext.com/", + "logo": "logo-opentext.png", + "logoWidth": "200px", + "description": "a global AI software company. Canada's fourth-largest software company.", + "source": "https://careers.opentext.com/us/en/job/49641?source=selenide.org", + "tags": [ + "canada", + "it" + ] + }, + { + "name": "AVIZVA", + "id": "avizva", + "link": "https://www.avizva.com/", + "logo": "logo-avizva.svg", + "logoWidth": "200px", + "description": "a Healthcare Technology Organization", + "source": "https://www.foundit.in/job/engineer-test-automation-avizva-gurugram-35905327", + "tags": [ + "healthcare", + "india", + "asia" + ] + }, + { + "name": "Atlys", + "id": "atlys", + "link": "https://www.atlys.com/", + "logo": "logo-atlys.png", + "logoWidth": "200px", + "description": "the world’s most delightful way to get your visas on time, guaranteed.", + "source": "https://in.indeed.com/q-selenide-jobs.html?vjk=b51d1efa15c1c393", + "tags": [ + "tourism", + "visa", + "india", + "usa" + ] + }, + { + "name": "Recruise", + "id": "recruise", + "link": "https://recruise.io/", + "logo": "logo-recruise.png", + "logoWidth": "160px", + "description": "end-to-end AI powered talent acquisition platform", + "source": "https://in.indeed.com/q-selenide-jobs.html?vjk=cd939a88bc3f796c", + "tags": [ + "india", + "hr" + ] + }, + { + "name": "Whoop, inc.", + "id": "whoop", + "link": "https://www.whoop.com/", + "logo": "logo-whoop.png", + "logoWidth": "180px", + "description": "an American wearable technology company headquartered in Boston, Massachusetts.", + "source": "https://jobs.lever.co/whoop/71b76796-5544-4700-8852-01b77552e522", + "tags": [ + "usa", + "healthcare" + ] + }, + { + "name": "Natera", + "id": "natera", + "link": "https://www.natera.com/", + "logo": "logo-natera.svg", + "logoWidth": "200px", + "description": "A global leader in cell-free DNA testing", + "source": "https://rubrain.com/profile/J95rbY4", + "tags": [ + "usa", + "healthcare" + ] + }, + { + "name": "Brüel & Kjær", + "id": "bruel-and-kaer", + "link": "https://www.hbkworld.com/", + "logo": "logo-bruel-and-kaer.jpeg", + "logoWidth": "100px", + "description": "a Danish engineering and electronics company. It was the largest producer in the world of equipment for acoustic and vibrational measurements.", + "source": "https://theirstack.com/en/technology/selenide/dk", + "tags": [ + "denmark", + "europe", + "manufacturing" + ] + }, + { + "name": "Corning", + "id": "corning", + "link": "https://www.corning.com/worldwide/en.html", + "logo": "logo-corning.png", + "logoWidth": "180px", + "description": "производство специальных стекол, керамики и передовой оптики для промышленного и научного применения", + "source": "https://app.theirstack.com/home?search-company=Corning", + "tags": [ + "usa", + "manufacturing" + ] + }, + { + "name": "Luxium Solutions", + "id": "luxium-solutions", + "link": "https://luxiumsolutions.com/", + "logo": "logo-luxium.svg", + "logoWidth": "200px", + "description": "a worldwide technology leader and provider of high-performance crystals used in photonics and radiation detection applications", + "source": "https://app.theirstack.com/home?search-company=Luxium%20Solutions,%20LLC", + "tags": [ + "usa", + "manufacturing" + ] + }, + { + "name": "CPS Energy", + "id": "cps-energy", + "link": "https://www.cpsenergy.com/", + "logo": "logo-cps-energy.svg", + "logoWidth": "200px", + "description": "муниципальная электроэнергетическая компания, Сан-Антонио, Техас.", + "source": "https://app.theirstack.com/home?search-company=CPS%20Energy", + "tags": [ + "usa", + "resources" + ] + }, + { + "name": "Wiley", + "id": "wiley", + "link": "https://www.wiley.com/", + "logo": "logo-wiley.svg", + "logoWidth": "160px", + "description": "международное издательство, специализируется на выпуске академических изданий для студентов и преподавателей высших учебных заведений, исследователей, учёных, медиков.", + "source": "https://app.theirstack.com/home?search-company=Wiley", + "tags": [ + "usa" + ] + }, + { + "name": "Grid Dynamics", + "id": "grid-dynamics", + "link": "https://www.griddynamics.com/", + "logo": "logo-grid-dynamics.svg", + "logoWidth": "210px", + "description": "technology consulting, platform engineering, AI, and digital engagement services", + "source": "https://app.theirstack.com/home?search-company=Grid%20Dynamics", + "tags": [ + "usa", + "it" + ] + }, + { + "name": "Perfect Art", + "id": "perfect-art", + "link": "http://perfectart.com", + "logo": "logo-perfect-art.jpeg", + "logoWidth": "80px", + "description": "IT Services and IT Consulting, London", + "source": "https://www.linkedin.com/in/ksadomtsev/details/experience/", + "tags": [ + "britain", + "serbia", + "europe", + "it" + ] + }, + { + "name": "Oril", + "id": "oril", + "link": "https://oril.co", + "logo": "logo-oril.svg", + "logoWidth": "80px", + "description": "ПО на заказ: недвижимость, строительство, аналитика данных и экологичные технологии", + "source": "https://oril.co/blog/ui-testing-with-selenide/", + "tags": [ + "it", + "usa", + "ukraine" + ] + }, + { + "name": "DataArt", + "id": "data-art", + "link": "https://www.dataart.com/", + "logo": "logo-dataart.png", + "logoWidth": "250px", + "description": "a global software engineering firm with customers including Nasdaq, Travelport, Ocado, Centrica/Hive, Paddy Power Betfair, IWG, Univision, Meetup and Apple Leisure Group.", + "source": "https://www.dataart.team/vacancies/QAA00162?utm_source=selenide.org", + "tags": [ + "usa", + "ukraine", + "it" + ] + }, + { + "name": "Capgemini", + "id": "capgemini", + "link": "https://www.capgemini.com/", + "logo": "logo-capgemini.png", + "logoWidth": "240px", + "description": "одна из крупнейших в мире консалтинговых компаний в сфере менеджмента и IT", + "source": "https://app.theirstack.com/home?search-company=Capgemini", + "tags": [ + "it", + "global", + "europe", + "france", + "usa" + ] + }, + { + "name": "Deloitte Consulting", + "id": "deloitte", + "link": "https://www.deloitte.com/", + "logo": "logo-deloitte.png", + "logoWidth": "160px", + "description": "Business Consulting and Services", + "source": "https://www.linkedin.com/in/varun-bali-891b1985/", + "tags": [ + "it", + "usa", + "canada", + "india", + "asia" + ] + }, + { + "name": "Alpega Group", + "id": "alpega", + "link": "https://www.alpegagroup.com", + "logo": "logo-alpega.png.webp", + "logoWidth": "180px", + "description": "a global logistics software company", + "source": "https://rubrain.com/profile/EoZznxo", + "tags": [ + "usa", + "europe", + "asia", + "logistics" + ] + }, + { + "name": "Qvalon Inc.", + "id": "qvalon", + "link": "https://qvalon.com/", + "logo": "logo-qvalon.png", + "logoWidth": "220px", + "description": "a SaaS to manage, analyse and improve retailers' in-store operations", + "source": "https://rubrain.com/profile/39MjzD4", + "tags": [ + "usa", + "logistics" + ] + }, + { + "name": "Spiral Scout", + "id": "spiral-scout", + "link": "https://spiralscout.com/", + "logo": "spiral-scout-logo.svg", + "logoWidth": "180px", + "description": "Web Design and Development; creators of Spiral Framework", + "source": "https://spiralscout.com/case/software-testing-solution-for-demo-automation-software", + "tags": [ + "usa", + "it" + ] + }, + { + "name": "AlphaSense", + "id": "alpha-sense", + "link": "https://www.alpha-sense.com/", + "logo": "logo-alpha-sense.svg", + "logoWidth": "200px", + "description": "The market intelligence solution for leading consulting companies", + "source": "https://app.theirstack.com/home?search-company=AlphaSense", + "tags": [ + "usa", + "it" + ] + }, + { + "name": "Inter Cars S.A.", + "id": "inter-cars", + "link": "https://intercars.com/en", + "logo": "logo-inter-cars.webp", + "logoWidth": "160px", + "description": "ведущий дистрибьютор автомобильных запчастей в Центральной и Восточной Европе", + "source": "https://app.theirstack.com/home?search-company=Inter%20Cars%20S.A.", + "tags": [ + "poland", + "europe" + ] + }, + { + "name": "Sysco", + "id": "sysco", + "link": "https://en.wikipedia.org/wiki/Sysco", + "logo": "logo-sysco.png", + "logoWidth": "160px", + "description": "American multinational corporation, a global leader in food service, educational facilities, sports stadiums. Houston, Texas.", + "source": "https://careers.sysco.com/en/job/texas/mobile-quality-engineer/1105/85961557456", + "tags": [ + "food", + "usa", + "global" + ] + }, + { + "name": "Digital Turbine", + "id": "digital-turbine", + "link": "http://www.digitalturbine.com/", + "logo": "logo-digital-turbine.jpeg", + "logoWidth": "100px", + "description": "independent mobile growth platform headquartered in Austin, Texas", + "source": "https://www.linkedin.com/in/serge-soloshchenko/", + "tags": [ + "usa", + "poland", + "europe", + "global", + "it" + ] + }, + { + "name": "Rohlik Group", + "id": "rohlik", + "link": "https://www.rohlik.group/", + "logo": "logo-rohlik-group.svg", + "logoWidth": "100px", + "description": "европейский лидер в области технологий электронной торговли продуктами питания", + "source": "https://app.theirstack.com/home?search-company=Rohlik%20Group", + "tags": [ + "czech", + "europe", + "food" + ] + }, + { + "name": "PrivatBank", + "id": "privat-bank", + "link": "https://privatbank.ua/about", + "logo": "logo-privat-bank.png", + "logoWidth": "220px", + "description": "Крупнейший банк Украины", + "source": "https://djinni.co/jobs/762628-middle-general-qa-liqpay/", + "tags": [ + "ukraine", + "europe", + "finances", + "it" + ] + }, + { + "name": "Credit Dnipro Bank", + "id": "credit-dnipro-bank", + "link": "http://www.creditdnepr.com.ua", + "logo": "logo-credit-dnepr-bank.jpeg", + "logoWidth": "170px", + "description": "Украинский коммерческий банк, в TOP-17 финансовых учреждений по размеру активов.", + "source": "https://www.linkedin.com/in/mykhailo-ishchuk-64581423a/", + "tags": [ + "ukraine", + "finances", + "it" + ] + }, + { + "name": "Moondigo Sp. z o.o.o", + "id": "moondigo", + "link": "https://www.moondigo.com/", + "logo": "logo-moondigo.webp", + "logoWidth": "120px", + "description": "DevSecOps | Managed Service | CyberSecurity | Near Shoring | IT Outsourcing | Delivery Hubs", + "source": "https://nofluffjobs.com/company/moondigo-o-j4plfyi8", + "tags": [ + "poland", + "europe", + "it" + ] + }, + { + "name": "Scalo", + "id": "scalo", + "link": "https://www.scalosoft.com/", + "logo": "logo-scalo.webp", + "logoWidth": "160px", + "description": "Software Development Company", + "source": "https://nofluffjobs.com/job/automation-tester-qa-java-scalo-katowice-4", + "tags": [ + "poland", + "europe", + "it" + ] + }, + { + "name": "Sii", + "id": "sii", + "link": "https://sii.pl/en/", + "logo": "logo-si.jpg", + "logoWidth": "120px", + "description": "Technology consulting, digital transformation, engineering and business services", + "source": "https://nofluffjobs.com/job/java-developer-in-test-investment-banking-project-sii-polska-cracow", + "tags": [ + "poland", + "sweden", + "scandinavia", + "ukraine", + "europe", + "it" + ] + }, + { + "name": "Bridge", + "id": "bridge", + "link": "https://www.getbridge.com/", + "logo": "logo-bridge.webp", + "description": "a learning management system designed to make training easy and effective", + "source": "https://nofluffjobs.com/cz/job/senior-software-engineer-in-test-get-bridge-budapest-1?lang=en", + "tags": [ + "hungary", + "britain", + "india", + "europe", + "usa", + "asia", + "it" + ] + }, + { + "name": "Proxet", + "id": "proxet", + "link": "https://www.proxet.com/", + "logo": "logo-proxet.svg", + "logoWidth": "200px", + "description": "Разработка веб-сайтов, мобильных приложений и программного обеспечения", + "source": "https://nation.proxet.com/careers/senior-qa-ba-engineer-4", + "tags": [ + "ukraine", + "poland", + "europe", + "usa", + "it" + ] + }, + { + "name": "Upwind", + "id": "upwind", + "link": "https://www.upwind.io/", + "logo": "logo-upwind.svg", + "logoWidth": "160px", + "description": "The Cloud Native Security Platform", + "source": "https://djinni.co/jobs/716164-automation-qa-engineer-java-selenide-selenium/", + "tags": [ + "ukraine", + "europe", + "usa" + ] + }, + { + "name": "SecureOffice", + "id": "secure-office", + "link": "https://secureoffice.com/", + "logo": "logo-secure-office.svg", + "logoWidth": "160px", + "description": "document management cyber security (San Francisco)", + "source": "https://career.habr.com/artmelnikov", + "tags": [ + "usa", + "it" + ] + }, + { + "name": "GoHealth", + "id": "gohealth", + "link": "https://www.gohealth.com/", + "logo": "logo-go-health.png", + "logoWidth": "180px", + "description": "marketplace for Medicare plans and health insurance", + "source": "https://app.theirstack.com/home?search-company=GoHealth", + "tags": [ + "usa", + "healthcare", + "insurance" + ] + }, + { + "name": "Virtual Health", + "id": "virtual-health", + "link": "https://www.virtualhealth.com/", + "logo": "logo-virtual-health.png", + "logoWidth": "220px", + "description": "Системная интеграция медицинских компаний (Нью-Йорк, США)", + "source": "https://career.habr.com/olgachert", + "tags": [ + "usa", + "healthcare" + ] + }, + { + "name": "Aledade", + "id": "aledade", + "link": "https://www.aledade.com", + "logo": "logo-aledade.jpeg", + "logoWidth": "140px", + "description": "Услуги здравоохранения, Бетесда, Мэриленд, США.", + "tags": [ + "usa", + "healthcare" + ] + }, + { + "name": "Whimstay", + "id": "whimstay", + "link": "https://whimstay.com", + "logo": "logo-whimstay.png", + "logoWidth": "160px", + "description": "горящие предложения по аренде на время отпуска, Сан-Франциско.", + "source": "https://career.habr.com/igorek9191", + "tags": [ + "usa" + ] + }, + { + "name": "Alyce", + "id": "alyce", + "link": "https://www.alyce.com/careers/", + "logo": "logo-alyce.png", + "description": "a personal gifting platform (Boston, Massachusetts).", + "source": "https://alyce.applytojob.com/apply/lYngDM1QfS/QA-Automation-Engineer-Application-Development-Location-Flexible-US", + "tags": [ + "usa" + ] + }, + { + "name": "RealAtom", + "id": "realatom", + "link": "https://realatom.com/", + "logo": "logo-real-atom.png", + "description": "the first online marketplace for commercial real estate loans (Washington, DC)", + "source": "https://career.habr.com/bogachevvy", + "tags": [ + "usa" + ] + }, + { + "name": "Wallet One", + "id": "wallet-one", + "link": "https://www.walletone.com/ru/wallet/", + "logo": "logo-walletone.png", + "logoWidth": "160px", + "description": "международный платёжный сервис № 1.", + "tags": [ + "usa", + "finances" + ] + }, + { + "name": "Elinext", + "id": "elinext", + "link": "https://www.elinext.com/", + "logo": "logo-elinext.png", + "logoWidth": "180px", + "description": "Software Development Company", + "source": "https://rubrain.com/profile/goQBwQ9", + "tags": [ + "usa", + "asia", + "europe", + "poland", + "it" + ] + }, + { + "name": "Transaction Junction", + "id": "transaction-junction", + "link": "https://transactionjunction.co.za/", + "logo": "logo-transaction-junction.png", + "logoWidth": "96px", + "description": "Компания по разработке программного обеспечения в Кейптауне (Южная Африка)", + "tags": [ + "africa", + "it" + ] + }, + { + "name": "CGI", + "id": "cgi", + "link": "https://www.cgi.com/", + "logo": "logo-cgi.jpeg", + "logoWidth": "100px", + "description": "one of the largest IT and business consulting services firms in the world", + "source": "https://app.theirstack.com/home?search-company=CGI", + "tags": [ + "canada", + "europe", + "it" + ] + }, + { + "name": "Unlimit", + "id": "unlimit", + "link": "https://www.unlimit.com/", + "logo": "logo-unlimit.svg", + "logoWidth": "140px", + "description": "global payment infrastructure for eCommerce", + "source": "https://app.theirstack.com/home?search-company=Unlimint", + "tags": [ + "britain", + "finances", + "it" + ] + }, + { + "name": "KoronaPay Europe", + "id": "korona-pay", + "link": "https://koronapay.com/", + "logo": "logo-korona-pay.svg.png", + "logoWidth": "180px", + "description": "online money transfer service", + "source": "https://www.linkedin.com/posts/tatsianadavydzenka_qa-%D0%B0qa-vacancy-activity-6876268590065041408-2Lgc/", + "tags": [ + "europe", + "cyprus", + "finances" + ] + }, + { + "name": "SavvyMatics", + "id": "savvymatics", + "link": "https://savvymatics.com/", + "logo": "logo-savvy-matics.jpeg", + "logoWidth": "110px", + "description": "Разработка мобильных и веб продуктов (Канада, Россия)", + "source": "https://savvymatics.com/qa-engineer-bank-a", + "tags": [ + "canada", + "russia", + "finances", + "it" + ] + }, + { + "name": "Blueberries Consulting", + "id": "blueberries", + "link": "https://www.blueberrycs.com/", + "logo": "logo-blueberry-consulting.png", + "logoWidth": "260px", + "description": "full-cycle technology services with niche and emerging technologies (Birmingham, Britain)", + "source": "https://career.habr.com/ctac63", + "tags": [ + "britain", + "europe", + "it" + ] + }, + { + "name": "Unbiased", + "id": "unbiased", + "link": "https://www.unbiased.co.uk/pro/", + "logo": "logo-unbiasedpro.svg", + "logoWidth": "240px", + "description": "Internet Publishing (London)", + "source": "https://www.linkedin.com/in/olga-alferova-66b17a15a/", + "tags": [ + "britain", + "europe" + ] + }, + { + "name": "Lingoda GmbH", + "id": "lingoda", + "link": "https://www.lingoda.com/ru/", + "logo": "logo-lingoda.png", + "logoWidth": "180px", + "description": "online language school founded in Berlin: German, English, French, Spanish, Italian.", + "source": "https://www.linkedin.com/in/daria-elfimova/details/experience/", + "tags": [ + "germany", + "europe", + "education" + ] + }, + { + "name": "Valamis", + "id": "valamis", + "link": "https://www.valamis.com/", + "logo": "logo-valamis.png", + "logoWidth": "220px", + "description": "цифровые обучающие решения для крупных организаций (Финляндия, Россия, Германия, Нидерланды, Индия, Великобритания, США)", + "source": "https://career.habr.com/1001001", + "tags": [ + "finland", + "scandinavia", + "russia", + "global", + "education" + ] + }, + { + "name": "iute", + "id": "iute", + "link": "https://iute.com/about-us/solutions/", + "logo": "logo-iute-credit.png", + "logoWidth": "200px", + "description": "финансовая компания, предлагающая кредиты на Балканах и в Молдове. Основана в Эстонии в 2008 году.", + "source": "https://www.linkedin.com/in/risto-porila/", + "tags": [ + "europe", + "finances" + ] + }, + { + "name": "Prosper Funding LLC", + "id": "prosper-funding", + "link": "https://www.prosper.com/", + "logo": "logo-prosper.png", + "logoWidth": "180px", + "description": "Personal Loans & Other Online Financial Solutions / San Francisco", + "source": "https://smartbrain.io/profile/R6AZQbo", + "tags": [ + "usa", + "finances" + ] + }, + { + "name": "BetterMe", + "id": "betterme", + "link": "https://betterme.world/", + "logo": "logo-better-me.png", + "logoWidth": "220px", + "description": "Health Coaching and Mental Health", + "source": "https://app.theirstack.com/home?search-company=BetterMe", + "tags": [ + "ukraine", + "europe", + "healthcare" + ] + }, + { + "name": "River soft", + "id": "river-soft", + "link": "https://river-soft.net/", + "logo": "logo-river-soft.png", + "logoWidth": "180px", + "description": "українська продуктова IT-компанія", + "source": "https://rubrain.com/profile/EoZznxo", + "tags": [ + "ukraine", + "it" + ] + }, + { + "name": "Aimprosoft", + "id": "aimprosoft", + "link": "https://www.aimprosoft.com/services/it-outsourcing/", + "logo": "logo-aimprosoft.svg", + "logoWidth": "200px", + "description": "IT Outsourcing Company", + "source": "https://www.aimprosoft.com/services/it-outsourcing/", + "tags": [ + "ukraine", + "it" + ] + }, + { + "name": "Solid gate", + "id": "solid-gate", + "link": "https://solidgate.com/", + "logo": "logo-solidgate.png", + "logoWidth": "200px", + "description": "Smart Online Payments", + "source": "https://jobs.dou.ua/companies/solid/vacancies/132145/", + "tags": [ + "ukraine", + "finances" + ] + }, + { + "name": "Skelia", + "id": "skelia", + "link": "https://www.skelia.com", + "logo": "logo-skelia.png", + "logoWidth": "100px", + "description": "a global IT company providing software development, quality assurance, consulting and outsourcing services", + "source": "https://rubrain.com/profile/EoZznxo", + "tags": [ + "ukraine", + "europe", + "it" + ] + }, + { + "name": "SoftServe", + "id": "softserve", + "link": "https://www.softserveinc.com/en-us", + "logo": "softserve-logo.png", + "description": "украинская ИТ компания, работающая в сфере разработки программного обеспечения и предоставления консультационных услуг.", + "source": "https://dou.ua/forums/topic/49915/", + "tags": [ + "ukraine", + "usa", + "global", + "it" + ] + }, + { + "name": "Provectus", + "id": "provectus", + "link": "https://careers.provectus.com/jobs/", + "logo": "logo-provectus-ua.svg", + "logoWidth": "200px", + "description": "Artificial Intelligence consultancy and solutions provider", + "source": "https://www.facebook.com/provectuslife/posts/2830387173641166/,https://drive.google.com/file/d/14AUphaV_diRFSE-uUlT9Z_iAtd2uERSu/view", + "tags": [ + "ukraine", + "usa" + ] + }, + { + "name": "DeviQA", + "id": "deviqa", + "link": "https://www.deviqa.com/", + "logo": "logo-deviqa.jpeg", + "description": "one of the global leaders in Quality Assurance and Testing", + "source": "https://www.g2.com/products/deviqa/reviews", + "tags": [ + "ukraine", + "it" + ] + }, + { + "name": "VEON", + "id": "veon", + "link": "https://www.veon.com/", + "logo": "logo-veon.svg", + "logoWidth": "200px", + "description": "a global digital operator with ~160 million customers", + "source": "https://rubrain.com/profile/e9q2xa4", + "tags": [ + "europe", + "netherlands", + "ukraine", + "asia" + ] + }, + { + "name": "ING", + "id": "ing", + "link": "https://www.ing.com/", + "logo": "logo-ing.svg.png", + "logoWidth": "160px", + "description": "a Dutch multinational banking and financial services corporation", + "source": "https://app.theirstack.com/home?search-company=ING", + "tags": [ + "finances", + "netherlands", + "europe" + ] + }, + { + "name": "DICTU", + "id": "dictu", + "link": "https://www.dictu.nl/", + "logo": "logo-dictu.webp", + "logoWidth": "210px", + "description": "один из крупнейших поставщиков ИКТ-услуг в системе центрального правительства Нидерландов", + "source": "https://app.theirstack.com/home?search-company=DICTU", + "tags": [ + "government", + "netherlands", + "europe", + "it" + ] + }, + { + "name": "Symphony Solutions", + "id": "symphony", + "link": "https://symphony-solutions.com/", + "logo": "logo-symphony-solutions.jpeg", + "logoWidth": "70px", + "description": "a Cloud and AI-driven IT company headquartered in the Netherlands. Custom iGaming, Healthcare, and Airline solutions.", + "source": "https://www.linkedin.com/in/artem-aksani/details/experience/", + "tags": [ + "netherlands", + "poland", + "europe", + "it", + "gambling", + "healthcare" + ] + }, + { + "name": "TBC", + "id": "tbc", + "link": "https://www.tbcbank.ge/web/en/web/guest/personal-banking", + "logo": "logo-tbc-bank.png", + "description": "один из крупнейших банков Грузии (Тбилиси)", + "source": "", + "tags": [ + "georgia", + "europe", + "finances" + ] + }, + { + "name": "HSBC", + "id": "hsbc", + "link": "https://www.hsbc.com/", + "logo": "logo-hsbc.webp", + "description": "one of the world’s largest banking and financial services organisations", + "source": "https://freakingrocky.com/", + "tags": [ + "poland", + "europe", + "finances" + ] + }, + { + "name": "Яндекс", + "id": "yandex", + "link": "https://yandex.ru/", + "logo": "logo-yandex.svg", + "logoWidth": "100px", + "description": "российская транснациональная ИТ компания: поиск информации, навигация, электронная коммерция, развлечения и облачные технологии.", + "source": "https://www.linkedin.com/posts/activity-7377287901664923649-tOJG/", + "tags": [ + "russia", + "it" + ] + }, + { + "name": "Qiwi", + "id": "qiwi", + "link": "https://qiwi.com/", + "logo": "logo-qiwi.svg.png", + "logoWidth": "220px", + "description": "Ведущий платёжный сервис в России и странах СНГ", + "source": "https://career.habr.com/vacancies/1000098960", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "Гринатом", + "id": "greenatom", + "link": "https://www.greenatom.ru/", + "logo": "logo-green-atom.png", + "logoWidth": "180px", + "description": "ведущий ИТ-интегратор Госкорпорации «Росатом»", + "source": "https://career.habr.com/aykoryakin", + "tags": [ + "russia", + "it" + ] + }, + { + "name": "Мир Plat.Form", + "id": "mir-platform", + "link": "https://mir-platform.ru/", + "logo": "logo-mir-platform.svg", + "logoWidth": "180px", + "description": "Инструменты и сервисы Национальной системы платёжных карт МИР", + "source": "https://career.habr.com/vacancies/1000100343", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "МТС", + "id": "mts", + "link": "https://career.habr.com/companies/mts", + "logo": "logo-mts.png", + "logoWidth": "200px", + "description": "крупнейшая телекоммуникационная компания в России и странах СНГ", + "source": "https://career.habr.com/feverhowl", + "tags": [ + "russia", + "telecom" + ] + }, + { + "name": "Центр Финансовых Технологий (ЦФТ)", + "id": "cft", + "link": "https://team.cft.ru/", + "logo": "logo-cft.png", + "logoWidth": "220px", + "description": "Крупнейшая IT-компания на финансовом рынке России", + "source": "https://career.habr.com/masta54", + "tags": [ + "it", + "finances", + "russia" + ] + }, + { + "name": "Ростелеком", + "id": "rostelekom", + "link": "https://rtkit.ru/", + "logo": "logo-rostelekom.png", + "logoWidth": "220px", + "description": "Wink, ЕГЭ, «Умный дом» и «Ключ»", + "source": "https://career.habr.com/jeckons", + "tags": [ + "russia", + "it", + "telecom" + ] + }, + { + "name": "Глонасс мобайл", + "id": "glonass", + "link": "https://gmdp.ru/index.html", + "logo": "logo-glonass-mobile.png", + "logoWidth": "140px", + "description": "платформа мобильной дистрибуции ГЛОНАСС (GMDP)", + "source": "https://career.habr.com/alexseyprohin", + "tags": [ + "russia", + "telecom" + ] + }, + { + "name": "IT Basis", + "id": "it-basis", + "link": "http://it-basis.com/", + "logo": "logo-it-basis.png", + "description": "поддержка и развитие существующих CRM решений Заказчиков на базе продукта Microsoft Dynamics CRM.", + "source": "https://www.linkedin.com/in/sergei-tolmachev-21732a160/", + "tags": [ + "russia", + "it" + ] + }, + { + "name": "Центробанк", + "id": "central-bank-of-russia", + "link": "https://cbr.ru/", + "logo": "logo-cbr.png", + "logoWidth": "120px", + "description": "центральный банк российской федерации", + "source": "https://rubrain.com/profile/L9DylW4", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "Тинькофф Банк", + "id": "tinkoff", + "link": "https://www.tinkoff.ru/", + "logo": "logo-tinkoff-bank.png", + "logoWidth": "160px", + "description": "Крупнейший в мире онлайн-банк (по количеству клиентов)", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "Райффайзенбанк", + "id": "raiffeisen", + "link": "https://www.raiffeisen.ru/", + "logo": "logo-raiffeisen-bank.svg.png", + "logoWidth": "180px", + "description": "International Bank Holding from Austria", + "source": "https://www.linkedin.com/in/nikita-kryvenko-3896192b0/", + "tags": [ + "austria", + "europe", + "russia", + "ukraine", + "finances" + ] + }, + { + "name": "Банк «Кубань Кредит»", + "id": "bank-kuban-kredit", + "link": "https://kb.kk.bank/", + "logo": "logo-kuban-kredit.png", + "logoWidth": "160px", + "description": "один из самых активных и растущих банков Краснодарского края. Постоянно внедряет новые компьютерные технологии!", + "source": "https://www.linkedin.com/in/verakosheleva/", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "Банк «Открытие»", + "id": "otkritie", + "link": "https://www.open.ru/", + "logo": "logo-bank-oktrytie.png", + "logoWidth": "220px", + "description": "в топ-10 крупнейших банков России", + "source": "https://career.habr.com/vacancies/1000100441", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "Газпромбанк Инвестиции", + "id": "gazprombank-investments", + "link": "https://gazprombank.investments/", + "logo": "logo-gazprombank-investments.png", + "logoWidth": "200px", + "description": "сервис для инвестиций на фондовом и валютном рынке", + "source": "https://career.habr.com/vacancies/1000103633", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "ВТБ Банк", + "id": "vtb", + "link": "https://www.vtb.ru/", + "logo": "logo-vtb-bank.svg", + "logoWidth": "120px", + "description": "российский универсальный коммерческий банк c государственным участием", + "source": "https://rubrain.com/profile/v6mxzj4", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "T1 Cloud", + "id": "t1", + "link": "https://t1-cloud.ru", + "logo": "logo-t1-cloud.svg", + "description": "Российский облачный провайдер", + "source": "https://pub.recruitcoders.com/3tn7-injener-po-testirovaniu-qa/", + "tags": [ + "russia", + "it" + ] + }, + { + "name": "Magenta Technology", + "id": "magenta", + "link": "https://magenta-technology.ru/", + "logo": "logo-magenta.png", + "logoWidth": "160px", + "description": "лидер в автоматизации логистики в составе международной продуктовой компании с офисами в Самаре и Лондоне", + "tags": [ + "russia", + "europe", + "logistics" + ] + }, + { + "name": "VK Group", + "id": "vk", + "link": "https://vk.com/", + "logo": "logo-vk.svg.png", + "logoWidth": "220px", + "description": "ВКонтакте, Одноклассники, Delivery Club, Ситимобил, GeekBrains, Skillbox - всего более 200 проектов.", + "tags": [ + "russia", + "taxi", + "it" + ] + }, + { + "name": "ЛокоТех-Сигнал", + "id": "locotech", + "link": "https://tmhsmart.ru/", + "logo": "logo-locotech-signal.jpeg", + "logoWidth": "200px", + "description": "системы управления движением рельсового транспорта в России и СНГ", + "source": "https://career.habr.com/nshakirov123", + "tags": [ + "russia" + ] + }, + { + "name": "Детский мир", + "id": "children-world", + "link": "https://www.detmir.ru/", + "logo": "logo-detskij-mir.png", + "logoWidth": "180px", + "description": "Российская сеть магазинов товаров для детей", + "source": "https://career.habr.com/vacancies/1000073158", + "tags": [ + "russia" + ] + }, + { + "name": "Kvando Technologies", + "id": "kvando-tech", + "link": "https://www.kvando.tech/en", + "logo": "logo-kvando-tech.webp", + "logoWidth": "180px", + "description": "Цифровые решения для финтеха, здравоохранения, торговых площадок и телекоммуникаций", + "source": "https://hh.ru/vacancy/121477509", + "tags": [ + "it", + "finances", + "russia" + ] + }, + { + "name": "Iiko", + "id": "iiko", + "link": "https://iiko.ru/", + "logo": "logo-iiko.webp", + "logoWidth": "200px", + "description": "Программное обеспечение для автоматизации ресторанов", + "source": "https://www.linkedin.com/in/yura-primyshev/", + "tags": [ + "russia", + "food", + "it" + ] + }, + { + "name": "Перекрёсток", + "id": "perekrestok", + "link": "https://career.habr.com/companies/perekrestok-ru", + "logo": "logo-perekrestok.png", + "logoWidth": "180px", + "description": "крупнейшая российская сеть супермаркетов, онлайн-супермаркет и сервис доставки.", + "source": "https://career.habr.com/leramt", + "tags": [ + "russia", + "retail" + ] + }, + { + "name": "Группа «М.Видео-Эльдорадо»", + "id": "mvideo-eldorado", + "link": "https://mvideoeldorado.ru/ru/", + "logo": "logo-mvideo-eldorado.jpg", + "logoWidth": "350px", + "description": "Крупнейший продавец бытовой техники и электроники в России", + "source": "https://www.linkedin.com/in/ivsvetlana/", + "tags": [ + "russia", + "retail" + ] + }, + { + "name": "Северсталь", + "id": "severstal", + "link": "https://www.severstal.com/rus/", + "logo": "logo-severstal.png", + "logoWidth": "200px", + "description": "горнодобывающая и металлургическая компания, Череповец", + "tags": [ + "russia", + "resources" + ] + }, + { + "name": "ImmoViewer", + "id": "immo-viewer", + "link": "https://www.immoviewer.com/", + "logo": "logo-immoviewer.png", + "logoWidth": "140px", + "description": "Automated video creation & simple, affordable 3D 360° tours", + "source": "https://career.habr.com/nastenkomisha", + "tags": [ + "usa" + ] + }, + { + "name": "The MathWorks Inc", + "id": "mathworks", + "link": "https://www.mathworks.com/", + "logo": "mathworks-logo.jpeg", + "logoWidth": "256px", + "description": "Создатели MATLAB и Simulink", + "source": "https://us.bebee.com/job/20240109-28cef27bb96c7f058ce44559ec7c6192", + "tags": [ + "usa" + ] + }, + { + "name": "Encoding.com", + "id": "encoding", + "link": "https://www.encoding.com/", + "logo": "logo-encoding.com.png", + "logoWidth": "220px", + "description": "Крупнейший в мире сервис транскодирования видео в облаке", + "source": "https://career.habr.com/tambolskiy", + "tags": [ + "usa", + "global", + "russia" + ] + }, + { + "name": "ntile", + "id": "ntile", + "link": "https://ntile.app/user/login", + "logo": "logo-ntile.svg", + "logoWidth": "180px", + "description": "collaborative cloud work with text documents and interactive tables", + "source": "https://rubrain.com/profile/EoZznxo", + "tags": [ + "ukraine", + "it" + ] + }, + { + "name": "Orange Systems S.A.", + "id": "orange-systems", + "link": "https://www.orangesystem.it/", + "logo": "logo-orange-system.png", + "logoWidth": "200px", + "description": "Audiophile Democracy", + "source": "https://rubrain.com/profile/34rgya6", + "tags": [ + "europe", + "italy" + ] + }, +{ + "name": "Firebird Tours", + "id": "firebird", + "link": "https://www.firebirdtours.com/", + "logo": "logo-firebird-tours.png", + "logoWidth": "200px", + "description": "американская туристическая компания", + "source": "https://hirify.me/jobs/42423-middle-java-developer-qa-automation", + "tags": [ + "usa", + "tourism" + ] + }, + { + "name": "Lean Solutions", + "id": "lean", + "link": "https://www.leangroup.com/", + "logo": "logo-lean-solutions.svg", + "logoWidth": "200px", + "description": "a top workforce optimization company", + "source": "https://app.theirstack.com/home?search-company=Lean%20Tech", + "tags": [ + "colombia", + "south-america", + "usa" + ] + }, + { + "name": "PointPay", + "id": "pointpay", + "link": "https://pointpay.io/", + "logo": "logo-point-pay.png", + "logoWidth": "200px", + "description": "криптовалютная банковская экосистема", + "source": "https://career.habr.com/vacancies/1000095358", + "tags": [ + "finances", + "global", + "central-america" + ] + }, + { + "name": "Exness", + "id": "exness", + "link": "https://www.exness.uk/", + "logo": "logo-exness.png", + "logoWidth": "160px", + "description": "a Leading Trading Broker", + "source": "https://rubrain.com/profile/L9DylW4", + "tags": [ + "finances", + "europe" + ] + }, + { + "name": "Bell Integrator", + "id": "bell", + "link": "https://www.bellintegrator.com/", + "logo": "logo-bellintegrator.png", + "logoWidth": "160px", + "description": "международная компания, специализирующаяся на консалтинге, технологических услугах и аутсорсинге.", + "source": "https://career.habr.com/igorek9191", + "tags": [ + "usa", + "europe", + "it" + ] + }, + { + "name": "AmazingHiring", + "id": "amazing-hiring", + "link": "https://amazinghiring.com", + "logo": "logo-amazinghiring.svg", + "logoWidth": "160px", + "description": "Веб-приложение для поиска технических талантов.", + "tags": [ + "usa", + "hr" + ] + }, + { + "name": "Aquiva Labs", + "id": "aquiva-labs", + "link": "https://aquivalabs.com/", + "logo": "logo-aquiva-labs.png", + "logoWidth": "180px", + "description": "Заказная разработка на платформе Salesforce для американских и европейских клиентов (США, Россия, Аргентина, Уругвай, Германия)", + "source": "https://career.habr.com/companies/aquivalabs", + "tags": [ + "usa", + "russia", + "it" + ] + }, + { + "name": "Valor Software", + "id": "valor", + "link": "https://valor-software.com/", + "logo": "logo-valor-software.png", + "logoWidth": "150px", + "description": "a custom software development company and IT solutions provider", + "source": "https://remotive.com/remote/jobs/qa/qa-automation-engineer-2356173", + "tags": [ + "czech", + "europe", + "it" + ] + }, + { + "name": "Faptic Technology", + "id": "faptic", + "link": "https://faptic.com/", + "logo": "logo-faptic.webp", + "logoWidth": "200px", + "description": "Award winning transformation partner specialising in Software/AI, Data/AI, Cloud, Security and Business Change.", + "source": "https://remotive.com/remote/jobs/qa/senior-qa-software-test-automation-engineer-2474923", + "tags": [ + "united-kingdom", + "europe", + "it" + ] + }, + { + "name": "Paysenger", + "id": "paysenger", + "link": "https://paysenger.com/", + "logo": "logo-paysenger.svg", + "logoWidth": "300px", + "description": "a platform that helps creators monetize their content like never before", + "source": "https://rubrain.com/profile/M4WR7k9", + "tags": [ + "global" + ] + }, + { + "name": "Tango Me", + "id": "tango-me", + "link": "https://www.tango.me/live/recommended", + "logo": "logo-tango-me.png", + "logoWidth": "120px", + "description2": "The top live-streaming platform for content creators to share their talents and monetize their supporters", + "description": "общение в режиме онлайн. Более 400 млн пользователей из разных стран.", + "source": "https://career.habr.com/evgenii-popovich", + "tags": [ + "global", + "russia", + "belarus", + "ukraine" + ] + }, + { + "name": "Лаборатория Качества", + "id": "quality-lab", + "link": "https://vk.com/quality_lab", + "logo": "logo-quality-lab.jpeg", + "logoWidth": "120px", + "description": "Разработка и тестирование программного обеспечения", + "source": "https://career.habr.com/igorek9191", + "tags": [ + "russia", + "it" + ] + }, + { + "name": "Maxilect", + "id": "maxilect", + "link": "https://maxilect.ru/", + "logo": "logo-maxilect.svg", + "logoWidth": "200px", + "description": "Заказная разработка программного обеспечения (Ad Tech, Blockchain, ML, AI)", + "tags": [ + "russia", + "it" + ] + }, + { + "name": "БКС", + "id": "bcs", + "link": "https://bcs.ru", + "logo": "bcs-logo.jpeg", + "logoWidth": "200px", + "description": "один из лидеров российского рынка брокерских услуг", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "SEMrush", + "id": "semrush", + "link": "https://ru.semrush.com", + "logo": "semrush-logo.png", + "logoWidth": "200px", + "description": "ведущая глобальная SaaS-платформа для управления видимостью бизнеса в интернете", + "tags": [ + "russia" + ] + }, + { + "name": "Propeller Ads", + "id": "propeller-ads", + "link": "https://propellerads.com/", + "logo": "propeller-logo.png", + "logoWidth": "200px", + "description": "международная рекламная сеть, основные усилия которой направлены на создание самой удобной, эффективной и надёжной рекламной платформы.", + "tags": [ + "russia" + ] + }, + { + "name": "Albedis", + "id": "albedis", + "link": "https://www.albedis.com/", + "logo": "logo-albedis.png", + "logoWidth": "180px", + "description": "Швейцарское кадровое агентство", + "source": "https://www.glassdoor.com/Job/selenium-testing-engineer-jobs-SRCH_IC3289087_KO0,25.htm", + "tags": [ + "switzerland", + "europe" + ] + }, + { + "name": "ERGO Technology & Services", + "id": "ergo", + "link": "https://www.ergo.com/en/Unternehmen/ERGO-Technologie", + "logo": "logo-ergo.jpeg", + "logoWidth": "100px", + "description": "one of the major insurance groups in Germany and Europe. Represented in 20+ countries in Europe and Asia.", + "source": "https://www.linkedin.com/in/alena-badzilouskaya/details/experience/", + "tags": [ + "insurance", + "europe", + "germany", + "it" + ] + }, + { + "name": "Xceptance", + "id": "xceptance", + "link": "https://www.xceptance.com/en/products/", + "logo": "logo-xceptance.svg", + "logoWidth": "200px", + "description": "тестирование и контроль качества ПО. Создатели Neodymium - платформы автоматизации тестирования с открытым исходным кодом на основе Selenide.", + "source": "https://www.xceptance.com/en/products/neodymium/", + "tags": [ + "europe", + "germany", + "usa", + "it" + ] + }, + { + "name": "Uptempo", + "id": "uptempo", + "link": "https://www.uptempo.io/", + "logo": "logo-uptempo.svg", + "logoWidth": "180px", + "description": "Marketing operations software", + "source": "https://rubrain.com/profile/Q9NBmE9", + "tags": [ + "canada", + "europe", + "germany", + "bulgaria", + "russia" + ] + }, + { + "name": "UBS AG", + "id": "ubs-ag", + "link": "https://www.ubs.com/global/en.html", + "logo": "ubs-logo.png", + "logoWidth": "180px", + "description": "крупнейший швейцарский финансовый холдинг, предоставляющий различные финансовые услуги по всему миру.", + "tags": [ + "switzerland", + "europe", + "finances" + ] + }, + { + "name": "Альфа банк", + "id": "alfa-bank", + "link": "https://alfabank.ru", + "logo": "alfa-bank-logo.png", + "logoWidth": "200px", + "description": "один из крупнейших российских коммерческих банков. На основе Selenide создали опен-сорс библиотеку для BDD спецификаций Akita.", + "source": "https://career.habr.com/honorzor", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "Министерство социальных дел Эстонии", + "id": "estonian-ministry-of-social-affairs", + "link": "https://www.sm.ee/en", + "logo": "sotsiaalministeerium.svg", + "logoWidth": "300px", + "description": "министерство правительства Эстонии, ответственное за социальную политику страны.", + "source": "https://www.tehik.ee/sites/default/files/2021-04/AV-IT-Profiil-280920-1316-38.pdf", + "tags": [ + "government", + "estonia", + "europe" + ] + }, + { + "name": "Symantec", + "id": "symantec", + "link": "https://en.wikipedia.org/wiki/Broadcom#Symantec_Enterprise_Security", + "logo": "logo-symantec.svg_.png", + "logoWidth": "200px", + "description": "Легендарный антивирус и куча другой безопасности", + "source": "https://stackoverflow.com/questions/60913724/selenide-test-fails-with-org-openqa-selenium-nosuchsessionexception", + "tags": [ + "it", + "estonia", + "europe" + ] + }, + { + "name": "Pipedrive", + "id": "pipedrive", + "link": "https://www.pipedrive.com/ru", + "logo": "pipedrive-logo.svg", + "logoWidth": "200px", + "description": "инструмент управления продажами, один из самых успешных эстонских стартапов.
    Более 50 000 клиентов, среди них Amazon, SkyScanner, Vimeo.", + "tags": [ + "estonia", + "europe", + "usa" + ] + }, + { + "name": "Tele2", + "id": "tele2", + "link": "https://tele2.ee/", + "logo": "logo-tele2.svg.png", + "logoWidth": "100px", + "description": "Телекоммуникации (Швеция, Эстония, Россия)", + "source": "https://career.habr.com/vacancies/1000071594", + "tags": [ + "estonia", + "sweden", + "scandinavia", + "russia", + "telecom" + ] + }, + { + "name": "Omniva", + "id": "omniva", + "link": "https://www.omniva.ee", + "logo": "omniva-logo.png", + "logoWidth": "100px", + "description": "международное логистическое предприятие. Локомотив электронной торговли в странах Балтии.", + "tags": [ + "estonia", + "logistics" + ] + }, + { + "name": "Pragmatic Coders", + "id": "pragmatic-coders", + "link": "https://www.pragmaticcoders.com/", + "logo": "pragmatic-coders.png", + "logoWidth": "150px", + "description": "a leading software house in the e-commerce and fintech sector.
    Dedicated teams of highly qualified developers provide full spectrum of Python and Java development services.
    Agile way of thinking at Pragmatic Coders continuously helps startups to grow and corporates to implement innovations.", + "tags": [ + "europe", + "it" + ] + }, + { + "name": "Skywind group", + "id": "skywind", + "link": "https://www.skywindgroup.com/en-US/home", + "logo": "skywind-logo.svg", + "logoWidth": "320px", + "description": "Online gaming - games, back-office and content management systems, hosting solutions, infrastructure.", + "source": "https://www.linkedin.com/in/oleg-dereka-bb88b7119", + "tags": [ + "europe", + "asia", + "ukraine", + "belarus", + "gambling" + ] + }, + { + "name": "Bally's Interactive", + "id": "bally", + "link": "https://www.linkedin.com/company/ballysinteractive/", + "logo": "logo-ballysinteractive.jpeg", + "logoWidth": "100px", + "description": "Gambling Facilities and Casinos Providence", + "source": "https://www.linkedin.com/in/ovodenko/details/experience/", + "tags": [ + "estonia", + "europe", + "gambling" + ] + }, + { + "name": "Delasport", + "id": "delasport", + "link": "https://www.delasport.com/", + "logo": "logo-delasport.png", + "logoWidth": "180px", + "description": "sports betting, online casinos and PAM for the iGaming industry", + "source": "https://djinni.co/jobs/764172-senior-qa-automation-engineer-java/", + "tags": [ + "ukraine", + "europe", + "gambling", + "sport" + ] + }, + { + "name": "SportsTG", + "id": "sportstg", + "link": "https://mygameday.app", + "logo": "sportstg-logo.png", + "logoWidth": "150px", + "description": "австралийская компания, ведущий поставщик ПО для индустрии спорта.", + "tags": [ + "australia", + "sport" + ] + }, + { + "name": "Softswiss", + "id": "softswiss", + "link": "https://www.softswiss.com/", + "logo": "logo-softswiss.png", + "logoWidth": "160px", + "description": "iGaming и крипта в сфере онлайн-развлечений", + "source": "https://career.habr.com/evgenii-popovich", + "tags": [ + "belarus", + "global", + "gaming" + ] + }, + { + "name": "Infotech Group", + "id": "infotech", + "link": "https://infotech.group/ru", + "logo": "logo-infotech-group.svg", + "logoWidth": "150px", + "description": "российский разработчик программного обеспечения, занимающийся разработкой и построением систем автоматизации управления городом и предприятием.", + "tags": [ + "russia", + "it" + ] + }, + { + "name": "КБ «Ренессанс Кредит»", + "id": "renaissance", + "link": "https://rencredit.ru", + "logo": "rencredit-logo.png", + "logoWidth": "150px", + "description": "входит в ТОП-100 крупнейших банков России и активно развивает собственное IT подразделение.", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "QA Service", + "id": "qa-service", + "link": "https://softengi.com/expertise/software-testing/", + "logo": "qa3s-logo.png", + "logoWidth": "150px", + "description": "Департамент QA Service входит в состав компании Softengi –\n поставщика услуг в области ИT аутсорсинга на европейских и американских рынках.", + "tags": [ + "ukraine", + "it" + ] + }, + { + "name": "XSolve", + "id": "xsolve", + "link": "https://www.xsolve.pl", + "logo": "xsolve-logo.jpg", + "logoWidth": "150px", + "description": "Agile Software House focused on PHP/Symfony/Java/Mobile (iOS-Android-Windows)", + "tags": [ + "europe", + "it" + ] + }, + { + "name": "Sportradar", + "id": "sportradar", + "link": "https://www.sportradar.com", + "logo": "sportradar-logo.jpeg", + "logoWidth": "150px", + "description": "a global leader in understanding and leveraging the power of sports data", + "tags": [ + "europe", + "sport" + ] + }, + { + "name": "Luxoft", + "id": "luxoft", + "link": "https://career.luxoft.com/", + "logo": "logo-luxoft.png", + "logoWidth": "180px", + "description": "разработка ПО для крупных транснациональных корпораций по всему миру", + "source": "https://career.habr.com/jieo", + "tags": [ + "it", + "russia", + "switzerland", + "europe", + "global" + ] + }, + { + "name": "EPAM", + "id": "epam", + "link": "https://www.epam.com/", + "logo": "logo-epam.png", + "description": "американская ИТ-компания, основанная в 1993 году. Программное обеспечение на заказ, консалтинг. Представлена более чем в 40 странах мира.", + "source": "https://career.habr.com/leoscream", + "tags": [ + "usa", + "belarus", + "russia", + "ukraine", + "it" + ] + }, + { + "name": "Accenture", + "id": "accenture", + "link": "https://www.accenture.com/us-en", + "logo": "logo-accenture.jpeg", + "logoWidth": "160px", + "description": "Глобальная компания, предоставляющая услуги в области стратегии, управленческого консалтинга, информационных технологий. Входит в ТОП 500 крупнейших компаний мира.", + "source": "https://career.habr.com/johnfrolov", + "tags": [ + "global", + "russia", + "it" + ] + }, + { + "name": "B2B Soft", + "id": "b2b-soft", + "link": "https://b2bsoft.com/", + "logo": "b2bsoft-logo.svg", + "logoWidth": "120px", + "description": "Industry Leader of Innovative Software and Hardware Solutions for Telco Retail | POS, Kiosks & Locker Stations", + "source": "https://www.linkedin.com/in/oleg-dereka-bb88b7119/", + "tags": [ + "it", + "usa", + "ukraine" + ] + }, + { + "name": "Arrival", + "id": "arrival", + "link": "https://arrival.com/", + "logo": "logo-arrival.png", + "logoWidth": "180px", + "description": "британский производитель электромобилей", + "source": "https://app.theirstack.com/home?search-company=Arrival", + "tags": [ + "europe", + "united-kingdom", + "logistics" + ] + }, + { + "name": "Ciklum", + "id": "ciklum", + "link": "https://www.ciklum.com/", + "logo": "logo-ciklum.webp", + "logoWidth": "200px", + "description": "a globally recognized provider of software engineering services. Founded in Denmark, headquarters to London.", + "source": "https://jobitt.com/job-openings/senior-automation-qa-java-engineer-3852", + "tags": [ + "europe", + "denmark", + "united-kingdom", + "ukraine", + "belarus", + "poland", + "spain", + "it" + ] + }, + { + "name": "Social Discovery Group (SDG)", + "id": "social-discovery-group", + "link": "https://socialdiscoverygroup.com/", + "logo": "logo-sdg.jpeg", + "logoWidth": "100px", + "description": "the world's largest group of social discovery companies which unites more than 50 brands", + "source": "https://www.linkedin.com/jobs/view/senior-aqa-engineer-java-at-social-discovery-group-3781191310/", + "tags": [ + "global", + "europe", + "poland", + "serbia", + "malta" + ] + }, + { + "name": "PrimeXM", + "id": "primexm", + "link": "https://primexm.com/", + "logo": "logo-primexm.png", + "logoWidth": "200px", + "description": "world-class financial institutions, liquidity partners and prime brokers", + "source": "https://www.linkedin.com/in/marian-stasiuk-412a5425a/details/skills/", + "tags": [ + "finances", + "dubai", + "britain", + "cyprus", + "asia" + ] + }, + { + "name": "Deutsche Bank", + "id": "deutsche-bank", + "link": "https://www.db.com", + "logo": "logo-deutsche-bank.png", + "logoWidth": "160px", + "description": "крупнейший финансовый конгломерат Германии", + "source": "", + "tags": [ + "europe", + "germany", + "finances" + ] + }, + { + "name": "Deutsche Telekom", + "id": "deutsche-telekom", + "link": "https://www.telekom.com/", + "logo": "logo-deutsche-telekom.jpeg", + "logoWidth": "120px", + "description": "немецкая телекоммуникационная компания, крупнейшая в Европе и четвёртая в мире.", + "source": "https://app.theirstack.com/home?search-company=Deutsche%20Telekom", + "tags": [ + "europe", + "germany", + "telecom" + ] + }, + { + "name": "Rhenus Group", + "id": "rhenus", + "link": "https://www.rhenus.group/", + "logo": "logo-rhenus-logistics.webp", + "logoWidth": "200px", + "description": "международный поставщик логистических услуг, Германия. Филиалы в Европе, Индии, Америке, Азии, Африке и Океании.", + "source": "https://app.theirstack.com/home?search-company=Rhenus%20Group", + "tags": [ + "europe", + "germany", + "global", + "logistics" + ] + }, + { + "name": "Bergmann Infotech", + "id": "bergmann-infotech", + "link": "https://bergmann-infotech.de/en/homepage/", + "logo": "logo-bergman-infotech.svg", + "logoWidth": "180px", + "description": "Software solutions for your business (Germany)", + "source": "https://career.habr.com/podnk", + "tags": [ + "europe", + "germany", + "it" + ] + }, + { + "name": "DPI solutions", + "id": "dpi", + "link": "https://www.linkedin.com/company/dpi-solutions-ltd-/", + "logo": "dpi-solutions-logo.png", + "logoWidth": "150px", + "description": "High-quality software through multi-purpose IT consulting and professional trainings", + "tags": [ + "belarus", + "it" + ] + }, + { + "name": "STRABAG", + "id": "strabag", + "link": "https://www.strabag.com/", + "logo": "logo-strabag.png", + "logoWidth": "160px", + "description": "публичная австрийская строительная компания, один из самых крупных строительных концернов Европы.", + "source": "https://app.theirstack.com/home?search-company=STRABAG", + "tags": [ + "austria", + "europe", + "building" + ] + }, + { + "name": "Soramitsu", + "id": "soramitsu", + "link": "https://soramitsu.co.jp/ru", + "logo": "logo-soramitsu.svg", + "logoWidth": "220px", + "description": "финансовые приложения нового поколения (Япония)", + "source": "https://career.habr.com/s3rgh", + "tags": [ + "japan", + "asia", + "finances" + ] + }, + { + "name": "Lazada", + "id": "lazada", + "link": "https://www.lazada.com/en/", + "logo": "logo-lazada.svg", + "logoWidth": "180px", + "description": "инновационный E-commerce в Юго-Восточной Азии", + "source": "https://career.habr.com/maresko", + "tags": [ + "asia", + "finances", + "russia" + ] + }, + { + "name": "Contour Software", + "id": "contour-software", + "link": "https://www.contour-software.com", + "logo": "logo-contour-software.png", + "logoWidth": "160px", + "description": "IT Services and IT Consulting", + "source": "https://www.linkedin.com/in/m-naeem-qa/", + "tags": [ + "it", + "pakistan", + "asia" + ] + }, + { + "name": "G-Plans", + "id": "g-plans", + "link": "https://g-plans.com/", + "logo": "logo-gplans.svg", + "logoWidth": "180px", + "description": "Трекинг программ питания (Сан-Диего, США)", + "source": "https://career.habr.com/alekseyb137", + "tags": [ + "usa", + "healthcare" + ] + }, + { + "name": "Bereke bank", + "id": "bereke-bank", + "link": "https://berekebank.kz/ru", + "logo": "logo-berekebank.svg", + "logoWidth": "200px", + "description": "казахстанский коммерческий банк", + "source": "https://rubrain.com/profile/d4zrPV4", + "tags": [ + "kazakhstan", + "asia", + "finances" + ] + }, + { + "name": "Home Credit Bank Kazakhstan", + "id": "home-credit-bank", + "link": "https://home.kz/", + "logo": "logo-home-credit-bank.svg.png", + "logoWidth": "100px", + "description": "a part of international Home Credit Group with 20 years of experience in financial business", + "source": "https://www.linkedin.com/in/makarov87/details/experience/", + "tags": [ + "kazakhstan", + "asia", + "finances" + ] + }, + { + "name": "Newmax Technologies", + "id": "newmax", + "link": "https://career.habr.com/companies/newmax-url", + "logo": "logo-newmax.jpeg", + "logoWidth": "150px", + "description": "Сервисы в Узбекистане: Express24.uz, MyTaxi.uz, MaxTrack.uz, Workly.uz", + "source": "https://career.habr.com/rustam-abduraxmonov", + "tags": [ + "uzbekistan", + "asia", + "it", + "taxi" + ] + }, + { + "name": "LHV Bank", + "id": "lhv", + "link": "https://www.lhv.ee/", + "logo": "logo-lhv.svg.png", + "logoWidth": "100px", + "description": "the largest domestic financial group and capital provider in Estonia", + "source": "https://www.linkedin.com/in/dea-taur-b61b5753/", + "tags": [ + "estonia", + "europe", + "britain", + "finances" + ] + }, + { + "name": "Luminor group", + "id": "luminor", + "link": "https://luminor.ee/", + "logo": "logo-luminor.svg", + "logoWidth": "160px", + "description": "третий по величине поставщик финансовых услуг в странах Балтии.", + "source": "https://www.linkedin.com/in/risto-porila/", + "tags": [ + "estonia", + "europe", + "finances" + ] + }, + { + "name": "BlurOr bank", + "id": "bluror-bank", + "link": "https://www.bluorbank.lv/latvija/en", + "logo": "logo-bluor-bank.jpeg", + "logoWidth": "96px", + "description": "systemically significant Latvian bank", + "source": "https://www.linkedin.com/in/julyan-slabko", + "tags": [ + "europe", + "finances" + ] + }, + { + "name": "Swedbank", + "id": "swedbank", + "link": "https://www.swedbank.ee/about/careers/work/career", + "logo": "logo-swedbank.png", + "logoWidth": "240px", + "description": "крупнейший банк в Эстонии, Латвии и Литве.", + "source": "https://www.cvkeskus.ee/software-engineer-quality-assurance-origination-team-tallinnas-swedbank-as-774418", + "tags": [ + "estonia", + "europe", + "finances" + ] + }, + { + "name": "SEB bank", + "id": "seb", + "link": "https://www.seb.ee/", + "logo": "logo-seb.png", + "logoWidth": "160px", + "description": "SEB Grupp является ведущей группой финансовых услуг в Северной Европе.", + "source": "https://www.linkedin.com/jobs/view/3008104368/", + "tags": [ + "estonia", + "europe", + "finances" + ] + }, + { + "name": "BigBank", + "id": "bigbank", + "link": "https://www.bigbank.ee/ru", + "logo": "logo-bigbank.png", + "logoWidth": "220px", + "description": "Эстонский банк, работающий в девяти европейских странах", + "source": "https://jobs.bigbank.eu/open-positions/quality-engineer-2", + "tags": [ + "estonia", + "europe", + "finances" + ] + }, + { + "name": "Банк Citadele", + "id": "citadele", + "link": "https://www.citadele.lv/ru/", + "logo": "citadele-banka.png", + "logoWidth": "150px", + "description": "Латвийский банк, партнёр American Express® в странах Балтии", + "tags": [ + "europe", + "finances" + ] + }, + { + "name": "Plumbr", + "id": "plumbr", + "link": "https://www.splunk.com/en_us/newsroom/press-releases/2020/splunk-to-acquire-plumbr-and-rigor-expanding-the-worlds-most-comprehensive-observability-portfolio.html", + "logo": "plumbr-logo.jpeg", + "logoWidth": "150px", + "description": "Инструмент для обнаружения утечек памяти в Java приложениях", + "tags": [ + "estonia", + "it" + ] + }, + { + "name": "Nortal", + "id": "nortal", + "link": "https://nortal.com/", + "logo": "logo-nortal.png", + "logoWidth": "180px", + "description": "Многонациональная компания, занимающаяся стратегическими изменениями и технологиями, со штаб-квартирой в Эстонии и операциями в США, Европе, на Ближнем Востоке и в Африке.", + "source": "https://www.linkedin.com/in/karltiirik", + "tags": [ + "estonia", + "europe", + "usa", + "africa", + "it" + ] + }, + { + "name": "Gilbarco Autotank", + "id": "gilbarco-autotank", + "link": "https://www.gilbarco.com/eu/", + "logo": "gilbarco-autotank-logo.jpg", + "logoWidth": "128px", + "description": "система управления автоматическими заправочными станциями, использующаяся практически всеми АЗС в Эстонии.", + "tags": [ + "estonia", + "resources" + ] + }, + { + "name": "Ettevõtluskeskus", + "id": "ettevotluskeskus", + "link": "https://www.ettevotluskeskus.ee/", + "logo": "logo-evk.jpg", + "logoWidth": "160px", + "description": "Бизнес-консультации, обучение, рекомендации по финансированию и налаживание связей для предпринимателей и малого бизнеса", + "tags": [ + "estonia", + "education" + ] + }, + { + "name": "УБРиР", + "id": "ubrr", + "link": "https://www.ubrr.ru", + "logo": "ubrr-logo.jpeg", + "logoWidth": "150px", + "description": "Уральский банк реконструкции и развития", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "Outlines Tech", + "id": "outlines", + "link": "https://outlines.tech/", + "logo": "logo-outline-tech.jpeg", + "description": "программное обеспечение для банков, страховых компаний, брокеров и бирж.", + "source": "https://vc.ru/s/outlines-tech-67935/307949-specialist-po-avtotestirovaniyu-na-java", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "РТЛабс", + "id": "rtlabs", + "link": "https://rtlabs.ru", + "logo": "logo-rt-labs.png", + "logoWidth": "180px", + "description": "Госуслуги — это мы (системы электронного правительства, платформа биометрической идентификации и пр.)", + "source": "https://career.habr.com/vacancies/1000100539", + "tags": [ + "government", + "russia" + ] + }, + { + "name": "Sportmaster Lab", + "id": "sportmaster", + "link": "https://www.sportmaster.ru/", + "logo": "logo-sportmaster-lab.png", + "description": "ИТ-подразделение крупнейшей в России сети по продаже спортивных товаров", + "source": "https://career.habr.com/av0x", + "tags": [ + "russia", + "sport" + ] + }, + { + "name": "Tieto Eesti AS", + "id": "tieto", + "link": "https://www.tietoevry.com/ee", + "logo": "tieto.png", + "logoWidth": "96px", + "description": "крупнейшая ИТ-компания в Северной Европе, предоставляющая полный спектр ИТ-услуг частному и корпоративному сектору. Разработки Tieto находят глобальное применение, а сервисные центры компании расположены в различных уголках мира.", + "tags": [ + "estonia", + "it" + ] + }, + { + "name": "TestDevLab", + "id": "testdevlab", + "link": "https://www.testdevlab.com/", + "logo": "logo-testdevlab.svg", + "logoWidth": "180px", + "description": "QA & Software Testing Service Provider", + "source": "https://www.testdevlab.com/blog/selenium-or-selenide-which-testing-framework-best-fits-your-needs", + "tags": [ + "latvia", + "lithuania", + "estonia", + "europe", + "it" + ] + }, + { + "name": "FirstLine software", + "id": "first-line-software", + "link": "https://firstlinesoftware.com/", + "logo": "logo-first-line-software.jpeg", + "logoWidth": "140px", + "description": "Managed AI Services for Business Impact", + "source": "https://careers.firstlinesoftware.com/spotlights/ui-test-automation-with-selenide-and-java-for-optimizely-example", + "tags": [ + "it", + "usa", + "montenegro", + "europe" + ] + }, + { + "name": "Bellwood systems", + "id": "bellwood", + "link": "https://hh.ru/employer/593183", + "logo": "bellwood-logo.png", + "logoWidth": "px", + "description": "разработчик систем скоринга и андеррайтинга для финансовых продуктов.", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "Zeroturnaround", + "id": "zeroturnaround", + "link": "https://zeroturnaround.com", + "logo": "logo-zt.png", + "description": "Создатели известных на весь мир продуктов JRebel и LiveRebel,
    номинанты премии Jolt Awards.", + "tags": [ + "estonia", + "it" + ] + }, + { + "name": "Rouge Wave Software", + "id": "rouge-wave", + "link": "http://www.roguewave.com", + "logo": "logo-rogue-wave.jpeg", + "logoWidth": "120px", + "description": "Everything to write, test, and run complex code: from cloud-based-services to native platform applications to portable software libraries.", + "source": "https://www.linkedin.com/in/karltiirik/", + "tags": [ + "usa", + "it" + ] + }, + { + "name": "Банк Санкт-Петербург", + "id": "bspb", + "link": "https://i.bspb.ru/home", + "logo": "bspb_logo.jpg", + "description": "В ТОП-3 лучших российских интернет-банков", + "tags": [ + "russia", + "finances" + ] + }, + { + "name": "Eesti Energia", + "id": "eesti-energia", + "link": "https://www.energia.ee/ru/avaleht", + "logo": "ee_logo.png", + "description": "Крупнейший поставщик электричества в Эстонии", + "tags": [ + "estonia", + "resources" + ] + }, + { + "name": "Proekspert", + "id": "proekspert", + "link": "https://www.proekspert.ee/", + "logo": "proekspert_logo.png", + "logoWidth": "350px", + "description": "Ведущий разработчик программного обеспечения промышленной автоматизации в Эстонии. Мы вдыхаем жизнь в оборудование.", + "tags": [ + "estonia", + "it" + ] + }, + { + "name": "Regio", + "id": "regio", + "link": "https://www.regio.ee/", + "logo": "logo-regio.jpeg", + "logoWidth": "180px", + "description": "A premium provider of location-based solutions in the Eastern Hemisphere for telecom, transport and infrastructure sectors.", + "tags": [ + "estonia", + "it" + ] + }, + { + "name": "Codeborne", + "id": "codeborne", + "link": "https://codeborne.com/ru/", + "logo": "codeborne-logo-small.png", + "logoWidth": "240px", + "description": "Единственная софтверная компания в Эстонии, использующая TDD и другие практики XP от звонка до звонка. Создатели open-source библиотек Selenide, pdf-test и др.", + "tags": [ + "estonia", + "europe", + "it" + ] + } +] diff --git a/hugo-en.toml b/hugo-en.toml new file mode 100644 index 000000000..1f14051c1 --- /dev/null +++ b/hugo-en.toml @@ -0,0 +1,3 @@ +baseURL = "https://selenide.org" +defaultContentLanguage = "en" +disableLanguages = ["ru"] diff --git a/hugo-ru.toml b/hugo-ru.toml new file mode 100644 index 000000000..eaacb828b --- /dev/null +++ b/hugo-ru.toml @@ -0,0 +1,3 @@ +baseURL = "https://ru.selenide.org" +defaultContentLanguage = "ru" +disableLanguages = ["en"] diff --git a/hugo.toml b/hugo.toml index 3d963eecf..7d979459b 100644 --- a/hugo.toml +++ b/hugo.toml @@ -1,23 +1,18 @@ baseURL = "https://selenide.org" -languageCode = "en" title = "Selenide" +defaultContentLanguage = "en" -# Build future-dated posts (matching Jekyll --future flag) buildFuture = true -# Disable unused built-in pages disableKinds = ["taxonomy", "term"] -# Allow raw HTML in Markdown content [markup.goldmark.renderer] unsafe = true -# Use CSS classes for syntax highlighting (not inline styles) [markup.highlight] noClasses = false [params] - tagline = "Concise UI tests in Java" selenideVersion = "7.16.0" seleniumChangelog = "https://raw.githubusercontent.com/SeleniumHQ/selenium/master/java/CHANGELOG" googleAnalyticsId = "UA-39031927-1" @@ -28,11 +23,25 @@ disableKinds = ["taxonomy", "term"] github = "asolntsev" twitter = "selenide" -# Blog post permalinks match old Jekyll URLs: /YYYY/MM/DD/title/ +[languages] + [languages.en] + contentDir = "content/en" + languageCode = "en" + languageName = "English" + weight = 1 + [languages.en.params] + tagline = "Concise UI tests in Java" + [languages.ru] + contentDir = "content/ru" + languageCode = "ru" + languageName = "Русский" + weight = 2 + [languages.ru.params] + tagline = "Лаконичные и стабильные UI тесты на Java" + [permalinks] blog = "/:year/:month/:day/:slug/" -# Built-in RSS feed [outputFormats.RSS] mediaType = "application/rss+xml" baseName = "rss" @@ -42,7 +51,6 @@ disableKinds = ["taxonomy", "term"] home = ["HTML", "RSS"] section = ["HTML"] -# Local dev server: redirect /rss to /rss.xml [[server.redirects]] from = "/rss" to = "/rss.xml" diff --git a/i18n/en.toml b/i18n/en.toml new file mode 100644 index 000000000..8669618c0 --- /dev/null +++ b/i18n/en.toml @@ -0,0 +1,260 @@ +# Main menu +[menu_quick_start] +other = "Quick start" + +[menu_docs] +other = "Docs" + +[menu_faq] +other = "FAQ" + +[menu_blog] +other = "Blog" + +[menu_javadoc] +other = "Javadoc" + +[menu_users] +other = "Users" + +[menu_quotes] +other = "Quotes" + +[menu_thanks] +other = "Many thanks" + +[news_released] +other = "Released Selenide" + +[news_mcp] +other = "Selenide MCP server" + +# Donate +[donate_title] +other = "Selenide Supports Ukraine" + +[donate_social_drone_url] +other = "https://www.socialdrone.com.ua/en" + +[donate_social_drone] +other = "Social Drone" + +[donate_charity] +other = "Charity supporting the Ukrainian army" + +[donate_un_fund] +other = "UN's Ukraine Humanitarian Fund" + +# Quicklinks +[quicklink_view_on] +other = "View on" + +[quicklink_search_in] +other = "Search in" + +[quicklink_read_our] +other = "Read our" + +[quicklink_blog] +other = "Blog" + +[quicklink_follow_at] +other = "Follow at" + +[quicklink_subscribe_to] +other = "Subscribe to" + +# 404 +[err_page_not_found] +other = "Page not found" + +# Homepage +[home_what_is_title] +other = "What is Selenide?" + +[home_what_is_subtitle] +other = "Selenide is a framework for test automation powered by Selenium WebDriver that brings the following advantages:" + +[home_concise_api] +other = "Concise fluent API for tests" + +[home_stable_tests] +other = "Stable tests" + +[home_powerful_selectors] +other = "Powerful selectors" + +[home_simple_config] +other = "Simple configuration" + +[home_what_is_desc1] +other = "You don't need to think how to shut down browser, handle timeouts and StaleElement Exceptions or search for relevant log lines, debugging your tests." + +[home_what_is_desc2] +other = "Just focus on your business logic and let Selenide do the rest!" + +[home_quick_start_title] +other = "Quick start" + +[home_quick_start_subtitle] +other = "It's extremely easy to start using Selenide. Definitely not a rocket science." + +[home_quick_start_desc1_pre] +other = "Just add" + +[home_quick_start_desc1_post] +other = "to your project and you are done." + +[home_quick_start_desc2] +other = "See Quick start guide for more details." + +[home_docs_title] +other = "Documentation" + +[home_docs_subtitle_1] +other = "Poor software" + +[home_docs_subtitle_1b] +other = "doesn't have" + +[home_docs_subtitle_1c] +other = "documentation." + +[home_docs_subtitle_2] +other = "Brilliant software" + +[home_docs_subtitle_2b] +other = "doesn't need" + +[home_docs_subtitle_2c] +other = "documentation." + +[home_docs_desc1] +other = "We are proud to claim that Selenide is so simple that you don't need to read tons of documentation." + +[home_docs_desc2] +other = "The whole work with Selenide consists of three simple things!" + +[home_contacts_title] +other = "Contacts" + +[home_contacts_subtitle] +other = "Do you want to talk about it?" + +[home_contacts_desc] +other = "Where You can ask question or discuss any topic about Selenide in English:" + +[home_googlegroup_url] +other = "mailto:selenide@googlegroups.com" + +[home_googlegroup] +other = "Google group" + +[home_gitter_url] +other = "https://gitter.im/codeborne/selenide" + +[home_telegram_url] +other = "https://t.me/selenide" + +[home_testimonials_title] +other = "Testimonials" + +[home_testimonials_quote] +other = '"Selenide is really nice and capable tool for writing functional/acceptance tests for your browser-based UI. I encourage you to check Selenide out and give it a try."' + +[home_testimonials_author_role] +other = "LiveRebel engineer at ZeroTurnaround" + +[home_thanks_title] +other = "Many thanks to:" + +[home_jetbrains_alt] +other = "JetBrains. Intellij IDEA - the best Java IDE on the Milky Way!" + +[home_browser_testing_via] +other = "Browser testing via" + +# Users page +[users_tell_us_title] +other = "Tell us about yourself!" + +[users_share_experience] +other = "Share your experience with others!" + +[users_want_logo_pre] +other = "Want to see your logo on this page?" + +[users_email_us] +other = "Email us!" + +[users_really_want] +other = "We really want to know more about you: tell what you tried, what succeeded, what failed." + +[users_ask_feedback] +other = "Ask questions or give a feedback!" + +[users_ask] +other = "Ask" + +[users_people] +other = "people" + +[users_read] +other = "Read" + +[users_ggroup] +other = "GGroup" + +[users_ggroup_url] +other = "https://groups.google.com/forum/?fromgroups#!forum/selenide" + +[users_ggroup_title] +other = "Selenide googlegroup archive" + +[users_email] +other = "Email" + +[users_me] +other = "me" + +[users_write_to] +other = "Write to" + +[users_twitter] +other = "twitter" + +# Documentation menu +[docs_menu_docs] +other = "Docs" + +[docs_menu_api] +other = "API" + +[docs_menu_page_objects] +other = "Page Objects" + +[docs_menu_screenshots] +other = "Screenshots" + +[docs_menu_reports] +other = "Reports" + +[docs_menu_clouds] +other = "Clouds" + +[docs_menu_selenide_vs_selenium] +other = "Selenide vs Selenium" + +[docs_menu_resources] +other = "Resources" + +[docs_menu_video] +other = "Video" + +# Meta +[meta_keywords] +other = "Selenide, Selenium, WebDriver, Test automation, automated tests, TDD, ATDD, concise UI tests" + +# Footer +[footer_maintained_by] +other = "The project is maintained by" diff --git a/i18n/ru.toml b/i18n/ru.toml new file mode 100644 index 000000000..22a045b0e --- /dev/null +++ b/i18n/ru.toml @@ -0,0 +1,260 @@ +# Main menu +[menu_quick_start] +other = "С чего начать?" + +[menu_docs] +other = "Док" + +[menu_faq] +other = "ЧАВО" + +[menu_blog] +other = "Блог" + +[menu_javadoc] +other = "Javadoc" + +[menu_users] +other = "Пользователи" + +[menu_quotes] +other = "Отзывы" + +[menu_thanks] +other = "Мы говорим спасибо" + +[news_released] +other = "Вышла Selenide" + +[news_mcp] +other = "Selenide MCP server" + +# Donate +[donate_title] +other = "Селенид поддерживает Украину" + +[donate_social_drone_url] +other = "https://www.socialdrone.com.ua/" + +[donate_social_drone] +other = "Social Drone" + +[donate_charity] +other = "Фонд поддержки украинской армии" + +[donate_un_fund] +other = "Гуманитарный фонд ООН" + +# Quicklinks +[quicklink_view_on] +other = "View on" + +[quicklink_search_in] +other = "Search in" + +[quicklink_read_our] +other = "Read our" + +[quicklink_blog] +other = "Blog" + +[quicklink_follow_at] +other = "Follow at" + +[quicklink_subscribe_to] +other = "Subscribe to" + +# 404 +[err_page_not_found] +other = "Страница не найдена" + +# Homepage +[home_what_is_title] +other = "Что такое Selenide?" + +[home_what_is_subtitle] +other = "Selenide - это фреймворк для автоматизированного тестирования веб-приложений на основе Selenium WebDriver, дающий следующие преимущества:" + +[home_concise_api] +other = "Изящный API" + +[home_stable_tests] +other = "Стабильные тесты" + +[home_powerful_selectors] +other = "Мощные селекторы" + +[home_simple_config] +other = "Простая конфигурация" + +[home_what_is_desc1] +other = "Вам больше не нужно заботиться о том, как закрыть браузер, обработать таймауты и StaleElement Exceptions или искать соответствующую строку в логах, отлаживая свои тесты." + +[home_what_is_desc2] +other = "Просто сконцентрируйтесь на бизнес-логике и позвольте Selenide сделать все остальное!" + +[home_quick_start_title] +other = "С чего начать?" + +[home_quick_start_subtitle] +other = "Начать использовать Selenide невероятно просто." + +[home_quick_start_desc1_pre] +other = "Просто добавьте" + +[home_quick_start_desc1_post] +other = "в ваш проект. И начинайте писать тесты!" + +[home_quick_start_desc2] +other = "" + +[home_docs_title] +other = "Документация" + +[home_docs_subtitle_1] +other = "Плохой софт" + +[home_docs_subtitle_1b] +other = "не имеет" + +[home_docs_subtitle_1c] +other = "документации." + +[home_docs_subtitle_2] +other = "Отличный софт" + +[home_docs_subtitle_2b] +other = "не нуждается" + +[home_docs_subtitle_2c] +other = "в документации." + +[home_docs_desc1] +other = "Мы с гордостью заявляем, что Selenide настолько прост, что вам не нужно читать тонны документации, чтобы начать с ним работать." + +[home_docs_desc2] +other = "Вся работа с Selenide состоит всего из трёх простых вещей." + +[home_contacts_title] +other = "Контакты" + +[home_contacts_subtitle] +other = "Ты хочешь поговорить об этом?" + +[home_contacts_desc] +other = "Где можно задать вопрос или обсудить любой вопрос насчёт Selenide на русском языке:" + +[home_googlegroup_url] +other = "mailto:selenide-ru@googlegroups.com" + +[home_googlegroup] +other = "Гуглогруппа" + +[home_gitter_url] +other = "https://gitter.im/codeborne/selenide-ru" + +[home_telegram_url] +other = "https://t.me/selenide_ru" + +[home_testimonials_title] +other = "Отзывы" + +[home_testimonials_quote] +other = '"Selenide - мощный инструмент для написания функциональных тестов. Рекомендую."' + +[home_testimonials_author_role] +other = "Инженер LiveRebel в ZeroTurnaround" + +[home_thanks_title] +other = "Большое спасибо:" + +[home_jetbrains_alt] +other = "JetBrains. Intellij IDEA - лучшая IDE для Java на Млечном Пути!" + +[home_browser_testing_via] +other = "Browser testing via" + +# Users page +[users_tell_us_title] +other = "Сообщи о себе!" + +[users_share_experience] +other = "Поделись с нами опытом!" + +[users_want_logo_pre] +other = "Хотите увидеть здесь и свой логотип?" + +[users_email_us] +other = "Напишите нам!" + +[users_really_want] +other = "Нам чертовски интересно узнать про вас: что пробовали, что получилось, какие встретили проблемы." + +[users_ask_feedback] +other = "Задай свои вопросы или оставь отзыв!" + +[users_ask] +other = "Спроси у" + +[users_people] +other = "людей" + +[users_read] +other = "Читай" + +[users_ggroup] +other = "ГГруппу" + +[users_ggroup_url] +other = "https://groups.google.com/forum/?fromgroups#!forum/selenide-ru" + +[users_ggroup_title] +other = "Архив гуглогруппы selenide-ru" + +[users_email] +other = "Напиши" + +[users_me] +other = "мне" + +[users_write_to] +other = "Пиши в" + +[users_twitter] +other = "твиттер" + +# Documentation menu +[docs_menu_docs] +other = "Доки" + +[docs_menu_api] +other = "API" + +[docs_menu_page_objects] +other = "Page Objects" + +[docs_menu_screenshots] +other = "Скриншоты" + +[docs_menu_reports] +other = "Отчёты" + +[docs_menu_clouds] +other = "Облака" + +[docs_menu_selenide_vs_selenium] +other = "Selenide vs Selenium" + +[docs_menu_resources] +other = "Ресурсы" + +[docs_menu_video] +other = "Видео" + +# Meta +[meta_keywords] +other = "Selenide, Selenium, WebDriver, Test automation, ATDD, concise UI tests, Селенид, Селениум, вебдрайвер, автоматизация тестирования, автотесты, ТДД, АТДД, лаконичные тесты" + +# Footer +[footer_maintained_by] +other = "The project is maintained by" diff --git a/layouts/404.html b/layouts/404.html index a03bcfa23..6f9b6cf8f 100644 --- a/layouts/404.html +++ b/layouts/404.html @@ -3,7 +3,7 @@

    - Page not found

    FAQ | Blog + {{ T "err_page_not_found" }}

    {{ T "menu_faq" }} | {{ T "menu_blog" }}
    diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index c2deeb299..ea145e137 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -1,11 +1,11 @@ - + - + {{ .Title }} @@ -52,7 +52,7 @@

    {{ .Title }}