· 6 years ago · Dec 02, 2019, 02:46 PM
1public abstract class WebDriverPageObject<T extends WebDriverPageObject<T>> implements WebStepRepository<T>, StepWrapperSteps<T> {
2 @SuppressWarnings("unused")
3 private WebDriverPageObjectFactory pageObjectFactory;
4
5 protected WebDriver driver;
6 protected WebDriverWait driverWait;
7
8 /**
9 * Метод для перехода между PageObject
10 * @param pageClass - класс PageObject'а
11 * @param <D> - обобщенный тип
12 * @return - объект класса pageClass
13 */
14 public final <D extends WebDriverPageObject<D>> D seePage(final Class<D> pageClass) {
15 assertNotEquals(this.getClass(), pageClass,
16 "Не передавайте в параметр Class<D> nextPage ту же самую страницу, на которой находитесь, " +
17 "используйте методы без параметра ( ͡° ͜ʖ ͡°)");
18 return pageObjectFactory.createPageObject(pageClass);
19 }
20
21 @Override
22 public T openUrl(final String url) {
23 driver.get(url);
24 return (T) this;
25 }
26
27 protected void sendKeys(final String xpath, final CharSequence... value) {
28 getWebElement(xpath).sendKeys(value);
29 }
30
31 protected void click(final String xpath) {
32 getWebElement(xpath).click();
33 }
34
35 protected void clear(final String xpath) {
36 getWebElement(xpath).clear();
37 }
38
39 protected WebElement getWebElement(final String xpath) {
40 return driver.findElement(By.xpath(xpath));
41 }
42
43 protected List<WebElement> getWebElementList(final String xpath) {
44 return driver.findElements(By.xpath(xpath));
45 }
46
47 protected void jsClick(String xpath) {
48 jsClick(getWebElement(xpath));
49 }
50
51 protected void jsClick(WebElement webElement) {
52 ((JavascriptExecutor) driver).executeScript("arguments[0].click();", webElement);
53 }
54
55 protected void scrollIntoView(WebElement webElement) {
56 ((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", webElement);
57 }
58
59 protected void scrollIntoView(String xpath) {
60 scrollIntoView(getWebElement(xpath));
61 }
62
63 protected void waitUntilPageIsLoaded() {
64 driverWait.until(webDriver -> (((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete")));
65 }
66}
67
68final class WebDriverPageObjectFactory {
69 private static final Logger LOGGER = LogManager.getLogger(WebDriverPageObjectFactory.class);
70
71 private int COUNTER;
72 private final WebDriver webDriver;
73 private final WebDriverWait webDriverWait;
74 private final Map<Class<? extends WebDriverPageObject<?>>, WebDriverPageObject<? extends WebDriverPageObject<?>>> pageObjectCache = new HashMap<>();
75
76 WebDriverPageObjectFactory(final WebDriver webDriver, final WebDriverWait webDriverWait) {
77 this.webDriver = webDriver;
78 this.webDriverWait = webDriverWait;
79 }
80
81 /**
82 * Создание pageObject
83 * Сначала создает инстанс передаваемого класса через дефолтный конструктор,
84 * потом подсовывает через Reflection API значения драйвера
85 * @param pageObjectClass - класс страницы
86 * @param <T> - обобщенный параметр
87 * @return - инициализированный объект страницы
88 */
89 <T extends WebDriverPageObject<T>> T createPageObject(final Class<T> pageObjectClass) {
90 isSupported(pageObjectClass);
91
92 LOGGER.debug("Создание PageObject " + pageObjectClass.getName());
93
94 WebDriverPageObject<? extends WebDriverPageObject<?>> cachedPageObject = pageObjectCache.get(pageObjectClass);
95
96 // Если ответ не нулевой, то вернуть кешированный объект
97 // если нулевой, то проинициализировать объект, положить его в мапу и вернуть
98 if (cachedPageObject != null) {
99 LOGGER.debug("Обрашение к кешу № " + COUNTER++);
100 return pageObjectClass.cast(cachedPageObject);
101 } else {
102 try {
103 Constructor<T> constructor = pageObjectClass.getDeclaredConstructor();
104 constructor.setAccessible(true);
105 T instance = constructor.newInstance();
106 initPage(instance, pageObjectClass);
107 pageObjectCache.put(pageObjectClass, instance);
108 return instance;
109 } catch (final InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
110 e.printStackTrace();
111 throw new PageNotInitializedException("Страница не инициализирована, проблема в конструкторе по умолчанию");
112 }
113 }
114 }
115
116 private <T extends WebDriverPageObject<T>> void isSupported(final Class<T> pageObjectClass) {
117 LOGGER.debug("Проверка валидности пары PageObject " + pageObjectClass.getName() + " и PageObjectFactory " + this.getClass().getName());
118 Class<?> superClass = pageObjectClass.getSuperclass();
119
120 if (!superClass.equals(WebDriverPageObject.class)) {
121 throw new PageNotInitializedException(this.getClass().getName() + " не поддерживает PageObject класса " + pageObjectClass.getName());
122 }
123 }
124
125 void shutdown() {
126 LOGGER.debug("Закрытие фабрики");
127 webDriver.quit();
128 }
129
130 byte[] makeScreenshot() {
131 LOGGER.debug("Создание скриншота");
132 return ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.BYTES);
133 }
134
135/**
136 * Инициализация объекта страницы
137 * @param pageObjectInstance - инстанс, созданный через дефолтный конструктор
138 * @param <T> - обобщенный параметр, ограниченный сверху WebDriverPageObject
139 */
140 private <T extends WebDriverPageObject<T>> void initPage(final T pageObjectInstance, Class<T> pageObjectClass) {
141 //Страница уже проверена на валидность, можно спокойно кастовать
142 @SuppressWarnings("unchecked")
143 Class<WebDriverPageObject<?>> superClass = (Class<WebDriverPageObject<?>>) pageObjectClass.getSuperclass();
144
145 Map<String, Object> nameAndValues = Map.of(
146 "driver", webDriver,
147 "driverWait", webDriverWait,
148 "pageObjectFactory", this
149 );
150
151 // Получение полей страницы и инициализация
152 setFieldValue(superClass, pageObjectInstance, nameAndValues);
153 }
154 private <T> void setFieldValue(Class<T> toSearch, Object instance, Map<String, Object> nameAndValues) {
155 nameAndValues
156 .forEach((key, value) -> {
157 try {
158 Field field = toSearch.getDeclaredField(key);
159 field.setAccessible(true);
160 field.set(instance, value);
161 } catch (NoSuchFieldException | IllegalAccessException e) {
162 e.printStackTrace();
163 throw new PageNotInitializedException("Не удалось инициализировать страницу " + instance.getClass().getName());
164 }
165 });
166 }
167
168 private static class PageNotInitializedException extends RuntimeException {
169 PageNotInitializedException(final String message) {
170 super(message);
171 }
172 }
173}
174
175public final class WebDriverPageObjectFactoryCallbacks implements BeforeEachCallback, AfterEachCallback, ParameterResolver, TestExecutionExceptionHandler {
176 private static final Logger LOGGER = LogManager.getLogger();
177
178 private final Set<Class<? extends WebDriverPageObject<?>>> pageObjectClassSet;
179
180 private WebDriverPageObjectFactory pageObjectFactory;
181
182 public WebDriverPageObjectFactoryCallbacks(Set<Class<? extends WebDriverPageObject<?>>> pageObjectClassList) {
183 this.pageObjectClassSet = pageObjectClassList;
184 }
185 @Override
186 public void beforeEach(ExtensionContext context) {
187 this.pageObjectFactory = createWebDriverFactory();
188 }
189
190 @Override
191 public void afterEach(ExtensionContext context) {
192 this.pageObjectFactory.shutdown();
193 }
194
195 @Override
196 public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
197 return pageObjectClassSet
198 .stream()
199 .anyMatch(pageObjectClass -> parameterContext.getParameter().getType().equals(pageObjectClass));
200 }
201 //Если передать не поддерживаемый тип PageObject, то будет брошено исключение
202 @SuppressWarnings("unchecked")
203 @Override
204 public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
205 return pageObjectFactory.createPageObject((Class<? extends WebDriverPageObject>) parameterContext.getParameter().getType());
206 }
207
208 @Override
209 public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable {
210 LOGGER.debug("Тест кинул исключение");
211 Allure.getLifecycle().addAttachment("Скриншот", "image/png", "", pageObjectFactory.makeScreenshot());
212 throw throwable;
213 }
214}
215
216final class PageObjectFactoryManager {
217 private static final Config CONFIG = ConfigFactory.load();
218 private static final Logger LOGGER = LogManager.getLogger();
219
220 static WebDriverPageObjectFactory createWebDriverFactory() {
221 String browser = CONFIG.getString("selenium.browser");
222 int timeToWait = CONFIG.getInt("selenium.timeToWait");
223 boolean isHeadless = CONFIG.getBoolean("selenium.isHeadless");
224
225 LOGGER.debug("Считаны параметры selenium.browser=" + browser + ", selenium.timeToWait=" + timeToWait + ", selenium.isHeadless=" + isHeadless);
226
227 WebDriver webDriver = getWebDriver(browser, timeToWait, isHeadless);
228 WebDriverWait webDriverWait = new WebDriverWait(webDriver, timeToWait);
229
230 return new WebDriverPageObjectFactory(webDriver, webDriverWait);
231 }
232}
233
234@StepRepository
235public interface ButtonStepRepository<T> {
236 @Step("Нажатие кнопки {name}")
237 default T clickButton(final String name) {
238 throw new NotImplementedException("Реализуйте метод");
239 }
240
241 @Step("Нажатие кнопок {names}")
242 default T clickButton(final List<String> names) {
243 throw new NotImplementedException("Реализуйте метод");
244 }
245
246 @Step("Проверка отображения кнопки {name}")
247 default T checkButtonIsDisplayed(final String name) {
248 throw new NotImplementedException("Реализуйте метод");
249 }
250
251 @Step("Проверка отображения кнопок {names}")
252 default T checkButtonIsDisplayed(final List<String> names) {
253 throw new NotImplementedException("Реализуйте метод");
254 }
255}
256
257@StepRepository
258public interface CheckboxStepRepository<T> {
259 @Step("Клик чекбокса {name}")
260 default T clickCheckbox(final String name) {
261 throw new NotImplementedException("Реализуйте метод");
262 }
263
264 @Step("Клик чекбоксов {names}")
265 default T clickCheckbox(final List<String> names) {
266 throw new NotImplementedException("Реализуйте метод");
267 }
268
269 @Step("Проверка выбора чекбокса {name}")
270 default T checkCheckboxIsSelected(final String name) {
271 throw new NotImplementedException("Реализуйте метод");
272 }
273
274 @Step("Проверка выбора чекбоксов {names}")
275 default T checkCheckboxIsSelected(final List<String> names) {
276 throw new NotImplementedException("Реализуйте метод");
277 }
278
279 @Step("Проверка что чекбокс {name} не выбран")
280 default T checkCheckboxIsNotSelected(final String name) {
281 throw new NotImplementedException("Реализуйте метод");
282 }
283
284 @Step("Проверка что чекбоксы не выбраны {names}")
285 default T checkCheckboxIsNotSelected(final List<String> names) {
286 throw new NotImplementedException("Реализуйте метод");
287 }
288
289 @Step("Проверка отображения чекбокса {name}")
290 default T checkCheckboxIsDisplayed(final String name) {
291 throw new NotImplementedException("Реализуйте метод");
292 }
293
294 @Step("Проверка отображения чекбоксов {names}")
295 default T checkCheckboxIsDisplayed(final List<String> names) {
296 throw new NotImplementedException("Реализуйте метод");
297 }
298}
299
300@StepRepository
301public interface DropdownStepRepository<T> {
302 @Step("Выбор {value} из выпадающего списка {name}")
303 default T selectFromDropdownList(final String name, final String value) {
304 throw new NotImplementedException("Реализуйте метод");
305 }
306
307 @Step("Выбор соответствующих значений из выпадающего списка {values}")
308 default T selectFromDropdownList(final Map<String, String> values) {
309 throw new NotImplementedException("Реализуйте метод");
310 }
311
312 @Step("Очистка выпадающего списка {name}")
313 default T clearDropdownList(final String name) {
314 throw new NotImplementedException("Реализуйте метод");
315 }
316
317 @Step("Очистка выпадающих списков {names}")
318 default T clearDropdownList(final List<String> names) {
319 throw new NotImplementedException("Реализуйте метод");
320 }
321}
322@StepRepository
323public interface FieldStepRepository<T> {
324 @Step("Проверка что поле {name} не пустое")
325 default T checkFieldIsNotEmpty(final String name) {
326 throw new NotImplementedException("Реализуйте метод");
327 }
328
329 @Step("Проверка что поля {names} не пустые")
330 default T checkFieldIsNotEmpty(final List<String> names) {
331 throw new NotImplementedException("Реализуйте метод");
332 }
333
334 @Step("Проверка пустоты поля {name}")
335 default T checkFieldIsEmpty(final String name) {
336 throw new NotImplementedException("Реализуйте метод");
337 }
338
339 @Step("Проверка пустоты полей {names}")
340 default T checkFieldIsEmpty(final List<String> names) {
341 throw new NotImplementedException("Реализуйте метод");
342 }
343
344 @Step("Запоминаю {name} как {key}")
345 default T putFieldValueInMap(final String name, final String key, final Map<String, String> map) {
346 throw new NotImplementedException("Реализуйте метод");
347 }
348
349 @Step("Проверка содержания полем {name} значения {expectedValue}")
350 default T checkFieldContainsValue(final String name, final String expectedValue) {
351 throw new NotImplementedException("Реализуйте метод");
352 }
353
354 @Step("Проверка содержания полями соответствующих значений {values}")
355 default T checkFieldContainsValue(final Map<String, String> values) {
356 throw new NotImplementedException("Реализуйте метод");
357 }
358
359 @Step("Проверка что поле {name} не содержит значения {unexpectedValue}")
360 default T checkFieldDoesntContainValue(final String name, final String unexpectedValue) {
361 throw new NotImplementedException("Реализуйте метод");
362 }
363
364 @Step("Проверка что поля не содержат соответствующих значений {values}")
365 default T checkFieldDoesntContainValue(final Map<String, String> values) {
366 throw new NotImplementedException("Реализуйте метод");
367 }
368
369@Step("Заполнение поля {name} значением {value}")
370 default T fillField(final String name, final String value) {
371 throw new NotImplementedException("Реализуйте метод");
372 }
373
374 @Step("Заполнение полей соответствующими значениями {values}")
375 default T fillField(final Map<String, String> values) {
376 throw new NotImplementedException("Реализуйте метод");
377 }
378
379 @Step("Очистка поля {name}")
380 default T clearField(final String name) {
381 throw new NotImplementedException("Реализуйте метод");
382 }
383}
384@StepRepository
385public interface MessagesStepRepository<T> {
386 @Step("Проверка отображения предупреждения {warning}")
387 default T warningIsDisplayed(final String warning) {
388 throw new NotImplementedException("Реализуйте метод");
389 }
390
391 @Step("Проверка отображения предупреждений {warnings}")
392 default T warningIsDisplayed(final List<String> warnings) {
393 throw new NotImplementedException("Реализуйте метод");
394 }
395
396 @Step("Проверка отображения текста {text}")
397 default T textIsDisplayed(final String text) {
398 throw new NotImplementedException("Реализуйте метод");
399 }
400
401 @Step("Проверка отображения текста {texts}")
402 default T textIsDisplayed(final List<String> texts) {
403 throw new NotImplementedException("Реализуйте метод");
404 }
405
406 @Step("Проверка отображения ошибки {error}")
407 default T errorIsDisplayed(final String error) {
408 throw new NotImplementedException("Реализуйте метод");
409 }
410
411 @Step("Проверка отображения ошибок {errors}")
412 default T errorIsDisplayed(final List<String> errors) {
413 throw new NotImplementedException("Реализуйте метод");
414 }
415}
416
417@StepRepository
418public interface RadioButtonStepRepository<T> {
419 @Step("Нажатие радиокнопки {name}")
420 default T clickRadioButton(final String name) {
421 throw new NotImplementedException("Реализуйте метод");
422 }
423
424 @Step("Нажатие радиокнопок {names}")
425 default T clickRadioButton(final List<String> names) {
426 throw new NotImplementedException("Реализуйте метод");
427 }
428
429 @Step("Проверка выбора радиокнопки {name}")
430 default T checkRadioButtonIsSelected(final String name) {
431 throw new NotImplementedException("Реализуйте метод");
432 }
433
434 @Step("Проверка выбора радиокнопкок {names}")
435 default T checkRadioButtonIsSelected(final List<String> names) {
436 throw new NotImplementedException("Реализуйте метод");
437 }
438
439 @Step("Проверка что радиокнопка {name} не выбрана")
440 default T checkRadioButtonIsNotSelected(final String name) {
441 throw new NotImplementedException("Реализуйте метод");
442 }
443
444 @Step("Проверка что радиокнопки не выбраны {names}")
445 default T checkRadioButtonIsNotSelected(final List<String> names) {
446 throw new NotImplementedException("Реализуйте метод");
447 }
448
449 @Step("Проверка отображения радиокнопки {name}")
450 default T checkRadioButtonIsDisplayed(final String name) {
451 throw new NotImplementedException("Реализуйте метод");
452 }
453
454 @Step("Проверка отображения радиокнопок {names}")
455 default T checkRadioButtonIsDisplayed(final List<String> names) {
456 throw new NotImplementedException("Реализуйте метод");
457 }
458}
459
460@StepRepository
461public interface TableFilterStepRepository<T> {
462 @Step("Выбор значения {value} из фильтров {name}")
463 default T selectFromFilter(final String name, final String value) {
464 throw new NotImplementedException("Не реализовано");
465 }
466 @Step("Выбор значений из соответствуюших фильтров {values}")
467 default T selectFromFilter(final Map<String, String> values) {
468 throw new NotImplementedException("Не реализовано");
469 }
470
471 @Step("Заполнение фильтра {name} значением {value}")
472 default T fillFilter(final String name, final String value) {
473 throw new NotImplementedException("Реализуйте метод");
474 }
475
476 @Step("Заполнение фильтров соответствующими значениями {values}")
477 default T fillFilter(final Map<String, String> values) {
478 throw new NotImplementedException("Реализуйте метод");
479 }
480
481 @Step("Очистка фильтра {name}")
482 default T clearFilter(final String name) {
483 throw new NotImplementedException("Реализуйте метод");
484 }
485
486 @Step("Очистка фильтров {names}")
487 default T clearFilter(final List<String> names) {
488 throw new NotImplementedException("Реализуйте метод");
489 }
490
491 @Step("Очистка фильтра-выпадающего списка {name}")
492 default T deselectFilter(final String name) {
493 throw new NotImplementedException("Не реализовано");
494 }
495
496 @Step("Очистка фильтров-выпадающих списков {names}")
497 default T deselectFilter(final List<String> names) {
498 throw new NotImplementedException("Не реализовано");
499 }
500
501 @Step("Проверка содержания фильтром {name} значения {value}")
502 default T checkFilterContainsValue(final String name, final String value) {
503 throw new NotImplementedException("Не реализовано");
504 }
505
506 @Step("Проверка содержания фильтрами соответствующих значений {values}")
507 default T checkFilterContainsValue(final Map<String, String> values) {
508 throw new NotImplementedException("Не реализовано");
509 }
510
511 @Step("Проверка пустоты фильтра {name}")
512 default T checkFilterIsEmpty(final String name) {
513 throw new NotImplementedException("Не реализовано");
514 }
515
516 @Step("Проверка пустоты фильтров {names}")
517 default T checkFilterIsEmpty(final List<String> names) {
518 throw new NotImplementedException("Не реализовано");
519 }
520}
521
522@StepRepository
523public interface TableSortingRepository<T> {
524 @Step("Проверка что колонка {column} отсортирована по {way}")
525 default T checkColumnSorted(final String column, final Sorting way, final Comparator comparator) {
526 throw new NotImplementedException("Реализуйте метод");
527 }
528
529 @Step("Проверка что колонка с датами {column} отсортирована по {way}")
530 default T checkDateColumnSorted(final String column, final Sorting way) {
531 throw new NotImplementedException("Реализуйте метод");
532 }
533
534 @Step("Проверка что колонка с датами {column} отсортирована по {way}")
535 default T checkDateColumnSorted(final String column, final Sorting way, final DateTimeFormatter formatter,
536 final Comparator<LocalDate> comparator) {
537 throw new NotImplementedException("Реализуйте метод");
538 }
539
540 enum Sorting {
541 ASCENDING(),
542 DESCENDING()
543 }
544}
545
546@StepRepository
547public interface TableStepRepository<T> {
548 @Step("Клик на заголовок {name}")
549 default T clickOnHeader(final String name) {
550 throw new NotImplementedException("Реализуйте метод");
551 }
552
553 @Step("Клик на заголовки {names}")
554 default T clickOnHeader(final List<String> names) {
555 throw new NotImplementedException("Реализуйте метод");
556 }
557
558 @Step("Проверка заголовка {name}")
559 default T headerIsPresent(final String name) {
560 throw new NotImplementedException("Реализуйте метод");
561 }
562
563 @Step("Проверка заголовков {headers}")
564 default T headerIsPresent(final List<String> headers) {
565 throw new NotImplementedException("Реализуйте метод");
566 }
567
568 @Step("Проверка пустоты таблицы")
569 default T checkTableIsEmpty() {
570 throw new NotImplementedException("Не реализовано");
571 }
572
573 @Step("Нажатие на ячейку {column} в строке {row}")
574 default T clickOnEntry(final String column, final int row) {
575 throw new NotImplementedException("Реализуйте метод");
576 }
577
578 @Step("Нажатие на ячейку {column} со значением {value}")
579 default T clickOnEntry(final String column, final String value) {
580 throw new NotImplementedException("Реализуйте метод");
581 }
582
583 @Step("Запоминаю значение колонки {column} в строке {row} как {key}")
584 default T getCellValueAndPutInMap(final String column, final String key, final int row,
585 final Map<String, String> map) {
586 throw new NotImplementedException("Реализуйте метод");
587 }
588
589 @Step("Получение ненулевого значения колонки {column}")
590 default T getNonNullValue(final String column, final Map<String, String> map) {
591 throw new NotImplementedException("Реализуйте метод");
592 }
593
594 @Step("Проверка что колонка {column} содержит {value}")
595 default T checkColumnContainsValue(final String column, final String value) {
596 throw new NotImplementedException("Реализуйте метод");
597 }
598
599 @Step("Проверка что колонка {column} в строке {row} содержит {value}")
600 default T checkCellContainsValue(final String column, final String value, final int row) {
601 throw new NotImplementedException("Реализуйте метод");
602 }
603
604 @Step("Проверка что колонка {column} НЕ содержит {value}")
605 default T checkColumnDoesntContainValue(final String column, final String value) {
606 throw new NotImplementedException("Реализуйте метод");
607 }
608
609 @Step("Проверка что колонка {column} пуста")
610 default T checkColumnIsEmpty(final String column) {
611 throw new NotImplementedException("Реализуйте метод");
612 }
613 @Step("Проверка что колонка {column} НЕ пуста")
614 default T checkColumnIsNotEmpty(final String column) {
615 throw new NotImplementedException("Реализуйте метод");
616 }
617
618 @Step("Проверка что размер колонки {column} равен {size}")
619 default T checkColumnSize(final String column, final int size) {
620 throw new NotImplementedException("Реализуйте метод");
621 }
622}
623
624@StepRepository
625public interface WebStepRepository<T> {
626 @Step("Переход по ссылке {url}")
627 default T openUrl(final String url) {
628 throw new NotImplementedException("Реализуйте метод");
629 }
630
631 @Step("Проверка отображения формы {name}")
632 default T checkFormIsDisplayed(String name) {
633 throw new NotImplementedException("Реализуйте метод");
634 }
635}
636
637public final class AllureConcurrentLoggerAttachmentsExtension implements AfterEachCallback {
638 //Путь до файла логов читается из commons/src/main/resources/application.conf
639 private static final String LOG_PATH = ConfigFactory.load().getString("logging.path");
640 private final String[] regex;
641
642 public AllureConcurrentLoggerAttachmentsExtension(String... regex) {
643 this.regex = regex;
644 }
645
646 @Override
647 public void afterEach(ExtensionContext context) throws IOException {
648 //Группировка логов по айдишнику
649 String groupedLogMessages = getMessagesWithId(Allure.getLifecycle().getCurrentTestCase().orElseThrow());
650
651 for (String regex: regex) {
652 groupedLogMessages = groupedLogMessages.replaceAll(regex, "*****");
653 }
654
655 Allure
656 .getLifecycle()
657 .addAttachment("Полный лог", "text/plain", ".txt", groupedLogMessages.getBytes(UTF_8));
658 }
659
660 private String getMessagesWithId(String uuid) throws IOException {
661 String uuidTemplate = "[" + uuid + "] ";
662 return Files
663 .readAllLines(Path.of(System.getProperty("user.dir") + LOG_PATH), UTF_8)
664 .stream()
665 //Фильтрация сообщений по id
666 .filter(logMessage -> logMessage.contains(uuidTemplate))
667 //Удаление id из текста сообщений
668 .map(logMessage -> logMessage.replaceAll("\\[" + uuid + "] ", ""))
669 //Конвертация Stream в строку с делимитером \n
670 .collect(Collectors.joining("\n"));
671 }
672}
673
674@Aspect
675public final class StepAspect {
676 private static final Set<Class<?>> REPOSITORY_CLASSES = new AnnotatedTypeScanner(true, StepRepository.class)
677 .findTypes("ru.gazprombank.automation")
678 .stream()
679 .filter(Class::isInterface)
680 .collect(toSet());
681
682 @Pointcut("execution(public * ru.gazprombank.automation.testapps.*..*(..))")
683 public void anyMethod() {
684 }
685
686 @Around("anyMethod()")
687 public Object processStepMethod(ProceedingJoinPoint joinPoint) throws Throwable {
688 MethodSignature signature = (MethodSignature) joinPoint.getSignature();
689
690 Class<?>[] implementedInterfaces = signature.getMethod().getDeclaringClass().getInterfaces();
691
692 Set<Class<?>> stepInterfaces = Stream
693 .of(implementedInterfaces)
694 .filter(REPOSITORY_CLASSES::contains)
695 .collect(toSet());
696
697 if (stepInterfaces.size() != 0) {
698 Method foundMethod = stepInterfaces
699 .stream()
700 .flatMap(type -> Stream.of(type.getDeclaredMethods()))
701 .filter(Method::isDefault)
702 .filter(method -> sameSignature(signature, method))
703 .findAny()
704 .orElse(null);
705
706 if (foundMethod != null) {
707 Step step = foundMethod.getDeclaredAnnotation(Step.class);
708
709 String name = getName(step.value(), signature, joinPoint.getArgs());
710 List<Parameter> parameters = getParameters(signature, joinPoint.getArgs());
711
712 String uuid = UUID.randomUUID().toString();
713
714 StepResult result = new StepResult()
715 .setName(name)
716 .setParameters(parameters);
717
718 getLifecycle().startStep(uuid, result);
719
720 try {
721 Object res = joinPoint.proceed(joinPoint.getArgs());
722 getLifecycle()
723 .updateStep(s -> s.setStatus(Status.PASSED));
724 getLifecycle()
725 .stopStep();
726 return res;
727 } catch (Throwable throwable) {
728 getLifecycle()
729 .updateStep(s -> s
730 .setStatus(getStatus(throwable).orElse(Status.BROKEN))
731 .setStatusDetails(getStatusDetails(throwable).orElse(null))
732 );
733 getLifecycle()
734 .stopStep();
735 throw throwable;
736 }
737 }
738 }
739
740 return joinPoint.proceed(joinPoint.getArgs());
741 }
742 private boolean sameSignature(MethodSignature signature, Method method) {
743 return signature.getName().equals(method.getName()) &&
744 signature.getModifiers() == method.getModifiers() &&
745 Arrays.equals(signature.getParameterTypes(), method.getParameterTypes());
746 }
747
748 private AllureLifecycle getLifecycle() {
749 return Allure.getLifecycle();
750 }
751}
752
753public final class DataSourceProvider {
754 private static final Config CONFIG = ConfigFactory.load();
755
756 private static final String URL = CONFIG.getString("database.url");
757 private static final String USERNAME = CONFIG.getString("database.username");
758 private static final String PASSWORD = CONFIG.getString("database.password");
759 private static final String DRIVER_CLASS_NAME = CONFIG.getString("database.driverClassName");
760 private static final String CATALOG = CONFIG.getString("database.catalog");
761 private static DataSource INSTANCE;
762
763 private DataSourceProvider() {}
764
765 static DataSource get() {
766 if (INSTANCE == null) {
767 INSTANCE = createDataSource();
768 }
769
770 return INSTANCE;
771 }
772
773 private static DataSource createDataSource() {
774 DriverManagerDataSource dataSource = new DriverManagerDataSource();
775
776 dataSource.setDriverClassName(DRIVER_CLASS_NAME);
777 dataSource.setUrl(URL);
778 dataSource.setUsername(USERNAME);
779 dataSource.setPassword(PASSWORD);
780 dataSource.setCatalog(CATALOG);
781
782 return dataSource;
783 }
784}
785
786public final class SqlConstructionSteps implements StepWrapperSteps<SqlConstructionSteps> {
787 private final DriverManagerDataSource dataSource = new DriverManagerDataSource();
788
789 private SqlConstructionSteps() {
790 }
791
792 public static SqlConstructionSteps sqlConstructDatabase() {
793 return new SqlConstructionSteps();
794 }
795
796 @Step("Добавление драйвера {className}")
797 public SqlConstructionSteps withDriverClassName(String className) {
798 dataSource.setDriverClassName(className);
799 return this;
800 }
801
802 @Step("Добавление ссылки {url}")
803 public SqlConstructionSteps withUrl(String url) {
804 dataSource.setUrl(url);
805 return this;
806 }
807
808 @Step("Добавление имени пользователя {username}")
809 public SqlConstructionSteps withUsername(String username) {
810 dataSource.setUsername(username);
811 return this;
812 }
813
814 @Step("Добавление пароля {password}")
815 public SqlConstructionSteps withPassword(String password) {
816 dataSource.setPassword(password);
817 return this;
818 }
819
820 @Step("Добавление каталога {catalog}")
821 public SqlConstructionSteps withCatalog(String catalog) {
822 dataSource.setCatalog(catalog);
823 return this;
824 }
825
826 public DataSource build() {
827 return dataSource;
828 }
829}
830
831public final class SqlQuerySteps implements StepWrapperSteps<SqlQuerySteps> {
832 private final JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSourceProvider.get());
833
834 private SqlQuerySteps() {
835 }
836
837 public static SqlQuerySteps sqlQuery() {
838 return new SqlQuerySteps();
839 }
840
841 @Step("Отправка запроса {query}")
842 public SqlUpdateValidationSteps update(String query) {
843 return new SqlUpdateValidationSteps(jdbcTemplate.update(query));
844 }
845
846 @Step("Отправка запроса {query} с параметрами {params}")
847 public SqlUpdateValidationSteps update(String query, Object... params) {
848 return new SqlUpdateValidationSteps(jdbcTemplate.update(query, params));
849 }
850}
851
852public final class SqlUpdateValidationSteps {
853 private final int updatedRows;
854
855 SqlUpdateValidationSteps(int updatedRows) {
856 this.updatedRows = updatedRows;
857 }
858
859 @Step("Количество затронутых строк равно {updatedRows}")
860 public SqlUpdateValidationSteps updatedRowsEquals(int updatedRows) {
861 assertEquals(updatedRows, this.updatedRows);
862 return this;
863 }
864
865 @Step("Количество затронутых строк больше {updatedRows}")
866 public SqlUpdateValidationSteps updatedRowsMoreThan(int updatedRows) {
867 assertTrue(this.updatedRows > updatedRows,
868 "Количество затронутых строк " + this.updatedRows + " меньше ожидаемого " + updatedRows);
869 return this;
870 }
871
872 @Step("Количество затронутых строк больше или равно {updatedRows}")
873 public SqlUpdateValidationSteps updatedRowsMoreThanOrEquals(int updatedRows) {
874 assertTrue(this.updatedRows > updatedRows,
875 "Количество затронутых строк " + this.updatedRows + " меньше ожидаемого " + updatedRows);
876 return this;
877 }
878
879 @Step("Количество затронутых строк меньше {updatedRows}")
880 public SqlUpdateValidationSteps updatedRowsLessThan(int updatedRows) {
881 assertTrue(this.updatedRows < updatedRows,
882 "Количество затронутых строк " + this.updatedRows + " больше ожидаемого " + updatedRows);
883 return this;
884 }
885
886 @Step("Количество затронутых строк меньше или равно {updatedRows}")
887 public SqlUpdateValidationSteps updatedRowsLessThanOrEquals(int updatedRows) {
888 assertTrue(this.updatedRows <= updatedRows,
889 "Количество затронутых строк " + this.updatedRows + " больше ожидаемого " + updatedRows);
890 return this;
891 }
892
893 public SqlQuerySteps next() {
894 return sqlQuery();
895 }
896}