From 454a63ea7de5e03a6cd7981f846ce9a9561b5b80 Mon Sep 17 00:00:00 2001 From: Barbora B Date: Sat, 8 Nov 2025 15:35:07 +0100 Subject: [PATCH 1/2] add test properties --- .../cz/czechitas/automation/TestRunner.java | 21 +++++++++++++++++-- src/test/resources/test.properties | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 src/test/resources/test.properties diff --git a/src/test/java/cz/czechitas/automation/TestRunner.java b/src/test/java/cz/czechitas/automation/TestRunner.java index fa47d94..b580907 100644 --- a/src/test/java/cz/czechitas/automation/TestRunner.java +++ b/src/test/java/cz/czechitas/automation/TestRunner.java @@ -7,6 +7,10 @@ import org.openqa.selenium.WebDriver; import cz.czechitas.automation.assertion.AssertionFacade; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + /** * Base test runner class for low code automation on the {@code https://czechitas-app.kutac.cz/} page * @@ -16,6 +20,7 @@ class TestRunner { private final WebDriver webDriver; + private final String baseUrl; protected final SeleniumActionFacade browser; protected final AssertionFacade asserter; @@ -28,11 +33,23 @@ public TestRunner() { this.browser = new SeleniumActionFacade(webDriver); this.asserter = new AssertionFacade(webDriver); this.screenshotExtension = new ScreenshotOnFailExtension(webDriver); + + Properties props = new Properties(); + try (InputStream in = getClass().getClassLoader().getResourceAsStream("test.properties")) { + if (in != null) { + props.load(in); + } + } catch (IOException e) { + throw new RuntimeException("Failed to load test.properties", e); + } + + // System property overrides file property; fallback to a sensible default + this.baseUrl = System.getProperty("app.url", props.getProperty("app.url", "https://team8-2022brno.herokuapp.com/")); } @BeforeEach void setUp() { - webDriver.get("https://team8-2022brno.herokuapp.com/"); + webDriver.get(baseUrl); } @AfterEach @@ -44,4 +61,4 @@ void tearDown() { throw new RuntimeException(e); } } -} +} \ No newline at end of file diff --git a/src/test/resources/test.properties b/src/test/resources/test.properties new file mode 100644 index 0000000..4b9ac2f --- /dev/null +++ b/src/test/resources/test.properties @@ -0,0 +1 @@ +app.url=https://team8-2022brno.herokuapp.com/ \ No newline at end of file From 2fff5aecf62ce6183ac8125751265d4d2bc08199 Mon Sep 17 00:00:00 2001 From: Barbora B Date: Sat, 8 Nov 2025 15:35:17 +0100 Subject: [PATCH 2/2] add checkColumn values plus test, edit some typos --- pom.xml | 27 ++++++ .../czechitas/automation/ElementFinder.java | 4 +- .../automation/ElementFinderInterface.java | 20 +++++ .../cz/czechitas/automation/ExampleTest.java | 2 +- .../assertion/ApplicationAssertion.java | 36 ++++++-- .../assertion/ApplicationAssertionTest.java | 89 +++++++++++++++++++ .../assertion/ApplicationDetailAssertion.java | 6 +- .../automation/assertion/AssertionFacade.java | 7 +- 8 files changed, 176 insertions(+), 15 deletions(-) create mode 100644 src/main/java/cz/czechitas/automation/ElementFinderInterface.java create mode 100644 src/test/java/cz/czechitas/automation/assertion/ApplicationAssertionTest.java diff --git a/pom.xml b/pom.xml index 0381d87..76927a9 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,33 @@ webdrivermanager 5.9.2 + + + org.mockito + mockito-core + 5.5.0 + test + + + org.mockito + mockito-junit-jupiter + 5.5.0 + test + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + -Dnet.bytebuddy.experimental=true + + + + + \ No newline at end of file diff --git a/src/main/java/cz/czechitas/automation/ElementFinder.java b/src/main/java/cz/czechitas/automation/ElementFinder.java index 5e7ab47..1322fc5 100644 --- a/src/main/java/cz/czechitas/automation/ElementFinder.java +++ b/src/main/java/cz/czechitas/automation/ElementFinder.java @@ -15,7 +15,7 @@ * @since 1.0.0 */ @ParametersAreNonnullByDefault -public final class ElementFinder { +public class ElementFinder implements ElementFinderInterface { private final WebDriver driver; @@ -32,7 +32,7 @@ public ElementFinder(WebDriver driver) */ @Nonnull public WebElement findByXPath(String xpathExpression) { - return driver.findElement(By.xpath(Objects.requireNonNull(xpathExpression))); + return driver.findElement(By.xpath(Objects.requireNonNull(xpathExpression))); } /** diff --git a/src/main/java/cz/czechitas/automation/ElementFinderInterface.java b/src/main/java/cz/czechitas/automation/ElementFinderInterface.java new file mode 100644 index 0000000..bce5cf9 --- /dev/null +++ b/src/main/java/cz/czechitas/automation/ElementFinderInterface.java @@ -0,0 +1,20 @@ +package cz.czechitas.automation; + +import org.openqa.selenium.WebElement; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + +/** + * Used for mocking in testing + */ +@ParametersAreNonnullByDefault +public interface ElementFinderInterface { + + @Nonnull + WebElement findByXPath(String xpathExpression); + + @Nonnull + WebElement findByCssSelector(String cssSelector); +} + diff --git a/src/test/java/cz/czechitas/automation/ExampleTest.java b/src/test/java/cz/czechitas/automation/ExampleTest.java index 57dc150..2a5f4d9 100644 --- a/src/test/java/cz/czechitas/automation/ExampleTest.java +++ b/src/test/java/cz/czechitas/automation/ExampleTest.java @@ -27,7 +27,7 @@ void successfulLoginTest() { asserter.checkIsLoggedIn(); } - // paramertized test - find out what is wrong with this test + // parametrized test - find out what is wrong with this test @ParameterizedTest() @ValueSource(strings = {"123456789", "ASDFBVC", "123"}) void icoFieldTest(String icoValue) { diff --git a/src/test/java/cz/czechitas/automation/assertion/ApplicationAssertion.java b/src/test/java/cz/czechitas/automation/assertion/ApplicationAssertion.java index 87ea7c7..155392c 100644 --- a/src/test/java/cz/czechitas/automation/assertion/ApplicationAssertion.java +++ b/src/test/java/cz/czechitas/automation/assertion/ApplicationAssertion.java @@ -1,6 +1,6 @@ package cz.czechitas.automation.assertion; -import cz.czechitas.automation.ElementFinder; +import cz.czechitas.automation.ElementFinderInterface; import javax.annotation.ParametersAreNonnullByDefault; import java.util.Objects; @@ -16,15 +16,39 @@ @ParametersAreNonnullByDefault public final class ApplicationAssertion { - private final ElementFinder elementFinder; + private final ElementFinderInterface elementFinder; - ApplicationAssertion(ElementFinder elementFinder) { + ApplicationAssertion(ElementFinderInterface elementFinder) { this.elementFinder = Objects.requireNonNull(elementFinder); } - public void checkColumnExists(String columnName) { - var column = elementFinder.findByXPath("//table[@id='DataTables_Table_0']/thead/tr"); - assertThat(column.getText()).contains(columnName); + public void checkColumnExists(String... columnNames) { + Objects.requireNonNull(columnNames); + for (String columnName : columnNames) { + Objects.requireNonNull(columnName); + String xpath = "//table[@id='DataTables_Table_0']/thead/tr/th[normalize-space(.) = " + xpathLiteral(columnName) + "]"; + var column = elementFinder.findByXPath(xpath); + assertThat(column.getText()).contains(columnName); + } + } + + private static String xpathLiteral(String s) { + if (!s.contains("'")) { + return "'" + s + "'"; + } + if (!s.contains("\"" ) ) { + return "\"" + s + "\""; + } + String[] parts = s.split("'"); + StringBuilder sb = new StringBuilder("concat("); + for (int i = 0; i < parts.length; i++) { + if (i > 0) { + sb.append(", \"'\", "); + } + sb.append("'").append(parts[i]).append("'"); + } + sb.append(")"); + return sb.toString(); } public void checkApplicationsTableIsEmpty() { diff --git a/src/test/java/cz/czechitas/automation/assertion/ApplicationAssertionTest.java b/src/test/java/cz/czechitas/automation/assertion/ApplicationAssertionTest.java new file mode 100644 index 0000000..bd1c5e8 --- /dev/null +++ b/src/test/java/cz/czechitas/automation/assertion/ApplicationAssertionTest.java @@ -0,0 +1,89 @@ +package cz.czechitas.automation.assertion; + +import cz.czechitas.automation.ElementFinderInterface; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.openqa.selenium.WebElement; + +import javax.annotation.ParametersAreNonnullByDefault; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.mockito.Mockito.*; + +@ParametersAreNonnullByDefault +@ExtendWith(MockitoExtension.class) +class ApplicationAssertionTest { + + @Mock + ElementFinderInterface elementFinder; + + private static WebElement mockElementWithText(String text) { + WebElement el = mock(WebElement.class); + when(el.getText()).thenReturn(text); + return el; + } + + // Re-implementation of production xpathLiteral for building expected xpath in tests + private static String xpathLiteralForTest(String s) { + if (!s.contains("'")) { + return "'" + s + "'"; + } + if (!s.contains("\"")) { + return "\"" + s + "\""; + } + String[] parts = s.split("'"); + StringBuilder sb = new StringBuilder("concat("); + for (int i = 0; i < parts.length; i++) { + if (i > 0) { + sb.append(", \"'\", "); + } + sb.append("'").append(parts[i]).append("'"); + } + sb.append(")"); + return sb.toString(); + } + + @Test + void checkColumnExists_singleColumn() { + String column = "Name"; + String expectedXpath = "//table[@id='DataTables_Table_0']/thead/tr/th[normalize-space(.) = " + xpathLiteralForTest(column) + "]"; + doReturn(mockElementWithText(column)).when(elementFinder).findByXPath(expectedXpath); + + ApplicationAssertion assertion = new ApplicationAssertion(elementFinder); + + assertThatCode(() -> assertion.checkColumnExists(column)).doesNotThrowAnyException(); + verify(elementFinder).findByXPath(expectedXpath); + } + + @Test + void checkColumnExists_multipleColumns() { + String col1 = "Name"; + String col2 = "Email"; + + String xpath1 = "//table[@id='DataTables_Table_0']/thead/tr/th[normalize-space(.) = " + xpathLiteralForTest(col1) + "]"; + String xpath2 = "//table[@id='DataTables_Table_0']/thead/tr/th[normalize-space(.) = " + xpathLiteralForTest(col2) + "]"; + + doReturn(mockElementWithText(col1)).when(elementFinder).findByXPath(xpath1); + doReturn(mockElementWithText(col2)).when(elementFinder).findByXPath(xpath2); + + ApplicationAssertion assertion = new ApplicationAssertion(elementFinder); + + assertThatCode(() -> assertion.checkColumnExists(col1, col2)).doesNotThrowAnyException(); + verify(elementFinder).findByXPath(xpath1); + verify(elementFinder).findByXPath(xpath2); + } + + @Test + void checkColumnExists_columnWithBothQuotes() { + String col = "O'Hara \"Test\""; + String expectedXpath = "//table[@id='DataTables_Table_0']/thead/tr/th[normalize-space(.) = " + xpathLiteralForTest(col) + "]"; + doReturn(mockElementWithText(col)).when(elementFinder).findByXPath(expectedXpath); + + ApplicationAssertion assertion = new ApplicationAssertion(elementFinder); + + assertThatCode(() -> assertion.checkColumnExists(col)).doesNotThrowAnyException(); + verify(elementFinder).findByXPath(expectedXpath); + } +} diff --git a/src/test/java/cz/czechitas/automation/assertion/ApplicationDetailAssertion.java b/src/test/java/cz/czechitas/automation/assertion/ApplicationDetailAssertion.java index b9c72a3..2e96235 100644 --- a/src/test/java/cz/czechitas/automation/assertion/ApplicationDetailAssertion.java +++ b/src/test/java/cz/czechitas/automation/assertion/ApplicationDetailAssertion.java @@ -1,6 +1,6 @@ package cz.czechitas.automation.assertion; -import cz.czechitas.automation.ElementFinder; +import cz.czechitas.automation.ElementFinderInterface; import javax.annotation.ParametersAreNonnullByDefault; import java.util.Objects; @@ -16,9 +16,9 @@ @ParametersAreNonnullByDefault public final class ApplicationDetailAssertion { - private final ElementFinder elementFinder; + private final ElementFinderInterface elementFinder; - public ApplicationDetailAssertion(ElementFinder elementFinder) + public ApplicationDetailAssertion(ElementFinderInterface elementFinder) { this.elementFinder = Objects.requireNonNull(elementFinder); } diff --git a/src/test/java/cz/czechitas/automation/assertion/AssertionFacade.java b/src/test/java/cz/czechitas/automation/assertion/AssertionFacade.java index ea49f74..762b5d7 100644 --- a/src/test/java/cz/czechitas/automation/assertion/AssertionFacade.java +++ b/src/test/java/cz/czechitas/automation/assertion/AssertionFacade.java @@ -1,6 +1,7 @@ package cz.czechitas.automation.assertion; import cz.czechitas.automation.ElementFinder; +import cz.czechitas.automation.ElementFinderInterface; import org.openqa.selenium.WebDriver; import javax.annotation.ParametersAreNonnullByDefault; @@ -16,7 +17,7 @@ @ParametersAreNonnullByDefault public final class AssertionFacade { - private final ElementFinder elementFinder; + private final ElementFinderInterface elementFinder; public final ApplicationAssertion applicationSection; public final ApplicationDetailAssertion applicationDetailAction; @@ -37,12 +38,12 @@ public void checkIsLoggedIn() { assertThat(loggedInText.getText()).isEqualTo("Přihlášen"); } - public void checkProgrammingSectionPresense() { + public void checkProgrammingSectionPresence() { var programmingText = elementFinder.findByCssSelector(".main_content .card-img-overlay"); assertThat(programmingText.getText().trim()).isEqualTo("Programování"); } - public void checkRegistrationButtonPresense() { + public void checkRegistrationButtonPresence() { var registerButton = elementFinder.findByCssSelector(".btn-secondary"); assertThat(registerButton.getText().trim()).isEqualTo("Zaregistrujte se"); }