{
15 | // local variables
16 | private static final String WELCOME_TITLE = "Welcome";
17 | private static final String MENU_TITLE = "Menu";
18 | protected static enum WELCOME_PAGE_IMG { PASSION_TEA_CO, LEAF, ORGANIC, TEA_CUP, HERBAL_TEA, LOOSE_TEA, FLAVORED_TEA };
19 | protected static enum MENU_LINKS { MENU, MORE_1, MORE_2, HERBAL_TEA, LOOSE_TEA, FLAVORED_TEA, SEE_COLLECTION1, SEE_COLLECTION2, SEE_COLLECTION3 };
20 |
21 | // constructor
22 | public PassionTeaCoWelcomePO() throws Exception {
23 | super();
24 |
25 | setTitle(WELCOME_TITLE);
26 | }
27 |
28 | // elements
29 | @FindBy(css = "img[src*='7cbbd331e278a100b443a12aa4cce77b']")
30 | protected M teaCupImg;
31 |
32 | @FindBy(xpath = "//h1[contains(text(),'We're passionate about tea')]")
33 | protected M caption;
34 |
35 | @FindBy(xpath = "//span[contains(text(),'For more than 25 years')]")
36 | protected M paragraph;
37 |
38 | @FindBy(css = "a[href='http://www.seleniumframework.com']")
39 | protected M seleniumFramework;
40 |
41 | @FindBy(xpath = "//span[.='Herbal Tea']")
42 | protected M herbalTea;
43 |
44 | @FindBy(xpath = "//span[.='Loose Tea']")
45 | protected M looseTea;
46 |
47 | @FindBy(xpath = "//span[.='Flavored Tea']")
48 | protected M flavoredTea;
49 |
50 | @FindBy(css = "img[src*='d892360c0e73575efa3e5307c619db41']")
51 | protected M herbalTeaImg;
52 |
53 | @FindBy(css = "img[src*='18f9b21e513a597e4b8d4c805321bbe3']")
54 | protected M looseTeaImg;
55 |
56 | @FindBy(css = "img[src*='d0554952ea0bea9e79bf01ab564bf666']")
57 | protected M flavoredTeaImg;
58 |
59 | @FindBy(xpath = "(//span[contains(@class,'button-content')])[1]")
60 | protected M flavoredTeaCollect;
61 |
62 | @FindBy(xpath = "(//span[contains(@class,'button-content')])[2]")
63 | protected M herbalTeaCollect;
64 |
65 | @FindBy(xpath = "(//span[contains(@class,'button-content')])[3]")
66 | protected M looseTeaCollect;
67 |
68 | // abstract methods
69 |
70 | /**
71 | * setTitle method to set page title
72 | *
73 | * @param pageTitle
74 | */
75 | @Override
76 | protected void setTitle(String pageTitle) {
77 | this.pageTitle = pageTitle;
78 | }
79 |
80 | /**
81 | * getTitle method to get page title
82 | *
83 | * @return String
84 | */
85 | @Override
86 | public String getTitle() {
87 | return this.pageTitle;
88 | }
89 |
90 | // common methods
91 |
92 | /**
93 | * verifyImgSrc method to verify page image source
94 | *
95 | * @param img
96 | * @param src
97 | * @throws AssertionError
98 | */
99 | public void verifyImgSrc(WELCOME_PAGE_IMG img, String src) throws AssertionError {
100 | String getText = null;
101 |
102 | switch(img) {
103 | case PASSION_TEA_CO:
104 | getText = passionTeaCoImg.getAttribute("src");
105 | break;
106 | case LEAF:
107 | getText = leafImg.getAttribute("src");
108 | break;
109 | case ORGANIC:
110 | getText = organicImg.getAttribute("src");
111 | break;
112 | case TEA_CUP:
113 | getText = teaCupImg.getAttribute("src");
114 | break;
115 | case HERBAL_TEA:
116 | getText = herbalTeaImg.getAttribute("src");
117 | break;
118 | case LOOSE_TEA:
119 | getText = looseTeaImg.getAttribute("src");
120 | break;
121 | case FLAVORED_TEA:
122 | getText = flavoredTeaImg.getAttribute("src");
123 | break;
124 | }
125 |
126 | assertEquals(getText, src, "Verify Image Source");
127 | }
128 |
129 | /**
130 | * navigateMenuLink method to navigate page menu links
131 | *
132 | * @param link
133 | * @param title
134 | * @throws AssertionError
135 | */
136 | public void navigateMenuLink(MENU_LINKS link, String title) throws Exception {
137 | String index = null;
138 | WebDriver driver = CreateDriver.getInstance().getDriver();
139 |
140 | switch(link) {
141 | case HERBAL_TEA:
142 | index = "1";
143 | break;
144 | case MENU:
145 | index = "2";
146 | break;
147 | case SEE_COLLECTION3:
148 | index = "3";
149 | break;
150 | case MORE_2:
151 | index = "4";
152 | break;
153 | case MORE_1:
154 | index = "5";
155 | break;
156 | case LOOSE_TEA:
157 | index = "6";
158 | break;
159 | case SEE_COLLECTION1:
160 | index = "7";
161 | break;
162 | case SEE_COLLECTION2:
163 | index = "8";
164 | break;
165 | case FLAVORED_TEA:
166 | index = "9";
167 | break;
168 | }
169 |
170 | // Firefox occasionally fails to execute WebDriver API click
171 | String query = "(//a[@href='menu.html'])" + "[" + index + "]";
172 |
173 | try {
174 | driver.findElement(By.xpath(query)).click();
175 | BrowserUtils.waitFor(MENU_TITLE, Global_VARS.TIMEOUT_ELEMENT);
176 | }
177 |
178 | // make 2nd attempt with JavaScript API click
179 | catch(TimeoutException e) {
180 | BrowserUtils.click(By.xpath(query));
181 | BrowserUtils.waitFor(MENU_TITLE, Global_VARS.TIMEOUT_ELEMENT);
182 | }
183 |
184 | assertEquals(MENU_TITLE, title, "Navigate Menu Link");
185 | }
186 |
187 | }
188 |
--------------------------------------------------------------------------------
/Chapter18/TestNG_ConsoleRunner.java:
--------------------------------------------------------------------------------
1 | package com.framework.ux.utils.chapter10;
2 |
3 | import org.testng.ITestContext;
4 | import org.testng.ITestResult;
5 | import org.testng.TestListenerAdapter;
6 |
7 | import java.io.*;
8 | import java.text.DateFormat;
9 | import java.text.SimpleDateFormat;
10 | import java.util.Date;
11 |
12 | /**
13 | * @author Carl Cocchiaro
14 | *
15 | * TestNG Listener Utility Class
16 | *
17 | */
18 | public class TestNG_ConsoleRunner extends TestListenerAdapter {
19 | private static String logFile = null;
20 |
21 | /**
22 | * onStart method
23 | *
24 | * @param testContext
25 | */
26 | @Override
27 | public void onStart(ITestContext testContext) {
28 | super.onStart(testContext);
29 | }
30 |
31 | /**
32 | * onFinish method
33 | *
34 | * @param testContext
35 | */
36 | @Override
37 | public void onFinish(ITestContext testContext) {
38 | log("\nTotal Passed = " + getPassedTests().size() + ", Total Failed = " + getFailedTests().size() + ", Total Skipped = " + getSkippedTests().size() + "\n");
39 |
40 | super.onFinish(testContext);
41 | }
42 |
43 | /**
44 | * onTestStart method
45 | *
46 | * @param tr
47 | */
48 | @Override
49 | public void onTestStart(ITestResult tr) {
50 | if ( logFile == null ) {
51 | logFile = Global_VARS.LOGFILE_PATH + Global_VARS.SUITE_NAME + "-" + new SimpleDateFormat("MM.dd.yy.HH.mm.ss").format(new Date()) + ".log";
52 | }
53 |
54 | log("\n---------------------------------- Test '" + tr.getName() + getTestDescription(tr) + "' ----------------------------------\n");
55 | log(tr.getStartMillis(),"START-> " + tr.getName() + "\n");
56 | log(" ***Test Parameters = " + getTestParams(tr) + "\n");
57 |
58 | super.onTestStart(tr);
59 | }
60 |
61 | /**
62 | * onTestSuccess method
63 | *
64 | * @param tr
65 | */
66 | @Override
67 | public void onTestSuccess(ITestResult tr) {
68 | log(" ***Result = PASSED\n");
69 | log(tr.getEndMillis(),"END -> " + tr.getName());
70 | log("\n---\n");
71 |
72 | super.onTestSuccess(tr);
73 | }
74 |
75 | /**
76 | * onTestFailure method
77 | *
78 | * @param tr
79 | */
80 | @Override
81 | public void onTestFailure(ITestResult tr) {
82 | if ( !getTestMessage(tr).equals("") ) {
83 | log(getTestMessage(tr) + "\n");
84 | }
85 |
86 | log(" ***Result = FAILED\n");
87 | log(tr.getEndMillis(),"END -> " + tr.getInstanceName() + "." + tr.getName());
88 | log("\n---\n");
89 |
90 | super.onTestFailure(tr);
91 | }
92 |
93 | /**
94 | * onTestSkipped method
95 | *
96 | * @param tr
97 | */
98 | @Override
99 | public void onTestSkipped(ITestResult tr) {
100 | if ( !getTestMessage(tr).equals("") ) {
101 | log(getTestMessage(tr) + "\n");
102 | }
103 |
104 | log(" ***Result = SKIPPED\n");
105 | log(tr.getEndMillis(),"END -> " + tr.getInstanceName() + "." + tr.getName());
106 | log("\n---\n");
107 |
108 | super.onTestSkipped(tr);
109 | }
110 |
111 | /**
112 | * onConfigurationSuccess method
113 | *
114 | * @param itr
115 | */
116 | @Override
117 | public void onConfigurationSuccess(ITestResult itr) {
118 | super.onConfigurationSuccess(itr);
119 | }
120 |
121 | /**
122 | * onConfigurationFailure method
123 | *
124 | * @param tr
125 | */
126 | @Override
127 | public void onConfigurationFailure(ITestResult tr) {
128 | if ( !getTestMessage(tr).equals("") ) {
129 | log(getTestMessage(tr) + "\n");
130 | }
131 |
132 | log(" ***Result = CONFIGURATION FAILED\n");
133 | log(tr.getEndMillis(),"END CONFIG -> " + tr.getInstanceName() + "." + tr.getName());
134 | log("\n---\n");
135 |
136 | super.onConfigurationFailure(tr);
137 | }
138 |
139 | /**
140 | * onConfigurationSkip method
141 | *
142 | * @param tr
143 | */
144 | @Override
145 | public void onConfigurationSkip(ITestResult tr) {
146 | log(getTestMessage(tr));
147 | log(" ***Result = CONFIGURATION SKIPPED\n");
148 | log(tr.getEndMillis(),"END CONFIG -> " + tr.getInstanceName() + "." + tr.getName());
149 | log("\n---\n");
150 |
151 | super.onConfigurationSkip(tr);
152 | }
153 |
154 | /**
155 | * log method
156 | *
157 | * @param dateMillis
158 | * @param line
159 | */
160 | public void log(long dateMillis,String line) {
161 | System.out.format("%s: %s%n",String.valueOf(new Date(dateMillis)),line);
162 |
163 | if ( logFile != null ) {
164 | writeTestngLog(logFile, line);
165 | }
166 | }
167 |
168 | /**
169 | * log method
170 | *
171 | * @param line
172 | */
173 | public void log(String line) {
174 | System.out.format("%s%n", line);
175 |
176 | if ( logFile != null ) {
177 | writeTestngLog(logFile, line);
178 | }
179 | }
180 |
181 | /**
182 | * getTestMessage method
183 | *
184 | * @param tr
185 | * @return String
186 | */
187 | public String getTestMessage(ITestResult tr) {
188 | Boolean found = false;
189 |
190 | if ( tr != null && tr.getThrowable() != null ) {
191 | found = true;
192 | }
193 |
194 | if ( found == true ) {
195 | return tr.getThrowable().getMessage() == null ? "" : tr.getThrowable().getMessage();
196 | }
197 |
198 | else {
199 | return "";
200 | }
201 | }
202 |
203 | /**
204 | * getTestParams method
205 | *
206 | * @param tr
207 | * @return String
208 | */
209 | public String getTestParams(ITestResult tr) {
210 | int iLength = tr.getParameters().length;
211 | String message = "";
212 |
213 | try {
214 | if ( tr.getParameters().length > 0 ) {
215 | message = tr.getParameters()[0].toString();
216 |
217 | for ( int iCount = 0; iCount < iLength; iCount++ ) {
218 | if ( iCount == 0 ) {
219 | message = tr.getParameters()[0].toString();
220 | }
221 | else {
222 | message = message + ", " + tr.getParameters()[iCount].toString();
223 | }
224 | }
225 | }
226 | }
227 |
228 | catch(Exception e) {
229 | // do nothing...
230 | }
231 |
232 | return message;
233 | }
234 |
235 | /**
236 | * getTestDescription method
237 | *
238 | * @param tr
239 | * @return String
240 | */
241 | public String getTestDescription(ITestResult tr) {
242 | String message = "";
243 |
244 | try {
245 | if ( tr.getParameters().length > 0 ) {
246 | message = ": " + tr.getParameters()[1].toString();
247 | }
248 | }
249 |
250 | catch(Exception e) {
251 | // do nothing...
252 | }
253 |
254 | return message;
255 | }
256 |
257 | /**
258 | * writeTestngLog method
259 | *
260 | * @param logFile
261 | * @param line
262 | */
263 | public void writeTestngLog(String logFile,String line) {
264 | DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
265 | Date date = new Date();
266 | File directory = new File(Global_VARS.LOGFILE_PATH);
267 | File file = new File(logFile);
268 |
269 | try {
270 | if ( !directory.exists() ) {
271 | directory.mkdirs();
272 | }
273 |
274 | else if ( !file.exists() ) {
275 | file.createNewFile();
276 | }
277 |
278 | BufferedWriter writer = new BufferedWriter(new FileWriter(logFile, true));
279 |
280 | if ( line.contains("START") || line.contains("END") ) {
281 | writer.append("[" + dateFormat.format(date) + "] " + line);
282 |
283 | }
284 |
285 | else {
286 | writer.append(line);
287 | }
288 |
289 | writer.newLine();
290 | writer.close();
291 | }
292 |
293 | catch(IOException e) {
294 | // do nothing...
295 | }
296 | }
297 |
298 | }
299 |
300 |
--------------------------------------------------------------------------------
/Chapter18/extent-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | standard
7 |
8 |
9 |
10 | UTF-8
11 |
12 |
13 |
14 | https
15 |
16 |
17 |
18 |
19 |
20 |
21 |
23 |
24 |
25 |
26 |
27 | bottom
28 |
29 |
30 |
31 |
32 |
33 |
34 | MM-dd-yyyy
35 |
36 |
37 |
38 | HH:mm:ss
39 |
40 |
41 |
42 |
47 |
48 |
49 |
50 |
51 | i:nth-child(1) { color: #1e90ff; }
67 | .category-content .category-status-counts:nth-child(3) { background-color: #1e90ff; }
68 | .yellow.darken-2 { background-color: #1e90ff !important; }
69 | ]]>
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/Chapter18/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 | org.seleniumhq.selenium
4 | selenium-java
5 | 3.7.1
6 | selenium-java
7 |
8 | Selenium automates browsers. That's it! What you do with that power is entirely up to you.
9 |
10 | http://www.seleniumhq.org/
11 |
12 |
13 | The Apache Software License, Version 2.0
14 | http://www.apache.org/licenses/LICENSE-2.0.txt
15 | repo
16 |
17 |
18 |
19 | scm:git:git@github.com:SeleniumHQ/selenium.git
20 | scm:git:git@github.com:SeleniumHQ/selenium.git
21 | https://github.com/SeleniumHQ/selenium/
22 |
23 |
24 |
25 | org.seleniumhq.selenium
26 | selenium-api
27 | 3.7.1
28 |
29 |
30 |
31 | org.seleniumhq.selenium
32 | selenium-chrome-driver
33 | 3.7.1
34 |
35 |
36 |
37 | org.seleniumhq.selenium
38 | selenium-edge-driver
39 | 3.7.1
40 |
41 |
42 |
43 | org.seleniumhq.selenium
44 | selenium-firefox-driver
45 | 3.7.1
46 |
47 |
48 |
49 | org.seleniumhq.selenium
50 | selenium-ie-driver
51 | 3.7.1
52 |
53 |
54 |
55 | org.seleniumhq.selenium
56 | selenium-opera-driver
57 | 3.7.1
58 |
59 |
60 |
61 | org.seleniumhq.selenium
62 | selenium-remote-driver
63 | 3.7.1
64 |
65 |
66 |
67 | org.seleniumhq.selenium
68 | selenium-safari-driver
69 | 3.7.1
70 |
71 |
72 |
73 | org.seleniumhq.selenium
74 | selenium-support
75 | 3.7.1
76 |
77 |
78 |
79 | net.bytebuddy
80 | byte-buddy
81 | 1.7.5
82 |
83 |
84 |
85 | org.apache.commons
86 | commons-exec
87 | 1.3
88 |
89 |
90 |
91 | commons-codec
92 | commons-codec
93 | 1.10
94 |
95 |
96 |
97 | commons-logging
98 | commons-logging
99 | 1.2
100 |
101 |
102 |
103 | com.google.code.gson
104 | gson
105 | 2.8.2
106 |
107 |
108 |
109 | com.google.guava
110 | guava
111 | 23.0
112 |
113 |
114 |
115 | org.apache.httpcomponents
116 | httpclient
117 | 4.5.3
118 |
119 |
120 |
121 | org.apache.httpcomponents
122 | httpcore
123 | 4.4.6
124 |
125 |
126 |
127 | net.java.dev.jna
128 | jna
129 | 4.1.0
130 |
131 |
132 |
133 | net.java.dev.jna
134 | jna-platform
135 | 4.1.0
136 |
137 |
138 |
139 | org.testng
140 | testng
141 | 6.11
142 | test
143 |
144 |
145 | io.appium
146 | java-client
147 | 5.0.4
148 |
149 |
150 |
151 | javax.mail
152 | mail
153 | 1.4.7
154 |
155 |
156 |
157 | commons-io
158 | commons-io
159 | 2.5
160 |
161 |
162 |
163 | com.googlecode.json-simple
164 | json-simple
165 | 1.1.1
166 |
167 |
168 |
169 | com.aventstack
170 | extentreports
171 | 3.1.0
172 | provided
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
--------------------------------------------------------------------------------
/Chapter18/selenium.properties:
--------------------------------------------------------------------------------
1 | # Selenium Properties File
2 |
3 | selenium.revision=3.7.1
4 | geckodriver.revision=0.19.1
5 | chromedriver.revision=2.33
6 | iedriver.revision=11.0
7 |
8 | firefox.revision=57.0
9 | chrome.revision=62.0
10 | ie.revision=11.0
11 |
12 | gecko.driver.windows.path=drivers/geckodriver.exe
13 | chrome.driver.windows.path=drivers/chromedriver.exe
14 | ie.driver.windows.path=drivers/IEDriverServer.exe
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Packt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # Learn-Selenium
5 | The Selenium WebDriver 3.x is an open source API to test both browser and mobile applications. With a solid foundation, you can easily perform end-to-end testing on web and mobile browsers.
6 |
7 | You’ll begin by getting introduced to the Selenium page object design patterns in software development. You’ll architect your own framework with a scalable driver class, Java utility classes, and support for third-party tools and plugins. You'll design and build a Selenium grid from scratch to enable the framework to scale and support different browsers, mobile devices, and platforms. You’ll strategize and handle rich web UI using the advanced WebDriver API and learn techniques to handle real-time challenges in WebDriver. You’ll perform different types of testing, such as cross-browser testing, load testing, and mobile testing. Finally, you will also be introduced to data-driven testing using TestNG to create your own automation framework.
8 |
9 | By the end of this Learning Path, you’ll be able to design your own automation testing framework and perform data-driven testing with Selenium WebDriver.
10 |
11 | This Learning Path includes content from the following Packt products:
12 | Selenium WebDriver 3 Practical Guide - Second Edition by Unmesh Gundecha
13 | Selenium Framework Design in Data-Driven Testing by Carl Cocchiaro
14 |
15 | #What you'll learn
16 |
17 | Use different mobile and desktop browser platforms with Selenium 3
18 | Use the Actions API for performing various keyboard and mouse actions
19 | Design the Selenium Driver Class for local, remote, and third-party grid support
20 | Build page object classes with the Selenium Page Object Model
21 | Develop data-driven test classes using the TestNG framework
22 | Encapsulate data using the JSON protocol
23 | Build a Selenium Grid for RemoteWebDriver testing
24 | Build and use utility classes in synchronization, file I/O, reporting and test listener classes
25 |
26 | #Software Requirements
27 |
28 | Java JDK 1.8
29 | IntelliJ IDEA 2017.3+
30 | Selenium WebDriver 3.7.1+ JAR
31 | Selenium Stand-alone Server 3.7.1+ JAR
32 | Appium Java Client 5.0.4+ JAR
33 | Appium Server 1.7.1 JAR for iOS or Linux
34 | TestNG 6.11 JAR
35 | ExtentReports 3.1.0 JAR
36 | Browsers: Google Chrome 62.0, Mozilla Firefox 57.0, Microsoft Internet Explorer 11.0
37 | Drivers: chromedriver.exe 2.33, geckodriver.exe 0.19.1, IEDriverServer.exe 3.7.1+
38 | Apple Xcode and iPhone Simulators for iOS
39 | Google Android SDK and Samsung Galaxy emulators for Linux
40 | VMware virtual machines
41 |
42 |
43 | ### Download a free PDF
44 |
45 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
46 | https://packt.link/free-ebook/9781838983048
--------------------------------------------------------------------------------