commit 6f1478bb5918bd9fe37ce77232dbaf32c26ef0ae Author: Dmitry Isaenko Date: Tue Mar 5 19:05:27 2024 +0300 init repo diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c722c96 --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +target/ +test-output/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5c93f45 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..9fdce65 --- /dev/null +++ b/README.MD @@ -0,0 +1,5 @@ +### Marinesco tests + +https://git.redrise.ru/desu/marinesco/ + +Execute tests: `mvn -P RunSuites test` \ No newline at end of file diff --git a/api.xml b/api.xml new file mode 100644 index 0000000..567535d --- /dev/null +++ b/api.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/error_messages.xlsx b/error_messages.xlsx new file mode 100644 index 0000000..0d3cd5c Binary files /dev/null and b/error_messages.xlsx differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..08dc6c6 --- /dev/null +++ b/pom.xml @@ -0,0 +1,112 @@ + + + 4.0.0 + + ru.redrise + marinesco-tests + 1.0-SNAPSHOT + + + 19 + 19 + 5.2.5 + 5.4.0 + UTF-8 + + + + + org.testng + testng + 7.9.0 + + + + org.seleniumhq.selenium + selenium-java + 4.17.0 + + + + org.slf4j + slf4j-api + 2.0.12 + + + org.slf4j + slf4j-simple + 2.0.12 + + + + + + org.apache.poi + poi + ${apache-poi.version} + + + + + org.apache.poi + poi-ooxml + ${apache-poi.version} + + + + + + io.rest-assured + rest-assured + ${rest-assured.version} + + + + io.rest-assured + json-schema-validator + ${rest-assured.version} + test + + + + + + RunSuites + + true + + + + + + maven-surefire-plugin + + false + + testng.xml + + + + + + + + + + + + + + maven-surefire-plugin + + + testng.xml + + + + + + + \ No newline at end of file diff --git a/server configuration files/test.inpx b/server configuration files/test.inpx new file mode 100755 index 0000000..e5d4c8f Binary files /dev/null and b/server configuration files/test.inpx differ diff --git a/src/main/resources/author.json b/src/main/resources/author.json new file mode 100644 index 0000000..86a41f8 --- /dev/null +++ b/src/main/resources/author.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "authorName": { + "type": "string" + } + }, + "required": [ + "id", + "authorName" + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/book.json b/src/main/resources/book.json new file mode 100644 index 0000000..6ac6642 --- /dev/null +++ b/src/main/resources/book.json @@ -0,0 +1,119 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "libraryId": { + "type": "integer" + }, + "libraryVersion": { + "type": "string" + }, + "authors": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "authorName": { + "type": "string" + } + }, + "required": [ + "id", + "authorName" + ] + } + ] + }, + "genres": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "genreId": { + "type": "string" + }, + "humanReadableDescription": { + "type": ["string", "null"] + } + }, + "required": [ + "genreId", + "humanReadableDescription" + ] + } + ] + }, + "title": { + "type": "string" + }, + "series": { + "type": "string" + }, + "serNo": { + "type": "string" + }, + "fsFileName": { + "type": "string" + }, + "fileSize": { + "type": "integer" + }, + "fileSizeForHumans": { + "type": "string" + }, + "libId": { + "type": "string" + }, + "deleted": { + "type": "string" + }, + "fileExtension": { + "type": "string" + }, + "addedDate": { + "type": "string" + }, + "container": { + "type": "string" + }, + "position": { + "type": "integer" + }, + "line": { + "type": ["string", "null"] + } + }, + "required": [ + "id", + "libraryId", + "libraryVersion", + "authors", + "genres", + "title", + "series", + "serNo", + "fsFileName", + "fileSize", + "fileSizeForHumans", + "libId", + "deleted", + "fileExtension", + "addedDate", + "container", + "position", + "line" + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/simplelogger.properties b/src/main/resources/simplelogger.properties new file mode 100644 index 0000000..30e66e2 --- /dev/null +++ b/src/main/resources/simplelogger.properties @@ -0,0 +1,8 @@ +org.slf4j.simpleLogger.defaultLogLevel=info +org.slf4j.simpleLogger.log.org.testng=warn + +#org.slf4j.simpleLogger.showDateTime=false +org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z +#org.slf4j.simpleLogger.showThreadName=true +#org.slf4j.simpleLogger.showLogName=true +#org.slf4j.simpleLogger.showShortLogName=false \ No newline at end of file diff --git a/src/test/java/ru/redrise/ReportListener.java b/src/test/java/ru/redrise/ReportListener.java new file mode 100644 index 0000000..42f5f7e --- /dev/null +++ b/src/test/java/ru/redrise/ReportListener.java @@ -0,0 +1,27 @@ +package ru.redrise; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.ITestContext; +import org.testng.ITestListener; + +public class ReportListener implements ITestListener { + private final Logger log = LoggerFactory.getLogger(getClass()); + + @Override + public void onFinish(ITestContext testContext) { + log.info("PASSED TEST CASES"); + testContext.getPassedTests().getAllResults() + .forEach(result -> + log.info(result.getName())); + + log.info("FAILED TEST CASES"); + testContext.getFailedTests().getAllResults() + .forEach(result -> + log.info(result.getName())); + + log.info( + "Test completed on: " + testContext.getEndDate().toString()); + } + +} \ No newline at end of file diff --git a/src/test/java/ru/redrise/api/AuthorsApiTest.java b/src/test/java/ru/redrise/api/AuthorsApiTest.java new file mode 100644 index 0000000..8a2f01c --- /dev/null +++ b/src/test/java/ru/redrise/api/AuthorsApiTest.java @@ -0,0 +1,110 @@ +package ru.redrise.api; + +import io.restassured.module.jsv.JsonSchemaValidator; +import io.restassured.path.json.JsonPath; +import io.restassured.specification.RequestSpecification; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.List; +import java.util.Map; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.*; + +public class AuthorsApiTest { + + //private final Logger log = LoggerFactory.getLogger(getClass()); + + private static final int RECENT_RECORDS_LIST_SIZE = 10; + private static final String TEST_AUTHOR_NAME = "파르나르"; + private static final long TEST_AUTHOR_ID = 1656621508; + + private static final String HOST_URI = "http://localhost"; + private static final int HOST_PORT = 8080; // default 8080 + + private RequestSpecification specification; + + @BeforeClass + public void beforeClass() { + this.specification = given() + .baseUri(HOST_URI) + .port(HOST_PORT); + } + + // note: remember '.log().all()' + @Test(testName = "Check recent authors") + public void checkAuthors() { + JsonPath recent = specification + .when() + .get("/api/author") + .then() + .assertThat() + .statusCode(200) + .log().body() + .extract() + .jsonPath(); + + List> list = recent.getList("$"); + + Assert.assertEquals(RECENT_RECORDS_LIST_SIZE, list.size()); + } + + @Test(testName = "Check authors schema") + public void checkSchema() { + specification + .when() + .get("/api/author?recent") + .then() + .assertThat() + .statusCode(200) + .body( + JsonSchemaValidator.matchesJsonSchemaInClasspath("author.json") + ); + } + + //curl 'localhost:8080/api/author/by/name/Kern' + @Test(testName = "Check by name") + public void checkAuthors1() { + String requestedPath = "/api/author/by/name/" + TEST_AUTHOR_NAME; + + JsonPath namesMatched = specification + .when() + .get(requestedPath) + .then() + .assertThat() + .statusCode(200) + .log().body() + .extract() + .jsonPath(); + + List> list = namesMatched.getList(""); + + Assert.assertFalse(list.isEmpty()); + } + + // curl 'localhost:8080/api/author/by/id/-605622692' + /* Expected: + { + "id": 1656621508, + "authorName": "파르나르" + } + * */ + @Test(testName = "Check by id") + public void checkAuthors2() { + String requestedPath = "/api/author/by/id/" + TEST_AUTHOR_ID; + + specification + .when() + .get(requestedPath) + .then() + .assertThat() + .statusCode(200) + .body("$", hasEntry("id", 1656621508)) + .body("authorName", equalTo("파르나르")) + .log().body() + .extract() + .jsonPath(); + } +} diff --git a/src/test/java/ru/redrise/api/BooksApiTest.java b/src/test/java/ru/redrise/api/BooksApiTest.java new file mode 100644 index 0000000..0bce480 --- /dev/null +++ b/src/test/java/ru/redrise/api/BooksApiTest.java @@ -0,0 +1,189 @@ +package ru.redrise.api; + +import io.restassured.module.jsv.JsonSchemaValidator; +import io.restassured.path.json.JsonPath; +import io.restassured.specification.RequestSpecification; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.*; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.*; + +public class BooksApiTest { + + //private final Logger log = LoggerFactory.getLogger(getClass()); + + private static final String TEST_TITLE = "Евгений Онегин"; + private static final String TEST_SERIES = "Сборник «У солдата есть невеста»"; + private static final Integer TEST_BOOK_ID = -2092944816; + + private static final String HOST_URI = "http://localhost"; + private static final int HOST_PORT = 8080; // default 8080 + + private RequestSpecification specification; + + @BeforeClass + public void beforeClass() { + this.specification = given() + .baseUri(HOST_URI) + .port(HOST_PORT); + } + + @Test(testName = "Check recent books") + public void checkRecent() { + JsonPath recent = specification + .when() + .get("/api/book?recent") + .then() + .assertThat() + .statusCode(200) + .log().body() + .extract() + .jsonPath(); + + List> list = recent.getList(""); + + Assert.assertFalse(list.isEmpty()); + } + + @Test(testName = "Check JSON Schema") + public void checkSchema() { + specification + .when() + .get("/api/book?recent") + .then() + .assertThat() + .statusCode(200) + .body( + JsonSchemaValidator.matchesJsonSchemaInClasspath("book.json") + ); + } + + @Test(testName = "Search books by title") + public void checkByTitle() { + final String[] authorsExpected = { + "Комментарий к роману А. С. Пушкина «Евгений Онегин»", + "Евгений Онегин", + "Евгений Онегин (Роман в стихове)", + "Евгений Онегин" + }; + + JsonPath book = specification + .when() + .get("/api/book/by/title/" + TEST_TITLE) + .then() + .assertThat() + .statusCode(200) + .log().body() + .extract() + .jsonPath(); + + String[] authors = book + .getList("flatten().findAll{it.authors.authorName.contains('Пушкин Александр Сергеевич')}.collect().title") + .toArray(String[]::new); + + Arrays.sort(authorsExpected); + Arrays.sort(authors); + + Assert.assertEquals(authorsExpected, authors); + } + + @Test(testName = "Search books by series") + public void checkBySeries() { + JsonPath recent = specification + .when() + .get("/api/book/by/series/" + TEST_SERIES) + .then() + .assertThat() + .statusCode(200) + .log().body() + .extract() + .jsonPath(); + + List> list = recent.getList(""); + + Assert.assertTrue(list.size() > 1); + } + + /* Example: + { + "id": -2092944816, + "libraryId": 1, + "libraryVersion": "20240101", + "authors": [ + { + "id": -220073406, + "authorName": "Щеглов Михаил" + } + ], + "genres": [ + { + "genreId": "love_history", + "humanReadableDescription": null + }, + { + "genreId": "love_detective", + "humanReadableDescription": null + }, + { + "genreId": "love_short", + "humanReadableDescription": null + } + ], + "title": "Евгений Онегин, Александр Пушкин. Вся мораль книги с объяснением простыми словами, которую хотел донести автор", + "series": "", + "serNo": "", + "fsFileName": "765420", + "fileSize": 363564, + "fileSizeForHumans": "355,04 KB", + "libId": "765420", + "deleted": "0", + "fileExtension": "fb2", + "addedDate": "2023-12-31", + "container": "f.fb2-759836-765669", + "position": 0, + "line": null +} + * */ + @Test(testName = "Search books by id", + enabled = true) + public void checkById() { + JsonPath book = specification + .when() + .get("/api/book/by/id/" + TEST_BOOK_ID) + .then() + .assertThat() + .statusCode(200) + .body("", + allOf( + hasKey("title"), + hasKey("series"), + hasKey("serNo"), + hasEntry("fsFileName", "765420"), + hasKey("fileSizeForHumans"), + hasEntry("libId", "765420"), + hasEntry("deleted", "0"), + hasEntry("fileExtension", "fb2"), + hasEntry("addedDate", "2023-12-31"), + hasEntry("container", "f.fb2-759836-765669"), + hasEntry("line", null) + ) + ) + .body("fileSize", equalTo(363564)) + .body("position", equalTo(0)) + .log().body() + .extract() + .jsonPath(); + + Assert.assertEquals(book.getInt("id"), -2092944816); + Assert.assertEquals(book.getInt("libraryId"), 1); + Assert.assertEquals(book.getString("libraryVersion"), "20240101"); + Assert.assertEquals(book.getInt("authors[0].id"), -220073406); + Assert.assertEquals(book.get("authors[0].authorName"), "Щеглов Михаил"); + + } + +} diff --git a/src/test/java/ru/redrise/api/ExampleOnly.java b/src/test/java/ru/redrise/api/ExampleOnly.java new file mode 100644 index 0000000..3cdae17 --- /dev/null +++ b/src/test/java/ru/redrise/api/ExampleOnly.java @@ -0,0 +1,474 @@ +package ru.redrise.api; + +import io.restassured.module.jsv.JsonSchemaValidator; +import io.restassured.path.json.JsonPath; +import io.restassured.specification.RequestSpecification; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.Test; + +import java.util.List; +import java.util.Map; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.*; + +public class ExampleOnly { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private final String jsonExample = """ + [ + { + "addedDate" : "2024-01-01", + "authors" : [ + { + "authorName" : "Демиденко Светлана Владимировна", + "id" : -458202851 + } + ], + "container" : "f.fb2-759836-765669", + "deleted" : "0", + "fileExtension" : "fb2", + "fileSize" : 706185, + "fileSizeForHumans" : "689,63 KB", + "fsFileName" : "765663", + "genres" : [ + { + "genreId" : "nonf_biography", + "humanReadableDescription" : null + } + ], + "id" : -1826362880, + "libId" : "765663", + "libraryId" : 1, + "libraryVersion" : "20240101", + "line" : null, + "position" : 0, + "serNo" : "", + "series" : "", + "title" : "Перелистывая память" + }, + { + "addedDate" : "2024-01-01", + "authors" : [ + { + "authorName" : "Май Дмитрий", + "id" : 311992404 + } + ], + "container" : "f.fb2-759836-765669", + "deleted" : "0", + "fileExtension" : "fb2", + "fileSize" : 507378, + "fileSizeForHumans" : "495,49 KB", + "fsFileName" : "765643", + "genres" : [ + { + "genreId" : "child_tale", + "humanReadableDescription" : null + } + ], + "id" : -1782438812, + "libId" : "765643", + "libraryId" : 1, + "libraryVersion" : "20240101", + "line" : null, + "position" : 0, + "serNo" : "2", + "series" : "Детство", + "title" : "Новогодняя сказка" + }, + { + "addedDate" : "2024-01-01", + "authors" : [ + { + "authorName" : "Демиденко Светлана Владимировна", + "id" : -458202851 + } + ], + "container" : "f.fb2-759836-765669", + "deleted" : "0", + "fileExtension" : "fb2", + "fileSize" : 3526176, + "fileSizeForHumans" : "3,36 MB", + "fsFileName" : "765661", + "genres" : [ + { + "genreId" : "nonf_biography", + "humanReadableDescription" : null + } + ], + "id" : -1753421740, + "libId" : "765661", + "libraryId" : 1, + "libraryVersion" : "20240101", + "line" : null, + "position" : 0, + "serNo" : "", + "series" : "", + "title" : "Любите меня" + }, + { + "addedDate" : "2024-01-01", + "authors" : [ + { + "authorName" : "Алексеев Борис", + "id" : -1665780547 + } + ], + "container" : "f.fb2-759836-765669", + "deleted" : "0", + "fileExtension" : "fb2", + "fileSize" : 449204, + "fileSizeForHumans" : "438,68 KB", + "fsFileName" : "765633", + "genres" : [ + { + "genreId" : "adventure", + "humanReadableDescription" : null + }, + { + "genreId" : "child_tale", + "humanReadableDescription" : null + }, + { + "genreId" : "children", + "humanReadableDescription" : null + } + ], + "id" : -1665535280, + "libId" : "765633", + "libraryId" : 1, + "libraryVersion" : "20240101", + "line" : null, + "position" : 0, + "serNo" : "", + "series" : "", + "title" : "Новогоднее путешествие Большой Лужи" + }, + { + "addedDate" : "2024-01-01", + "authors" : [ + { + "authorName" : "Элья Крепкая", + "id" : -183449638 + } + ], + "container" : "f.fb2-759836-765669", + "deleted" : "0", + "fileExtension" : "fb2", + "fileSize" : 610834, + "fileSizeForHumans" : "596,52 KB", + "fsFileName" : "765654", + "genres" : [ + { + "genreId" : "sf_action", + "humanReadableDescription" : null + }, + { + "genreId" : "sf_heroic", + "humanReadableDescription" : null + }, + { + "genreId" : "adventure", + "humanReadableDescription" : null + } + ], + "id" : -1609360729, + "libId" : "765654", + "libraryId" : 1, + "libraryVersion" : "20240101", + "line" : null, + "position" : 0, + "serNo" : "", + "series" : "", + "title" : "Старый рыцарь" + }, + { + "addedDate" : "2024-01-01", + "authors" : [ + { + "authorName" : "Бёме Юлия", + "id" : 2108296075 + } + ], + "container" : "f.fb2-759836-765669", + "deleted" : "0", + "fileExtension" : "fb2", + "fileSize" : 12985383, + "fileSizeForHumans" : "12,38 MB", + "fsFileName" : "765630", + "genres" : [ + { + "genreId" : "child_tale", + "humanReadableDescription" : null + }, + { + "genreId" : "children", + "humanReadableDescription" : null + } + ], + "id" : -1518406716, + "libId" : "765630", + "libraryId" : 1, + "libraryVersion" : "20240101", + "line" : null, + "position" : 0, + "serNo" : "6", + "series" : "Приключения в саванне", + "title" : "Тафити и банда обезьян" + }, + { + "addedDate" : "2024-01-01", + "authors" : [ + { + "authorName" : "Макаров Марк", + "id" : -1967304956 + } + ], + "container" : "f.fb2-759836-765669", + "deleted" : "0", + "fileExtension" : "fb2", + "fileSize" : 491992, + "fileSizeForHumans" : "480,46 KB", + "fsFileName" : "765666", + "genres" : [ + { + "genreId" : "child_tale", + "humanReadableDescription" : null + } + ], + "id" : -1232223904, + "libId" : "765666", + "libraryId" : 1, + "libraryVersion" : "20240101", + "line" : null, + "position" : 0, + "serNo" : "", + "series" : "", + "title" : "Сказ о Иване царевиче и сером волке" + }, + { + "addedDate" : "2024-01-01", + "authors" : [ + { + "authorName" : "Блэк Архиус", + "id" : 1779566922 + } + ], + "container" : "f.fb2-759836-765669", + "deleted" : "0", + "fileExtension" : "fb2", + "fileSize" : 323584, + "fileSizeForHumans" : "316,00 KB", + "fsFileName" : "765635", + "genres" : [ + { + "genreId" : "sf_social", + "humanReadableDescription" : null + }, + { + "genreId" : "humor_anecdote", + "humanReadableDescription" : null + } + ], + "id" : -1163766944, + "libId" : "765635", + "libraryId" : 1, + "libraryVersion" : "20240101", + "line" : null, + "position" : 0, + "serNo" : "", + "series" : "", + "title" : "Огонь лишь начало" + }, + { + "addedDate" : "2024-01-01", + "authors" : [ + { + "authorName" : "Шабалина Валентина", + "id" : -1801290427 + } + ], + "container" : "f.fb2-759836-765669", + "deleted" : "0", + "fileExtension" : "fb2", + "fileSize" : 566330, + "fileSizeForHumans" : "553,06 KB", + "fsFileName" : "765647", + "genres" : [ + { + "genreId" : "child_tale", + "humanReadableDescription" : null + } + ], + "id" : -865309302, + "libId" : "765647", + "libraryId" : 1, + "libraryVersion" : "20240101", + "line" : null, + "position" : 0, + "serNo" : "", + "series" : "", + "title" : "Полуночный поросёнок" + }, + { + "addedDate" : "2024-01-01", + "authors" : [ + { + "authorName" : "Азк", + "id" : 1033971 + } + ], + "container" : "f.fb2-759836-765669", + "deleted" : "0", + "fileExtension" : "fb2", + "fileSize" : 746212, + "fileSizeForHumans" : "728,72 KB", + "fsFileName" : "765632", + "genres" : [ + { + "genreId" : "sf_action", + "humanReadableDescription" : null + }, + { + "genreId" : "adventure", + "humanReadableDescription" : null + }, + { + "genreId" : "network_literature", + "humanReadableDescription" : null + }, + { + "genreId" : "popadancy", + "humanReadableDescription" : null + } + ], + "id" : -853565692, + "libId" : "765632", + "libraryId" : 1, + "libraryVersion" : "20240101", + "line" : null, + "position" : 0, + "serNo" : "3", + "series" : "Дивизион", + "title" : "Маневры 4" + } + ] + + """; + + + @Test(testName = "example 1", + enabled = false) + public void check1() { + JsonPath jsonPath = new JsonPath(jsonExample); + + + log.info("" + jsonPath.get("[0].id")); + log.info("" + jsonPath.get("flatten()[0].id")); + log.info(jsonPath.get("flatten().findAll{e -> e.id == -1826362880}.genres") + ""); + log.info(jsonPath.get("flatten().findAll{it.id == -1826362880}.genres") + ""); + log.info(jsonPath.get("flatten().findAll{it.authors.id.contains(-458202851)}.id") + ""); + log.info(jsonPath.get("find{it.authors.id.contains(-458202851)}.id") + "\n"); + + List>> authorIds = jsonPath.getList("flatten().findAll{it.authors.authorName.contains('Азк')}.genres"); + for (List> authors : authorIds) { + for (Map map : authors) { + for (Map.Entry entry : map.entrySet()) { + log.info(entry.getKey() + "\t→\t" + entry.getValue()); + } + } + log.info("\n"); + } + + //log.info(authorId + "\n"); + + log.info(jsonPath.get("flatten().findAll{it.title.startsWith('Перелистывая')}.title") + "\n"); + + log.info("\n"); + // ------ + List> list = jsonPath.getList("$"); + + for (Map maps : list) { + for (Map.Entry entry : maps.entrySet()) { + log.info(entry.getKey() + "\t→\t" + entry.getValue()); + } + log.info("\n"); + } + } + + @Test(testName = "example 2") + public void check2() { + String HOST_URI = "http://localhost"; + int HOST_PORT = 8080; + + RequestSpecification specification = given() + .baseUri(HOST_URI) + .port(HOST_PORT); + + specification + .when() + .get("/api/book?recent") + .then() + .assertThat() + .statusCode(200) + .body("find{it.authors.id.contains(-458202851)}.genres", // Find single record among others + hasItems( + allOf( + hasEntry("genreId", "nonf_biography"), + hasEntry("humanReadableDescription", null) + ) + ) + ) + .body("find{it.authors.id.contains(1033971)}.genres", // Find single record among others + hasItems( + allOf( + hasEntry("genreId", "popadancy"), + hasEntry("humanReadableDescription", null) + ) + ) + ) + .body("find{it.authors.id.contains(311992404)}", // Find single record among others + allOf( + hasEntry("fileExtension", "fb2"), + hasEntry("serNo", "2") + ) + ) + .body("find{it.authors.id.contains(311992404)}", // Find single record among others + anyOf( + hasEntry("fileExtension", "fb2"), + hasEntry("fileExtension", "100511") + ) + ) + .body("find{it.authors.id.contains(311992404)}", // Find single record among others + allOf( + hasKey("libraryVersion"), + hasKey("id"), + not(hasKey("test")) + ) + ) + .log().body() + .extract() + .jsonPath(); + } + + @Test(testName = "example 3") + public void check3() { + String HOST_URI = "http://localhost"; + int HOST_PORT = 8080; + + given() + .baseUri(HOST_URI) + .port(HOST_PORT) + .when() + .get("/api/book?recent") + .then() + .assertThat() + .statusCode(200) + .body( + JsonSchemaValidator.matchesJsonSchemaInClasspath("book.json") + ); + } +} diff --git a/src/test/java/ru/redrise/api/GenresApiTest.java b/src/test/java/ru/redrise/api/GenresApiTest.java new file mode 100644 index 0000000..4bb5b7b --- /dev/null +++ b/src/test/java/ru/redrise/api/GenresApiTest.java @@ -0,0 +1,146 @@ +package ru.redrise.api; + +import io.restassured.http.ContentType; +import io.restassured.path.json.JsonPath; +import io.restassured.response.Response; +import io.restassured.specification.RequestSpecification; +import org.apache.http.HttpStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; + +public class GenresApiTest { + private final Logger log = LoggerFactory.getLogger(getClass()); + + private static final String HOST_URI = "http://localhost"; + private static final int HOST_PORT = 8080; // default 8080 + + private RequestSpecification specification; + + private static final String genreId1 = "test01"; + private static final String genreId2 = "test02"; + + @BeforeClass + public void beforeClass() { + this.specification = given() + .baseUri(HOST_URI) + .port(HOST_PORT); + } + + @Test(testName = "Genres fetch") + public void genresFetch() { + JsonPath recent = specification + .when() + .get("/api/genres") + .then() + .assertThat() + .statusCode(200) + .log().body() + .extract() + .jsonPath(); + + List> list = recent.getList(""); + + Assert.assertFalse(list.isEmpty()); + } + + ///api/genres + @Test(testName = "Genres create 1", + enabled = true) + public void genresCreate1() { + String payload = String.format(""" + { + "genreId" : "%s", + "humanReadableDescription" : "test 01 description" + } + """, genreId1); + + Response response = specification + .contentType(ContentType.JSON) + .body(payload) + .log().body() + .post("/api/genres"); + + Assert.assertEquals(response.getStatusCode(), HttpStatus.SC_CREATED); + } + + @Test(testName = "Genres create 2", + enabled = true) + public void genresCreate2() { + Map jsonData = new HashMap<>(); + jsonData.put("genreId", genreId2); + jsonData.put("humanReadableDescription", "test 02 description " + + LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME)); + + Response response = specification + .contentType(ContentType.JSON) + .body(jsonData) + .log().body() + .post("/api/genres"); + + Assert.assertEquals(response.getStatusCode(), HttpStatus.SC_CREATED); + } + + @Test(testName = "Replace genre (PUT)", + priority = 1, + dependsOnMethods = {"genresCreate1", "genresCreate2"}) + public void genresReplace() { + String genreDesc = "REPLACED DESCRIPTION " + + LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME); + + Map jsonData = new HashMap<>(); + jsonData.put("genreId", genreId2); + jsonData.put("humanReadableDescription", genreDesc); + + log.info("about to update:"); + Response response = specification + .contentType(ContentType.JSON) + .body(jsonData) + .log().body() + .put("/api/genres/" + genreId2); + + Assert.assertEquals(response.getStatusCode(), HttpStatus.SC_OK); + + log.info("Just updated:"); + specification.when() + .get("/api/genres/by/id/" + genreId2) + .then() + .assertThat() + .statusCode(200) + .body("$", hasEntry("genreId", genreId2)) + .body("humanReadableDescription", equalTo(genreDesc)) + .log().body() + .extract() + .jsonPath(); + } + + @Test(testName = "Delete test", + priority = 1, + dependsOnMethods = {"genresReplace"}) + public void genresDelete(){ + int record1status = specification + .log().body() + .delete("/api/genres/" + genreId1) + .statusCode(); + + int record2status = specification + .log().body() + .delete("/api/genres/" + genreId2) + .statusCode(); + + Assert.assertEquals(record1status, HttpStatus.SC_NO_CONTENT); + Assert.assertEquals(record2status, HttpStatus.SC_NO_CONTENT); + } +} diff --git a/src/test/java/ru/redrise/users_management/LoginTest.java b/src/test/java/ru/redrise/users_management/LoginTest.java new file mode 100644 index 0000000..384527c --- /dev/null +++ b/src/test/java/ru/redrise/users_management/LoginTest.java @@ -0,0 +1,112 @@ +package ru.redrise.users_management; + +import org.openqa.selenium.*; +import org.openqa.selenium.support.ui.WebDriverWait; +import org.testng.Assert; +import org.testng.annotations.*; + +import java.time.Duration; + +public class LoginTest extends ScreenshotsMaker{ + private WebDriver driver; + + @BeforeClass + public void beforeClass() { + driver = Suite.driver; + } + + @BeforeMethod + public void beforeMethod(){ + driver.get("http://localhost:8080/"); + } + + @Test(testName = "Login page availability", + groups = "Login tests") + public void checkAdminLogin() { + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + WebElement header = driver.findElement(By.tagName("header")); + + WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + wait.until(f -> header.isDisplayed()); + + WebElement signInLink = driver.findElement( + By.xpath("//nav[@id='header_right_block']/div[@class='block_inner']/ul/li/a[1]")); + + Assert.assertTrue(signInLink.getAttribute("href").endsWith("/login")); + + WebElement userNameInput = driver.findElement(By.xpath("//input[@id='username']")); + + Assert.assertEquals(userNameInput.getAttribute("type"), "text"); + + WebElement psswdInput = driver.findElement(By.xpath("//input[@id='password']")); + + Assert.assertEquals(psswdInput.getAttribute("type"), "password"); + + try{ + driver.findElement(By.xpath("//a[@id='logout']")).click(); + } + catch (Exception ignore){} + } + + @Test(priority = 1, + testName = "Login Failure Test", + groups = "Login tests") + public void loginFailureCheck() { + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + WebElement userNameInput = driver.findElement(By.xpath("//input[@id='username']")); + + WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + wait.until(f -> userNameInput.isDisplayed()); + + userNameInput.sendKeys("incorrect-values-set"); + + WebElement psswdInput = driver.findElement(By.xpath("//input[@id='password']")); + + psswdInput.sendKeys("incorrect-values-set"); + + driver.findElement(By.xpath("//button[@type='submit']")).click(); + + WebElement settingsLink = driver.findElement( + By.xpath("//span[@class='validationError']")); + + wait.until(f -> settingsLink.isDisplayed()); + + try{ + driver.findElement(By.xpath("//a[@id='logout']")).click(); + } + catch (Exception ignore){} + } + + + @Parameters({"admin_username", "admin_password"}) + @Test(testName = "Default admin login", + groups = "Login tests") + public void loginAsAdminCheck(String user, String password) { + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + WebElement userNameInput = driver.findElement(By.xpath("//input[@id='username']")); + + WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + wait.until(f -> userNameInput.isDisplayed()); + + userNameInput.sendKeys(user); + + WebElement psswdInput = driver.findElement(By.xpath("//input[@id='password']")); + + psswdInput.sendKeys(password); + + driver.findElement(By.xpath("//button[@type='submit']")).click(); + + WebElement settingsLink = driver.findElement( + By.xpath("//nav[@id='header_right_block']/div[@class='block_inner']/ul/li/a[@href='/settings']")); + + wait.until(f -> settingsLink.isDisplayed()); + + try{ + driver.findElement(By.xpath("//a[@id='logout']")).click(); + } + catch (Exception ignore){} + } +} diff --git a/src/test/java/ru/redrise/users_management/RegistrationAllowTest.java b/src/test/java/ru/redrise/users_management/RegistrationAllowTest.java new file mode 100644 index 0000000..7b64670 --- /dev/null +++ b/src/test/java/ru/redrise/users_management/RegistrationAllowTest.java @@ -0,0 +1,111 @@ +package ru.redrise.users_management; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.WebDriverWait; +import org.testng.Assert; +import org.testng.annotations.*; + +import java.time.Duration; + +public class RegistrationAllowTest extends ScreenshotsMaker { + + private WebDriver driver; + private WebDriverWait wait; + + @BeforeClass + public void beforeClass(){ + driver = Suite.driver; + wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + } + + @BeforeMethod + public void beforeMethod(){ + driver.get("http://localhost:8080/"); + } + + @AfterMethod + public void logout(){ + try{ + driver.findElement(By.xpath("//a[@id='logout']")).click(); + } + catch (Exception ignore){} + } + + + @Parameters({"admin_username", "admin_password"}) + @Test(testName = "Check registration NOT allowed", + priority = 1, + groups = "registration_configuration") + public void checkRegNotAllowed(String user, String password){ + latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + loginAsAdmin(user, password); + openSettings(); + setRegistrationAllowed(false); + + Assert.assertTrue(getRegistrationLink().getAttribute("href").endsWith("/true")); + + // logout; alternate element picking approach + driver + .findElement(By.xpath("//nav[@id='header_right_block']/div[@class='block_inner']/ul/li[4]/a[1]")) + .click(); + + WebElement registerLink = driver.findElement(By.xpath("//div[@class='container base']/a[1]")); + + wait.until(f -> registerLink.isDisplayed()); + + registerLink.click(); + + WebElement text = driver.findElement(By.tagName("h1")); + wait.until(f -> text.isDisplayed()); + + Assert.assertTrue(text.getText().contains("Currently we're closed to new registrations")); + } + + @Parameters({"admin_username", "admin_password"}) + @Test(testName = "Check registration allowed", + priority = 2, + groups = "registration_configuration") + public void checkRegAllowed(String user, String password){ + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + loginAsAdmin(user, password); + openSettings(); + setRegistrationAllowed(true); + + Assert.assertTrue(getRegistrationLink().getAttribute("href").endsWith("/false")); + // deep validation would be done within other tests + } + + private void loginAsAdmin(String user, String password){ + WebElement userNameInput = driver.findElement(By.xpath("//input[@id='username']")); + + wait.until(f -> userNameInput.isDisplayed()); + + userNameInput.sendKeys(user); + + driver.findElement(By.xpath("//input[@id='password']")).sendKeys(password); + driver.findElement(By.xpath("//button[@type='submit']")).click(); + } + private void openSettings(){ + WebElement settingsLink = driver.findElement( + By.xpath("//nav[@id='header_right_block']/div[@class='block_inner']/ul/li/a[@href='/settings']")); + + wait.until(f -> settingsLink.isDisplayed()); + + settingsLink.click(); + } + private WebElement getRegistrationLink(){ + return driver.findElement(By.xpath("//a[@id='registration']")); + } + private void setRegistrationAllowed(boolean isAllowed){ + WebElement registrationLink = getRegistrationLink(); + if (registrationLink.getAttribute("href").endsWith(isAllowed ? "/true" : "/false")) { + registrationLink.click(); + + wait.until(f -> getRegistrationLink().isDisplayed()); + } + } +} diff --git a/src/test/java/ru/redrise/users_management/RegistrationTest.java b/src/test/java/ru/redrise/users_management/RegistrationTest.java new file mode 100644 index 0000000..85d87cb --- /dev/null +++ b/src/test/java/ru/redrise/users_management/RegistrationTest.java @@ -0,0 +1,411 @@ +package ru.redrise.users_management; + +import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.WebDriverWait; +import org.testng.Assert; +import org.testng.annotations.*; +import ru.redrise.utils.TwoColumnsExcelReader; + +import java.time.Duration; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Random; + +public class RegistrationTest extends ScreenshotsMaker{ + //private final Logger log = LoggerFactory.getLogger(getClass()); + + private String registeredUserLogin; + + private WebDriver driver; + private WebDriverWait wait; + + private final HashMap allMyHandyErrors = new HashMap<>(); + + @BeforeClass + public void beforeClass() throws Exception{ + driver = Suite.driver; + wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + + Arrays.stream(TwoColumnsExcelReader.getFromFile(true, "error_messages.xlsx", "Лист1")) + .forEach(e -> allMyHandyErrors.put( + ((String) e[0]).trim(), ((String) e[1]).trim()) + ); + } + + @BeforeMethod + public void beforeMethod(){ + driver.get("http://localhost:8080/"); + logout(); + } + + @Parameters({"test_user_login", "test_user_password", "test_user_displayedname"}) + @Test(priority = 3, + testName = "Registration - positive", + dependsOnGroups = "registration_configuration") + public void regularRegistration(String user, String password, String displayedName) throws Exception{ + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + Random random = new Random(); + + for (int i = 0; registerAttempt(user+random.nextInt(9999), password, displayedName); i++){ + if (i >= 10) + throw new Exception("Unable to register new user"); + } + } + private boolean registerAttempt(String user, String password, String displayedName) { + WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + + pickUserNameField().sendKeys(user); + pickPasswordField().sendKeys(password); + pickPasswordConfirmField().sendKeys(password); + pickDisplaynameField().sendKeys(displayedName); + pickRegisterButton().click(); + + try{ + WebElement alreadyExistsError = driver.findElement(By.xpath("//span[@class='validationError']")); + wait.until(f -> alreadyExistsError.isDisplayed()); + + return true; + } + catch (Exception ignore){ } + + registeredUserLogin = user; + + return false; + } + + @Parameters({"test_user_password", "test_user_displayedname"}) + @Test(priority = 4, + testName = "Registration - already registered", + dependsOnGroups = "registration_configuration") + public void duplicateRegistration(String password, String displayedName) { + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + WebElement registerLink = driver.findElement(By.xpath("//div[@class='container base']/a[1]")); + + WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + wait.until(f -> registerLink.isDisplayed()); + + registerLink.click(); + + Assert.assertTrue(registerAttempt(registeredUserLogin, password, displayedName)); + + WebElement error = driver.findElement(By.xpath("//span[@id='duplicate_error']")); + wait.until(f -> error.isDisplayed()); + + Assert.assertEquals(error.getText(), allMyHandyErrors.get("duplicate_error")); + } + + @Parameters({"test_user_password", "test_user_displayedname"}) + @Test(priority = 4, + testName = "Registration - failure - no name", + dependsOnGroups = "registration_configuration") + public void registrationFailureNoName1(String password, String displayedName) { + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + pickPasswordField().sendKeys(password); + pickPasswordConfirmField().sendKeys(password); + pickDisplaynameField().sendKeys(displayedName); + pickRegisterButton().click(); + + WebElement error = driver.findElement(By.xpath("//span[@id='username_error']")); + wait.until(f -> error.isDisplayed()); + + Assert.assertTrue(registerAttempt(registeredUserLogin, password, displayedName)); + } + + @Parameters({"test_user_password", "test_user_displayedname"}) + @Test(priority = 4, + testName = "Registration - failure - wrong name - short", + dependsOnGroups = "registration_configuration") + public void registrationFailureShortName(String password, String displayedName) { + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + pickUserNameField().sendKeys(getRandomLettersName(2)); + pickPasswordField().sendKeys(password); + pickPasswordConfirmField().sendKeys(password); + pickDisplaynameField().sendKeys(displayedName); + pickRegisterButton().click(); + + WebElement error = driver.findElement(By.xpath("//span[@id='username_error']")); + wait.until(f -> error.isDisplayed()); + + Assert.assertEquals(error.getText(), allMyHandyErrors.get("username_error")); + } + + @Parameters({"test_user_password", "test_user_displayedname"}) + @Test(priority = 4, + testName = "Registration - failure - wrong name - huge", + dependsOnGroups = "registration_configuration") + public void registrationFailureBigName(String password, String displayedName) { + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + pickUserNameField().sendKeys(getRandomLettersName(33)); + pickPasswordField().sendKeys(password); + pickPasswordConfirmField().sendKeys(password); + pickDisplaynameField().sendKeys(displayedName); + pickRegisterButton().click(); + + WebElement error = driver.findElement(By.xpath("//span[@id='username_error']")); + wait.until(f -> error.isDisplayed()); + + Assert.assertEquals(error.getText(), allMyHandyErrors.get("username_error")); + } + + @Test(priority = 4, + testName = "Registration - failure - Correct name only entered", + expectedExceptions = { NoSuchElementException.class }, + dependsOnGroups = "registration_configuration") + public void registrationFailuresCorrectNameOnly() throws Exception{ + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + pickUserNameField().sendKeys(getRandomLettersName(10)); + pickRegisterButton().click(); + + WebElement error = driver.findElement(By.xpath("//span[@id='username_error']")); + wait.until(f -> error.isDisplayed()); + } + + // PASSWORD TESTING + + @Parameters({"not_being_registered_login", "test_user_displayedname"}) + @Test(priority = 4, + testName = "Registration - failure - no passwords", + dependsOnGroups = "registration_configuration") + public void registrationFailureNoPassword1(String name, String displayedName) { + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + pickUserNameField().sendKeys(name); + pickDisplaynameField().sendKeys(displayedName); + pickRegisterButton().click(); + + WebElement error = driver.findElement(By.xpath("//span[@id='password_error']")); + wait.until(f -> error.isDisplayed()); + + Assert.assertEquals(error.getText(), allMyHandyErrors.get("password_error")); + } + + @Parameters({"not_being_registered_login", "test_user_displayedname"}) + @Test(priority = 4, + testName = "Registration - failure - wrong passord - short", + dependsOnGroups = "registration_configuration") + public void registrationFailureShortPassword(String name, String displayedName) { + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + String shortPassword = getRandomLettersName(7); + + pickUserNameField().sendKeys(name); + pickPasswordField().sendKeys(shortPassword); + pickPasswordConfirmField().sendKeys(shortPassword); + pickDisplaynameField().sendKeys(displayedName); + pickRegisterButton().click(); + + WebElement error = driver.findElement(By.xpath("//span[@id='password_error']")); + wait.until(f -> error.isDisplayed()); + + Assert.assertEquals(error.getText(), allMyHandyErrors.get("password_error")); + } + + @Parameters({"not_being_registered_login", "test_user_displayedname"}) + @Test(priority = 4, + testName = "Registration - failure - wrong passord - huge", + dependsOnGroups = "registration_configuration") + public void registrationFailureBigPassword(String name, String displayedName) { + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + String shortPassword = getRandomLettersName(33); + + pickUserNameField().sendKeys(name); + pickPasswordField().sendKeys(shortPassword); + pickPasswordConfirmField().sendKeys(shortPassword); + pickDisplaynameField().sendKeys(displayedName); + pickRegisterButton().click(); + + WebElement error = driver.findElement(By.xpath("//span[@id='password_error']")); + wait.until(f -> error.isDisplayed()); + + Assert.assertEquals(error.getText(), allMyHandyErrors.get("password_error")); + } + + @Parameters({"test_user_password"}) + @Test(priority = 4, + testName = "Registration - failure - Correct password only entered", + expectedExceptions = { NoSuchElementException.class }, + dependsOnGroups = "registration_configuration") + public void registrationFailuresCorrectPasswordOnly(String password) throws Exception{ + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + pickPasswordField().sendKeys(password); + pickRegisterButton().click(); + + WebElement error = driver.findElement(By.xpath("//span[@id='password_error']")); + wait.until(f -> error.isDisplayed()); + } + + @Parameters({"test_user_password"}) + @Test(priority = 4, + testName = "Registration - failure - Correct password (both) only entered", + expectedExceptions = { NoSuchElementException.class }, + dependsOnGroups = "registration_configuration") + public void registrationFailuresCorrectPasswordsOnly(String password) throws Exception{ + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + pickPasswordField().sendKeys(password); + pickPasswordConfirmField().sendKeys(password); + pickRegisterButton().click(); + + WebElement error = driver.findElement(By.xpath("//span[@id='password_error']")); + wait.until(f -> error.isDisplayed()); + } + + // Repeat password field tests + + @Parameters({"not_being_registered_login", "test_user_password", "test_user_displayedname"}) + @Test(priority = 4, + testName = "Registration - failure - no duplicate password", + dependsOnGroups = "registration_configuration") + public void registrationFailureNoDuplicatePassword(String name, String password, String displayedName) { + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + pickUserNameField().sendKeys(name); + pickPasswordField().sendKeys(password); + pickDisplaynameField().sendKeys(displayedName); + pickRegisterButton().click(); + + WebElement error = driver.findElement(By.xpath("//span[@id='password_dup_error']")); + wait.until(f -> error.isDisplayed()); + + Assert.assertEquals(error.getText(), allMyHandyErrors.get("password_dup_error")); + } + + @Parameters({"not_being_registered_login", "test_user_password", "test_user_displayedname"}) + @Test(priority = 4, + testName = "Registration - failure - password no match", + dependsOnGroups = "registration_configuration") + public void registrationWrongDuplicPassword(String name, String password, String displayedName) { + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + pickUserNameField().sendKeys(name); + pickPasswordField().sendKeys(password); + pickPasswordConfirmField().sendKeys("42test"); + pickDisplaynameField().sendKeys(displayedName); + pickRegisterButton().click(); + + WebElement error = driver.findElement(By.xpath("//span[@id='password_dup_error']")); + wait.until(f -> error.isDisplayed()); + + Assert.assertEquals(error.getText(), allMyHandyErrors.get("password_dup_error")); + } + + // DISPLAY NAME TESTING + + @Parameters({"not_being_registered_login", "test_user_password"}) + @Test(priority = 4, + testName = "Registration - failure - no display name", + dependsOnGroups = "registration_configuration") + public void registrationFailureNoDisplayName(String name, String password) { + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + pickUserNameField().sendKeys(name); + pickPasswordField().sendKeys(password); + pickPasswordConfirmField().sendKeys(password); + pickRegisterButton().click(); + + WebElement error = driver.findElement(By.xpath("//span[@id='displayname_error']")); + wait.until(f -> error.isDisplayed()); + + Assert.assertEquals(error.getText(), allMyHandyErrors.get("displayname_error")); + } + + @Test(priority = 4, + testName = "Registration - failure - Correct display name only entered", + expectedExceptions = { NoSuchElementException.class }, + dependsOnGroups = "registration_configuration") + public void registrationFailuresCorrectDisplayNameOnly() throws Exception{ + this.latestTestMethodName = Thread.currentThread().getStackTrace()[1].getMethodName(); + + openRegistrationPage(); + + pickDisplaynameField().sendKeys("test test test"); + pickRegisterButton().click(); + + WebElement error = driver.findElement(By.xpath("//span[@id='displayname_error']")); + wait.until(f -> error.isDisplayed()); + } + + private void openRegistrationPage(){ + WebElement header = driver.findElement(By.tagName("header")); + wait.until(f -> header.isDisplayed()); + WebElement registerLink = driver.findElement(By.xpath("//div[@class='container base']/a[1]")); + registerLink.click(); + } + + private WebElement pickUserNameField(){ + return driver.findElement(By.xpath("//input[@id='username']")); + } + + private WebElement pickPasswordField(){ + return driver.findElement(By.xpath("//input[@id='password']")); + } + + private WebElement pickPasswordConfirmField() { + return driver.findElement(By.xpath("//input[@id='passwordConfirm']")); + } + + private WebElement pickDisplaynameField() { + return driver.findElement(By.xpath("//input[@id='displayname']")); + } + + private WebElement pickRegisterButton() { + return driver.findElement(By.xpath("//button[@id='register_submit']")); + } + + private String getRandomLettersName(int length){ + if (length <= 0) + return ""; + + Random random = new Random(); + StringBuilder name = new StringBuilder((char) random.nextInt(0x41, 0x5A)); + + for (int i = 0; i < length; i++) + name.append((char) random.nextInt(0x41, 0x5A)); + + return name.toString(); + } + + private void logout(){ + try{ + driver.findElement(By.xpath("//a[@id='logout']")).click(); + } + catch (Exception ignore){} + } +} diff --git a/src/test/java/ru/redrise/users_management/ScreenshotsMaker.java b/src/test/java/ru/redrise/users_management/ScreenshotsMaker.java new file mode 100644 index 0000000..92aec52 --- /dev/null +++ b/src/test/java/ru/redrise/users_management/ScreenshotsMaker.java @@ -0,0 +1,30 @@ +package ru.redrise.users_management; + +import org.openqa.selenium.OutputType; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; + +public abstract class ScreenshotsMaker{ + protected String latestTestMethodName; + + @AfterMethod + public void takeScreenshot() throws IOException { + final String finalFileLocation = String.format("/tmp/tests-output/%s - %s.png", + getClass().toString().replaceAll("^.*\\.", ""), latestTestMethodName); + + File screenshot = Suite.driver.getScreenshotAs(OutputType.FILE); + File finalLocation = new File(finalFileLocation); + + if (!finalLocation.getParentFile().exists()) + Assert.assertTrue(finalLocation.getParentFile().mkdirs()); + + Files.move(screenshot.toPath(), finalLocation.toPath(), StandardCopyOption.REPLACE_EXISTING); + + this.latestTestMethodName = ""; + } +} diff --git a/src/test/java/ru/redrise/users_management/Suite.java b/src/test/java/ru/redrise/users_management/Suite.java new file mode 100644 index 0000000..d02a46a --- /dev/null +++ b/src/test/java/ru/redrise/users_management/Suite.java @@ -0,0 +1,26 @@ +package ru.redrise.users_management; + +import org.openqa.selenium.Dimension; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeSuite; + +public class Suite{ + static ChromeDriver driver; + + @BeforeSuite + public void beforeSuite() { + ChromeOptions options = new ChromeOptions(); + options.addArguments("--remote-allow-origins=*"); + options.addArguments("--headless"); + + driver = new ChromeDriver(options); + driver.manage().window().setSize(new Dimension(1024, 768)); + } + + @AfterSuite + public void afterSuite() { + driver.close(); + } +} diff --git a/src/test/java/ru/redrise/utils/TwoColumnsExcelReader.java b/src/test/java/ru/redrise/utils/TwoColumnsExcelReader.java new file mode 100644 index 0000000..920a79b --- /dev/null +++ b/src/test/java/ru/redrise/utils/TwoColumnsExcelReader.java @@ -0,0 +1,33 @@ +package ru.redrise.utils; + +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import java.io.FileInputStream; + +public class TwoColumnsExcelReader { + private static final int COLUMN_COUNT = 2; + + private TwoColumnsExcelReader(){} + + public static Object[][] getFromFile(boolean firstRowIsTitle, String fileLocation, String sheetName) throws Exception{ + return getFromFile(0, firstRowIsTitle ? 1 : 0, fileLocation, sheetName); + } + public static Object[][] getFromFile(int startColumn, int startRow, String fileLocation, String sheetName) throws Exception{ + XSSFWorkbook excelWorkbook = new XSSFWorkbook(new FileInputStream(fileLocation)); + XSSFSheet excelSpreadsheet = excelWorkbook.getSheet(sheetName); + int rowsCount = excelSpreadsheet.getLastRowNum(); + + String[][] results = new String[rowsCount - startRow][COLUMN_COUNT]; + int j = 0; + for (int i = startRow; i < rowsCount; i++) { + Row row = excelSpreadsheet.getRow(i); + results[j][0] = row.getCell(startColumn).getStringCellValue(); + results[j][1] = row.getCell(startColumn+1).getStringCellValue(); + j++; + } + + return results; + } +} \ No newline at end of file diff --git a/testng.xml b/testng.xml new file mode 100644 index 0000000..f55e99b --- /dev/null +++ b/testng.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/ui.xml b/ui.xml new file mode 100644 index 0000000..787846c --- /dev/null +++ b/ui.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file