├── .gitignore
├── .gitpod.yml
├── .idea
└── .gitignore
├── LICENSE
├── README.md
├── graphics
├── EyalAvatar.png
├── NikolayAndMia.JPG
├── best-practices-java.jpeg
├── chris.jpg
└── large_Sauce_Bkpk_2021.png
└── workshop
├── docs
├── ATOMIC-TESTS.MD
├── CONCLUSIONS.MD
├── E2E-TESTS.MD
├── PARALLEL.MD
├── TEST-STRATEGY.MD
└── VISUAL.MD
├── images
├── run-time.jpg
└── run-time2.jpg
├── pom.xml
└── src
└── test
└── java
└── com
└── saucedemo
├── exercises
├── E2ETests.java
├── SanityTest.java
├── VisualDataDrivenTests.java
└── VisualTests.java
└── solution
├── AbstractTestBase.java
├── E2ESolutionTests.java
├── VisualDataDrivenSolutionTests.java
├── VisualSolutionTests.java
└── pages
├── AbstractBasePage.java
├── CheckoutCompletePage.java
├── CheckoutOverviewPage.java
├── CheckoutStepOnePage.java
├── LoginPage.java
├── ProductsPage.java
└── ShoppingCartPage.java
/.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 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 |
25 | *.idea
26 | target
27 | /workshop/workshop.iml
28 |
--------------------------------------------------------------------------------
/.gitpod.yml:
--------------------------------------------------------------------------------
1 | tasks:
2 | - before: |
3 | cd workshop
4 | init: |
5 | mvn clean install -DskipTests=true
6 | clear
7 | command: echo 'Ready to test!'
8 |
9 | vscode:
10 | extensions:
11 | - vscjava.vscode-java-test
12 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saucelabs-training/automation-best-practices-java/e8ab9d344e284f9ddc3920ab224c704e096b2f24/.idea/.gitignore
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 saucelabs-training
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 | # Automation best practices w/ Java workshop
2 |
3 |
4 |
5 | [#testing4good](https://twitter.com/hashtag/Testing4Good)
6 |
7 | In this automation best practices workshop you will learn the latest and greatest tools and techniques to drastically improve your testing!
8 |
9 | We will focus on a holistic approach of risk mitigation by doing:
10 |
11 | * functional web testing,
12 | * visual testing,
13 | * accessibility testing,
14 | * and many other things in between 😁
15 |
16 | [👉**Register for workshop**](https://info.saucelabs.com/testing-for-good-workshop-java-113021.html)
17 |
18 | [Join Slack](https://join.slack.com/t/testingforgood/shared_invite/zt-zc64x3pc-9ebUXVeXW1fB0JxU1R_9ew)
19 |
20 | **This workshop serves 2 purposes**
21 |
22 | 1. For me to give back to the testing world and help us all upskill 🚀
23 | 2. For us all to help a greater cause than ourselves 🌍
24 |
25 | ### [ABOUT CHARITY](https://code.org/)
26 |
27 | Code.org® is a nonprofit dedicated to expanding access to computer science in schools and increasing participation by young women and students from other underrepresented groups. Their vision is that every student in every school has the opportunity to learn computer science as part of their core K-12 education. The leading provider of K-12 computer science curriculum in the largest school districts in the United States, Code.org also created the annual Hour of Code campaign, which has engaged more than 15% of all students in the world.
28 |
29 | **Working together, we can reduce the digital divide!**
30 |
31 | With the Testing for Good event, we're helping to give every student the opportunity to learn computer science — online and in schools where Code.org will establish permanent courses and train teachers. For every dollar you donate, one child will be introduced to computer science.
32 |
33 | To make your donations go even further, Sauce Labs will match up to $2,500.
34 |
35 | 👇👇👇
36 |
37 | [Please donate whatever you feel appropriate.](https://www.gofundme.com/f/testing-for-good-codeorg) 100% of the donations go to the cause.
38 |
39 | ## 🧠You will learn to
40 |
41 | * Create a framework for doing comprehensive web testing
42 | * Use industry-standard best practices
43 | * Create functional browser tests using Selenium
44 | * Code visual e2e tests using Screener
45 | * Run in massive parallel (100s of tests in < 5 min)
46 | * Automatically get robust test reports with logs + videos
47 |
48 | ## 🔧Technologies you will use
49 |
50 | 1. Sauce Labs
51 | 2. Selenium
52 | 3. Sauce Visual
53 | 4. Github Actions
54 | 5. Java
55 | 6. Maven
56 |
57 | ## Table Of Contents
58 |
59 | * Introduction to workshop
60 | * [Local environment setup](#local-environment-setup)
61 | * [If you can't setup local, then use Gitpod](#gitpod-setup)
62 | * [E2E browser tests](./workshop/docs/E2E-TESTS.MD)
63 | * [Atomic tests](./workshop/docs/ATOMIC-TESTS.MD)
64 | * [Visual e2e tests](./workshop/docs/VISUAL.MD)
65 | * [Parallelization](./workshop/docs/PARALLEL.MD)
66 | * [Conclusions](./workshop/docs/CONCLUSIONS.MD)
67 |
68 |
69 | ## Requirements
70 |
71 | **This is NOT a beginners course and you will not learn Java testing fundamentals here. However, you will learn a number of amazing skills, techniques, and tools to help you test web applications**
72 |
73 | * At least 1 year of Java programming
74 | * Deep understanding of Selenium WebDriver
75 | * Deep understanding of OOP
76 | * Java 8 installed
77 | * Java IDE installed
78 | * [Git](https://git-scm.com/downloads)
79 | * [Maven installed](https://maven.apache.org/install.html)
80 |
81 |
82 |
83 | ## Your Instructor: Nikolay Advolodkin
84 |
85 |
86 |
87 | - 🔭 I’m the founder of [Ultimate QA](https://ultimateqa.com/)
88 | - 🏢 I’m a Sr Solutions Architect at Sauce Labs
89 | - 🌱 I’m currently working on [Sauce Bindings](https://github.com/saucelabs/sauce_bindings)
90 | - 💬 Ask me about environmentalism, veganism, test automation, and fitness
91 | - 😄 Pronouns: he/him
92 | - ⚡ Fun fact: I'm a vegan that's super pasionate about saving the planet, saving animals, and helping underpriveleged communities
93 | - 📫 Follow me for testing and dev training
94 | - [Java Testing Newsletter](https://ultimateqa.ck.page/selenium-java-tips
95 | )
96 | - [Youtube](https://youtube.com/ultimateqa)
97 | - [LinkedIn](https://www.linkedin.com/in/nikolayadvolodkin/)
98 | - [Twitter](https://twitter.com/intent/follow?screen_name=nikolay_a00®ion=follow_link)
99 |
100 | ## Your TAs
101 |
102 | ### Eyal Yovel
103 |
104 |
105 |
106 | ### Chris Eccleston
107 |
108 |
109 |
110 | [💻Join Slack #help-desk for tech support](https://join.slack.com/t/testingforgood/shared_invite/zt-zc64x3pc-9ebUXVeXW1fB0JxU1R_9ew)
111 |
112 | ## Setup
113 |
114 | ### Sign up for account
115 |
116 | 1. Free [Sauce account](https://saucelabs.com/sign-up)
117 | 2. Request [Demo Secreener account](https://saucelabs.com/demo-request-vt). **!You must request this at least a week before the workshop as it's a manual process to add users.**
118 |
119 | ### Get your username and api key
120 |
121 | 1. Save your Sauce Labs Username and Access Key by going to the [Sauce Labs user settings page](https://app.saucelabs.com/user-settings)
122 | 2. Save your Screener API Key by going to the [API key](https://screener.io/v2/account/api-key) page in your Screener settings
123 | 1. Need to sign up for [demo account before](https://saucelabs.com/demo-request-vt)
124 |
125 |
126 | ### Local environment setup
127 |
128 | [💻Join Slack #help-desk for tech support](https://join.slack.com/t/testingforgood/shared_invite/zt-zc64x3pc-9ebUXVeXW1fB0JxU1R_9ew)
129 |
130 | Fork then clone the repo
131 |
132 | 1. Sign up for a free [GitHub account](https://github.com/)
133 | 2. [Fork this repository](https://docs.github.com/en/get-started/quickstart/fork-a-repo)
134 | * Make sure you are logged into GitHub
135 | * Click the Fork in the upper right of the GitHub.
136 | 3. Clone your fork of the repository to your machine. Must have [Git installed](https://git-scm.com/downloads)
137 |
138 | ```bash
139 | git clone URL_OF_YOUR_FORK
140 | ```
141 |
142 | Setup environment variables on your system
143 | * [Mac/Linux](https://docs.saucelabs.com/basics/environment-variables/#setting-up-environment-variables-on-macos-and-linux-systems)
144 | * [Windows](https://docs.saucelabs.com/basics/environment-variables/#setting-up-environment-variables-on-windows-systems)
145 |
146 | Navigate to the directory of where you cloned your repo
147 |
148 | `cd YOUR_FORK_DIR/automation-best-practices/workshop`
149 |
150 | Run sanity tests
151 |
152 | ```java
153 | mvn test -Dtest=SanityTest -X
154 | ```
155 |
156 |
157 |
158 |
159 | Click here to see an example console output.
160 |
161 |
162 |
163 | Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 54.305 sec
164 |
165 | Results :
166 |
167 | Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
168 |
169 | [INFO] ------------------------------------------------------------------------
170 | [INFO] BUILD SUCCESS
171 | [INFO] ------------------------------------------------------------------------
172 | [INFO] Total time: 56.063 s
173 | [INFO] Finished at: 2021-11-03T16:03:20-04:00
174 | [INFO] ------------------------------------------------------------------------
175 |
176 |
177 |
178 |
179 |
180 |
181 | ### ✅👏Environment setup is complete if tests passed
182 |
183 | > If you weren't successful at setting up you local env, then use the [Gitpod approach](#gitpod-setup)👇
184 |
185 | ### Add static code analysis
186 |
187 | :information_source: Optional Bonus
188 |
189 | * Follow [Codacy instructions to setup static code analysis for your first repo](https://docs.codacy.com/getting-started/codacy-quickstart/)
190 | * Adding and analyzing takes a bit
191 | * [Configure code patterns for the repo](https://docs.codacy.com/repositories-configure/configuring-code-patterns/#pattern-filters)
192 |
193 | ---
194 |
195 | ### Gitpod setup
196 |
197 | [💻Join Slack #help-desk for tech support](https://join.slack.com/t/testingforgood/shared_invite/zt-zc64x3pc-9ebUXVeXW1fB0JxU1R_9ew)
198 |
199 |
200 | :information_source: Gitpod lets you run an entire Dev environment from a browser! You can use this approach if you don't know how to setup a local Java environment.
201 |
202 | 1. Sign up for a free [GitHub account](https://github.com/)
203 | 2. Fork this repository
204 | * Make sure you are logged into GitHub
205 | * Click the fork in the upper right of GitHub
206 | * Select your username as the location to fork the repo
207 | 3. In the browser address bar, prepend the GitHub url (`https://github.com/USERNAME/automation-best-practices-java`) with `https://gitpod.io/#`
208 | * The resulting url should look as follows:
209 |
210 | > https://gitpod.io/#https://github.com/USERNAME/automation-best-practices-java
211 |
212 | 4. Once the Gitpod.io URL is loaded, you will need to sign in with the GitHub account you created earlier
213 | 5. Once the development environment is loaded, you should see 'Ready to test!' in the Terminal window in the lower portion of the window, run the following commands in that Terminal to set your `SAUCE_USERNAME`, `SAUCE_ACCESS_KEY`, and `SCREENER_API_KEY`:
214 |
215 | :information_source: You can get your Sauce Labs Username and Access Key by going to the [Sauce Labs user settings page](https://app.saucelabs.com/user-settings)
216 |
217 | :information_source: You can get your Screener API Key by going to the [API key](https://screener.io/v2/account/api-key) page in your Screener settings
218 |
219 | ```bash
220 | eval $(gp env -e SAUCE_USERNAME=)
221 | eval $(gp env -e SAUCE_ACCESS_KEY=)
222 | eval $(gp env -e SCREENER_API_KEY=)
223 | ```
224 |
225 | > Replace , , and with your credentials
226 |
227 | Once you have run those 3 commands, you can run the following commands to test your environment variables:
228 |
229 | ```bash
230 | echo $SAUCE_USERNAME
231 | echo $SAUCE_ACCESS_KEY
232 | echo $SCREENER_API_KEY
233 | ```
234 |
235 | Run sanity tests
236 |
237 | ```bash
238 | mvn test -Dtest=SanityTest -X
239 | ```
240 |
241 |
242 |
243 |
244 | Click here to see an example console output.
245 |
246 |
247 |
248 | Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 54.305 sec
249 |
250 | Results :
251 |
252 | Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
253 |
254 | [INFO] ------------------------------------------------------------------------
255 | [INFO] BUILD SUCCESS
256 | [INFO] ------------------------------------------------------------------------
257 | [INFO] Total time: 56.063 s
258 | [INFO] Finished at: 2021-11-03T16:03:20-04:00
259 | [INFO] ------------------------------------------------------------------------
260 |
261 |
262 |
263 |
264 |
265 |
266 | ### ✅👏Environment setup is complete if tests passed
267 |
268 | ## Stay to the end and win a prize!
269 |
270 | Stay to the end and 2 lucky people can win a snazzy Back Pack!
271 |
272 |
273 |
274 | ## Key
275 |
276 | 💡 this is a tip
277 |
278 | 🏋️♀️ this is an exercise for you to do
279 |
280 | ❓ this is a question for us to think and talk about. Try not to scroll beyond this question before we discuss
281 |
282 |
283 |
--------------------------------------------------------------------------------
/graphics/EyalAvatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saucelabs-training/automation-best-practices-java/e8ab9d344e284f9ddc3920ab224c704e096b2f24/graphics/EyalAvatar.png
--------------------------------------------------------------------------------
/graphics/NikolayAndMia.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saucelabs-training/automation-best-practices-java/e8ab9d344e284f9ddc3920ab224c704e096b2f24/graphics/NikolayAndMia.JPG
--------------------------------------------------------------------------------
/graphics/best-practices-java.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saucelabs-training/automation-best-practices-java/e8ab9d344e284f9ddc3920ab224c704e096b2f24/graphics/best-practices-java.jpeg
--------------------------------------------------------------------------------
/graphics/chris.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saucelabs-training/automation-best-practices-java/e8ab9d344e284f9ddc3920ab224c704e096b2f24/graphics/chris.jpg
--------------------------------------------------------------------------------
/graphics/large_Sauce_Bkpk_2021.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saucelabs-training/automation-best-practices-java/e8ab9d344e284f9ddc3920ab224c704e096b2f24/graphics/large_Sauce_Bkpk_2021.png
--------------------------------------------------------------------------------
/workshop/docs/ATOMIC-TESTS.MD:
--------------------------------------------------------------------------------
1 | # Automated Atomic Tests
2 |
3 |
4 |
5 | No, not the best tests that we can code
6 |
7 | An **automated atomic test (AAT)** is one that tests only a single feature or component. An AAT should form a single irreducible unit. An automated test should not do something like end-to-end automation.
8 |
9 | We can usually tell that a test is atomic when:
10 |
11 | * The test will only have one assertion or two assertions at most. Because sometimes we need one assertion to make sure our state is correct
12 | * Atomic tests have very few UI interactions and they’re only on a maximum of two screens. In rare cases, an atomic test might navigate through 3 screens (although I’d like to see this example)
13 |
14 | ## Advantages of atomic tests
15 | 1. Atomic tests fail fast
16 | 2. Atomic tests decrease flaky behavior
17 | 3. Atomic checks allow for focused testing
18 | 4. Atomic tests are short and fast
19 |
20 | As an aside, this concept is already well understood in unit and integration tests, but UI tests continue to lag behind.
21 |
22 | [Read more](https://ultimateqa.com/automated-atomic-tests/)
23 |
24 | ## The steps to creating atomic tests
25 |
26 | 1. Find the functionality that you want to test
27 | 2. Isolate/Mock/Fake all irrelevant actions
28 | 3. Test the relevant feature through UI
29 |
30 | ## 👀How does our app work under the hood?
31 |
32 | Let's take a look at how a login and cart functionality works at the code level
33 |
34 | ## Let's make our tests atomic
35 |
36 | 1. 🏋️♀️Go to E2ETests.java and follow instructions in `userCanCheckoutAtomic()` to create an atomic test that validates checkout logic
37 | 2. Don't forget to run the test until it passes
38 |
39 | ---
40 |
41 | ### ❓Questions or concerns about this process
42 |
43 | ---
44 |
45 | [🧪Let's review test coverage](TEST-STRATEGY.MD)
46 |
47 | ## ⏭️Next, we will use visual tests to:
48 |
49 | * Massively increase browser coverage
50 | * Drastically decrease the code we need to maintain
51 | * Drastically increase test suite stability
52 |
53 | [Visual testing](VISUAL.MD)
54 |
--------------------------------------------------------------------------------
/workshop/docs/CONCLUSIONS.MD:
--------------------------------------------------------------------------------
1 | # before you go!
2 |
3 |
4 |
5 | 1. If you enjoyed this free workshop, please pay it forward and [donate whatever you feel appropriate.](https://www.gofundme.com/f/testing-for-good-codeorg)
6 |
7 | > 100% of the donations go to help kids learn computer science.
8 |
9 | 2. 📫 Follow me to stay up to date on the next Testing for Good workshop!
10 |
11 | - [Java Testing Newsletter](https://ultimateqa.ck.page/selenium-java-tips)
12 | - [Youtube](https://youtube.com/ultimateqa)
13 | - [LinkedIn](https://www.linkedin.com/in/nikolayadvolodkin/)
14 | - [Twitter](https://twitter.com/Nikolay_A00)
15 |
16 | 3. Please give me [anonymous feedback on the workshop](https://forms.gle/UT1SVtuZDq84XWFR7)
17 | 4. 💃Let's pick 2 winners for backpacks!
18 |
19 |
20 |
21 |
22 | ## Thanks so much for your time and generosity 🙌👏
23 |
24 |
25 |
26 |
27 | ## Extra resources
28 |
29 | * [Complete Selenium WebDriver Java Bootcamp](https://ultimateqa.com/selenium-java)
30 | * [Parallelization with Junit4,Junit5,TestNg](https://youtu.be/ufccoaURMIc)
31 | * [21+ Automation best practices](https://ultimateqa.com/automation-patterns-antipatterns/)
32 |
33 |
--------------------------------------------------------------------------------
/workshop/docs/E2E-TESTS.MD:
--------------------------------------------------------------------------------
1 | # E2E Tests
2 |
3 | ## Review test strategy
4 |
5 | [Let's review our testing gaps](TEST-STRATEGY.MD)
6 |
7 | ## Covering business risk
8 |
9 | We can use **functional e2e UI** tests to cover some of the risks
10 |
11 | ## 🏋️♀️Write tests using best practices
12 |
13 | 1. Go to `com.saucedemo.exercises.E2ETests.java` and finish all of the tests.
14 | 2. Run each test to make sure they work
15 | 3. At the end, run all tests with `mvn test -Dtest=E2ETests`
16 |
17 |
18 | **Rules**
19 |
20 | ✅ Use page objects
21 |
22 | ✅ One test for one feature
23 |
24 | ❌ Don't create any new code, simply reuse existing code
25 |
26 | ### ️👀How does this work?
27 |
28 | Let's walk through the code
29 |
30 | [🧪Let's review test coverage](TEST-STRATEGY.MD)
31 |
32 | ---
33 |
34 | ## ❓Are these the best tests that we can write
35 |
36 | ---
37 |
38 | [👉Answer in the next section](ATOMIC-TESTS.MD)
39 |
--------------------------------------------------------------------------------
/workshop/docs/PARALLEL.MD:
--------------------------------------------------------------------------------
1 | # Parallel Execution
2 |
3 |
4 |
5 |
6 | ## 🧠You will learn
7 |
8 | ✅ How to create ridiculously fast test suites
9 |
10 | ✅ How to implement parallelization
11 |
12 | ## In today's world, it's improbable to succeed without parallelization
13 |
14 | > "Once you have these automated tests, our analysis shows it’s important to run them regularly. Every commit should trigger a build of the software and running a set of fast, automated tests. Developers should get feedback from a more comprehensive suite of acceptance and performance tests every day. Furthermore, current builds should be available to testers for exploratory testing." (Nicole Forsgren PhD, Jez Humble, Gene Kim, Accelerate: The Science of Lean Software and DevOps: Building and Scaling High Performing Technology Organizations)
15 |
16 | Try to run the current suite of tests:
17 |
18 | ```text
19 | mvn test -Dtest="E2ESolutionTests,VisualDataDrivenSolutionTests"
20 | ```
21 |
22 | This is how long my tests took
23 |
24 |
25 |
26 | 241 sec/8 tests = 30 sec/test
27 |
28 | ---
29 |
30 | ### ❓What's the problem with this approach?
31 |
32 | ---
33 |
34 | ## 🏋️♀Implement parallelization
35 |
36 | 1. Go to `pom.xml` and add the following at the same level as the `` node
37 |
38 | ```xml
39 |
40 |
41 |
42 | org.apache.maven.plugins
43 | maven-surefire-plugin
44 | 3.0.0-M5
45 |
46 | all
47 | 100
48 | true
49 | false
50 |
51 |
52 |
53 |
54 | ```
55 |
56 | 2. In terminal run
57 |
58 | ```text
59 | mvn test -Dtest="E2ESolutionTests,VisualDataDrivenSolutionTests"
60 | ```
61 |
62 | 3. Login to saucelabs.com and watch tests run in parallel
63 |
64 | My results
65 |
66 |
67 |
68 | ## What we just achieved ✅💪
69 |
70 | ✅ 78% speed improvement in < 5 min
71 |
72 | ✅ 0 degradation to our test quality
73 |
74 | ✅ Enabled parallel scaling
75 |
76 | ## 📝Summary
77 |
78 | ✅ Parallel testing is awesome
79 |
80 | ## Extra resources
81 |
82 | [Achieving 97% test suite run time improvement](https://devops.com/4-steps-to-achieve-a-66-reduction-in-test-run-time/)
83 |
84 | ## [⏭️Let's summarize](CONCLUSIONS.MD)
85 |
--------------------------------------------------------------------------------
/workshop/docs/TEST-STRATEGY.MD:
--------------------------------------------------------------------------------
1 | ## 🧪Our Testing Strategy
2 |
3 | | Expected Behavior | Tested? | Test Type | Technologies/Comments |
4 | |---|---|---|---|
5 | | Login page renders | ✅ | visual e2e | Selenium, Sauce Labs, Screener, |
6 | | Valid user can login | ✅ | ui/e2e/functional | Selenium, Sauce Labs |
7 | | User can checkout with a product | ✅ | ui/e2e/functional | Selenium, Sauce Labs, Cookie injection, and JS injection |
8 | | Login page looks as expected on Chrome on most popular resolution | ✅ | visual e2e | Screener, Sauce, Selenium |
9 | | Products page looks as expected on Chrome on most popular resolution | ✅ | visual e2e | Screener, Sauce, Selenium |
10 | | Cart page looks as expected on Chrome on most popular resolution | ✅ | visual e2e | Screener, Sauce, Selenium |
11 | | Login page looks as expected on Safari on most popular resolution | ✅ | visual e2e | Screener, Sauce, Selenium |
12 | | Products page looks as expected on Safari on most popular resolution | ✅ | visual e2e | Screener, Sauce, Selenium |
13 | | Cart page looks as expected on Safari on most popular resolution | ✅ | visual e2e | Screener, Sauce, Selenium |
14 | | App is accessibility friendly | 🙅♂️ | | |
15 | | Front-end performance is at least a B | 🙅♂️ | | |
16 | | App is secure | 🙅♂️ | | |
17 | | Multiple other testing types... | 🙅♂️ | | |
18 |
--------------------------------------------------------------------------------
/workshop/docs/VISUAL.MD:
--------------------------------------------------------------------------------
1 | # Visual Testing
2 |
3 |
4 |
5 | ## 🧠You will learn
6 |
7 | ✅ What is visual testing
8 |
9 | ✅ How to implement a visual test
10 |
11 | ## What is visual testing?
12 |
13 | [Quick presentation](https://docs.google.com/presentation/d/13jYXXoKb36aFt1HLnNnAmsPqw9yaFhVrB4iFH_5_WkI/edit#slide=id.gcc181d5a54_0_21)
14 |
15 | [🧪Let's review test coverage](TEST-STRATEGY.MD)
16 |
17 | ## 🏋️♀Implement visual tests
18 |
19 | Go to `VisualTests.java` and follow instructions to implement visual tests
20 |
21 | ---
22 |
23 | ### ❓Questions?
24 |
25 | ---
26 |
27 | ---
28 |
29 | ### ❓How do we do the same thing on Safari?
30 |
31 | ---
32 |
33 | ## 🏋️♀Implement data-driven visual tests
34 |
35 | 1. Go to VisualDataDrivenTests.java and follow instructions. Be sure to read the explanations.
36 | 2. Run data-driven tests use `mvn test -Dtest="VisualData*"`
37 | 3. Check results in Screener.io dashboard
38 |
39 | ## [🧪Let's review test coverage](TEST-STRATEGY.MD)
40 |
41 | ---
42 |
43 | ### ❓Any redundant tests?
44 |
45 | ---
46 |
47 | ## 📝Summary
48 |
49 | ✅Visual e2e testing is a simple and efficient way to test your web app cross-platform
50 |
51 | ✅Visual e2e testing should be part of every web app's test suite
52 |
53 | ## [⏭️ Next, let's make our suite really fast!](PARALLEL.MD)
54 |
--------------------------------------------------------------------------------
/workshop/images/run-time.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saucelabs-training/automation-best-practices-java/e8ab9d344e284f9ddc3920ab224c704e096b2f24/workshop/images/run-time.jpg
--------------------------------------------------------------------------------
/workshop/images/run-time2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saucelabs-training/automation-best-practices-java/e8ab9d344e284f9ddc3920ab224c704e096b2f24/workshop/images/run-time2.jpg
--------------------------------------------------------------------------------
/workshop/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | workshop
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 8
13 | 8
14 |
15 |
16 |
17 |
18 | com.saucelabs
19 | sauce_bindings
20 | 1.2.0
21 | test
22 |
23 |
24 |
25 | org.seleniumhq.selenium
26 | selenium-java
27 | 4.0.0
28 | test
29 |
30 |
31 |
32 | com.saucelabs
33 | saucebindings-junit4
34 | 1.0.1
35 | test
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/workshop/src/test/java/com/saucedemo/exercises/E2ETests.java:
--------------------------------------------------------------------------------
1 | package com.saucedemo.exercises;
2 |
3 | import com.saucedemo.solution.pages.*;
4 | import com.saucelabs.saucebindings.junit4.SauceBaseTest;
5 | import org.junit.Ignore;
6 | import org.junit.Test;
7 | import org.openqa.selenium.By;
8 | import org.openqa.selenium.Cookie;
9 | import org.openqa.selenium.JavascriptExecutor;
10 | import org.openqa.selenium.NoSuchElementException;
11 |
12 | import static org.junit.Assert.assertEquals;
13 | import static org.junit.Assert.assertTrue;
14 |
15 | public class E2ETests extends SauceBaseTest {
16 | // Here's the first test to get you started. Try to run it
17 | @Test()
18 | public void appRenders() {
19 | LoginPage loginPage = new LoginPage(driver);
20 | loginPage.visit();
21 | assertTrue(loginPage.isDisplayed());
22 | }
23 | @Test()
24 | public void loginWorks() {
25 | LoginPage loginPage = new LoginPage(driver);
26 | /*
27 | * Add your code below this
28 | * */
29 |
30 |
31 |
32 | /*
33 | * ^^^^^^^^ AddYour code above this ^^^^^^^^^
34 | * */
35 | assertTrue(new ProductsPage(driver).isDisplayed());
36 | }
37 | @Test()
38 | public void userCanCheckout() {
39 | /*
40 | * Add your code below this
41 | * */
42 |
43 |
44 |
45 | /*
46 | * ^^^^^^^^ AddYour code above this ^^^^^^^^^
47 | * */
48 | assertTrue(new CheckoutCompletePage(driver).isDisplayed());
49 | }
50 |
51 | /*
52 | * Don't do or look at the test below until the atomic tests section
53 | * */
54 | @Test()
55 | @Ignore("Ignoring until atomic tests section")
56 | public void userCanCheckoutAtomic() {
57 | /*
58 | * Add your code below this
59 | * */
60 |
61 | /*
62 | * 1. First navigate to the LoginPage
63 | * */
64 |
65 | /*
66 | * 2. Removing UI Login
67 | * We already know that our user can successfully login with loginWorks()
68 | * hence, we don't need to waste time, web requests, or add flakiness
69 | *
70 | * Uncomment the code below to make this possible
71 | * */
72 | // driver.manage().deleteAllCookies();
73 | // ((JavascriptExecutor)driver).executeScript("localStorage.clear();");
74 | // Cookie loginCookie = new Cookie("session-username", "standard_user");
75 | // //try document.cookie="session-username=standard_user" in browser Console
76 | // driver.manage().addCookie(loginCookie);
77 | //PS. In production code you can Hide this behavior in an App object.
78 | // I put it here only for clarity
79 | //You can create an App.setState(AppState appStateObject)
80 | // or Browser.clearLocalStorage()
81 |
82 | /*
83 | * 3. Add item to cart without UI interactions
84 | *
85 | * We also don't care whether or not clicking a button will add an item to a cart
86 | * We can easily cover this risk with another test
87 | * Hence, let's simulate adding an item to a cart by updating localStorage
88 | *
89 | * Uncomment the code below
90 | * */
91 | // ShoppingCartPage cart = new ShoppingCartPage(driver);
92 | // //this won't be possible if you're not logged in
93 | // cart.visit();
94 | // ((JavascriptExecutor)driver).executeScript("localStorage.setItem(\"cart-contents\", \"[4]\")");
95 | // driver.navigate().refresh();
96 | // //checking that app is in correct state
97 | // assertEquals(1, cart.getItemsCount());
98 |
99 | /*
100 | * 4. Truly test the checkout flow
101 | * All the preconditions have been met
102 | * - User is logged in
103 | * - User has item in a cart
104 | * Does the checkout process work?
105 | *
106 | * Fill in the code, you've done this before
107 | * */
108 |
109 |
110 | /*
111 | * ^^^^^^^^ AddYour code above this ^^^^^^^^^
112 | * */
113 | assertTrue(new CheckoutCompletePage(driver).isDisplayed());
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/workshop/src/test/java/com/saucedemo/exercises/SanityTest.java:
--------------------------------------------------------------------------------
1 | package com.saucedemo.exercises;
2 |
3 | import com.saucelabs.saucebindings.SauceSession;
4 | import org.junit.After;
5 | import org.junit.Test;
6 | import org.openqa.selenium.JavascriptExecutor;
7 | import org.openqa.selenium.MutableCapabilities;
8 | import org.openqa.selenium.remote.CapabilityType;
9 | import org.openqa.selenium.remote.RemoteWebDriver;
10 |
11 | import java.net.MalformedURLException;
12 | import java.net.URL;
13 | import java.util.Map;
14 |
15 | import static org.junit.Assert.assertNotNull;
16 | import static org.junit.Assert.assertNull;
17 |
18 | public class SanityTest {
19 | RemoteWebDriver driver;
20 | @Test
21 | public void functionalWorks() {
22 | driver = new SauceSession().start();
23 | assertNotNull("Register for your free sauce account https://saucelabs.com/sign-up", driver);
24 | }
25 |
26 | @Test
27 | public void visualWorks() throws MalformedURLException {
28 | MutableCapabilities capabilities = new MutableCapabilities();
29 | capabilities.setCapability(CapabilityType.BROWSER_NAME, "chrome");
30 | capabilities.setCapability(CapabilityType.BROWSER_VERSION, "latest");
31 | capabilities.setCapability(CapabilityType.PLATFORM_NAME, "Windows 10");
32 |
33 | MutableCapabilities sauceOptions = new MutableCapabilities();
34 | sauceOptions.setCapability("username", System.getenv("SAUCE_USERNAME"));
35 | sauceOptions.setCapability("accesskey", System.getenv("SAUCE_ACCESS_KEY"));
36 | capabilities.setCapability("sauce:options", sauceOptions);
37 |
38 | MutableCapabilities visualOptions = new MutableCapabilities();
39 | visualOptions.setCapability("apiKey", System.getenv("SCREENER_API_KEY"));
40 | visualOptions.setCapability("projectName", "java-sanity");
41 | visualOptions.setCapability("viewportSize", "1280x1024");
42 | visualOptions.setCapability("failOnNewStates", false);
43 | capabilities.setCapability("sauce:visual", visualOptions);
44 |
45 | URL url = new URL("https://hub.screener.io/wd/hub");
46 | driver = new RemoteWebDriver(url, capabilities);
47 |
48 | driver.get("https://saucedemo.com");
49 |
50 | ((JavascriptExecutor)driver).executeScript("/*@visual.init*/", "Simple visual test");
51 | ((JavascriptExecutor)driver).executeScript("/*@visual.snapshot*/", "Home");
52 | Map response = (Map) ((JavascriptExecutor)driver).executeScript("/*@visual.end*/");
53 | assertNull(response.get("message"));
54 | }
55 |
56 | @After
57 | public void tearDown() {
58 | if(driver != null){
59 | driver.quit();
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/workshop/src/test/java/com/saucedemo/exercises/VisualDataDrivenTests.java:
--------------------------------------------------------------------------------
1 | package com.saucedemo.exercises;
2 |
3 | import com.saucedemo.solution.AbstractTestBase;
4 | import com.saucedemo.solution.pages.LoginPage;
5 | import com.saucedemo.solution.pages.ProductsPage;
6 | import com.saucedemo.solution.pages.ShoppingCartPage;
7 | import org.junit.Before;
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 | import org.junit.runners.Parameterized;
11 | import org.openqa.selenium.MutableCapabilities;
12 | import org.openqa.selenium.remote.CapabilityType;
13 | import org.openqa.selenium.remote.RemoteWebDriver;
14 |
15 | import java.net.URL;
16 | import java.util.Arrays;
17 | import java.util.Collection;
18 | import java.util.Map;
19 |
20 | import static org.junit.Assert.assertNull;
21 |
22 | @RunWith(Parameterized.class)
23 | public class VisualDataDrivenTests extends AbstractTestBase {
24 | //declare a bunch of variables
25 | private RemoteWebDriver driver;
26 |
27 | /*
28 | * Configure our data driven parameters
29 | * Each field gets a @Parameterized.Parameter annotation with an index
30 | * The order of these indices corresponds to the order of the strings
31 | * in the crossBrowserData()
32 | * For example, "chrome" = public String browserName
33 | * Hence, any value in the 0th index position will go into browserName
34 | * */
35 | @Parameterized.Parameter
36 | public String browserName;
37 | @Parameterized.Parameter(1)
38 | public String platform;
39 | @Parameterized.Parameter(2)
40 | public String browserVersion;
41 | @Parameterized.Parameter(3)
42 | public String viewportSize;
43 | // resolutionName is an identifier of the browser resolution
44 | @Parameterized.Parameter(4)
45 | public String resolutionName;
46 |
47 | /*
48 | * This is our collection of data driven values.
49 | * For demonstration purposes the data is hardcoded in the class.
50 | * It can also be read from an external data source.
51 | *
52 | * For each row of data, a new test method will be created.
53 | * In this case, we have 2 rows of data meaning that visualFlow()
54 | * will run 2 times, using the data from each row.
55 | * If we had 10 rows, the visualFlow() would execute 10 times
56 | *
57 | * In visual testing it's very valuable to data-drive a test method
58 | * across many browser/os/resolution combinations as rendering bugs
59 | * are extremely common in responsive web apps.
60 | * However, it's also possible to data drive on something like languages
61 | * if you want to see each page rendered in a corresponding language
62 | * */
63 | @Parameterized.Parameters()
64 | public static Collection