diff --git a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/condition/Color.java b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/condition/Color.java new file mode 100644 index 000000000..7c2bd1142 --- /dev/null +++ b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/condition/Color.java @@ -0,0 +1,10 @@ +package guru.qa.niffler.condition; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum Color { + yellow("rgba(255, 183, 3, 1)"), green("rgba(53, 173, 123, 1)"); + + public final String rgb; +} diff --git a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/condition/StatConditions.java b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/condition/StatConditions.java new file mode 100644 index 000000000..45f141c13 --- /dev/null +++ b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/condition/StatConditions.java @@ -0,0 +1,83 @@ +package guru.qa.niffler.condition; + +import com.codeborne.selenide.CheckResult; +import com.codeborne.selenide.Driver; +import com.codeborne.selenide.WebElementCondition; +import com.codeborne.selenide.WebElementsCondition; +import org.apache.commons.lang3.ArrayUtils; +import org.jetbrains.annotations.NotNull; +import org.openqa.selenium.WebElement; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static com.codeborne.selenide.CheckResult.accepted; +import static com.codeborne.selenide.CheckResult.rejected; + +@ParametersAreNonnullByDefault +public class StatConditions { + + @Nonnull + public static WebElementCondition color(Color expectedColor) { + return new WebElementCondition("color " + expectedColor.rgb) { + @NotNull + @Override + public CheckResult check(Driver driver, WebElement element) { + final String rgba = element.getCssValue("background-color"); + return new CheckResult( + expectedColor.rgb.equals(rgba), + rgba + ); + } + }; + } + + @Nonnull + public static WebElementsCondition color(@Nonnull Color... expectedColors) { + return new WebElementsCondition() { + + private final String expectedRgba = Arrays.stream(expectedColors).map(c -> c.rgb).toList().toString(); + + @NotNull + @Override + public CheckResult check(Driver driver, List elements) { + if (ArrayUtils.isEmpty(expectedColors)) { + throw new IllegalArgumentException("No expected colors given"); + } + if (expectedColors.length != elements.size()) { + final String message = String.format("List size mismatch (expected: %s, actual: %s)", expectedColors.length, elements.size()); + return rejected(message, elements); + } + + boolean passed = true; + final List actualRgbaList = new ArrayList<>(); + for (int i = 0; i < elements.size(); i++) { + final WebElement elementToCheck = elements.get(i); + final Color colorToCheck = expectedColors[i]; + final String rgba = elementToCheck.getCssValue("background-color"); + actualRgbaList.add(rgba); + if (passed) { + passed = colorToCheck.rgb.equals(rgba); + } + } + + if (!passed) { + final String actualRgba = actualRgbaList.toString(); + final String message = String.format( + "List colors mismatch (expected: %s, actual: %s)", expectedRgba, actualRgba + ); + return rejected(message, actualRgba); + } + return accepted(); + } + + @Override + public String toString() { + return expectedRgba; + } + }; + } +} diff --git a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/jupiter/extension/ScreenShotTestExtension.java b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/jupiter/extension/ScreenShotTestExtension.java index cf841a270..993cb8907 100644 --- a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/jupiter/extension/ScreenShotTestExtension.java +++ b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/jupiter/extension/ScreenShotTestExtension.java @@ -40,17 +40,19 @@ public BufferedImage resolveParameter(ParameterContext parameterContext, Extensi @Override public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable { - ScreenDif screenDif = new ScreenDif( - "data:image/png;base64," + encoder.encodeToString(imageToBytes(getExpected())), - "data:image/png;base64," + encoder.encodeToString(imageToBytes(getActual())), - "data:image/png;base64," + encoder.encodeToString(imageToBytes(getDiff())) - ); - - Allure.addAttachment( - "Screenshot diff", - "application/vnd.allure.image.diff", - objectMapper.writeValueAsString(screenDif) - ); + if (throwable.getMessage().contains("Screen comparison failure")) { + ScreenDif screenDif = new ScreenDif( + "data:image/png;base64," + encoder.encodeToString(imageToBytes(getExpected())), + "data:image/png;base64," + encoder.encodeToString(imageToBytes(getActual())), + "data:image/png;base64," + encoder.encodeToString(imageToBytes(getDiff())) + ); + + Allure.addAttachment( + "Screenshot diff", + "application/vnd.allure.image.diff", + objectMapper.writeValueAsString(screenDif) + ); + } throw throwable; } diff --git a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/MainPage.java b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/MainPage.java index c9a026746..4089cd7af 100644 --- a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/MainPage.java +++ b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/MainPage.java @@ -23,6 +23,12 @@ public Header getHeader() { return header; } + @Nonnull + public StatComponent getStatComponent() { + statComponent.getSelf().scrollIntoView(true); + return statComponent; + } + @Nonnull public SpendingTable getSpendingTable() { spendingTable.getSelf().scrollIntoView(true); diff --git a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/component/SearchField.java b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/component/SearchField.java index 7fed29d35..e04a67c11 100644 --- a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/component/SearchField.java +++ b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/component/SearchField.java @@ -1,6 +1,7 @@ package guru.qa.niffler.page.component; import com.codeborne.selenide.SelenideElement; +import io.qameta.allure.Step; import javax.annotation.Nonnull; @@ -19,6 +20,7 @@ public SearchField() { private final SelenideElement clearSearchInputBtn = $("#input-clear"); + @Step("Perform search for query {query}") @Nonnull public SearchField search(String query) { clearIfNotEmpty(); @@ -26,6 +28,7 @@ public SearchField search(String query) { return this; } + @Step("Try to clear search field") @Nonnull public SearchField clearIfNotEmpty() { if (self.is(not(empty))) { diff --git a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/component/SelectField.java b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/component/SelectField.java index eb6b639b7..79118d583 100644 --- a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/component/SelectField.java +++ b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/component/SelectField.java @@ -1,6 +1,7 @@ package guru.qa.niffler.page.component; import com.codeborne.selenide.SelenideElement; +import io.qameta.allure.Step; import static com.codeborne.selenide.Condition.text; import static com.codeborne.selenide.Selenide.$$; @@ -18,6 +19,7 @@ public void setValue(String value) { $$("li[role='option']").find(text(value)).click(); } + @Step("Check that selected value is equal to {value}") public void checkSelectValueIsEqualTo(String value) { self.shouldHave(text(value)); } diff --git a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/component/StatComponent.java b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/component/StatComponent.java index c2edbebcd..469953b21 100644 --- a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/component/StatComponent.java +++ b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/page/component/StatComponent.java @@ -1,8 +1,18 @@ package guru.qa.niffler.page.component; import com.codeborne.selenide.ElementsCollection; +import com.codeborne.selenide.SelenideElement; +import guru.qa.niffler.condition.Color; +import io.qameta.allure.Step; + +import javax.annotation.Nonnull; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; import static com.codeborne.selenide.Selenide.$; +import static guru.qa.niffler.condition.StatConditions.color; +import static java.util.Objects.requireNonNull; public class StatComponent extends BaseComponent { public StatComponent() { @@ -10,4 +20,18 @@ public StatComponent() { } private final ElementsCollection bubbles = self.$("#legend-container").$$("li"); + private final SelenideElement chart = $("canvas[role='img']"); + + @Step("Get screenshot of stat chart") + @Nonnull + public BufferedImage chartScreenshot() throws IOException { + return ImageIO.read(requireNonNull(chart.screenshot())); + } + + @Step("Check that stat bubbles contains colors {expectedColors}") + @Nonnull + public StatComponent checkBubbles(Color... expectedColors) { + bubbles.should(color(expectedColors)); + return this; + } } diff --git a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/test/web/SpendingWebTest.java b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/test/web/SpendingWebTest.java index 153ff0b90..c84308d5f 100644 --- a/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/test/web/SpendingWebTest.java +++ b/niffler-e-2-e-tests/src/test/java/guru/qa/niffler/test/web/SpendingWebTest.java @@ -1,6 +1,7 @@ package guru.qa.niffler.test.web; import com.codeborne.selenide.Selenide; +import guru.qa.niffler.condition.Color; import guru.qa.niffler.jupiter.annotation.ScreenShotTest; import guru.qa.niffler.jupiter.annotation.Spending; import guru.qa.niffler.jupiter.annotation.User; @@ -8,16 +9,15 @@ import guru.qa.niffler.model.rest.UserJson; import guru.qa.niffler.page.LoginPage; import guru.qa.niffler.page.MainPage; +import guru.qa.niffler.page.component.StatComponent; import guru.qa.niffler.utils.RandomDataUtils; import guru.qa.niffler.utils.ScreenDiffResult; import org.junit.jupiter.api.Test; -import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Date; -import static com.codeborne.selenide.Selenide.$; import static org.junit.jupiter.api.Assertions.assertFalse; @WebTest @@ -115,7 +115,6 @@ void deleteSpendingTest(UserJson user) { .checkTableSize(0); } - @User( spendings = @Spending( category = "Обучение", @@ -124,16 +123,20 @@ void deleteSpendingTest(UserJson user) { ) ) @ScreenShotTest("img/expected-stat.png") - void checkStatComponentTest(UserJson user, BufferedImage expected) throws IOException { - Selenide.open(LoginPage.URL, LoginPage.class) + void checkStatComponentTest(UserJson user, BufferedImage expected) throws IOException, InterruptedException { + StatComponent statComponent = Selenide.open(LoginPage.URL, LoginPage.class) .fillLoginPage(user.username(), user.testData().password()) - .submit(new MainPage()); + .submit(new MainPage()) + .getStatComponent(); + + Thread.sleep(3000); - BufferedImage actual = ImageIO.read($("canvas[role='img']").screenshot()); assertFalse(new ScreenDiffResult( expected, - actual - )); + statComponent.chartScreenshot() + ), "Screen comparison failure"); + + statComponent.checkBubbles(Color.yellow); } }