I’ve been challenged to start the #100DayCodeChallenge, and guess what?! Challenge Accepted!! So for the next 100 days, I’ll be sharing my knowledge, learning, and experiences.
Below is my progress from previous days, and I’ll now be updating regularly from today. If you’re up for it, join me on this adventure!
Day 2: Getting Started with Automation Testing: A Journey into Selenium
In the next few weeks, I’ll be sharing insights on using automation tools for testing, starting with Selenium! To follow along, ensure you’re familiar with basic programming concepts, web development, and have Selenium, WebDriver, and a supported browser installed. Get ready to dive into automation!
What is Selenium:
Selenium is an open-source tool for automating web browsers, widely used for testing web applications. It allows developers to simulate user interactions, validate functionality, and ensure web app reliability across different browsers and platforms.
Prerequisites for using Selenium:
Software Required:
Selenium WebDriver: Install Selenium via a package manager:
Python: pip install selenium
Java: Add Selenium dependencies to your pom.xml (for Maven) or build.gradle (for Gradle).
WebDriver Executable: Download the browser-specific driver to automate the chosen browser:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
# Set up the WebDriver (use your appropriate driver like ChromeDriver, GeckoDriver, etc.)
driver = webdriver.Chrome() # Make sure you have installed the appropriate driver
# Navigate to the website
driver.get("https://the-internet.herokuapp.com/login")
# Locate the username and password fields and enter values
username_field = driver.find_element(By.ID, "username")
password_field = driver.find_element(By.ID, "password")
username_field.send_keys("tomsmith") # Valid username
password_field.send_keys("SuperSecretPassword!") # Valid password
# Locate and click the login button
login_button = driver.find_element(By.CSS_SELECTOR, "button.radius")
login_button.click()
# Verify successful login
success_message = driver.find_element(By.CSS_SELECTOR, ".flash.success")
assert "You logged into a secure area!" in success_message.text
print("logged in successfully")
# Close the browser
#driver.quit()
How It Works:
Navigate to the Login Page: The script opens the login page of the website.
Enter Credentials: It fills in the username (tomsmith) and password (SuperSecretPassword!), which are valid test credentials provided by the website.
Click Login: The login button is clicked to submit the form.
Verify Success: It checks if the success message is displayed after login.
I remember feeling proud after submitting a fully functional solution to an assignment I had worked hard to solve in my sophomore year, only to be surprised with disappointing feedback. My professor told me, ‘I don’t care if it works if I have to struggle to understand your spaghetti code.’
That moment stuck with me and taught me a powerful lesson: writing code isn’t just about making it functional—it’s about making it clear, maintainable, and readable.
Functional code solves a problem, but clean code solves it efficiently and allows others (and your future self) to understand and build upon it. Since then, I’ve committed myself to focus on clarity and simplicity, making sure my code reflects these principles:
• Readability: Write code that doesn’t require someone to “decode” your thought process.
• Consistency: Follow patterns and formatting rules, making the logic predictable.
• Documentation: Don’t leave others guessing—use clear comments and meaningful names for variables, functions, and classes.
This experience reminded me of a quote by Robert C. Martin (Uncle Bob):
“Clean code is simple and direct. Clean code reads like well-written prose.”
What I did today:
I revisited one of my older projects and refactored redundant, messy blocks of code into modular, reusable functions. The result? Simpler, cleaner, and more efficient.
My clean code checklist:
• Use meaningful names for variables, functions, and classes.
• Keep functions short and focused on a single task.
• Eliminate unnecessary comments—let your code be self-explanatory.
• Stick to consistent formatting and indentation.
Let’s raise the bar for quality! What are your go-to practices for writing clean code? 100daysofcodelebanon-mug
Starting your coding journey can be daunting at first, trying to learn it all at once.
When I first dove into coding, I was overwhelmed by the vastness of it all. The endless programming languages, frameworks, tools, and concepts felt like too much to grasp in one go. I remember sitting in front of my screen, looking at tutorials and thinking, “Where do I even start?” It felt like I was chasing a moving target, trying to catch it all at once.
But what I realized over time is that trying to build everything in one day is when I felt the most frustrated. I was pushing myself too hard, setting unrealistic goals for what I could achieve in such a short amount of time. The constant pressure to “get everything right” left me feeling stuck and disheartened.
Then something changed. I started focusing on the small steps—focusing on learning just one thing at a time. I set a goal to commit a small amount of code every day, no matter how insignificant it seemed. The biggest leaps came not when I tried to rush my progress, but when I embraced consistency. Slowly, I began to realize that every line of code, every small improvement, was building the foundation of something bigger.
You may feel like you’re barely improving day by day, but fast forward a year, and you’d see how everything ties together. All those small wins, those tiny green squares on GitHub, they add up.
So trust the process, stay consistent, and keep those squares green
I’ve been challenged to start the #100DayCodeChallenge, and guess what?! Challenge Accepted!! So for the next 100 days, I’ll be sharing my knowledge, learning, and experiences.
Below is my progress from previous days, and I’ll now be updating regularly from today. If you’re up for it, join me on this adventure!
Day 4 of 100daysofcode : Mastering Selenium Locators
Locators in Selenium are used to identify and interact with web elements on a webpage, such as buttons, input fields, or links. They enable automated scripts to perform actions like clicking, typing, or retrieving information, making them essential for effective web automation.
Here’s a list of all the locators used in Selenium:
ID
Name
Class Name
Tag Name
Link Text
Partial Link Text
CSS Selector
XPath
DOM Locator (via JavaScript execution)
These locators provide a variety of ways to identify and interact with web elements depending on the structure of the webpage.
Day 5 of 100daysofcode : So, how do locators really work using Selenium?
Locators in Selenium work by identifying elements on a webpage using their unique attributes or properties, such as id, name, class, or tag structure.
Selenium communicates with the browser’s DOM (Document Object Model) to search for elements that match the specified locator. Once an element is located, Selenium enables interactions like clicking, typing, or extracting data.
By combining locators with Selenium’s powerful methods, testers can precisely target elements even on dynamic and complex web pages.
1. ID Locator
Description: Uses the id attribute of an HTML element.
Syntax:
element = driver.find_element(By.ID, "element_id")
Advantages:
Unique within a page.
Fast and reliable.
2. Name Locator
Description: Uses the name attribute of an HTML element.
Syntax:
element = driver.find_element(By.NAME, "element_name")
Advantages:
Simple and effective if name attributes are unique.
Disadvantages:
May not always be unique.
3. Class Name Locator
Description: Uses the class attribute of an HTML element.
Syntax:
element = driver.find_element(By.CLASS_NAME, "class_name")
Advantages:
Works well for elements with specific styling.
Disadvantages:
Fails when multiple elements share the same class.
4. Tag Name Locator
Description: Uses the HTML tag name (e.g., input, button).
Syntax:
element = driver.find_element(By.TAG_NAME, "tag_name")
Use Case:
Retrieving collections of elements like all links (<a> tags) on a page.
5. Link Text Locator
Description: Locates links based on their text.
Syntax:
element = driver.find_element(By.LINK_TEXT, "Link Text")
Use Case:
Ideal for links with unique text.
Disadvantages:
May not work well with long or dynamic text.
6. Partial Link Text Locator
Description: Locates links using partial text match.
Syntax:
element = driver.find_element(By.PARTIAL_LINK_TEXT, "Partial Text")
Use Case:
Useful when link text is too long or dynamic.
7. CSS Selector
Description: Uses CSS selectors to locate elements.
Syntax:
element = driver.find_element(By.CSS_SELECTOR, "css_selector")
Advantages:
Extremely flexible and powerful.
Supports complex matching patterns.
Examples:
By class: ".classname"
By ID: "#id"
By attribute: [type='submit']
Locators in Selenium are used to identify web elements on a webpage. They are a fundamental part of Selenium’s interaction with web applications. Here’s a detailed overview of the commonly used locators in Selenium:
from selenium import webdriver
from selenium.webdriver.common.by import By
# Initialize the WebDriver
driver = webdriver.Chrome()
# Open the practice login page
driver.get("https://practicetestautomation.com/practice-test-login/")
# Locate the username and password fields
username_field = driver.find_element(By.ID, "username")
password_field = driver.find_element(By.ID, "password")
# Enter credentials
username_field.send_keys("student")
password_field.send_keys("Password123")
# Locate and click the login button using a CSS Selector
login_button = driver.find_element(By.CSS_SELECTOR, "button[type='submit']")
login_button.click()
# Validate login by checking the URL or a success message
success_message = driver.find_element(By.TAG_NAME, "h1")
assert success_message.text == "Logged In Successfully", "Login failed!"
# Close the browser
driver.quit()
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
# Set up the WebDriver
driver = webdriver.Chrome()
try:
# Open the website
driver.get("https://the-internet.herokuapp.com/login")
# Locate the username field and enter text
username_field = driver.find_element(By.ID, "username")
username_field.send_keys("tomsmith") # Correct username
# Locate the password field and enter text
password_field = driver.find_element(By.ID, "password")
password_field.send_keys("SuperSecretPassword!") # Correct password
# Click the login button
login_button = driver.find_element(By.XPATH, "//button[@type='submit']")
login_button.click()
# Wait for a short while to allow the page to load
time.sleep(3)
# Verify if the login was successful by checking for a specific element
success_message = driver.find_element(By.XPATH, "//div[@class='flash success']")
assert "You logged into a secure area!" in success_message.text
print("Test Passed: Login successful!")
#Click the logout button
logout_button = driver.find_element(By.CLASS_NAME, "icon-2x icon-signout")
logout_button.click()
except AssertionError as e:
print("Test Failed: Assertion error -", e)
except Exception as e:
print("Test Failed: An error occurred -", e)
finally:
# Close the browser
driver.quit()
Day 9 of 100daysofcode : Top Challenges QA Engineers Face with Selenium—and How to Overcome Them
𝟭. 𝗦𝘁𝗲𝗲𝗽 𝗟𝗲𝗮𝗿𝗻𝗶𝗻𝗴 𝗖𝘂𝗿𝘃𝗲
𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲: Beginners may find it difficult to grasp Selenium due to its reliance on programming languages like Java, Python, or C#.
𝗦𝗼𝗹𝘂𝘁𝗶𝗼𝗻: Focus on learning the basics of the programming language first and gradually build Selenium skills.
𝟮. 𝗛𝗮𝗻𝗱𝗹𝗶𝗻𝗴 𝗗𝘆𝗻𝗮𝗺𝗶𝗰 𝗘𝗹𝗲𝗺𝗲𝗻𝘁𝘀
𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲: Many modern web applications use dynamic IDs or elements that change with each session, making it hard to locate elements reliably.
𝗦𝗼𝗹𝘂𝘁𝗶𝗼𝗻: Use robust locators like XPath, CSS selectors, or unique attributes.
𝟯. 𝗖𝗿𝗼𝘀𝘀-𝗕𝗿𝗼𝘄𝘀𝗲𝗿 𝗧𝗲𝘀𝘁𝗶𝗻𝗴
𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲: Ensuring compatibility across different browsers can lead to inconsistencies due to varying browser implementations.
𝗦𝗼𝗹𝘂𝘁𝗶𝗼𝗻: Use the WebDriver API and run extensive testing across all required browsers.
𝟰. 𝗗𝗲𝗯𝘂𝗴𝗴𝗶𝗻𝗴 𝗮𝗻𝗱 𝗧𝗲𝘀𝘁 𝗙𝗹𝗮𝗸𝗶𝗻𝗲𝘀𝘀
𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲: Tests can fail intermittently due to issues like timing, network latency, or improper waits.
𝗦𝗼𝗹𝘂𝘁𝗶𝗼𝗻: Implement explicit or fluent waits instead of implicit waits and ensure proper synchronization.
𝟱. 𝗜𝗻𝘁𝗲𝗴𝗿𝗮𝘁𝗶𝗼𝗻 𝘄𝗶𝘁𝗵 𝗢𝘁𝗵𝗲𝗿 𝗧𝗼𝗼𝗹𝘀
𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲: Integrating Selenium with CI/CD pipelines, reporting tools, or test management platforms can be complex.
𝗦𝗼𝗹𝘂𝘁𝗶𝗼𝗻: Use frameworks like TestNG, JUnit, or integrations with Jenkins, GitHub Actions, or other tools.
𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲: Automating tests involving captchas or 2FA is not straightforward.
𝗦𝗼𝗹𝘂𝘁𝗶𝗼𝗻: Use test environments with disabled captchas or simulate user behavior with backend support.
𝟳. 𝗛𝗮𝗻𝗱𝗹𝗶𝗻𝗴 𝗣𝗼𝗽-𝗨𝗽𝘀 𝗮𝗻𝗱 𝗔𝗹𝗲𝗿𝘁𝘀
𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲: Pop-ups, alerts, or authentication windows may not be handled seamlessly by Selenium.
𝗦𝗼𝗹𝘂𝘁𝗶𝗼𝗻: Use Selenium’s switchTo() methods or consider custom scripts for better handling.
𝟴. 𝗧𝗲𝘀𝘁𝗶𝗻𝗴 𝗠𝗼𝗯𝗶𝗹𝗲 𝗔𝗽𝗽𝗹𝗶𝗰𝗮𝘁𝗶𝗼𝗻𝘀
𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲: Selenium does not natively support mobile testing; you need tools like Appium for mobile platforms.
𝗦𝗼𝗹𝘂𝘁𝗶𝗼𝗻: Integrate Selenium with Appium or use other mobile testing tools.
𝟵. 𝗟𝗮𝗰𝗸 𝗼𝗳 𝗕𝘂𝗶𝗹𝘁-𝗶𝗻 𝗥𝗲𝗽𝗼𝗿𝘁𝗶𝗻𝗴
𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲: Selenium does not provide detailed reporting features.
𝗦𝗼𝗹𝘂𝘁𝗶𝗼𝗻: Use third-party libraries or frameworks such as Extent Reports, Allure, or TestNG reports.
𝟭𝟬. 𝗠𝗮𝗶𝗻𝘁𝗮𝗶𝗻𝗶𝗻𝗴 𝗧𝗲𝘀𝘁 𝗦𝗰𝗿𝗶𝗽𝘁𝘀
𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲: As applications evolve, maintaining Selenium test scripts becomes time-consuming.
𝗦𝗼𝗹𝘂𝘁𝗶𝗼𝗻: Follow modular frameworks, use Page Object Model (POM), and keep scripts well-documented.
𝟭𝟭. 𝗣𝗲𝗿𝗳𝗼𝗿𝗺𝗮𝗻𝗰𝗲 𝗮𝗻𝗱 𝗦𝗰𝗮𝗹𝗮𝗯𝗶𝗹𝗶𝘁𝘆 𝗜𝘀𝘀𝘂𝗲𝘀
𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲: Running extensive test suites can be time-consuming and resource-intensive.
𝗦𝗼𝗹𝘂𝘁𝗶𝗼𝗻: Use grid-based execution like Selenium Grid or cloud-based solutions like BrowserStack or Sauce Labs.
Day 10: Introduction to Cypress: A Modern End-to-End Testing Framework
Cypress is a modern, open-source JavaScript-based testing framework designed for end-to-end testing of web applications.
It provides a fast, reliable, and easy-to-use environment for writing, debugging, and running tests directly in the browser. Developers use Cypress to verify user flows, UI components, and application functionality across different browsers, ensuring a seamless user experience.
Day 12 of 100daysofcode : Top 5 scenarios where Cypress is most effective
1. End-to-End Testing
Cypress is primarily designed for E2E testing of web applications. Use it to test the complete workflow of an application, from the user interface to backend interactions.
Example: Testing a login process, form submission, or multi-step checkout process.
2. UI/UX Testing
Cypress excels at testing the user interface and ensuring elements are displayed correctly and behave as expected.
Example: Verifying that buttons, menus, modals, and animations work as intended.
3. Integration Testing
It is suitable for testing how different parts of your application interact with each other, especially in single-page applications.
Example: Checking that API responses update the UI as expected or that dependent components render correctly.
4. Cross-Browser Testing
Cypress supports multiple browsers like Chrome, Edge, and Firefox, making it a good choice for cross-browser compatibility testing.
Example: Ensuring that the application behaves consistently across supported browsers.
5. Continuous Integration/Delivery Pipelines
Cypress integrates seamlessly with CI/CD tools (like Jenkins, GitHub Actions, and GitLab CI) for automated testing during deployment.
Example: Running test suites on every code push or before a production release to catch regressions early.
Create a new project folder for your automation tests:
mkdir cypress-automation
cd cypress-automation
Initialize a new Node.js project:
npm init -y
This creates a package.json file to manage your project dependencies.
Step 3: Install Cypress
Run the following command to install Cypress:
npm install cypress --save-dev
This will add Cypress as a development dependency in your project.
Step 4: Open Cypress
After installation, you can open Cypress using the following command:
npx cypress open
This command will:
Launch the Cypress Test Runner.
Create a default folder structure (cypress/) in your project directory:
cypress/e2e: Place your test files here.
cypress/fixtures: Store static data (e.g., JSON files) for your tests.
cypress/support: Add custom commands or reusable logic here.
Step 5: Write Your First Test
Inside the cypress/e2e folder, create a new test file, for example:
touch cypress/e2e/sample_test.cy.js
Add a simple test in the file:
describe('My First Test', () => {
it('Visits the Cypress website', () => {
cy.visit('https://www.cypress.io');
cy.contains('Features').click();
cy.url().should('include', '/features');
});
});
Step 6: Run Tests
Start Cypress Test Runner:
npx cypress open
Select the test file you created (sample_test.cy.js) and run it.
Step 7: Configure Cypress (Optional)
You can customize Cypress settings in the cypress.config.js or cypress.config.ts file created in your project root. For example, to set a base URL for your tests:
To run Cypress tests in CI/CD pipelines, you can use the cypress run command. Add this step to your CI/CD configuration file (e.g., GitHub Actions, Jenkins, or CircleCI).
Day 15 of 100daysofcode : Cypress Test for Login Functionality
describe('Login Page Test', () => {
it('should allow a user to log in successfully', () => {
// Visit the login page
cy.visit('https://example.com/login');
// Enter username and password
cy.get('input[name="username"]').type('testuser');
cy.get('input[name="password"]').type('Password123');
// Click the login button
cy.get('button[type="submit"]').click();
// Assert the user is redirected to the dashboard
cy.url().should('include', '/dashboard');
// Assert the welcome message is displayed
cy.contains('Welcome, Test User!').should('be.visible');
});
});
Key Points:
cy.visit(): Navigates to the specified URL.
cy.get(): Finds elements using CSS selectors.
type(): Types text into an input field.
click(): Clicks on a button or element.
Assertions:
should('include') verifies the URL.
should('be.visible') confirms an element is visible.
This example assumes that the login page contains inputs with the names username and password and a button with type="submit". You can adapt the selectors and assertions based on your application.
beforeEach(() => {
// Visit the base URL before each test
cy.visit(${baseUrl}/login);
});
it(‘should login successfully with valid credentials’, () => {
cy.get(‘#username’).type(‘tomsmith’); // Enter valid username
cy.get(‘#password’).type(‘SuperSecretPassword!’); // Enter valid password
cy.get(‘button[type=“submit”]’).click(); // Click the Login button
// Assert successful login
cy.get('.flash.success').should('contain.text', 'You logged into a secure area!');
});
it(‘should show error for invalid credentials’, () => {
cy.get(‘#username’).type(‘invalidUser’); // Enter invalid username
cy.get(‘#password’).type(‘invalidPassword’); // Enter invalid password
cy.get(‘button[type=“submit”]’).click(); // Click the Login button
// Assert error message
cy.get('.flash.error').should('contain.text', 'Your username is invalid!');