Welcome to the SQL Quiz! This blog post features 25 multiple-choice questions that explore Subqueries concept of SQL.
1. What is a subquery in SQL?
a) A query that modifies data b) A query within another SQL query c) A query that creates tables d) A query that deletes data
Answer 1
b) A query within another SQL query
A subquery is a query nested within another SQL query, often used to provide results for the outer query to act upon
2. Which of the following is true about sub-queries?
a) They execute after the main query executes b) They execute in parallel to the main query c) The user can execute the main query and then, if wanted, execute the sub-query d) They execute before the main query executes.
Answer 2
d) They execute before the main query executes.
The sub-query always executes before the execution of the main query. Subqueries are completed first. The result of the subquery is used as input for the outer query.
3. Which of the following is a method for writing a sub-query in a main query?
a) By using JOINS b) By using WHERE clause c) By using the GROUP BY clause d) By writing a SELECT statement embedded in the clause of another SELECT statement
Answer 3
d) By writing a SELECT statement embedded in the clause of another SELECT statement
A subquery is a complete query nested in the SELECT, FROM, HAVING, or WHERE clause of another query. The subquery must be enclosed in parentheses and have a SELECT and aFROM clause, at a minimum
4. What will the following subquery do?
SELECT employee_id FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
a) Select employees with below-average salary b) Select employees with above-average salary c) Throw an error d) Select all employees
Answer 4
b) Select employees with above-average salary
It selects employees whose salary is greater than the average salary of all employees.
5. In the given scenarios, which one would appropriately justify the usage of sub-query?
a) When we need to sum up values b) When we need to convert character values into date or number values c) When we need to select rows from a table with a condition that depends on the data from the same or different table. d) None of the above
Answer 5
c) When we need to select rows from a table with a condition that depends on the data from the same or different table.
6. Which of the following single-row operators can be used for writing a sub-query?
a) >= b) < c) = d) All of the above
Answer 6
d) All of the above
Single-row operators include =, >, <, >=, <=, and <>
7. In which scenario is a subquery most appropriately used?
a) To sort data in descending order b) To filter results based on aggregated data from another table c) To duplicate data between tables d) To drop tables from a database
Answer 7
b) To filter results based on aggregated data from another table
Subqueries are commonly used to filter or manipulate data based on the results of a secondary query, especially with aggregated data.
8. What would be the effect of this query?
SELECT * FROM employees WHERE department_id = (SELECT department_id FROM departments WHERE name = 'Sales');
a) List all departments b) List all employees in all departments c) List all employees in the Sales department d) List all employees not in Sales department
Answer 8
c) List all employees in the Sales department
The subquery finds the department_id for ‘Sales’, and the outer query selects employees matching that department.
9. Which of the following multi-row operators can be used with a sub-query?
a) IN b) ANY c) ALL d) All of the above
Answer 9
d) All of the above
Multiple-row subqueries return more than one row of results.Operators that can beused with multiple-row subqueries include IN, ALL, ANY, and EXISTS.
10. Can a subquery return multiple columns and be used in a WHERE clause?
a) Yes, if using EXISTS b) Yes, if using JOIN c) No, must return a single column d) Yes, always
Answer 10
c) No, must return a single column
In a WHERE clause, subqueries must return a single column to be a valid comparison or condition.
11. Which of the following is a correlated subquery?
Choose one option
a) SELECT * FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
b) SELECT * FROM employees e WHERE salary > (SELECT AVG(salary) FROM employees WHERE department_id = e.department_id);
c) SELECT * FROM employees WHERE salary IN (SELECT salary FROM employees);
d) SELECT * FROM employees WHERE id IN (SELECT id FROM departments);
Answer 11
b)
It refers to the outer query’s row, making it a correlated subquery that executes for each row processed by the outer query.
12. How many levels of nested subqueries does SQL typically allow?
Choose one option
a) One b) Two c) Unlimited d) 255
Answer 12
d) 255
SQL standards typically allow up to 255 levels of nested subqueries, though this might vary by database implementation.
13. Where can subqueries NOT be used in SQL?
Choose one option
a) FROM clause b) SELECT clause c) JOIN clause d) IN clause
Answer 13
c) JOIN clause
Subqueries are not included as part of JOIN conditions; they appear as tables need explicit relations in a join.
14. What will be the output of the below query?
SELECT * FROM employees
WHERE salary BETWEEN (SELECT max(salary) FROM employees WHERE department_id = 100) AND
(SELECT min(salary) FROM employees WHERE department_id = 100);
This query returns an error. What is the reason for the error?
a) A GROUP BY clause should be used as the function MAX is used b) Both the sub-queries cannot use the same department ID in the same outer query c) BETWEEN operator cannot be used with a sub-query d) SELECT clause should have columns mentioned and not a asterix ∗
Answer 14
c) BETWEEN operator cannot be used with a sub-query
15. What kind of subquery is this?
SELECT department_id FROM departments WHERE department_id = (SELECT MAX(department_id) FROM departments);
Choose one option
a) Scalar b) Correlated c) Non-correlated d) Nested
Answer 15
a) Scalar
This is a scalar subquery that returns a single value and is used to select the row matching the maximum department_id
16. Which of the following is a valid example of a subquery within an UPDATE statement?
a) UPDATE employees SET salary = salary * 1.1 WHERE department_id = (SELECT department_id FROM departments);
b) UPDATE employees SET salary = salary * 1.1 WHERE department_id = (SELECT department_id FROM departments WHERE name = 'HR');
c) UPDATE employees USING (SELECT department_id FROM departments WHERE name = 'HR');
d) UPDATE employees SET salary = 1.1 * (SELECT salary FROM employees);
Answer 16
b)
This query uses a subquery to update employee salaries pertaining to the HR department only.
17. What does the following SQL statement do?
DELETE FROM employees WHERE manager_id IN (SELECT employee_id FROM employees WHERE department_id = 3);
Choose one option
a) Deletes all employees b) Deletes managers in department 3 c) Deletes employees managed by those in department 3 d) Deletes all managers
Answer 17
c) Deletes employees managed by those in department 3
This usage of a subquery identifies all employees who report directly to managers specified in department 3.
18. What will be the outcome of the following query?
SELECT first_name, last_name, salary FROM employees WHERE salary ANY
(SELECT salary FROM employees);
a) It executes successfully giving the desired results b) It executes successfully but does not give the desired results c) It throws an ORA error d) It executes successfully and gives two values for each row obtained in the result set
Answer 18
c) It throws an ORA error
Multi-row operators cannot be used in single-row sub-queries and vice versa.
19. Which of the following is a valid use of a subquery in the FROM clause?
a) SELECT * FROM (SELECT column1 FROM table1) AS subquery;
b) SELECT * FROM table1 WHERE column1 = (SELECT column2 FROM table2);
c) SELECT * FROM table1 INNER JOIN (SELECT column2 FROM table2) AS subquery;
d) SELECT column1 FROM table1 WHERE column2 = (SELECT column2 FROM table2) AND column3 = (SELECT column3 FROM table3);
Answer 19
a)
A valid use of a subquery in the FROM clause is treating the subquery as a temporary table, allowing the outer query to select from it.
20. What will be the outcome of the following query?
SELECT first_name, last_name FROM employees WHERE emp_id NOT IN
(SELECT manager_id, hire_date FROM employees WHERE manager_id IS NOT NULL);
Choose one option
a) The NOT IN operator used is invalid b) The WHERE clause in the sub-query is incorrectly written c) The column in the sub-query SELECT clause should only be one when there’s an inequality used in the main query d) The sub-query uses the same table as the main query
Answer 20
c) The column in the sub-query SELECT clause should only be one when there’s an inequality used in the main query
The columns selected in the sub-query should be same as on the other side of comparison operator. Any inequality of data type or number of columns would result in an ORA error.
21. When used in a SELECT statement, a subquery is also known as a:
a) Derived table b) Join c) Index d) Constraint
Answer 21
a) Derived table
When a subquery is used in the FROM clause, it’s often called a derived or inline table.
22. Which SQL statement can include a subquery?
a) SELECT b) INSERT c) UPDATE d) All of the above
Answer 22
d) All of the above
Subqueries can be used in SELECT, INSERT, UPDATE, or DELETE statements.
23. Which keyword can be used to handle subqueries that may return NULL?
a) IGNORE b) IS NOT NULL c) NVL or COALESCE d) NULLIF
Answer 23
c) NVL or COALESCE
The NVL or COALESCE functions can replace NULLs with a specified value if returned by a subquery.
24. What is a correlated subquery?
a) A subquery that can be run independently b) A subquery that references columns from the outer query c) A subquery that updates multiple tables d) A subquery that creates indices
Answer 24
b) A subquery that references columns from the outer query
Correlated subqueries use values from the outer query and run once for each row processed by the outer query.
25. What is the result of a subquery that returns NULL when it’s used with the IN operator?
a) Always includes NULL b) Excludes all NULLs and matches c) Returns no rows d) Matches nothing, including NULL
Answer 25
d) Matches nothing, including NULL
A subquery with NULL makes IN operator skip or ignore such direct results, unless IS NULL is explicitly used.
We would love to hear from you! Please leave your comments and share your scores in the section below
Playwright is integrated with Java, Cucumber, and Junit5. This integration creates a robust and scalable test automation framework for modern web applications. It is a BDD-driven framework.
Page Object Model (POM) is a design pattern used in test automation. It enhances test maintenance and reduces code duplication. In this pattern, web pages are represented as classes. The various elements on the page are defined as variables in the class. All possible user interactions can then be implemented as methods in the class.
What is Cucumber?
Cucumber is Behavior Driven Development (BDD). It is a methodology that integrates non-technical stakeholders, testers, and developers into the same conversation. This is achieved by using clearly defined specifications.
In behavior-driven development with Cucumber, test cases are written in Gherkin syntax. They use a Given-When-Then structure. This structure closely mirrors user stories and business rules.
Benefits of Using Cucumber with Playwright
1. Readable, business-friendly tests: Cucumber’s Gherkin syntax (Given–When–Then) makes test scenarios easy to understand for non-technical stakeholders, bridging the gap between QA, developers, and business teams.
2. Better Test Maintainability: With standardized step definitions and modularized test architecture, scaling up your test suite is effortless. Altering the suite won’t harm the entire framework.
3. Clear reporting and traceability: Cucumber’s reports map test results directly to feature files. They map directly to scenarios. This makes it easier to track coverage and failures against requirements.
4. Cross-browser and cross-platform coverage: When combined with Playwright, Cucumber scenarios can be executed across Chromium, Firefox, and WebKit without changing feature files
5. Scales well in CI/CD pipelines: The combination supports parallel execution. It offers tagging and selective test runs. This makes it suitable for continuous testing in CI environments.
What is JUnit5?
JUnit5 is a test execution engine. It discovers and runs Cucumber tests. It enhances integration testing with advanced annotations, nested tests, and parameterized testing. It simplifies test execution in Maven, Gradle, and Spring Boot with better assertions, Java dependency injection, and parallel execution.
System requirements
The following prerequisites are required to be installed on the machine to begin with a smooth setup and installation.
Java 11 or higher
IntelliJ IDE or any other IDE to create a project
Maven
Browsers on which tests need to be run, like Chrome, Firefox, etc.
Cucumber is installed
High-Level Architecture
Setting Up Cucumber BDD Framework with Playwright and JUnit5
1. Create a new Maven Project
The first step in setup is to create a new Maven project. I will be using IntelliJ in this tutorial. The following steps need to be followed to create a new Maven project :
Open IntelliJ, Navigate to File >> New >> Project
2. In the New Project window, enter the following details:
Name of the Project – Cucumber_Playwright_JUnit5
Location/path where the project needs to be saved – Documents/Playwright (my location)
Select JDK version — I am using JDK 17
Archetype — Search for “quickstart” and select maven-archetype-quickstartfrom the results
Click on the Create button to create the project.
This will create a a new project in IntelliJ.
2. Set Up the Environment
2.1 Add the Cucumber, Playwright Java, and JUnit5 dependencies
Add the Cucumber, Playwright Java, and JUnit5 dependencies to the pom.xml. The latest dependency can be found here.
The compiler plugin is used to compile the source code of a Maven project. This plugin has two goals, which are already bound to specific phases of the default lifecycle:
Creating a well-organized project structure is crucial for maintaining a scalable and efficient automation framework.
1. Maven Configuration (pom.xml): This file manages project dependencies, plugins, and other configurations.
2. Features (src/test/resources/…/features): It contains Gherkin feature files written in plain English.
3. StepDefinition (src/test/java/.../tests/): Here, you write your actual test cases, utilizing the page classes. Cucumber steps are implemented.
4. Runner (src/main/java/…runner/): It connects Cucumber feature files with Junit Platform and triggers execution.
5. Hooks (src/test/java/…/hooks): Hooks manage test lifecycle events like Launch browser before scenario, Close browser after scenario, Capture screenshots on failure
6. Page Classes (src/main/java/.../pages/): Each web page in your application should have a corresponding page class. This class encapsulates all the functionalities of the web page, following the Page Object Model.
7. Steps (src/test/java/…/steps): It is an extra abstraction layer between step definitions and pages. It contains code that is common across scenarios.
8. Utility Classes (src/main/java/.../utils/): These classes can include various utilities like configuration readers, browser factory, helper methods for common tasks, etc.
9. junit-platform.properties: It contains global configuration for Junit Platform.
4. Create a feature file under src/test/resources/features
It is recommended to create a features folder in the src/test/resources directory. Create all the feature files in this features folder. Feature file should be saved as an extension of .feature. The test scenarios in the Feature file are written in Gherkins language. Add the test scenarios in this feature file. I have added sample test scenarios.
Feature: Login to HRM Application
Background:
Given User is on HRMLogin page "https://opensource-demo.orangehrmlive.com/"
@ValidCredentials
Scenario: Login with valid credentials
When User enters username as "Admin" and password as "admin123"
Then User should be able to login successfully and new page opens with heading "Dashboard"
@InvalidCredentials
Scenario Outline: Login with invalid credentials
When User enters username as "<username>" and password as "<password>"
Then User should be able to see error message "<errorMessage>"
Examples:
| username | password | errorMessage |
| Admin | admin12$$ | Invalid credentials |
| admin$$ | admin123 | Invalid credentials |
| abc123 | xyz$$ | Invalid credentials |
@MissingUsername
Scenario: Login with blank username
When User enters username as " " and password as "admin123"
Then User should be able to see a message "Required" below Username
5. Create the utility package in src/test/java
Create a Playwright Factory that includes methods to start and close the browser.
package com.example.utils;
import com.microsoft.playwright.*;
public class PlaywrightFactory {
private static Playwright playwright;
private static Browser browser;
private static BrowserContext context;
private static Page page;
public static void initBrowser() {
playwright = Playwright.create();
browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
context = browser.newContext();
page = context.newPage();
}
public static Page getPage() {
return page;
}
public static void closeBrowser() {
if (page != null) page.close();
if (context != null) context.close();
if (browser != null) browser.close();
if (playwright != null) playwright.close();
}
}
6. Create the hooks package in src/test/java
Create a Hook class that contains the code that runs before or after each scenario. Here, it is responsible for
Each web page in your application should have a corresponding page class. This class encapsulates all the functionalities of the web page, following the Page Object Model.
LoginPage
package com.example.pages;
import com.microsoft.playwright.*;
public class LoginPage {
private Page page;
// Locators
private final Locator usernameLocator;
private final Locator passwordLocator;
private final Locator submitLocator;
private final Locator invalidCredentialsLocator;
private final Locator missingUsernameLocator;
public LoginPage(Page page) {
this.page = page;
this.usernameLocator = page.locator("input[name='username']");
this.passwordLocator = page.locator("input[name='password']");
this.submitLocator = page.locator("button[type='submit']");
this.invalidCredentialsLocator = page.locator("//p[contains(@class, "oxd-text oxd-text--p oxd-alert-content-text")]");
this.missingUsernameLocator = page.locator("//span[contains(@class, 'oxd-text oxd-text--span oxd-input-field-error-message oxd-input-group__message')]");
}
public void login(String user, String pass){
usernameLocator.fill(user);
passwordLocator.fill(pass);
submitLocator.click();
}
public void getUrl(String url){
page.navigate(url);
}
public String getMissingUsernameErrorMessage() {
return missingUsernameLocator.textContent();
}
public String getErrorMessage () {
return invalidCredentialsLocator.textContent();
}
}
DashboardPage
package com.example.pages;
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
public class DashboardPage {
private Page page;
private final Locator headingLocator;
public DashboardPage(Page page){
this.page = page;
this.headingLocator = page.locator("//h6[contains(@class, "oxd-topbar-header-breadcrumb-module")]");
}
public String getDashboardPageHeading() {
return headingLocator.textContent();
}
}
8. Create the step package in src/test/java
package com.example.steps;
import com.example.utils.PlaywrightFactory;
import com.microsoft.playwright.Page;
public class BaseStep {
protected Page getPage() {
Page page = PlaywrightFactory.getPage();
if (page == null) {
throw new RuntimeException(
"Page is NULL. Ensure @Before hook ran and glue includes hooks package."
);
}
return page;
}
}
9. Create the step definition class in src/test/java
Create the step definition class corresponding to the feature file to test the scenarios in the src/test/java directory. The StepDefinition files should be created in this definitionsdirectory within the folder called definitions.
Below is the step definition of the LoginPage feature file.
package com.example.definitions;
import com.example.pages.DashboardPage;
import com.example.pages.LoginPage;
import com.example.steps.BaseStep;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.junit.jupiter.api.Assertions;
public class LoginPageDefinitions extends BaseStep {
private LoginPage loginPage;
private DashboardPage dashboardPage;
@Given("User is on HRMLogin page {string}")
public void userIsOnHRMLoginPage(String baseUrl) {
loginPage = new LoginPage(getPage());
loginPage.getUrl(baseUrl);
}
@When("User enters username as {string} and password as {string}")
public void userEntersUsernameAsAndPasswordAs(String username, String password) {
loginPage.login(username, password);
}
@Then("User should be able to see error message {string}")
public void userShouldBeAbleToSeeErrorMessage(String expectedErrorMessage) {
Assertions.assertEquals(expectedErrorMessage, loginPage.getErrorMessage());
}
@Then("User should be able to see a message {string} below Username")
public void userShouldBeAbleToSeeAMessageBelowUsername(String expectedErrorMessage) {
Assertions.assertEquals(expectedErrorMessage, loginPage.getMissingUsernameErrorMessage());
}
@Then("User should be able to login successfully and new page opens with heading {string}")
public void userShouldBeAbleToLoginSuccessfullyAndNewPageOpen(String expectedHeading) {
dashboardPage = new DashboardPage(getPage());
Assertions.assertEquals(expectedHeading, dashboardPage.getDashboardPageHeading());
}
}
10. Create a JUnit Platform Cucumber Runner class in src/test/java
We need to create a class called Runner class to run the tests.
This JUnit 5 runner configures and launches Cucumber scenarios by selecting feature files, defining glue code packages, and executing them via the Cucumber engine on the JUnit Platform.
package com.example.runner;
import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;
@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("features")
@ConfigurationParameter(
key = GLUE_PROPERTY_NAME, value = "com.example"
)
public class RunnerTests {
}
1. @Suite – Marks this class as a JUnit 5 test suite. Acts as the entry point for test execution
2. @IncludeEngines(“cucumber”) – Tells JUnit Platform to use the Cucumber engine
3. @SelectClasspathResource(“features”) – Specifies the location of feature file
4. @ConfigurationParameter – Tells Cucumber where to find step definitions and hooks
11. Run the test using the Junit Platform Runner File
Go to the Runner class and right-click and select Run ‘RunnerTests’. The tests will run in IntelliJ.
Below is the test execution result. 1 test is failed intentionally to show the status of test execution in the report.
12. Run the tests from the Command Line
Run the command below in the command prompt to run the tests and to get the test execution report.
mvn clean site test
The execution screen looks like something as shown below.
13. Cucumber Report Generation
Add junit-platform.properties under src/test/resources and add the below instructions in the file.
cucumber.publish.enabled=true
Below is the image of the Cucumber Report generated using the Cucumber Service.
We can see the details of the failed test in the Report.
The highlighted part holds the screenshot of the failed test.
14. Surefire Report Generation
Maven Site Plugin creates a folder – site under the target directory.
Junit also produces an “index.html” report, and it resides under the target folder. The below image shows the index.html report. This is the latest theme of the report.
Recap of Key Points:
Playwright and Java: We explored the powerful combination of Playwright with Java. We highlighted the benefits of this duo in automated testing.
Build: Maven manage the dependencies and execution.
Cucumber (BDD Framework):It enables Behavior-Driven Development (BDD).
Feature: It uses Gherkin feature file to create the scenarios.
StepDefinition: Stepdefinition file contains the test code related to the feature file. When Cucumber executes a Gherkin step in a scenario, it will look for a matching step definition to execute.
Test Runner: It acts as a bridge between the feature and StepDefinition file.
JUnit5: It controls the test execution lifecycle. It integrates with Cucumber via Junit Platform runner.
Hooks: Hooks manage browser setup, teardown, and failure handling
Welcome to the SQL Quiz! This blog post features 25 multiple-choice questions that explore JOINS concept of SQL.
1. Which SQL JOIN returns only the rows that have matching values in both tables?
a) LEFT JOIN b) RIGHT JOIN c) INNER JOIN d) FULL OUTER JOIN
Answer 1
c) INNER JOIN
INNER JOIN matches records in both tables based on the join condition.
2. What does the following SQL query return?
SELECT products.product_name, orders.order_date
FROM products
INNER JOIN orders ON products.product_id = orders.product_id;
a) Only products that have been ordered b) All products, ordered and non-ordered c) All orders, regardless of the products d) None of the above
Answer 2
a) Only products that have been ordered
The INNER JOIN retrieves only products that have corresponding order records.
3. If you want all rows from the left table and only the matching rows from the right table, which join will you use?
a) INNER JOIN b) RIGHT JOIN c) LEFT JOIN d) FULL JOIN
Answer 3
c) LEFT JOIN
LEFT JOIN keeps all rows from the left table and adds NULLs for non-matching right table rows.
4. Which join type would you use to include all students and their respective grades, whether or not the grades are recorded?
SELECT students.student_name, grades.grade
FROM students
__________ JOIN grades ON students.student_id = grades.student_id;
a) INNER JOIN b) RIGHT JOIN c) LEFT JOIN d) FULL JOIN
Answer 4
c) LEFT JOIN
A LEFT JOIN includes all students and their grades, with NULL for students without recorded grades.
5. Which JOIN includes all records from both tables, filling NULLs where there are no matches?
a) INNER JOIN b) CROSS JOIN c) FULL OUTER JOIN d) SELF JOIN
Answer 5
c) FULL OUTER JOIN
FULL OUTER JOIN returns all rows from both tables with NULLs where no match exists.
6. What result does the following query produce?
SELECT a.name, b.address
FROM customers a
FULL OUTER JOIN orders b ON a.customer_id = b.customer_id;
a) Only matching customers and orders b) All customers and orders with matches and non-matches c) Customers without orders d) Orders without customers
Answer 6
b) All customers and orders with matches and non-matches
A FULL OUTER JOIN returns all records when there is a match in either table A or table B.
7. What does a CROSS JOIN do?
a) Matches only the common records b) Returns Cartesian product of two tables c) Returns only distinct records d) Works only on primary keys
Answer 7
b) Returns Cartesian product of two tables
CROSS JOIN multiplies all rows from one table with all rows of another.
8. What does the following SQL query do?
SELECT e.employee_id, e.name, d.department_name
FROM employees e
CROSS JOIN departments d;
a) Joins each employee with all departments b) Returns only matched employees and departments c) Lists employees without departments d) Lists departments without employees
Answer 8
a) Joins each employee with all departments
A CROSS JOIN creates a Cartesian product of both tables.
9. Which JOIN is used to join a table with itself?
a) CROSS JOIN b) SELF JOIN c) FULL OUTER JOIN d) NATURAL JOIN
Answer 9
b) SELF JOIN
SELF JOIN is useful for hierarchical or recursive relationships.
10. What is a primary use case for a self join in SQL?
a) To join two unrelated databases b) To compare rows within the same table c) To join tables with similar schemas d) To execute subqueries
Answer 10
b) To compare rows within the same table
SELECT a.employee_id, a.name, b.manager_id
FROM employees a
JOIN employees b ON a.manager_id = b.employee_id;
In the provided query, the employees table is joined with itself to find employees and their respective managers by matching employee IDs with manager IDs.
11. In a self join scenario, how would you distinguish between the different roles of the table being joined to itself?
Choose one option
a) Use different database instances b) Use table aliases c) Create a temporary table d) Use a different SQL dialect
Answer 11
b) Use table aliases
SELECT e1.name AS Employee, e2.name AS Manager
FROM employees e1
JOIN employees e2 ON e1.manager_id = e2.employee_id;
In a self join, table aliases are employed to differentiate between the roles of the same table. Here, `e1` represents employees, and `e2` represents managers, allowing us to fetch the employee names along with their corresponding managers.
12. To avoid a Cartesian product, always include a valid join condition in a WHERE clause.
Choose one option
a) True b) False
Answer 12
a) True
If we don’t use WHERE clause in a join, it will do a cartesian product.
13. Which type of JOIN is used to select all records from the right table and the matched records from the left table?
Choose one option
a) OUTER JOIN b) SELF JOIN c) RIGHT JOIN d) NATURAL JOIN
Answer 13
c) RIGHT JOIN
A RIGHT JOIN returns all records from the right table and the matched records from the left table. Unmatched left table records receive NULLs.
14. Given the tables employees and departments, which query will list all department names even if they have no employees?
Choose one option
a) LEFT JOIN b) SELF JOIN c) RIGHT JOIN d) INNER JOIN
Answer 14
c) RIGHT JOIN
SELECT departments.department_name, employees.name
FROM departments
RIGHT JOIN employees ON departments.id = employees.department_id;
The RIGHT JOIN returns all department names, including those with no associated employees.
15. Can multiple JOIN operations be used in a single SQL query?
Choose one option
a) True b) False
Answer 15
a) True
Multiple JOIN operations can be utilized in a single query to combine data from more than two tables.
16. In a SQL JOIN, what does the ON keyword do?
Choose one option
a) Specifies the columns for joining b) Specifies the conditions for joining c) Specifies the number of rows to return d) Specifies the order of columns
Answer 16
b) Specifies the conditions for joining
The ON keyword specifies conditions that determine which rows are retrieved in the join operation.
17. To combine data from multiple tables where relationships exist, which SQL feature should be used besides JOINs?
Choose one option
a) Subqueries b) Cursors c) Triggers d) Indexes
Answer 17
a) Subqueries
Subqueries can be used to combine data or perform operations that retrieve data from multiple tables based on conditions.
18. What is a NATURAL JOIN based on?
a) Explicit conditions b) Common columns automatically determined c) Primary keys d) Foreign keys
Answer 18
b) Common columns automatically determined
A NATURAL JOIN automatically joins tables based on columns with matching names and compatible data types.
19. Below two tables (A & B) are given.
What will be the result of inner join between these tables?
a) 1,3,4 b) 1,2,3,4,5,6,7,8,9,10,12 c) 1,2,3,4,5,6,7 d) 1,3,4,8,9,10,12
Answer 19
a) 1,3,4
20. What will be the result of FULL OUTER JOIN between these tables?
Choose one option
a) 1,3,4 b) 1,2,3,4,5,6,7,8,9,10,12 c) 1,2,3,4,5,6,7 d) 1,3,4,8,9,10,12
Answer 20
b) 1,2,3,4,5,6,7,8,9,10,12
21. Select the correct query/queries for cross join:
a) Select * FROM Table1 T1 CROSS JOIN Table1 T2;
b) Select * FROM Table1 T1 ALL CROSS JOIN Table1 T2;
c) Select * FROM Table1 T1,Table1 T2;
d) Select * FROM Table1 T1 CROSS Table1 T2;
Answer 21
a) Select * FROM Table1 T1 CROSS JOIN Table1 T2;
22. Which clause can be used with a JOIN to filter records?
a) WHERE b) HAVING c) GROUP BY d) ORDER BY
Answer 22
a) WHERE
The WHERE clause can be used to filter records after the JOIN operation, whereas HAVING is typically used with GROUP BY.
23. How can SQL JOINs be optimized for better performance?
a) Using indexes on join columns b) Avoiding WHERE clauses c) Using more complex joins d) Increasing database storage
Answer 23
a) Using indexes on join columns
Optimizing SQL JOIN performance generally involves using indexes on the columns involved in the join conditions.
24. Consider the tables `students` and `enrollments`, both having the column `student_id`. What will the following SQL statement do?
SELECT * FROM students NATURAL JOIN enrollments;
a) Join using all columns that are common between the two tables b) Require user to specify a join condition c) Join using columns named `student_id` d) Join with duplicate column names represented multiple times
Answer 24
c) Join using columns named `student_id`
The NATURAL JOIN will operate on all columns with the same name, joining on `student_id` as it’s the common column between `students` and `enrollments`.
25. What is a potential disadvantage of using NATURAL JOIN?
a) It is only available in a few SQL dialects b) Can join tables that have no related columns c) Lacks explicit control over join conditions d) Always results in Cartesian product of the tables
Answer 25
c) Lacks explicit control over join conditions
NATURAL JOIN does not allow you to specify which common columns to use for joining, which can lead to unforeseen results if multiple columns share the same name across tables.
We would love to hear from you! Please leave your comments and share your scores in the section below
Playwright is integrated with Java, Cucumber, and TestNG. This integration creates a robust and scalable test automation framework for modern web applications. It is a BDD-driven framework.
Page Object Model (POM) is a design pattern used in test automation. It enhances test maintenance and reduces code duplication. In this pattern, web pages are represented as classes. The various elements on the page are defined as variables in the class. All possible user interactions can then be implemented as methods in the class.
What is Cucumber?
Cucumber is Behavior Driven Development (BDD). It is a methodology that integrates non-technical stakeholders, testers, and developers into the same conversation. This is achieved by using clearly defined specifications.
In behavior-driven development with Cucumber, test cases are written in Gherkin syntax. They use a Given-When-Then structure. This structure closely mirrors user stories and business rules.
Benefits of Using Cucumber with Playwright
1. Readable, business-friendly tests: Cucumber’s Gherkin syntax (Given–When–Then) makes test scenarios easy to understand for non-technical stakeholders, bridging the gap between QA, developers, and business teams.
2. Better Test Maintainability: With standardized step definitions and modularized test architecture, scaling up your test suite is effortless. Altering the suite won’t harm the entire framework.
3. Clear reporting and traceability: Cucumber’s reports map test results directly to feature files. They map directly to scenarios. This makes it easier to track coverage and failures against requirements.
4. Cross-browser and cross-platform coverage: When combined with Playwright, Cucumber scenarios can be executed across Chromium, Firefox, and WebKit without changing feature files
5. Scales well in CI/CD pipelines: The combination supports parallel execution. It offers tagging and selective test runs. This makes it suitable for continuous testing in CI environments.
What is TestNG?
TestNG is a testing framework widely used with Selenium for building structured, maintainable, and efficient automated tests. Combining TestNG listeners with Playwright gives testers greater control over test monitoring, logging, and custom actions based on test outcomes. In TestNG you can initialize Playwright and Browser in @BeforeClass method and destroy them in @AfterClass.
System requirements
The following prerequisites are required to be installed on the machine to begin with a smooth setup and installation.
Java 11 or higher
IntelliJ IDE or any other IDE to create a project
Maven
Browsers on which tests need to be run, like Chrome, Firefox, etc.
High-Level Architecture
Setting Up Cucumber BDD Framework with Playwright and TestNG
1. Create a new Maven Project
The first step in setup is to create a new Maven project. I will be using IntelliJ in this tutorial. The following steps need to be followed to create a new Maven project :
Open IntelliJ, Navigate to File >> New >> Project
In the New Project window, enter the following details:
Name of the Project – Cucumber_Playwright_TestNG
Location/path where the project needs to be saved – Documents/Playwright (my location)
Select JDK version — I am using JDK 17
Archetype — Search for “quickstart” and select maven-archetype-quickstartfrom the results
Click on the Create button to create the project.
This will create a project as shown in IntelliJ.
2. Set Up the Environment
2.1 Add the Cucumber, Playwright Java, and TestNG dependencies
Add the Cucumber, Playwright Java, and TestNG dependencies to the pom.xml. The latest dependency can be found here.
The compiler plugin is used to compile the source code of a Maven project. This plugin has two goals, which are already bound to specific phases of the default lifecycle:
Creating a well-organized project structure is crucial for maintaining a scalable and efficient automation framework.
1. Maven Configuration (pom.xml): This file manages project dependencies, plugins, and other configurations.
2. Features (src/test/resources/…/features): Contains Gherkin feature files written in plain English.
3. StepDefinition (src/test/java/.../tests/): Here, you write your actual test cases, utilizing the page classes. Cucumber stepsare implemented.
4. Runner (src/main/java/…runner/): It connects Cucumber feature files with TestNGand triggers execution.
5. Hooks (src/test/java/…/hooks): Hooks manage test lifecycle events like Launch browser before scenario, Close browser after scenario, Capture screenshots on failure
6. Page Classes (src/main/java/.../pages/): Each web page in your application should have a corresponding page class. This class encapsulates all the functionalities of the web page, following the Page Object Model.
7. Steps (src/test/java/…/steps): It is an extra abstraction layer between step definitions and pages. It contains code which is common across scenarios.
8. Utility Classes (src/main/java/.../utils/): These classes can include various utilities like configuration readers, browser factory, helper methods for common tasks, etc.
9. Test Data Files (src/test/resources/testdata/): Externalizes test data to avoid hardcoding. This includes items like usernames and passwords. These are stored in external files for easy management.
10. cucumber.properties: It contains global configuration for Cucumber.
11. testng.xml: This file is the central configuration file that defines how the test suite should be executed.
4. Create a feature file under src/test/resources
It is recommended to create a features folder in the src/test/resources directory. Create all the feature files in this features folder. Feature file should be saved as an extension of .feature. The test scenarios in the Feature file are written in Gherkins language. Add the test scenarios in this feature file. I have added sample test scenarios. Out of 5 tests, 4 will pass and 1 will fail.
Feature: Login to HRM Application
Background:
Given User is on HRMLogin page "https://opensource-demo.orangehrmlive.com/"
@ValidCredentials
Scenario: Login with valid credentials
When User enters username as "Admin" and password as "admin123"
Then User should be able to login successfully and new page opens with heading "Dashboard"
@InvalidCredentials
Scenario Outline: Login with invalid credentials
When User enters username as "<username>" and password as "<password>"
Then User should be able to see error message "<errorMessage>"
Examples:
| username | password | errorMessage |
| Admin | admin12$$ | Invalid credentials |
| admin$$ | admin123 | Invalid credentials |
| abc123 | xyz$$ | Invalid credentials |
@MissingUsername
Scenario: Login with blank username
When User enters username as " " and password as "admin123"
Then User should be able to see a message "Required1" below Username
5. Create the utility package in src/test/java
Create a Playwright Factory that contains the methods to start the browser and close the browser.
package com.example.utils;
import com.microsoft.playwright.*;
public class PlaywrightFactory {
private static Playwright playwright;
private static Browser browser;
private static BrowserContext context;
private static Page page;
public static void initBrowser() {
playwright = Playwright.create();
browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
context = browser.newContext();
page = context.newPage();
}
public static Page getPage() {
return page;
}
public static void closeBrowser() {
if (page != null) page.close();
if (context != null) context.close();
if (browser != null) browser.close();
if (playwright != null) playwright.close();
}
}
6. Create the hooks package in src/test/java
Create a Hook class that contain the code that runs before or after each scenario. Here, it is responsible for
Each web page in your application should have a corresponding page class. This class encapsulates all the functionalities of the web page, following the Page Object Model.
LoginPage
package com.example.pages;
import com.microsoft.playwright.*;
public class LoginPage {
private Page page;
// Locators
private final Locator usernameLocator;
private final Locator passwordLocator;
private final Locator submitLocator;
private final Locator invalidCredentialsLocator;
private final Locator missingUsernameLocator;
public LoginPage(Page page) {
this.page = page;
this.usernameLocator = page.locator("input[name='username']");
this.passwordLocator = page.locator("input[name='password']");
this.submitLocator = page.locator("button[type='submit']");
this.invalidCredentialsLocator = page.locator("//p[contains(@class, \"oxd-text oxd-text--p oxd-alert-content-text\")]");
this.missingUsernameLocator = page.locator("//span[contains(@class, 'oxd-text oxd-text--span oxd-input-field-error-message oxd-input-group__message')]");
}
public void login(String user, String pass){
usernameLocator.fill(user);
passwordLocator.fill(pass);
submitLocator.click();
}
public void getUrl(String url){
page.navigate(url);
}
public String getMissingUsernameErrorMessage() {
return missingUsernameLocator.textContent();
}
public String getErrorMessage () {
return invalidCredentialsLocator.textContent();
}
}
DashboardPage
package com.example.pages;
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
public class DashboardPage {
private Page page;
private final Locator headingLocator;
public DashboardPage(Page page){
this.page = page;
this.headingLocator = page.locator("//h6[contains(@class, \"oxd-topbar-header-breadcrumb-module\")]");
}
public String getDashboardPageHeading() {
return headingLocator.textContent();
}
}
8. Create the step package in src/test/java
package com.example.steps;
import com.example.utils.PlaywrightFactory;
import com.microsoft.playwright.Page;
public class BaseStep {
protected Page getPage() {
Page page = PlaywrightFactory.getPage();
if (page == null) {
throw new RuntimeException(
"Page is NULL. Ensure @Before hook ran and glue includes hooks package."
);
}
return page;
}
}
9. Create the step definition class in src/test/java
Create the step definition class corresponding to the feature file to test the scenarios in the src/test/java directory. The StepDefinition files should be created in this definitionsdirectory within the folder called definitions.
Below is the step definition of the LoginPage feature file.
package com.example.definitions;
import com.example.steps.BaseStep;
import com.example.pages.DashboardPage;
import com.example.pages.LoginPage;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.testng.Assert;
public class LoginPageDefinitions extends BaseStep {
private LoginPage loginPage;
private DashboardPage dashboardPage;
@Given("User is on HRMLogin page {string}")
public void userIsOnHRMLoginPage(String baseUrl) {
loginPage = new LoginPage(getPage());
loginPage.getUrl(baseUrl);
}
@When("User enters username as {string} and password as {string}")
public void userEntersUsernameAsAndPasswordAs(String username, String password) {
loginPage.login(username, password);
}
@Then("User should be able to see error message {string}")
public void userShouldBeAbleToSeeErrorMessage(String expectedErrorMessage) {
Assert.assertEquals(loginPage.getErrorMessage(), expectedErrorMessage);
}
@Then("User should be able to see a message {string} below Username")
public void userShouldBeAbleToSeeAMessageBelowUsername(String expectedErrorMessage) {
Assert.assertEquals(loginPage.getMissingUsernameErrorMessage(), expectedErrorMessage);
}
@Then("User should be able to login successfully and new page opens with heading {string}")
public void userShouldBeAbleToLoginSuccessfullyAndNewPageOpen(String expectedHeading) {
dashboardPage = new DashboardPage(getPage());
Assert.assertEquals(dashboardPage.getDashboardPageHeading(), expectedHeading);
}
}
10. Create a TestNG Cucumber Runner class in src/test/java
We need to create a class called Runner class to run the tests. This class will use the TestNG annotation @RunWith(), which tells TestNG what is the test runner class. TestRunner should be created under src/test/java within the folder called runner.
AbstractTestNGCucumberTestsis a class provided by the Cucumber framework when we are integrating Cucumber with the TestNG test framework. This abstract class helps facilitate the execution of Cucumber tests using TestNG.
We need to specify the values of browser in the TestNG XML file that will pass to the test case file.
Let’s create a testng.xml file to run the test using TestNG.
Right click on the project, New >> File
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Playwright test suite" thread-count="3">
<test name="Chromium Tests">
<classes>
<class name="com.example.runner.RunnerTests"/>
</classes>
</test>
</suite>
12. Run the test through Runner Class
Go to the Runner class and right-click and select Run ‘RunnerTests’. The tests will run as TestNG tests (in IntelliJ).
Below is the test execution result.
13. Run the tests from TestNG.xml
Execute the tests by right-clicking on testng.xml and select Run ‘…testng.xml’
This will run the tests in chromium as mentioned in the .xml file.
The output of the above program is
14. Run the tests from the Command Line
Run the below command in the command prompt to run the tests and to get the test execution report.
mvn clean test
The execution screen looks like something as shown below.
15. Cucumber Report Generation
Add cucumber.properties under src/test/resources and add the below instructions in the file.
cucumber.publish.enabled=true
Below is the image of the Cucumber Report generated using the Cucumber Service.
The screenshot of the failed test is also attached in the Cucumber Report.
Click on the highlighted part. It contains the screenshot.
16. TestNG Report Generation
TestNG generates various types of reports under test-output folder like emailable-report.html, index.html, testng-results.xml.
We are interested in the emailable-report.html report. Open emailable-report.html, as this is an HTML report, and open it with the browser. The below image shows emailable-report.html.
TestNG also produces an “index.html” report, and it resides under the test-output folder. The below image shows the index.html report. This is the latest theme of the report.
Recap of Key Points:
Playwright and Java: We explored the powerful combination of Playwright with Java. We highlighted the benefits of this duo in automated testing.
Build: Maven manage the dependencies and execution.
Cucumber (BDD Framework):It enables Behavior-Driven Development (BDD).
Feature: It uses Gherkin feature file to create the scenarios.
StepDefinition: StepDefinition file contains the test code related to the feature file. When Cucumber executes a Gherkin step in a scenario, it will look for a matching step definition to execute.
Test Runner: It acts as a bridge between the feature and StepDefinition file.
TestNG: It controls the test execution lifecycle. It integrates with Cucumber via TestNG runner.
Hooks: Hooks manage browser setup, teardown, and failure handling
Large test suites can be structured to optimize ease of authoring and maintenance. Page object models are one such approach to structure the test suite. In this tutorial blog, we will learn to create and set up the project using Page Object Model in Playwright Java and JUnit5.
Page Object Model (POM) is a design pattern used in test automation. It enhances test maintenance and reduces code duplication. In this pattern, web pages are represented as classes. The various elements on the page are defined as variables in the class. All possible user interactions can then be implemented as methods in the class.
Why is Page Object Model Important?
1. Improved Test Maintenance: POM allows for easy updates to test scripts when the UI changes. The test logic is separated from the page definitions. This way, only the page objects need to be updated rather than all test scripts.
2. Maintainability: In this model, separate classes are created for different pages of a web application like login page, the home page, employee detail page, change password page, etc. So, if there is any change in any element of a website then we only need to make changes in one class, and not in all classes.
3. Reusability of Code: Shared page objects can be reused across multiple test cases, reducing redundancy. This ensures consistent interactions with web elements and actions, making the test code more efficient and easier to manage.
4. Facilitates Collaboration: A well-structured POM increases collaboration among teams. Each contributor can work on different parts of the application without interfering with one another. This approach helps in managing multiple test scenarios simultaneously.
5. Ease of Debugging: With POM, finding and fixing bugs becomes more straightforward since each page action is located in a specific place. Developers can easily pinpoint the location of a problem without sifting through complex test logic.
What is Playwright?
Page Object Model (POM) is a design pattern used in test automation. It enhances test maintenance and reduces code duplication. In this pattern, web pages are represented as classes. The various elements on the page are defined as variables in the class. All possible user interactions can then be implemented as methods in the class.
What is JUnit5?
JUnit5 is a test execution engine. It is used as testing framework for Java applications. It provides an easy-to-use platform for writing and executing tests. JUnit 5 is composed of three main modules: JUnit Platform, JUnit Jupiter and JUnit Vintage
System requirements
The following prerequisites are required to be installed on the machine to begin with a smooth setup and installation.
Java 11 or higher
IntelliJ IDE or any other IDE to create a project
Maven
Browsers on which tests need to be run, like Chrome, Firefox, etc.
Implementation Steps
1. Create a new Maven Project
The first step in setup is to create a new Maven project. I will be using IntelliJ in this tutorial. The following steps need to be followed to create a new Maven project :
Open IntelliJ, Navigate to File >> New >> Project
2. In the New Project window, enter the following details:
Name of the Project – PageObjectModel_Playwright_JUnit5
Location/path where the project needs to be saved – Documents/Playwright (my location)
Select JDK version — I am using JDK 17
Archetype — Search for “quickstart” and select maven-archetype-quickstart from the results
Click on the Create button to create the project.
This will create a project as shown below in the IntelliJ.
2. Setup Playwright with Java and JUnit5
Add the Playwright and JUnit5 dependencies to the pom.xml. The latest dependency can be found from here.
After adding the dependency, refresh the project. We will see that the Playwright jar files are downloaded in External Libraries.
3. Project Structure for Maintainability
Creating a well-organized project structure is crucial for maintaining a scalable and efficient automation framework.
Page Classes (src/main/java/.../pages/): Each web page in your application should have a corresponding page class. This class encapsulates all the functionalities of the web page, following the Page Object Model.
Utility Classes (src/main/java/.../utils/): These classes can include various utilities like configuration readers, helper methods for common tasks, etc.
Test Classes (src/test/java/.../tests/): Here, you write your actual test cases, utilizing the page classes.
Test Data Files (src/test/resources/testdata/): Keep your test data, like usernames and passwords, in external files for easy management and to avoid hardcoding.
Maven Configuration (pom.xml): This file manages project dependencies, plugins, and other configurations.
4. Creating Page Object Classes
Page classes serve as an interface to a web page’s UI elements. Each page class corresponds to a page in your application, encapsulating the actions that can be performed on that page.
Identify the UI Elements: Determine all the elements on the web page that your test will interact with, such as text boxes, buttons, and links.
Define Selectors:Store the selectors for these elements in your page class. It’s a best practice to externalize these selectors, but for simplicity, we’ll define them directly in the class.
Implement Actions:Create methods for each action that can be performed on the page, like entering text, clicking buttons, etc.
Creating LoginPage Class
import com.microsoft.playwright.Page;
public class LoginPage {
private Page page;
//Locators
private final String usernameLocator = "input[name='username']";
private final String passwordLocator = "input[name='password']";
private final String submitButton = "button[type='submit']";
private final String errorMessage = "//p[contains(@class, 'oxd-text oxd-text--p oxd-alert-content-text')]";
//Constructor
public LoginPage(Page page){
this.page = page;
}
public void login(String username, String password) {
page.fill(usernameLocator,username);
page.fill(passwordLocator,password);
page.click(submitButton);
}
public String getErrorMessage(){
return page.textContent(errorMessage);
}
}
Creating DashboardPage Class
package org.example.pages;
import com.microsoft.playwright.Page;
public class DashboardPage {
private Page page;
//Locators
private final String dashboardHeading = "//h6[contains(@class, 'oxd-topbar-header-breadcrumb-module')]";
//Constructor
public DashboardPage(Page page) {
this.page = page;
}
// Methods
public String getHeading() {
return page.textContent(dashboardHeading);
}
}
5. Write the Test Scripts
Create a Test files under src/test/java. Use these page classes in your test scripts to perform end-to-end scenarios. This will keep your tests clean and focused on logic rather than details about the UI elements.
A typical test class includes:
Setup Method: Initializes the Playwright browser and other prerequisites before each test.
Test Methods: Individual test cases, each representing a different scenario.
Teardown Method: Closes the browser and performs any cleanup after each test.
Creating BaseTests
This class contains the common variables and methods used throughout the project, like setup and teardown methods.
package org.example.utils;
package com.example.utils;
import com.microsoft.playwright.*;
import org.junit.jupiter.api.*;
// Subclasses will inherit PER_CLASS behavior.
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class BaseTests {
// Shared between all tests in the class.
static Playwright playwright;
static Browser browser;
// New instance for each test method.
BrowserContext context;
protected Page page;
@BeforeAll
public static void launchBrowser() {
playwright = Playwright.create();
browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
}
@AfterAll
public static void closeBrowser() {
playwright.close();
}
@BeforeEach
public void createContextAndPage() {
context = browser.newContext();
page = context.newPage();
page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
}
@AfterEach
public void closeContext() {
context.close();
}
}
Explanation
In JUnit you can initialize Playwright and Browser in @BeforeAll method and destroy them in @AfterAll. Use @TestInstance(TestInstance.Lifecycle.PER_CLASS) annotation to make JUnit create one instance of a class for all test methods within that class (by default each JUnit will create a new instance of the class for each test method). Store Playwright and Browser objects in instance fields. They will be shared between tests. Each instance of the class will use its own copy of Playwright.
1. Playwright playwright:
Initialized to manage the browser automation session, allowing interactions with different browsers.
2. Browser browser:
Declared to store the browser instance that will be shared across test methods within the class.
Playwright playwright;
Browser browser = null;
3. BrowserContext context:
Created anew for each test method to simulate independent browser sessions. This ensures that the browser state doesn’t carry over between tests.
4. Page page:
Represents a single tab or window in a browser used for performing actions and assertions.
BrowserContext context;
Page page;
5. @BeforeAll launchBrowser():
This method is annotated with @BeforeAll, indicating it runs once before any test methods in the current class. The browser is launched in non-headless mode (setHeadless(false)), meaning an actual browser window is opened.
This method runs before each test method in the class, as indicated by the @BeforeEach annotation. It creates a new BrowserContext and a Page, ensuring each test runs in a clean, isolated state. The method also navigates to a login page (“https://opensource-demo.orangehrmlive.com/web/index.php/auth/login”), setting up the initial state for each test.
Runs after each test method, annotated with @AfterMethod. Closes the BrowserContext, effectively closing the browser tab and cleaning up resources.
@AfterAll
public static void closeBrowser() {
playwright.close();
}
8. @AfterEach closeContext()
Runs once after all test methods in the current class have executed, as indicated by the @AfterEach annotation. Closes the Playwright instance, freeing up all resources used for automation.
@AfterEach
public void closeContext() {
context.close();
}
Creating a Login Page Test Class:
We will be automating the following test scenario using Playwright Java and run them in Chromium
Verify the invalid username generates error message “Invalid credentials”
package com.example.tests;
import com.example.pages.DashboardPage;
import com.example.pages.LoginPage;
import com.example.utils.BaseTests;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class LoginTests extends BaseTests {
@Test
public void unsuccessfulLogin() {
LoginPage loginPage = new LoginPage(page);
loginPage.login("abc","abc");
String actualErrorMessage = loginPage.getErrorMessage();
Assertions.assertEquals("Invalid credentials", actualErrorMessage, "");
}
@Test
public void successfulLogin() {
LoginPage loginPage = new LoginPage(page);
loginPage.login("Admin","admin123");
DashboardPage dashboardPage = new DashboardPage(page);
String actualHeading = dashboardPage.getDashboardPageHeading();
Assertions.assertEquals("Dashboard",actualHeading, "Unable to login to the application");
}
}
Explanation
1. successfulLogin
This method enters correct credentials and login to the application.
2. unsuccessfulLogin
This method enter the invalid username and password and click on the Submit button. Then, it assert that the error message generated by the application is equal to “Invalid credentials”.
7. Test Execution through IntelliJ
Go to the Test class and right-click and select Run ‘LoginTests’. The tests will run as JUnit5 tests (in IntelliJ).
Below is the test execution result.
8. Run the tests using the command line
Use the below command to run the tests using the command line.
mvn clean test site
This will run the tests in chromium as mentioned in the .xml file.
Chromium
The output of the above program is
9. JUnit5 Report Generation
Maven Site Plugin creates a folder – site under the target directory.
Right-click on the Junit5 Report.html and open it in the browser.
Recap of Key Points:
Playwright and Java: We explored the powerful combination of Playwright with Java, highlighting the benefits of this duo in automated testing.
Project Structure: An optimal project layout was discussed, emphasizing maintainability and organization.
Page Object Model (POM): The implementation of POM was outlined, showcasing its importance in creating scalable and maintainable test scripts.
Page Classes:We explored the creation of page classes. They are a core component of POM. We provided examples to illustrate their structure. The examples also showed their functionality.
Test Classes:The structure and best practices for writing test classes were covered. This ensures clarity. It also enhances efficiency in your tests.
Welcome to the SpringBoot Quiz! This article delves into the essential concepts and features of Spring Boot. It covers annotations, configuration properties, and metrics. The article also discusses caching mechanisms and shares best practices for building robust applications.
1. Which of the following is true about Spring Boot?
a) Spring Boot is a separate framework and not a part of the Spring ecosystem b) Spring Boot requires manual configuration for every aspect of the application c) Spring Boot simplifies the development of Spring applications by providing an opinionated approach and auto-configuration d) Spring Boot is only suitable for small-scale applications with limited functionality
Answer 1
c) Spring Boot simplifies the development of Spring applications by providing an opinionated approach and auto-configuration
Spring Boot simplifies the development of new Spring applications through convention over configuration and automatic setup. Spring Boot eliminates the need for manual configuration. It provides sensible defaults. It also offers automatic configuration based on classpath scanning and dependency management.
2. What is the purpose of the @ConfigurationProperties annotation?
@ConfigurationProperties(prefix = "app")
public class AppConfig {
private String name;
private String version;
// Getters and setters
}
a) It defines a bean with a specific name. b) It maps properties to a class. c) It creates a REST controller. d) It handles exceptions.
Answer 2
b) It maps properties to a class.
The @ConfigurationProperties annotation is used to bind external properties (e.g., those defined in application.properties or application.yml) to fields in a Java class. In the example provided, properties with keys like “app.name” and “app.version” would be mapped to the fields `name` and `version` in the `AppConfig` class.
3. Which of the following statements is true about the @Autowired annotation in Spring Boot?
a) @Autowired is used to inject dependencies into Spring Boot applications b) @Autowired is only applicable for injecting dependencies of type String c) @Autowired is optional and not required for dependency injection in Spring Boot d) @Autowired is mandatory in Spring Boot and can only be used in service classes
Answer 3
a) @Autowired is used to inject dependencies into Spring Boot applications
Autowired is used to inject dependencies into Spring Boot applications. With Autowired annotation, dependencies can be automatically injected into the dependent class by Springs dependency injection mechanism.
4. What does the @Autowired annotation do in the following code?
@Service
public class ArticleService {
@Autowired
private ArticleRepository articleRepository;
}
a) It creates a new instance of ArticleRepository. b) It injects an existing instance of ArticleRepository c) It defines a REST endpoint d) It marks the class as a Spring component
Answer 4
b) It injects an existing instance of ArticleRepository
The @Autowired annotation is used to inject an existing instance of the ArticleRepositoryinto the ArticleService
5. Which annotation is used to automatically configure a Spring Boot application for RESTful services?
a) @RestController b) @Service c) @Repository d) @Component
Answer 5
a) @RestController
The @RestController annotation is used to define a controller that handles RESTful web service requests.
6. Which of the following code snippets demonstrates the correct configuration of a Spring Boot REST Controller?
a)
@RestController
public class MyController {
@GetMapping("/hello")
public String hello() {
return "Hello, World!";
}
}
b)
@Controller
@RequestMapping("/api")
public class MyController {
@GetMapping("/hello")
public String hello() {
return "Hello, World!";
}
}
c)
@RestController
@RequestMapping("/api")
public class MyController {
@RequestMapping("/hello")
public String hello() {
return "Hello, World!";
}
}
d)
@Controller
public class MyController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
@ResponseBody
public String hello() {
return "Hello, World!";
}
}
Answer 6
Option a) has the correct configuration for a Spring Boot REST Controller utilizing the simplified annotations that Spring provides
Options b) and d) use @Controller which would require @ResponseBody for RESTful outputs if not using @RestController. Option c) incorrectly utilizes @RequestMapping instead of @GetMapping for the GET request.
7. Which of the following code snippets demonstrates the correct configuration of a Spring Boot application class?
a)
@Configuration
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
b)
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
c)
@RestController
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
d)
@Component
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
Answer 7
Option b) demonstrates the correct configuration of a Spring Boot application class. The @SpringBootApplication annotation is used to mark the class as the main application class in Spring Boot.
8. What is the purpose of the @Cacheable annotation?
@Cacheable("articles")
public Article getArticleById(Long id) {
return articleRepository.findById(id).orElse(null);
}
a) It stores the result in the database b) It caches the method’s result c) It logs the method’s execution time d) It defines a scheduled task
Answer 8
b) It caches the method’s result
The @Cacheable annotation caches the result of the method call, so subsequent calls with the same parameters can return the cached result.
9. In the context of Spring Boot, what does @SpringBootTest annotation do?
a) It is used to run unit tests only b) It loads the complete application context for integration tests c) It defines a REST endpoint for testing d) It initializes application properties
Answer 9
b) It loads the complete application context for integration tests
The @SpringBootTest annotation is used to create an application context for integration tests, allowing the entire application to be tested as a whole
10. What type of object is returned by a Spring Boot REST endpoint when using ResponseEntity?
a) A plain Java object b) A JSON string c) An HTTP response with status and body d) A configuration property
Answer 10
c) An HTTP response with status and body
The ResponseEntity class represents an HTTP response, including status code, headers, and body
11. How do you specify an endpoint that accepts JSON data in a POST request?
@PostMapping("/articles")
public ResponseEntity<Article> createArticle(@RequestBody Article article) {
// Save article logic
return ResponseEntity.status(HttpStatus.CREATED).body(savedArticle);
}
Choose one option
a) The endpoint only accepts URL-encoded data b) The method uses @RequestBody to map the request body to an Article object c) The endpoint does not return any response d) The method automatically handles validation
Answer 11
b) The method uses @RequestBody to map the request body to an Article object
The @RequestBody annotation binds the JSON data from the request body to the Article object
12. How do you disable a specific auto-configuration class in Spring Boot?
Choose one option
a) Set auto-configuration.enabled: false for the class b) Use the @DisableAutoConfiguration annotation c) Manually exclude the class from the application context d) Use the exclude attribute of @SpringBootApplication annotation
Answer 12
d) Use the exclude attribute of @SpringBootApplication annotation
The exclude attribute allows specifying auto-configuration classes to be excluded from the auto-configuration process.
13. What does the @PathVariable annotation do in a Spring Boot REST controller?
Choose one option
a) Maps the URL path to a specific request method b) Extracts values from the URL path placeholder c) Links to external web resources d) Automatically authenticates the request
Answer 13
b) Extracts values from the URL path placeholder
The @PathVariable annotation can be used to extract values from the URI template so that the method can use those values
14. How do you specify active profiles in a Spring Boot application?
Choose one option
a) By editing the maven settings.xml b) By specifying profiles in application.properties as spring.profiles.active c) By setting the profile configuration in web.xml d) Spring Boot does not support active profiles
Answer 14
b) By specifying profiles in application.properties as spring.profiles.active
Active profiles can be specified with the spring.profiles.active property, allowing for environment-specific configurations.
15. Which of the following code snippets demonstrates the correct configuration of Spring Boot Security for securing a REST API?
Option c) demonstrates the correct configuration of Spring Boot Security for securing a REST API. The code snippet uses the @Configuration annotation to mark the class as a Spring configuration. The @EnableWebSecurity annotation enables Spring Security features. The configure(HttpSecurity http) method is overridden to define the security rules. In this case, /api/** endpoint is restricted to authenticated users only while allowing public access to all other endpoints. The .httpBasic() method configures basic authentication for the REST API.
16. What is the result of the following code snippet?
@Bean
@ConditionalOnProperty(name = "app.feature.enabled", havingValue = "true")
public MyFeature myFeature() {
return new MyFeature();
}
Choose one option
a) The bean is always created b) The bean is created only if the property is set to true c) The bean is not created at all d) The property must be set to false for the bean to be created
Answer 16
b) The bean is created only if the property is set to true
The @ConditionalOnProperty annotation creates the bean only if the specified property is set to true.
17. In Spring Boot, what does the spring.jpa.hibernate.ddl-auto property control?
Choose one option
a) The caching mechanism b) The logging level of Hibernate c) The automatic schema generation strategy d) The transaction management settings
Answer 17
c) The automatic schema generation strategy
The spring.jpa.hibernate.ddl-auto property controls how Hibernate handles schema generation, such as create, update, or none.
18. Which of the following statements is true about Spring Database integration?
a) Spring provides a built-in database management system for relational databases b) Spring only supports integration with SQL Server and Oracle databases c) Spring provides support for accessing and interacting with databases through JDBC and Object-Relational Mapping (ORM) frameworks d) Spring Database integration is limited to NoSQL databases only
Answer 18
c) Spring provides support for accessing and interacting with databases through JDBC and Object-Relational Mapping (ORM) frameworks
Spring Framework, along with Spring Boot, offers comprehensive support for database access, including integration with JDBC and various ORM frameworks like Hibernate and JPA. This support extends across a wide range of relational and non-relational databases, facilitating easy configuration, transaction management, and data access within applications.
19. Which of the following is true about Spring Security?
a) Spring Security is a framework that provides authentication and authorization support for Spring-based applications b) Spring Security is only applicable for securing web applications and does not support other types of applications c) Spring Security is a stand-alone framework and cannot be integrated with other Spring modules d) Spring Security does not provide any out-of-the-box support for implementing multi-factor authentication
Answer 19
a) Spring Security is a framework that provides authentication and authorization support for Spring-based applications
It allows developers to easily secure their applications against common security vulnerabilities. It also has support for various authentication mechanisms, such as form-based, HTTP Basic, and OAuth.
20. How can you define a scheduled task in a Spring Boot application?
@Scheduled(fixedRate = 2000)
public void reportCurrentTime() {
System.out.println("Current time: " + new Date());
}
Choose one option
a) It runs every 2 seconds b) It is triggered by an event c) It executes only once d) It runs at application startup only
Answer 20
a) It runs every 2 seconds
21. Which of the following layers is not part of a typical Spring Boot application?
a) DAO layer b) Logger layer c) Service layer d) Controller layer
Answer 21
b) Logger layer
Common layers in a Spring Boot application include the DAO, Service, and Controller layers; logging is a cross-cutting concern, not a separate layer.
22. What is the default package used in a Spring Boot project if none is specified?
a) main.java b) default.package c) org.springframework.boot d) The root package specified in the @SpringBootApplication class
Answer 22
d) The root package specified in the @SpringBootApplication class
The @SpringBootApplication annotation triggers auto-configuration only within its package and sub-packages, so it acts as the root package if not specified.
23. How can you disable the default web server in a Spring Boot application in build process?
a) Set server.enabled: false in application.properties b) Set server.port: 0 in application.properties c) Use the @DisableWebServer annotation d) Use a command-line argument to set the server port to 0
Answer 23
b) Set server.port: 0 in application.properties
Setting the server port to 0 effectively disables the embedded web server.
24. How can you switch from using the default Tomcat server to Jetty in a Spring Boot application?
a) Modify server.xml b) Change the server property in application.properties c) Exclude Tomcat and include Jetty dependencies in pom.xml d) Use @EnableJetty annotation
Answer 24
c) Exclude Tomcat and include Jetty dependencies in pom.xml
Tomcat is included by default, so you must exclude it and add Jetty’s dependencies to switch the server.
25. What is Actuator in Spring Boot?
a) A tool to monitor and manage applications b) A GUI design tool c) A security framework d) A configuration tool
Answer 25
a) A tool to monitor and manage applications
Spring Boot Actuator provides various endpoints for monitoring and managing the application, such as health checks and metrics.
We would love to hear from you! Please leave your comments and share your scores in the section below
Large test suites can be structured to optimize ease of authoring and maintenance. Page object models are one such approach to structure the test suite. In this tutorial blog, we will learn to create and set up the project using Page Object Model in Playwright Java and TestNG.
Page Object Model (POM) is a design pattern used in test automation that enhances test maintenance and reduces code duplication where web pages are represented as classes, and the various elements on the page are defined as variables in the class and all possible user interactions can then be implemented as methods in the class.
Why is Page Object Model Important?
1. Improved Test Maintenance: POM allows for easy updates to test scripts when the UI changes. By separating the test logic from the page definitions, only the page objects need to be updated rather than all test scripts.
2. Maintainability: In this model, separate classes are created for different pages of a web application like login page, the home page, employee detail page, change password page, etc. So, if there is any change in any element of a website then we only need to make changes in one class, and not in all classes.
3. Reusability of Code: Shared page objects can be reused across multiple test cases, reducing redundancy. This ensures consistent interactions with web elements and actions, making the test code more efficient and easier to manage.
4. Facilitates Collaboration: A well-structured POM increases collaboration among teams, as each contributor can work on different parts of the application without interfering with one another. This approach helps in managing multiple test scenarios simultaneously.
5. Ease of Debugging: With POM, finding and fixing bugs becomes more straightforward since each page action is located in a specific place. Developers can easily pinpoint the location of a problem without sifting through complex test logic.
System requirements
The following prerequisites are required to be installed on the machine to begin with a smooth setup and installation.
Java 11 or higher
IntelliJ IDE or any other IDE to create a project
Maven
Browsers on which tests need to be run, like Chrome, Firefox, etc.
Implementation Steps
1. Create a new Maven Project
The first step in setup is to create a new Maven project. I will be using IntelliJ in this tutorial. The following steps need to be followed to create a new Maven project :
Open IntelliJ, Navigate to File >> New >> Project
2. In the New Project window, enter the following details:
Name of the Project – Playwright_TestNG_Demo
Location/path where the project needs to be saved – Documents/Playwright (my location)
Select JDK version — I am using JDK 17
Archetype — Search for “quickstart” and select maven-archetype-quickstart from the results
Click on the Create button to create the project.
This will create a project as shown below in the IntelliJ.
2. Set Up the Environment
Add the Playwright and TestNG dependencies to the pom.xml. The latest dependency can be found here.
After adding the dependency, refresh the project. We will see that the Playwright jar files are downloaded in External Libraries.
3. Project Structure for Maintainability
Creating a well-organized project structure is crucial for maintaining a scalable and efficient automation framework.
1. Page Classes (src/main/java/.../pages/): Each web page in your application should have a corresponding page class. This class encapsulates all the functionalities of the web page, following the Page Object Model.
2. Utility Classes (src/main/java/.../utils/): These classes can include various utilities like configuration readers, helper methods for common tasks, etc.
3. Test Classes (src/test/java/.../tests/): Here, you write your actual test cases, utilizing the page classes.
4. Test Data Files (src/test/resources/testdata/): Keep your test data in external files. This ensures easy management. It also helps to avoid hardcoding usernames and passwords.
5. Maven Configuration (pom.xml): This file manages project dependencies, plugins, and other configurations.
6. testng.xml: This file is the central configuration file that defines how the test suite should be executed.
4. Creating Page Object Classes
Page classes serve as an interface to a web page’s UI elements. Each page class corresponds to a page in your application, encapsulating the actions that can be performed on that page.
Identify the UI Elements: Determine all the elements on the web page that your test will interact with, such as text boxes, buttons, and links.
Define Selectors: Store the selectors for these elements in your page class. It’s a best practice to externalize these selectors, but for simplicity, we’ll define them directly in the class.
Implement Actions:Create methods for each action that can be performed on the page, like entering text, clicking buttons, etc.
Creating LoginPage Class
import com.microsoft.playwright.Page;
public class LoginPage {
private Page page;
//Locators
private final String usernameLocator = "input[name='username']";
private final String passwordLocator = "input[name='password']";
private final String submitButton = "button[type='submit']";
private final String errorMessage = "//p[contains(@class, 'oxd-text oxd-text--p oxd-alert-content-text')]";
//Constructor
public LoginPage(Page page){
this.page = page;
}
public void login(String username, String password) {
page.fill(usernameLocator,username);
page.fill(passwordLocator,password);
page.click(submitButton);
}
public String getErrorMessage(){
return page.textContent(errorMessage);
}
}
Creating DashboardPage Class
package org.example.pages;
import com.microsoft.playwright.Page;
public class DashboardPage {
private Page page;
//Locators
private final String dashboardHeading = "//h6[contains(@class, 'oxd-topbar-header-breadcrumb-module')]";
//Constructor
public DashboardPage(Page page) {
this.page = page;
}
// Methods
public String getHeading() {
return page.textContent(dashboardHeading);
}
}
5. Write the Test Scripts
Create a Test files under src/test/java. Use these page classes in your test scripts to perform end-to-end scenarios. This will keep your tests clean and focused on logic rather than details about the UI elements.
A typical test class includes:
Setup Method: Initializes the Playwright browser and other prerequisites before each test.
Test Methods: Individual test cases, each representing a different scenario.
Teardown Method:Closes the browser and performs any cleanup after each test.
We will be automating the following test scenario using Playwright Java and run them in Chromium.
Verify the invalid username generates error message “Invalid credentials”
Creating BaseClass
This class contains the common variables and methods used throughout the project, like setup and teardown methods.
package org.example.utils;
import com.microsoft.playwright.*;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
public class BaseTests {
// Shared between all tests in this class.
protected Playwright playwright;
protected Browser browser;
// New instance for each test method.
protected BrowserContext context;
protected Page page;
@BeforeClass
public void launchBrowser() {
playwright = Playwright.create();
browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
}
@BeforeMethod
public void createContextAndPage() {
context = browser.newContext();
page = context.newPage();
page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
}
@AfterMethod
public void closeContext() {
context.close();
}
@AfterClass
public void closeBrowser() {
playwright.close();
}
}
Explanation
1. Playwright playwright:
Initialized to manage the browser automation session, allowing interactions with different browsers.
2. Browser browser:
Declared to store the browser instance that will be shared across test methods within the class.
Playwright playwright;
Browser browser = null;
3. BrowserContext context:
Created anew for each test method to simulate independent browser sessions. This ensures that the browser state doesn’t carry over between tests.
4. Page page:
Represents a single tab or window in a browser used for performing actions and assertions.
BrowserContext context;
Page page;
5. @BeforeClass:
This method is annotated with @BeforeClass, indicating it runs once before any test methods in the current class. The browser is launched in non-headless mode (setHeadless(false)), meaning an actual browser window is opened.
This method runs before each test method in the class, as indicated by the @BeforeMethod annotation. It creates a new BrowserContext and a Page, ensuring each test runs in a clean, isolated state. The method also navigates to a login page (“https://opensource-demo.orangehrmlive.com/web/index.php/auth/login”), setting up the initial state for each test.
Runs once after all test methods in the current class have executed, as indicated by the @AfterClass annotation. Closes the Playwright instance, freeing up all resources used for automation.
package org.example.tests;
import org.example.pages.DashboardPage;
import org.example.pages.LoginPage;
import org.example.utils.BaseTests;
import org.testng.Assert;
import org.testng.annotations.Test;
public class LoginTests extends BaseTests {
@Test
public void loginToApplication(){
LoginPage loginPage = new LoginPage(page);
loginPage.login("Admin","admin123");
DashboardPage dashboardPage = new DashboardPage(page);
String actualHeading = dashboardPage.getHeading();
Assert.assertEquals(actualHeading,"Dashboard", "Unable to login to the application");
}
@Test
public void invalidCredentials() {
LoginPage loginPage = new LoginPage(page);
loginPage.login("Playwright","test");
Assert.assertEquals(loginPage.getErrorMessage(), "Invalid credentials" ,"Incorrect Error Message is displayed");
}
}
Explanation
1. loginToApplication
This method enters correct credentials and login to the application.
2. verifyInvalidCredentials
This method enter the invalid username and password and click on the Submit button. Then, it assert that the error message generated by the application is equal to “Invalid credentials”.
6. Create testng.xml
We need to specify the values of browser in the TestNG XML file that will pass to the test case file. Let’s create a testng.xml file to run the test using TestNG.
Right click on the project, New >> File
Below is the sample testng.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Page Object Model Playwright test suite">
<test name="Chrome Test">
<parameter name="browser" value="chromium" />
<classes>
<class name="org.example.tests.LoginTests"/>
</classes>
</test>
</suite>
7. Test Execution through IntelliJ
Go to the Test class and right-click and select Run ‘LoginTests’. The tests will run as TestNG tests (in IntelliJ).
Below is the test execution result.
8. Run the tests from TestNG.xml
Execute the tests by right-clicking on testng.xml and select Run ‘…testng.xml’
This will run the tests in chromium as mentioned in the .xml file.
The output of the above program is
9. TestNG Report Generation
TestNG generates various types of reports under test-output folder like emailable-report.html, index.html, testng-results.xml.
We are interested in the “emailable-report.html” report. Open “emailable-report.html“, as this is an HTML report, and open it with the browser. The below image shows emailable-report.html.
TestNG also produces an “index.html” report, and it resides under the test-output folder. The below image shows the index.html report. This is the latest theme of the report.
Recap of Key Points:
Playwright and Java:We explored the powerful combination of Playwright with Java. We highlighted the benefits of this duo in automated testing.
Project Structure:An optimal project layout was discussed, emphasizing maintainability and organization.
Page Object Model (POM): The implementation of POM was outlined, showcasing its importance in creating scalable and maintainable test scripts.
Page Classes:We explored how to create page classes, which are a core component of POM. We also provided examples to illustrate their structure. These examples demonstrate their functionality.
Test Classes:We covered the structure and best practices for writing effective test classes. This ensures clarity and efficiency in your tests.
In this tutorial, we will learn to create and set up the project using Cross Browser Testing in Playwright Java.
Cross-browser testing with Playwright and Java allows us to ensure consistent functionality in a web application. This can be achieved across major browser engines using a single, unified API. Playwright supports Chromium (Chrome/Edge), Firefox, and WebKit (Safari), enabling true engine-level testing rather than browser emulation.
Cross-browser testing is the process of checking whether a website or web application functions correctly and looks consistent across multiple web browsers, operating systems, and devices. This includes checking compatibility with various versions of browsers like Chrome, Firefox, Safari, Edge, and Internet Explorer, among others.
Why is Cross-Browser Testing Important?
1. User Experience: Different users use different browsers. Ensuring your website works smoothly across all of them enhances the overall user experience.
2. Functionality Testing: Different browsers can interpret HTML, CSS, and JavaScript differently. Cross-browser testing ensures all the functionality of your website works correctly, without errors or display issues.
Real Example:
Imagine a large e-commerce website like Amazon. Their site needs to function seamlessly across all browsers. This ensures users can view products. They can add items to the cart. They can also make purchases smoothly. Amazon employs cross-browser testing to ensure that images load correctly. Checkout processes function without glitches. Every element displays properly across various browsers and devices.
System requirements
The following prerequisites are required to be installed on the machine to begin with a smooth setup and installation.
Java 8 or higher
IntelliJ IDE or any other IDE to create a project
Maven
Browsers on which tests need to be run, like Chrome, Firefox, etc.
Implementation Steps
1. Create a new Maven Project
The first step in setup is to create a new Maven project. I will be using IntelliJ in this tutorial. The next steps need to be followed to create a new Maven project :
Open IntelliJ, Navigate to File >> New >> Project
2. In the New Project window, enter the following details:
Name of the Project – Playwright_TestNG_Demo
Location/path where the project needs to be saved – Documents/Playwright (my location)
Select JDK version — I am using JDK 17
Archetype — Search for “quickstart”and select maven-archetype-quickstartfrom the results
Click on the Create button to create the project.
This will create a project as shown in IntelliJ.
2. Setup Playwright with Java
Add the Playwright Java and TestNG dependencies to the pom.xml. The latest dependency can be found here.
Verify that the invalid username generates an error message “Invalid credentials”
Let us create a helper class that includes the methods to initialize and close the browser.
package com.example;
import com.microsoft.playwright.*;
import org.testng.annotations.*;
public class BaseClass {
// Shared between all tests in this class.
Playwright playwright;
Browser browser = null;
// New instance for each test method.
BrowserContext context;
Page page;
@BeforeClass
@Parameters("browser")
void launchBrowser(String browserName) {
playwright = Playwright.create();
BrowserType browserType = null;
if (browserName.equals("chromium")) {
browserType = playwright.chromium();
} else if (browserName.equals("firefox")) {
browserType = playwright.firefox();
} else if (browserName.equals("webkit")) {
browserType = playwright.webkit();
}
browser = browserType.launch(new BrowserType.LaunchOptions().setHeadless(false));
}
@BeforeMethod
void createContextAndPage() {
context = browser.newContext();
page = context.newPage();
page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
}
@AfterMethod
void closeContext() {
context.close();
}
@AfterClass
void closeBrowser() {
playwright.close();
}
}
Explanation
1. Playwright playwright:
Initialized to manage the browser automation session, allowing interactions with different browsers.
2. Browser browser:
Declared to store the browser instance that will be shared across test methods within the class.
Playwright playwright;
Browser browser = null;
3. BrowserContext context:
Created anew for each test method to simulate independent browser sessions. This ensures that the browser state doesn’t carry over between tests.
4. Page page:
Represents a single tab or window in a browser used for performing actions and assertions.
BrowserContext context;
Page page;
5. @BeforeClass:
This method is annotated with @BeforeClass, indicating it runs once before any test methods in the current class. It is parameterized (@Parameters(“browser”)) to accept a browser name as input, allowing the test to be run with different browsers. Depending on the browserName (chromium, firefox, or webkit), the corresponding Playwright BrowserType is used. The browser is launched in non-headless mode (setHeadless(false)), meaning an actual browser window is opened.
This method runs before each test method in the class, as indicated by the @BeforeMethod annotation. It creates a new BrowserContext and Page, ensuring each test runs in a clean, isolated state. The method also navigates to a login page (“https://opensource-demo.orangehrmlive.com/web/index.php/auth/login”), setting up the initial state for each test.
Runs once after all test methods in the current class have executed, as indicated by the @AfterClass annotation. Closes the Playwright instance, freeing up all resources used for automation.
This method verifies that the title of the web page is “OrangeHRM”.
2. verifyInvalidCredentials
This method enters an invalid username and password and clicks on the Submit button. Then, it asserts that the error message generated by the application is equal to “Invalid credentials”.
4. Create testng.xml
We need to specify the values of the browser in the TestNG XML file that will be passed to the test case file. Let’s create a testng.xml file to run the test using TestNG.
Go to the Test class and right-click and select Run ‘TestNG_Demo_Tests’. The tests will run as TestNG tests (in IntelliJ).
Below is the test execution result.
All the tests have failed with the error message – Parameter ‘browser’ is required by BeforeClass on method launchBrowser but has not been marked @Optional or defined. Parameter is expecting to get the browser name either through the command line or testng.xml which we have not provided.
We can mark the launchBrowser() method with Optional, so that if we don’t provide the browser name through testng.xml, it will run the tests on Chromium.
Execute the tests by right-clicking on crossbrowser_testng.xml and select Run ‘…\crossbrowser_testng.xml’
This will run the tests in all 3 browsers as mentioned in the .xml file.
Chromium
Firefox
Webkit
The output of the above program is
7. TestNG Report Generation
TestNG generates various types of reports under test-output folder like emailable-report.html, index.html, testng-results.xml.
We are interested in the “emailable-report.html” report. Open “emailable-report.html”, as this is an HTML report, and open it with the browser. The image shows emailable-report.html.
TestNG also produces an “index.html” report, and it resides under the test-output folder. The image shows the index.html report.
Conclusion:
Playwright and Java: We explored the powerful combination of Playwright with Java, highlighting the benefits of this duo in automated testing.
Setup & Configuration: Playwright integrates easily with Java projects via Maven or Gradle and manages browser installation automatically. Minimal configuration is required to get started.
TestNG Parameters: Dynamically inject browsers into tests.
Browser Support: Playwright supports Chromium (Chrome, Edge), Firefox, and WebKit (Safari). Tests run against real browser engines, offering high confidence in cross-browser compatibility.
Test Execution Approach: The same test logic can be executed across different browsers. This is done by switching the browser type programmatically or via system properties. This avoids code duplication and improves maintainability.
In this tutorial blog, we will learn to create and set up the project using Playwright Java with JUnit5. JUnit 5 controls the test lifecycle. Playwright controls the browser automation.
The following prerequisites are required to be installed on the machine to begin with a smooth setup and installation.
Java 8 or higher
IntelliJ IDE or any other IDE to create a project
Maven
Browsers on which tests need to be run, like Chrome, Firefox, etc.
Basic Lifecycle Mapping
JUnit 5 Annotation
Purpose
Playwright Action
@BeforeAll
Run once before all tests
Create Playwright + launch Browser
@BeforeEach
Run before every test
Create Context + Page
@AfterEach
Run after every test
Close Page + Context
@AfterAll
Run once after all tests
Close Browser + Playwright
Implementation Steps
1. Create a new Maven Project
The first step in setup is to create a new Maven project. I will be using IntelliJ in this tutorial. The following steps need to be followed to create a new Maven project :
Open IntelliJ, Navigate to File >> New >> Project
2. In the New Project window, enter the following details:
Name of the Project – Playwright_JUnit5_Demo
Location/path where the project needs to be saved – Documents/Playwright (my location)
Select JDK version — I am using JDK 17
Archetype — Search for “quickstart” and select maven-archetype-quickstart from the results
Click on the Create button to create the project.
This will create a project as shown below in the IntelliJ.
2. Setup Playwright with Java and JUnit5
Add the Playwright and JUnit5 dependencies to the pom.xml. The latest dependency can be found here.
Verify the successful login leads to Dashboard page
Verify the invalid username generates error message “Invalid credentials”
Below is the sample code for the above scenario. The test is using Chromium browser.
Let’s create a base test class that will be used by all our tests. It will set up Playwright and create a browser instance. The base test class will also create a new browser context and a new page for each test method.
package com.example;
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserContext;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;
import org.junit.jupiter.api.*;
// Subclasses will inherit PER_CLASS behavior.
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class BaseClass {
// Shared between all tests in the class.
Playwright playwright;
Browser browser;
@BeforeAll
void launchBrowser() {
playwright = Playwright.create();
browser = playwright.chromium().launch();
}
@AfterAll
void closeBrowser() {
playwright.close();
}
// New instance for each test method.
BrowserContext context;
Page page;
@BeforeEach
void createContextAndPage() {
context = browser.newContext();
page = context.newPage();
page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
}
@AfterEach
void closeContext() {
context.close();
}
}
Explanation
1. Use @TestInstance(TestInstance.Lifecycle.PER_CLASS) annotation to make JUnit create one instance of a class for all test methods within that class (by default each JUnit will create a new instance of the class for each test method).
2. Browser browser
Declared to store the browser instance that will be shared across test methods within the class.
Playwright playwright;
Browser browser;
3. BrowserContext context
Created anew for each test method to simulate independent browser sessions. This ensures that the browser state doesn’t carry over between tests.
4. Page page
Represents a single tab or window in a browser used for performing actions and assertions.
BrowserContext context;
Page page;
5. @BeforeAll
This method is annotated with @BeforeAll, indicating run this method once before ALL tests in this class.
The browser is launched in Chromium and non-headless mode (setHeadless(false)), meaning an actual browser window is opened.
6. @BeforeEachcreateContextAndPage()
This method runs before each test method in the class, as indicated by the@BeforeEach annotation. It creates a new BrowserContextand a Page, ensuring each test runs in a clean, isolated state. The method also navigates to a login page (“https://opensource-demo.orangehrmlive.com/web/index.php/auth/login”), setting up the initial state for each test.
This method is used to verify the heading of the application.
2. verifyLogin method
This method verifies that the application is successfully logged in using the correct credentials.
3. verifyInvalidCredentials method
This method asserts that an error message is generated when invalid username or password is entered in the login page.
4. Test Execution through IntelliJ
Go to the Test class and right-click and select Run ‘Playwright_Tests’ (in IntelliJ).
By default, the tests are run in headless mode, so the browser UI is not loaded.
Below is the test execution result.
5. Run the tests from command line
Execute the tests by using the below command:-
mvn clean test site
6. JUnit5 Report generation
Maven Site Plugin creates a folder – site under the target directory.
Junit also produces an “index.html” report, and it resides under the target folder. The below image shows the index.html report. This is the latest theme of the report.
The following prerequisites are required to be installed on the machine to begin with a smooth setup and installation.
Java 8 or higher
IntelliJ IDE or any other IDE to create a project
Maven
Browsers on which tests need to be run, like Chrome, Firefox, etc.
Implementation Steps
1. Create a new Maven Project
The first step in setup is to create a new Maven project. I will be using IntelliJ in this tutorial. The following steps need to be followed to create a new Maven project :
Open IntelliJ, Navigate to File >> New >> Project
2. In the New Project window, enter the following details:
Name of the Project – Playwright_TestNG_Demo
Location/path where the project needs to be saved – Documents/Playwright (my location)
Select JDK version — I am using JDK 17
Archetype — Search for “quickstart” and select maven-archetype-quickstart from the results
Click on the Create button to create the project.
This will create a project as shown below in the IntelliJ.
2. Update the Dependencies
Add the Playwright and TestNG dependencies to the pom.xml. The latest dependency can be found from here.
After adding the dependency, refresh the project. We will see that the Playwright and testng jar files are downloaded in External Libraries.
3. Create testng.xml
Let’s create a testng.xml file to run the test using TestNG.
Right click on the project, New >> File
It will help us execute the other tests by adding the test method name to the methods block in the file.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Playwright test suite">
<test name="Integration of Playwright Java with TestNG">
<classes>
<class name="com.example.TestNG_Demo_Tests">
</class>
</classes>
</test>
</suite>
4. Write the tests
Create a Test file under src/test/java called – TestNG_Demo_Tests.
We will be automating the following test scenario using Playwright Java.
Initialized to manage the browser automation session, allowing interactions with different browsers.
2. Browser browser
Declared to store the browser instance that will be shared across test methods within the class.
Playwright playwright;
Browser browser = null;
3. BrowserContext context
Created anew for each test method to simulate independent browser sessions. This ensures that the browser state doesn’t carry over between tests.
4. Page page
Represents a single tab or window in a browser used for performing actions and assertions.
BrowserContext context;
Page page;
5. @BeforeClass
This method is annotated with @BeforeClass, indicating it runs once before any test methods in the current class.
The browser is launched in Chromium and non-headless mode (setHeadless(false)), meaning an actual browser window is opened.
6. @BeforeMethod createContextAndPage()
This method runs before each test method in the class, as indicated by the@BeforeMethod annotation. It creates a new BrowserContextand a Page, ensuring each test runs in a clean, isolated state. The method also navigates to a login page (“https://opensource-demo.orangehrmlive.com/web/index.php/auth/login”), setting up the initial state for each test.
Runs once after all test methods in the current class have executed, as indicated by the @AfterClass annotation. Closes the Playwright instance, freeing up all resources used for automation.
Go to the Test class and right-click and select Run ‘TestNG_Demo_Tests’. The tests will run as TestNG tests (in IntelliJ).
By default, the tests are run in headless mode, so the browser UI is not loaded.
Below is the test execution result.
6. Run the tests from TestNG.xml
Execute the tests by right-clicking on testng.xml and select Run ‘…\testng.xml’
Below is the test execution result.
7. TestNG Report Generation
TestNG generates various types of reports under test-output folder like emailable-report.html, index.html, testng-results.xml.
We are interested in the “emailable-report.html” report. Open “emailable-report.html“, as this is an HTML report, and open it with the browser. The below image shows emailable-report.html.
TestNG also produces an “index.html” report, and it resides under the test-output folder. The below image shows the index.html report. This is the latest theme of the report.