├── .gitignore
├── README.md
├── build.gradle
└── src
└── test
├── java
└── cloud
│ └── autotests
│ ├── config
│ ├── Project.java
│ ├── ProjectConfig.java
│ └── demowebshop
│ │ ├── App.java
│ │ └── AppConfig.java
│ ├── docs
│ ├── CssXpathExamples.java
│ ├── JUnit5Annotations.java
│ └── SelenideSnippets.java
│ ├── helpers
│ ├── AllureAttachments.java
│ ├── AllureRestAssuredFilter.java
│ ├── DriverSettings.java
│ └── DriverUtils.java
│ └── tests
│ ├── TestBase.java
│ └── demowebshop
│ └── LoginTests.java
└── resources
├── config
├── demowebshop
│ └── app.properties
└── local.properties
└── tpl
├── request.ftl
└── response.ftl
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 | *.iml
22 |
23 | # Project gen files
24 | .idea
25 | .allure/
26 | .gradle/
27 | allure-results/
28 | gradle/
29 | build/
30 | bin/
31 | out/
32 | logs/
33 | target/
34 | .classpath
35 | .project
36 | .settings/org.eclipse.buildship.core.prefs
37 | .vscode
38 | /gradlew
39 | /gradlew.bat
40 | .todo
41 | *.properties
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Project in Allure TestOps with manual & automated tests
2 | allure.autotests.cloud/project/%s (ask admin@qa.guru for access)
3 |
4 | # Jenkins job
5 | jenkins.autotests.cloud/job/%s
6 |
7 |
8 | # USAGE examples
9 |
10 | ### For run remote tests need fill remote.properties or to pass value:
11 |
12 | * browser (default chrome)
13 | * browserVersion (default 89.0)
14 | * browserSize (default 1920x1080)
15 | * browserMobileView (mobile device name, for example iPhone X)
16 | * remoteDriverUrl (url address from selenoid or grid)
17 | * videoStorage (url address where you should get video)
18 | * threads (number of threads)
19 |
20 |
21 | Run tests with filled remote.properties:
22 | ```bash
23 | gradle clean test
24 | ```
25 |
26 | Run tests with not filled remote.properties:
27 | ```bash
28 | gradle clean -DremoteDriverUrl=https://%s:%s@selenoid.autotests.cloud/wd/hub/ -DvideoStorage=https://selenoid.autotests.cloud/video/ -Dthreads=1 test
29 | ```
30 |
31 | Serve report:
32 | ```bash
33 | allure serve build/allure-results
34 | ```
35 |
36 |
37 | ###### For further development there are some example tests in src/test/java/cloud.autotests/tests/demowebshop
38 | * remove @Disabled("...") annotation to run tests
39 | ```bash
40 | gradle clean demowebshop
41 | ```
42 |
43 | :heart: qa.guru
44 | :blue_heart: t.me/qa_automation
45 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | id 'io.qameta.allure' version '2.9.6'
4 | }
5 |
6 | repositories {
7 | mavenCentral()
8 | }
9 |
10 | def allureVersion = "2.17.3",
11 | selenideVersion = "6.5.0",
12 | junitVersion = "5.8.2"
13 |
14 | allure {
15 | report {
16 | version.set(allureVersion)
17 | }
18 | adapter {
19 | aspectjWeaver.set(true)
20 | frameworks {
21 | junit5 {
22 | adapterVersion.set(allureVersion)
23 | }
24 | }
25 | }
26 | }
27 |
28 | dependencies {
29 | testImplementation(
30 | "org.aspectj:aspectjweaver:1.9.6",
31 | "com.codeborne:selenide:$selenideVersion",
32 | "io.qameta.allure:allure-selenide:$allureVersion",
33 | "io.rest-assured:rest-assured:4.3.1",
34 | "io.qameta.allure:allure-rest-assured:$allureVersion",
35 | "org.aeonbits.owner:owner:1.0.12",
36 | "org.assertj:assertj-core:3.19.0",
37 | "org.slf4j:slf4j-simple:1.7.29",
38 | "org.junit.jupiter:junit-jupiter:$junitVersion")
39 | }
40 |
41 | tasks.withType(JavaCompile) {
42 | options.encoding = 'UTF-8'
43 | sourceCompatibility = JavaVersion.VERSION_1_8
44 | targetCompatibility = JavaVersion.VERSION_1_8
45 | }
46 |
47 | tasks.withType(Test) {
48 | systemProperties(System.getProperties())
49 | useJUnitPlatform()
50 |
51 | if (System.getProperty("threads") != null) {
52 | systemProperties += [
53 | 'junit.jupiter.execution.parallel.enabled' : true,
54 | 'junit.jupiter.execution.parallel.mode.default' : 'concurrent',
55 | 'junit.jupiter.execution.parallel.mode.classes.default' : 'concurrent',
56 | 'junit.jupiter.execution.parallel.config.strategy' : 'fixed',
57 | 'junit.jupiter.execution.parallel.config.fixed.parallelism': System.getProperty("threads").toInteger()
58 | ]
59 | }
60 |
61 | testLogging {
62 | lifecycle {
63 | // events "started", "failed"
64 | events "started", "skipped", "failed", "standard_error", "standard_out"
65 | exceptionFormat "short"
66 | }
67 | }
68 | }
69 |
70 | task demowebshop(type: Test) {
71 | useJUnitPlatform {
72 | includeTags 'demowebshop'
73 | }
74 | }
--------------------------------------------------------------------------------
/src/test/java/cloud/autotests/config/Project.java:
--------------------------------------------------------------------------------
1 | package cloud.autotests.config;
2 |
3 | import org.aeonbits.owner.ConfigFactory;
4 |
5 | public class Project {
6 | public static ProjectConfig config = ConfigFactory.create(ProjectConfig.class, System.getProperties());
7 |
8 | public static boolean isWebMobile() {
9 | return !config.browserMobileView().equals("");
10 | }
11 |
12 | public static boolean isRemoteWebDriver() {
13 | return !config.remoteDriverUrl().equals("");
14 | }
15 |
16 | public static boolean isVideoOn() {
17 | return !config.videoStorage().equals("");
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/test/java/cloud/autotests/config/ProjectConfig.java:
--------------------------------------------------------------------------------
1 | package cloud.autotests.config;
2 |
3 | import org.aeonbits.owner.Config;
4 |
5 | @Config.LoadPolicy(Config.LoadType.MERGE)
6 | @Config.Sources({
7 | "system:properties",
8 | "classpath:config/local.properties",
9 | "classpath:config/remote.properties"
10 | })
11 | public interface ProjectConfig extends Config {
12 |
13 | @DefaultValue("chrome")
14 | String browser();
15 | @DefaultValue("91.0")
16 | String browserVersion();
17 | @DefaultValue("1920x1080")
18 | String browserSize();
19 | String browserMobileView();
20 | String remoteDriverUrl();
21 | String videoStorage();
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/cloud/autotests/config/demowebshop/App.java:
--------------------------------------------------------------------------------
1 | package cloud.autotests.config.demowebshop;
2 |
3 | import org.aeonbits.owner.ConfigFactory;
4 |
5 | public class App {
6 | public static AppConfig config = ConfigFactory.create(AppConfig.class, System.getProperties());
7 | }
8 |
--------------------------------------------------------------------------------
/src/test/java/cloud/autotests/config/demowebshop/AppConfig.java:
--------------------------------------------------------------------------------
1 | package cloud.autotests.config.demowebshop;
2 |
3 | import org.aeonbits.owner.Config;
4 |
5 | @Config.LoadPolicy(Config.LoadType.MERGE)
6 | @Config.Sources({
7 | "system:properties",
8 | "classpath:config/demowebshop/app.properties"
9 | })
10 | public interface AppConfig extends Config {
11 |
12 | String webUrl();
13 | String apiUrl();
14 | String userLogin();
15 | String userPassword();
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/test/java/cloud/autotests/docs/CssXpathExamples.java:
--------------------------------------------------------------------------------
1 | package cloud.autotests.docs;
2 |
3 | import org.openqa.selenium.By;
4 |
5 | import static com.codeborne.selenide.Selectors.*;
6 | import static com.codeborne.selenide.Selenide.$;
7 | import static com.codeborne.selenide.Selenide.$x;
8 |
9 | /*
10 | Locators examples
11 | Author: https://github.com/svasenkov
12 | */
13 |
14 | public class CssXpathExamples {
15 |
16 | void cssXpathExamples() {
17 |
18 | //
19 |
20 | $("[data-testid=royal_email]");
21 | $(by("data-testid", "royal_email"));
22 |
23 |
24 | //
25 |
26 | $("#email");
27 | $(byId("email"));
28 | $(By.id("email"));
29 | $("[id=email]");
30 | $("[id='email']");
31 | $("[id=\"email\"]");
32 | $("input[id=email]");
33 | $("input#email");
34 | $(by("id", "email"));
35 | $x("//*[@id='email']");
36 | $x("//input[@id='email']");
37 | $(byXpath("//input[@id='email']"));
38 |
39 |
40 | //
41 |
42 | $("[name='email']");
43 | $("input[name='email']");
44 | $(by("name", "email"));
45 | $(byName("email"));
46 |
47 |
48 | //
49 |
50 | $(byClassName("login_form_input_box"));
51 | $(".login_form_input_box");
52 | $(".inputtext.login_form_input_box");
53 | $("input.inputtext.login_form_input_box");
54 | $x("//*[@class='login_form_input_box']");
55 |
56 | //
57 | //
58 | //
59 | $("input.inputtext .login_form_input_box");
60 |
61 | // Hello qa.guru
62 | $(byText("Hello qa.guru"));
63 | $(withText("lo qa.guru"));
64 | }
65 | }
--------------------------------------------------------------------------------
/src/test/java/cloud/autotests/docs/JUnit5Annotations.java:
--------------------------------------------------------------------------------
1 | package cloud.autotests.docs;
2 |
3 | import org.junit.jupiter.api.*;
4 |
5 | /*
6 | JUnit5 annotations examples
7 | Author: https://github.com/dtuchs
8 | */
9 |
10 | @Tag("junit5")
11 | public class JUnit5Annotations {
12 |
13 | @BeforeAll
14 | static void beforeAll() {
15 | System.out.println("this is before all methods!");
16 | }
17 |
18 | @BeforeEach
19 | void setUp() {
20 | System.out.println("this is before each method!");
21 | }
22 |
23 | @AfterEach
24 | void tearDown() {
25 | System.out.println("this is after each method!");
26 | }
27 |
28 | @AfterAll
29 | static void tearDownDown() {
30 | System.out.println("this is after all methods!");
31 | }
32 |
33 | // @Test
34 | void firstTest() {
35 | System.out.println("this is the first @test!");
36 | Assertions.assertTrue(true);
37 | }
38 |
39 | // @Test
40 | void secondTest() {
41 | System.out.println("this is the second @test!");
42 | Assertions.assertTrue(true);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/cloud/autotests/docs/SelenideSnippets.java:
--------------------------------------------------------------------------------
1 | package cloud.autotests.docs;
2 |
3 | import com.codeborne.selenide.*;
4 | import org.openqa.selenium.Keys;
5 |
6 | import java.io.File;
7 | import java.io.FileNotFoundException;
8 | import java.time.Duration;
9 |
10 | import static com.codeborne.selenide.CollectionCondition.*;
11 | import static com.codeborne.selenide.Condition.empty;
12 | import static com.codeborne.selenide.Condition.*;
13 | import static com.codeborne.selenide.Selectors.*;
14 | import static com.codeborne.selenide.Selenide.*;
15 |
16 | /*
17 | Selenide commands examples
18 | Author: https://github.com/vinogradoff
19 | this is not a full list, just the most common
20 | */
21 |
22 | public class SelenideSnippets {
23 |
24 | void browser_command_examples() {
25 |
26 | open("https://google.com");
27 | open("/customer/orders"); // -Dselenide.baseUrl=http://google.com
28 | open("/", AuthenticationType.BASIC,
29 | new BasicAuthCredentials("user", "password"));
30 |
31 | Selenide.back();
32 | Selenide.refresh();
33 |
34 | Selenide.clearBrowserCookies();
35 | Selenide.clearBrowserLocalStorage();
36 | executeJavaScript("sessionStorage.clear();"); // no Selenide command for this yet
37 |
38 | Selenide.confirm(); // OK in alert dialogs
39 | Selenide.dismiss(); // Cancel in alert dialogs
40 |
41 | Selenide.closeWindow(); // close active tab
42 | Selenide.closeWebDriver(); // close browser completely
43 |
44 | Selenide.switchTo().frame("new");
45 | Selenide.switchTo().defaultContent();
46 |
47 | Selenide.switchTo().window("The Internet");
48 | }
49 |
50 | void selectors_examples() {
51 | $("div").click();
52 | element("div").click();
53 |
54 | $("div", 2).click(); // the third div
55 |
56 | $x("//h1/div").click();
57 | $(byXpath("//h1/div")).click();
58 |
59 | $(byText("full text")).click();
60 | $(withText("ull tex")).click();
61 |
62 | $(byTagAndText("div", "full text"));
63 | $(withTagAndText("div", "ull text"));
64 |
65 | $("").parent(); // find parent element
66 | $("").sibling(2); // find down third sibling element
67 | $("").preceding(0); // find up first sibling element
68 | $("").closest("div"); // find up the tree the next element with tag
69 | $("").ancestor("div"); // the same as closest
70 | $("div:last-child");
71 |
72 | $("div").$("h1").find(byText("abc")).click();
73 |
74 | // very optional
75 | $(byAttribute("abc", "x")).click();
76 | $("[abc=x]").click();
77 |
78 | $(byId("mytext")).click();
79 | $("#mytext").click();
80 |
81 | $(byClassName("red")).click();
82 | $(".red").click();
83 | }
84 |
85 | void actions_examples() {
86 | $("").click();
87 | $("").doubleClick();
88 | $("").contextClick();
89 |
90 | $("").hover();
91 |
92 | $("").setValue("text");
93 | $("").append("text");
94 | $("").clear();
95 | $("").setValue(""); // clear
96 |
97 | $("div").sendKeys("c"); // hotkey c on element
98 | actions().sendKeys("c").perform(); //hotkey c on whole application
99 | actions().sendKeys(Keys.chord(Keys.CONTROL, "f")).perform(); // Ctrl + F
100 | $("html").sendKeys(Keys.chord(Keys.CONTROL, "f"));
101 |
102 | $("").pressEnter();
103 | $("").pressEscape();
104 | $("").pressTab();
105 |
106 | // complex actions with keybord and mouse, example
107 | actions().moveToElement($("div")).clickAndHold().moveByOffset(300, 200).release().perform();
108 |
109 | // old html actions don't work with many modern frameworks
110 | $("").selectOption("dropdown_option");
111 | $("").selectRadio("radio_options");
112 |
113 | }
114 |
115 | void assertions_examples() {
116 | $("").shouldBe(visible);
117 | $("").shouldNotBe(visible);
118 | $("").shouldHave(text("abc"));
119 | $("").shouldNotHave(text("abc"));
120 | $("").should(appear);
121 | $("").shouldNot(appear);
122 |
123 |
124 | //longer timeouts
125 | $("").shouldBe(visible, Duration.ofSeconds(30));
126 | // $("").waitUntil(visible, 30000); //is deprecated
127 |
128 | }
129 |
130 | void conditions_examples() {
131 | $("").shouldBe(visible);
132 | $("").shouldBe(hidden);
133 |
134 | $("").shouldHave(text("abc"));
135 | $("").shouldHave(exactText("abc"));
136 | $("").shouldHave(textCaseSensitive("abc"));
137 | $("").shouldHave(exactTextCaseSensitive("abc"));
138 | $("").should(matchText("[0-9]abc$"));
139 |
140 | $("").shouldHave(cssClass("red"));
141 | $("").shouldHave(cssValue("font-size", "12"));
142 |
143 | $("").shouldHave(value("25"));
144 | $("").shouldHave(exactValue("25"));
145 | $("").shouldBe(empty);
146 |
147 | $("").shouldHave(attribute("disabled"));
148 | $("").shouldHave(attribute("name", "example"));
149 | $("").shouldHave(attributeMatching("name", "[0-9]abc$"));
150 |
151 | $("").shouldBe(checked); // for checkboxes
152 |
153 | // Warning! Only checks if it is in DOM, not if it is visible! You don't need it in most tests!
154 | $("").should(exist);
155 |
156 | // Warning! Checks only the "disabled" attribute! Will not work with many modern frameworks
157 | $("").shouldBe(disabled);
158 | $("").shouldBe(enabled);
159 | }
160 |
161 | void collections_examples() {
162 |
163 | $$("div"); // does nothing!
164 |
165 | // selections
166 | $$("div").filterBy(text("123")).shouldHave(size(1));
167 | $$("div").excludeWith(text("123")).shouldHave(size(1));
168 |
169 | $$("div").first().click();
170 | elements("div").first().click();
171 | // $("div").click();
172 | $$("div").last().click();
173 | $$("div").get(1).click(); // the second! (start with 0)
174 | $("div", 1).click(); // same as previous
175 | $$("div").findBy(text("123")).click(); // finds first
176 |
177 | // assertions
178 | $$("").shouldHave(size(0));
179 | $$("").shouldBe(CollectionCondition.empty); // the same
180 |
181 | $$("").shouldHave(texts("Alfa", "Beta", "Gamma"));
182 | $$("").shouldHave(exactTexts("Alfa", "Beta", "Gamma"));
183 |
184 | $$("").shouldHave(textsInAnyOrder("Beta", "Gamma", "Alfa"));
185 | $$("").shouldHave(exactTextsCaseSensitiveInAnyOrder("Beta", "Gamma", "Alfa"));
186 |
187 | $$("").shouldHave(itemWithText("Gamma")); // only one text
188 |
189 | $$("").shouldHave(sizeGreaterThan(0));
190 | $$("").shouldHave(sizeGreaterThanOrEqual(1));
191 | $$("").shouldHave(sizeLessThan(3));
192 | $$("").shouldHave(sizeLessThanOrEqual(2));
193 |
194 | }
195 |
196 | void file_operation_examples() throws FileNotFoundException {
197 |
198 | File file1 = $("a.fileLink").download(); // only for links
199 | File file2 = $("div").download(DownloadOptions.using(FileDownloadMode.FOLDER)); // more common options, but may have problems with Grid/Selenoid
200 |
201 | File file = new File("src/test/resources/readme.txt");
202 | $("#file-upload").uploadFile(file);
203 | $("#file-upload").uploadFromClasspath("readme.txt");
204 | // don't forget to submit!
205 | $("uploadButton").click();
206 | }
207 |
208 | void javascript_examples() {
209 | executeJavaScript("alert('selenide')");
210 | executeJavaScript("alert(arguments[0]+arguments[1])", "abc", 12);
211 | long fortyTwo = executeJavaScript("return arguments[0]*arguments[1];", 6, 7);
212 | }
213 | }
--------------------------------------------------------------------------------
/src/test/java/cloud/autotests/helpers/AllureAttachments.java:
--------------------------------------------------------------------------------
1 | package cloud.autotests.helpers;
2 |
3 | import io.qameta.allure.Allure;
4 | import io.qameta.allure.Attachment;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | import java.io.FileNotFoundException;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.net.URL;
12 |
13 | import static com.codeborne.selenide.Selenide.sleep;
14 |
15 | public class AllureAttachments {
16 | public static final Logger LOGGER = LoggerFactory.getLogger(AllureAttachments.class);
17 |
18 | @Attachment(value = "{attachName}", type = "text/plain")
19 | private static String addMessage(String attachName, String text) {
20 | return text;
21 | }
22 |
23 | public static void addBrowserConsoleLogs() {
24 | addMessage("Browser console logs", DriverUtils.getConsoleLogs());
25 | }
26 |
27 | @Attachment(value = "{attachName}", type = "image/png")
28 | public static byte[] addScreenshotAs(String attachName) {
29 | return DriverUtils.getScreenshotAsBytes();
30 | }
31 |
32 | @Attachment(value = "Page source", type = "text/html")
33 | public static byte[] addPageSource() {
34 | return DriverUtils.getPageSourceAsBytes();
35 | }
36 |
37 | public static void addVideo(String sessionId) {
38 | URL videoUrl = DriverUtils.getVideoUrl(sessionId);
39 | if (videoUrl != null) {
40 | InputStream videoInputStream = null;
41 | sleep(1000);
42 |
43 | for (int i = 0; i < 20; i++) {
44 | try {
45 | videoInputStream = videoUrl.openStream();
46 | break;
47 | } catch (FileNotFoundException e) {
48 | sleep(1000);
49 | } catch (IOException e) {
50 | LOGGER.warn("[ALLURE VIDEO ATTACHMENT ERROR] Cant attach allure video, {}", videoUrl);
51 | e.printStackTrace();
52 | }
53 | }
54 | if (videoInputStream != null) {
55 | Allure.addAttachment("Video", "video/mp4", videoInputStream, "mp4");
56 | }
57 | }
58 | }
59 |
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/test/java/cloud/autotests/helpers/AllureRestAssuredFilter.java:
--------------------------------------------------------------------------------
1 | package cloud.autotests.helpers;
2 |
3 | import io.qameta.allure.restassured.AllureRestAssured;
4 |
5 | public class AllureRestAssuredFilter {
6 | private static final AllureRestAssured FILTER = new AllureRestAssured();
7 |
8 | public static AllureRestAssured withCustomTemplates() {
9 | FILTER.setRequestTemplate("request.ftl");
10 | FILTER.setResponseTemplate("response.ftl");
11 | return FILTER;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/test/java/cloud/autotests/helpers/DriverSettings.java:
--------------------------------------------------------------------------------
1 | package cloud.autotests.helpers;
2 |
3 | import cloud.autotests.config.Project;
4 | import com.codeborne.selenide.Configuration;
5 | import org.openqa.selenium.chrome.ChromeOptions;
6 | import org.openqa.selenium.remote.DesiredCapabilities;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | public class DriverSettings {
12 |
13 | public static void configure() {
14 | Configuration.browser = Project.config.browser();
15 | Configuration.browserVersion = Project.config.browserVersion();
16 | Configuration.browserSize = Project.config.browserSize();
17 | // Configuration.baseUrl = App.config.webUrl();
18 |
19 | DesiredCapabilities capabilities = new DesiredCapabilities();
20 | ChromeOptions chromeOptions = new ChromeOptions();
21 |
22 | chromeOptions.addArguments("--no-sandbox");
23 | chromeOptions.addArguments("--disable-infobars");
24 | chromeOptions.addArguments("--disable-popup-blocking");
25 | chromeOptions.addArguments("--disable-notifications");
26 | chromeOptions.addArguments("--lang=en-en");
27 |
28 | if (Project.isWebMobile()) { // for chrome only
29 | Map mobileDevice = new HashMap<>();
30 | mobileDevice.put("deviceName", Project.config.browserMobileView());
31 | chromeOptions.setExperimentalOption("mobileEmulation", mobileDevice);
32 | }
33 |
34 | if (Project.isRemoteWebDriver()) {
35 | capabilities.setCapability("enableVNC", true);
36 | capabilities.setCapability("enableVideo", true);
37 | Configuration.remote = Project.config.remoteDriverUrl();
38 | }
39 |
40 | capabilities.setCapability(ChromeOptions.CAPABILITY, chromeOptions);
41 | Configuration.browserCapabilities = capabilities;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/test/java/cloud/autotests/helpers/DriverUtils.java:
--------------------------------------------------------------------------------
1 | package cloud.autotests.helpers;
2 |
3 | import cloud.autotests.config.Project;
4 | import com.codeborne.selenide.Selenide;
5 | import org.openqa.selenium.OutputType;
6 | import org.openqa.selenium.TakesScreenshot;
7 | import org.openqa.selenium.remote.RemoteWebDriver;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import java.net.MalformedURLException;
12 | import java.net.URL;
13 | import java.nio.charset.StandardCharsets;
14 |
15 | import static com.codeborne.selenide.WebDriverRunner.getWebDriver;
16 | import static org.openqa.selenium.logging.LogType.BROWSER;
17 |
18 | public class DriverUtils {
19 | public static final Logger LOGGER = LoggerFactory.getLogger(DriverUtils.class);
20 |
21 |
22 | public static String getSessionId() {
23 | return ((RemoteWebDriver) getWebDriver()).getSessionId().toString();
24 | }
25 |
26 | public static byte[] getScreenshotAsBytes() {
27 | return ((TakesScreenshot) getWebDriver()).getScreenshotAs(OutputType.BYTES);
28 | }
29 |
30 | public static byte[] getPageSourceAsBytes() {
31 | return getWebDriver().getPageSource().getBytes(StandardCharsets.UTF_8);
32 | }
33 |
34 | public static URL getVideoUrl(String sessionId) {
35 | String videoUrl = Project.config.videoStorage() + sessionId + ".mp4";
36 |
37 | try {
38 | return new URL(videoUrl);
39 | } catch (MalformedURLException e) {
40 | LOGGER.warn("[ALLURE VIDEO ATTACHMENT ERROR] Wrong test video url, {}", videoUrl);
41 | e.printStackTrace();
42 | }
43 | return null;
44 | }
45 |
46 | public static String getConsoleLogs() { // todo refactor
47 | return String.join("\n", Selenide.getWebDriverLogs(BROWSER));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/test/java/cloud/autotests/tests/TestBase.java:
--------------------------------------------------------------------------------
1 | package cloud.autotests.tests;
2 |
3 | import cloud.autotests.config.Project;
4 | import cloud.autotests.helpers.AllureAttachments;
5 | import cloud.autotests.helpers.DriverSettings;
6 | import cloud.autotests.helpers.DriverUtils;
7 | import com.codeborne.selenide.Selenide;
8 | import com.codeborne.selenide.logevents.SelenideLogger;
9 | import io.qameta.allure.junit5.AllureJunit5;
10 | import io.qameta.allure.selenide.AllureSelenide;
11 | import org.junit.jupiter.api.AfterEach;
12 | import org.junit.jupiter.api.BeforeAll;
13 | import org.junit.jupiter.api.BeforeEach;
14 | import org.junit.jupiter.api.extension.ExtendWith;
15 |
16 |
17 | @ExtendWith({AllureJunit5.class})
18 | public class TestBase {
19 | @BeforeAll
20 | static void beforeAll() {
21 | DriverSettings.configure();
22 | }
23 |
24 | @BeforeEach
25 | public void beforeEach() {
26 | SelenideLogger.addListener("AllureSelenide", new AllureSelenide());
27 | }
28 |
29 | @AfterEach
30 | public void afterEach() {
31 | String sessionId = DriverUtils.getSessionId();
32 |
33 | AllureAttachments.addScreenshotAs("Last screenshot");
34 | AllureAttachments.addPageSource();
35 | // AllureAttachments.attachNetwork(); // todo
36 | AllureAttachments.addBrowserConsoleLogs();
37 |
38 | Selenide.closeWebDriver();
39 |
40 | if (Project.isVideoOn()) {
41 | AllureAttachments.addVideo(sessionId);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/cloud/autotests/tests/demowebshop/LoginTests.java:
--------------------------------------------------------------------------------
1 | package cloud.autotests.tests.demowebshop;
2 |
3 | import cloud.autotests.config.demowebshop.App;
4 | import cloud.autotests.helpers.AllureRestAssuredFilter;
5 | import cloud.autotests.tests.TestBase;
6 | import com.codeborne.selenide.Configuration;
7 | import io.qameta.allure.Story;
8 | import io.restassured.RestAssured;
9 | import org.junit.jupiter.api.*;
10 | import org.openqa.selenium.Cookie;
11 |
12 | import static com.codeborne.selenide.Condition.text;
13 | import static com.codeborne.selenide.Selenide.$;
14 | import static com.codeborne.selenide.Selenide.open;
15 | import static com.codeborne.selenide.WebDriverRunner.getWebDriver;
16 | import static io.qameta.allure.Allure.step;
17 | import static io.restassured.RestAssured.given;
18 |
19 | @Story("Login tests")
20 | public class LoginTests extends TestBase {
21 |
22 | static String login,
23 | password;
24 |
25 | @BeforeAll
26 | static void configureBaseUrl() {
27 | RestAssured.baseURI = App.config.apiUrl();
28 | Configuration.baseUrl = App.config.webUrl();
29 |
30 | login = App.config.userLogin();
31 | password = App.config.userPassword();
32 | }
33 |
34 | @Test
35 | @Tag("demowebshop")
36 | @Disabled("Example test code for further test development")
37 | @DisplayName("Successful authorization to some demowebshop (UI)")
38 | void loginTest() {
39 | step("Open login page", () ->
40 | open("/login"));
41 |
42 | step("Fill login form", () -> {
43 | $("#Email").setValue(login);
44 | $("#Password").setValue(password)
45 | .pressEnter();
46 | });
47 |
48 | step("Verify successful authorization", () ->
49 | $(".account").shouldHave(text(login)));
50 | }
51 |
52 | @Test
53 | @Tag("demowebshop")
54 | @Disabled("Example test code for further test development")
55 | @DisplayName("Successful authorization to some demowebshop (API + UI)")
56 | void loginWithCookieTest() {
57 | step("Get cookie by api and set it to browser", () -> {
58 | String authorizationCookie =
59 | given()
60 | .filter(AllureRestAssuredFilter.withCustomTemplates())
61 | .contentType("application/x-www-form-urlencoded; charset=UTF-8")
62 | .formParam("Email", login)
63 | .formParam("Password", password)
64 | .when()
65 | .post("/login")
66 | .then()
67 | .statusCode(302)
68 | .extract()
69 | .cookie("NOPCOMMERCE.AUTH");
70 |
71 | step("Open minimal content, because cookie can be set when site is opened", () ->
72 | open("/Themes/DefaultClean/Content/images/logo.png"));
73 |
74 | step("Set cookie to to browser", () ->
75 | getWebDriver().manage().addCookie(
76 | new Cookie("NOPCOMMERCE.AUTH", authorizationCookie)));
77 | });
78 |
79 | step("Open main page", () ->
80 | open(""));
81 |
82 | step("Verify successful authorization", () ->
83 | $(".account").shouldHave(text(login)));
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/test/resources/config/demowebshop/app.properties:
--------------------------------------------------------------------------------
1 | # usually, we do not store user credentials or other sensitive data in git,
2 | # that's only for an example project
3 | webUrl=http://demowebshop.tricentis.com
4 | apiUrl=http://demowebshop.tricentis.com
5 | userLogin=qaguru@qa.guru
6 | userPassword=qaguru@qa.guru1
--------------------------------------------------------------------------------
/src/test/resources/config/local.properties:
--------------------------------------------------------------------------------
1 | browser=chrome
2 | browserVersion=91.0
3 | browserSize=1920x1080
4 | browserMobileView=
5 | #browserMobileView=iPhone X
6 | remoteDriverUrl=
7 | videoStorage=
--------------------------------------------------------------------------------
/src/test/resources/tpl/request.ftl:
--------------------------------------------------------------------------------
1 |
2 | <#-- @ftlvariable name="data" type="io.qameta.allure.attachment.http.HttpRequestAttachment" -->
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
23 |
24 |
25 |
<#if data.method??>${data.method}<#else>GET#if>: <#if data.url??>${data.url}<#else>Unknown#if>
26 |
27 |
28 | <#if data.body??>
29 | Body
30 |
33 | #if>
34 |
35 | <#if (data.headers)?has_content>
36 | Headers
37 |
38 | <#list data.headers as name, value>
39 |
40 |
${name}: ${value}
41 |
42 | #list>
43 |
44 | #if>
45 |
46 |
47 | <#if (data.cookies)?has_content>
48 | Cookies
49 |
50 | <#list data.cookies as name, value>
51 |
52 |
${name}: ${value}
53 |
54 | #list>
55 |
56 | #if>
57 |
58 | <#if data.curl??>
59 | Curl
60 |
63 | #if>
64 |
65 |
--------------------------------------------------------------------------------
/src/test/resources/tpl/response.ftl:
--------------------------------------------------------------------------------
1 |
2 | <#-- @ftlvariable name="data" type="io.qameta.allure.attachment.http.HttpResponseAttachment" -->
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
23 |
24 | Status code
<#if data.responseCode??>
25 |
${data.responseCode}
26 | <#else>Unknown#if>
27 | <#if data.url??>
28 |
29 | #if>
32 |
33 | <#if (data.headers)?has_content>
34 | Headers
35 |
36 | <#list data.headers as name, value>
37 |
38 |
${name}: ${value}
39 |
40 | #list>
41 |
42 | #if>
43 |
44 | <#if data.body??>
45 | Body
46 |
49 | #if>
50 |
51 | <#if (data.cookies)?has_content>
52 | Cookies
53 |
54 | <#list data.cookies as name, value>
55 |
56 |
${name}: ${value}
57 |
58 | #list>
59 |
60 | #if>
61 |
62 |
--------------------------------------------------------------------------------