├── .gitignore ├── Jenkinsfile ├── pom.xml └── src ├── main └── java │ └── com │ └── qa │ └── opencart │ ├── constants │ └── AppConstants.java │ ├── factory │ └── PlaywrightFactory.java │ ├── listeners │ └── ExtentReportListener.java │ └── pages │ ├── HomePage.java │ └── LoginPage.java └── test ├── java └── com │ └── qa │ └── opencart │ ├── base │ └── BaseTest.java │ └── tests │ ├── HomePageTest.java │ └── LoginPageTest.java └── resources ├── config └── config.properties └── testrunners └── testng_regressions.xml /.gitignore: -------------------------------------------------------------------------------- 1 | allure-results/ 2 | screenshots/ 3 | screenshot/ 4 | test-output/ 5 | build/ 6 | 7 | application.log 8 | ############################## 9 | ## Java 10 | ############################## 11 | .mtj.tmp/ 12 | *.class 13 | *.jar 14 | *.war 15 | *.ear 16 | *.nar 17 | hs_err_pid* 18 | activityLog.log 19 | ############################## 20 | ## Maven 21 | ############################## 22 | target/ 23 | pom.xml.tag 24 | pom.xml.releaseBackup 25 | pom.xml.versionsBackup 26 | pom.xml.next 27 | pom.xml.bak 28 | release.properties 29 | dependency-reduced-pom.xml 30 | buildNumber.properties 31 | .mvn/timing.properties 32 | .mvn/wrapper/maven-wrapper.jar 33 | 34 | ############################## 35 | ## IntelliJ 36 | ############################## 37 | out/ 38 | .idea/ 39 | .idea_modules/ 40 | *.iml 41 | *.ipr 42 | *.iws 43 | ############################## 44 | ## Eclipse 45 | ############################## 46 | .settings/ 47 | bin/ 48 | tmp/ 49 | .metadata 50 | .classpath 51 | .project 52 | *.tmp 53 | *.bak 54 | *.swp 55 | *~.nib 56 | local.properties 57 | .loadpath 58 | .factorypath 59 | 60 | ## OS X 61 | ############################## 62 | .DS_Store 63 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline 2 | { 3 | agent any 4 | 5 | tools{ 6 | maven 'maven' 7 | } 8 | 9 | stages 10 | { 11 | stage('Build') 12 | { 13 | steps 14 | { 15 | git 'https://github.com/jglick/simple-maven-project-with-tests.git' 16 | sh "mvn -Dmaven.test.failure.ignore=true clean package" 17 | } 18 | post 19 | { 20 | success 21 | { 22 | junit '**/target/surefire-reports/TEST-*.xml' 23 | archiveArtifacts 'target/*.jar' 24 | } 25 | } 26 | } 27 | 28 | 29 | 30 | stage("Deploy to QA"){ 31 | steps{ 32 | echo("deploy to qa") 33 | } 34 | } 35 | 36 | stage('Regression Automation Test') { 37 | steps { 38 | catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { 39 | git 'https://github.com/naveenanimation20/Playwright-Java-PageObjectModel' 40 | sh "mvn clean test -Dsurefire.suiteXmlFiles=src/test/resources/testrunners/testng_regressions.xml" 41 | 42 | } 43 | } 44 | } 45 | 46 | 47 | stage('Publish Extent Report'){ 48 | steps{ 49 | publishHTML([allowMissing: false, 50 | alwaysLinkToLastBuild: false, 51 | keepAll: true, 52 | reportDir: 'build', 53 | reportFiles: 'TestExecutionReport.html', 54 | reportName: 'HTML Extent Report', 55 | reportTitles: '']) 56 | } 57 | } 58 | 59 | 60 | 61 | 62 | } 63 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 4.0.0 7 | 8 | PlaywrightPOMSeries 9 | PlaywrightPOMSeries 10 | 0.0.1-SNAPSHOT 11 | 12 | PlaywrightPOMSeries 13 | 14 | http://www.example.com 15 | 16 | 17 | UTF-8 18 | 1.8 19 | 1.8 20 | 5.0.8 21 | 22 | 23 | 24 | 25 | 26 | 27 | com.microsoft.playwright 28 | playwright 29 | 1.25.0 30 | 31 | 32 | 33 | org.testng 34 | testng 35 | 6.14.3 36 | 37 | 38 | 39 | com.aventstack 40 | extentreports 41 | ${extentreports-version} 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | org.apache.maven.plugins 52 | maven-compiler-plugin 53 | 3.8.1 54 | 55 | 1.8 56 | 1.8 57 | 58 | 59 | 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-surefire-plugin 64 | 2.20 65 | 66 | 67 | 3 68 | true 69 | -Xmx1024m -XX:MaxPermSize=256m 70 | 71 | src/test/resources/testrunners/testng_regressions.xml 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /src/main/java/com/qa/opencart/constants/AppConstants.java: -------------------------------------------------------------------------------- 1 | package com.qa.opencart.constants; 2 | 3 | public class AppConstants { 4 | 5 | 6 | public static final String HOME_PAGE_TITLE = "Your Store"; 7 | 8 | public static final String LOGIN_PAGE_TITLE = "Account Login"; 9 | 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/qa/opencart/factory/PlaywrightFactory.java: -------------------------------------------------------------------------------- 1 | package com.qa.opencart.factory; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | import java.nio.file.Paths; 7 | import java.util.Base64; 8 | import java.util.Properties; 9 | 10 | import com.microsoft.playwright.Browser; 11 | import com.microsoft.playwright.BrowserContext; 12 | import com.microsoft.playwright.BrowserType; 13 | import com.microsoft.playwright.BrowserType.LaunchOptions; 14 | import com.microsoft.playwright.Page; 15 | import com.microsoft.playwright.Playwright; 16 | 17 | public class PlaywrightFactory { 18 | 19 | Playwright playwright; 20 | Browser browser; 21 | BrowserContext browserContext; 22 | Page page; 23 | Properties prop; 24 | 25 | private static ThreadLocal tlBrowser = new ThreadLocal<>(); 26 | private static ThreadLocal tlBrowserContext = new ThreadLocal<>(); 27 | private static ThreadLocal tlPage = new ThreadLocal<>(); 28 | private static ThreadLocal tlPlaywright = new ThreadLocal<>(); 29 | 30 | public static Playwright getPlaywright() { 31 | return tlPlaywright.get(); 32 | } 33 | 34 | public static Browser getBrowser() { 35 | return tlBrowser.get(); 36 | } 37 | 38 | public static BrowserContext getBrowserContext() { 39 | return tlBrowserContext.get(); 40 | } 41 | 42 | public static Page getPage() { 43 | return tlPage.get(); 44 | } 45 | 46 | public Page initBrowser(Properties prop) { 47 | 48 | String browserName = prop.getProperty("browser").trim(); 49 | System.out.println("browser name is : " + browserName); 50 | 51 | // playwright = Playwright.create(); 52 | tlPlaywright.set(Playwright.create()); 53 | 54 | switch (browserName.toLowerCase()) { 55 | case "chromium": 56 | tlBrowser.set(getPlaywright().chromium().launch(new BrowserType.LaunchOptions().setHeadless(false))); 57 | break; 58 | case "firefox": 59 | tlBrowser.set(getPlaywright().firefox().launch(new BrowserType.LaunchOptions().setHeadless(false))); 60 | break; 61 | case "safari": 62 | tlBrowser.set(getPlaywright().webkit().launch(new BrowserType.LaunchOptions().setHeadless(false))); 63 | break; 64 | case "chrome": 65 | tlBrowser.set( 66 | getPlaywright().chromium().launch(new LaunchOptions().setChannel("chrome").setHeadless(false))); 67 | break; 68 | case "edge": 69 | tlBrowser.set( 70 | getPlaywright().chromium().launch(new LaunchOptions().setChannel("msedge").setHeadless(false))); 71 | break; 72 | 73 | default: 74 | System.out.println("please pass the right browser name......"); 75 | break; 76 | } 77 | 78 | tlBrowserContext.set(getBrowser().newContext()); 79 | tlPage.set(getBrowserContext().newPage()); 80 | getPage().navigate(prop.getProperty("url").trim()); 81 | return getPage(); 82 | 83 | } 84 | 85 | /** 86 | * this method is used to initialize the properties from config file 87 | */ 88 | public Properties init_prop() { 89 | 90 | try { 91 | FileInputStream ip = new FileInputStream("./src/test/resources/config/config.properties"); 92 | prop = new Properties(); 93 | prop.load(ip); 94 | } catch (FileNotFoundException e) { 95 | e.printStackTrace(); 96 | } catch (IOException e) { 97 | e.printStackTrace(); 98 | } 99 | 100 | return prop; 101 | 102 | } 103 | 104 | /** 105 | * take screenshot 106 | * 107 | */ 108 | 109 | public static String takeScreenshot() { 110 | String path = System.getProperty("user.dir") + "/screenshot/" + System.currentTimeMillis() + ".png"; 111 | //getPage().screenshot(new Page.ScreenshotOptions().setPath(Paths.get(path)).setFullPage(true)); 112 | 113 | byte[] buffer = getPage().screenshot(new Page.ScreenshotOptions().setPath(Paths.get(path)).setFullPage(true)); 114 | String base64Path = Base64.getEncoder().encodeToString(buffer); 115 | 116 | return base64Path; 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/com/qa/opencart/listeners/ExtentReportListener.java: -------------------------------------------------------------------------------- 1 | package com.qa.opencart.listeners; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.Files; 5 | import java.nio.file.Path; 6 | import java.nio.file.Paths; 7 | import java.util.Calendar; 8 | import java.util.Date; 9 | 10 | import org.testng.ITestContext; 11 | import org.testng.ITestListener; 12 | import org.testng.ITestResult; 13 | 14 | import com.aventstack.extentreports.ExtentReports; 15 | import com.aventstack.extentreports.ExtentTest; 16 | import com.aventstack.extentreports.MediaEntityBuilder; 17 | import com.aventstack.extentreports.reporter.ExtentSparkReporter; 18 | import static com.qa.opencart.factory.PlaywrightFactory.takeScreenshot; 19 | 20 | public class ExtentReportListener implements ITestListener { 21 | 22 | private static final String OUTPUT_FOLDER = "./build/"; 23 | private static final String FILE_NAME = "TestExecutionReport.html"; 24 | 25 | private static ExtentReports extent = init(); 26 | public static ThreadLocal test = new ThreadLocal(); 27 | private static ExtentReports extentReports; 28 | 29 | 30 | private static ExtentReports init() { 31 | 32 | Path path = Paths.get(OUTPUT_FOLDER); 33 | // if directory exists? 34 | if (!Files.exists(path)) { 35 | try { 36 | Files.createDirectories(path); 37 | } catch (IOException e) { 38 | // fail to create directory 39 | e.printStackTrace(); 40 | } 41 | } 42 | 43 | extentReports = new ExtentReports(); 44 | ExtentSparkReporter reporter = new ExtentSparkReporter(OUTPUT_FOLDER + FILE_NAME); 45 | reporter.config().setReportName("Open Cart Automation Test Results"); 46 | extentReports.attachReporter(reporter); 47 | extentReports.setSystemInfo("System", "MAC"); 48 | extentReports.setSystemInfo("Author", "Naveen AutomationLabs"); 49 | extentReports.setSystemInfo("Build#", "1.1"); 50 | extentReports.setSystemInfo("Team", "OMS"); 51 | extentReports.setSystemInfo("Customer Name", "NAL"); 52 | 53 | //extentReports.setSystemInfo("ENV NAME", System.getProperty("env")); 54 | 55 | return extentReports; 56 | } 57 | 58 | @Override 59 | public synchronized void onStart(ITestContext context) { 60 | System.out.println("Test Suite started!"); 61 | 62 | } 63 | 64 | @Override 65 | public synchronized void onFinish(ITestContext context) { 66 | System.out.println(("Test Suite is ending!")); 67 | extent.flush(); 68 | test.remove(); 69 | } 70 | 71 | @Override 72 | public synchronized void onTestStart(ITestResult result) { 73 | String methodName = result.getMethod().getMethodName(); 74 | String qualifiedName = result.getMethod().getQualifiedName(); 75 | int last = qualifiedName.lastIndexOf("."); 76 | int mid = qualifiedName.substring(0, last).lastIndexOf("."); 77 | String className = qualifiedName.substring(mid + 1, last); 78 | 79 | System.out.println(methodName + " started!"); 80 | ExtentTest extentTest = extent.createTest(result.getMethod().getMethodName(), 81 | result.getMethod().getDescription()); 82 | 83 | extentTest.assignCategory(result.getTestContext().getSuite().getName()); 84 | /* 85 | * methodName = StringUtils.capitalize(StringUtils.join(StringUtils. 86 | * splitByCharacterTypeCamelCase(methodName), StringUtils.SPACE)); 87 | */ 88 | extentTest.assignCategory(className); 89 | test.set(extentTest); 90 | test.get().getModel().setStartTime(getTime(result.getStartMillis())); 91 | } 92 | 93 | public synchronized void onTestSuccess(ITestResult result) { 94 | System.out.println((result.getMethod().getMethodName() + " passed!")); 95 | test.get().pass("Test passed"); 96 | test.get().pass(result.getThrowable(), MediaEntityBuilder.createScreenCaptureFromBase64String(takeScreenshot(),result.getMethod().getMethodName()).build()); 97 | test.get().getModel().setEndTime(getTime(result.getEndMillis())); 98 | } 99 | 100 | public synchronized void onTestFailure(ITestResult result) { 101 | System.out.println((result.getMethod().getMethodName() + " failed!")); 102 | test.get().fail(result.getThrowable(), MediaEntityBuilder.createScreenCaptureFromBase64String(takeScreenshot(),result.getMethod().getMethodName()).build()); 103 | test.get().getModel().setEndTime(getTime(result.getEndMillis())); 104 | } 105 | 106 | public synchronized void onTestSkipped(ITestResult result) { 107 | System.out.println((result.getMethod().getMethodName() + " skipped!")); 108 | test.get().skip(result.getThrowable(), MediaEntityBuilder.createScreenCaptureFromBase64String(takeScreenshot(), result.getMethod().getMethodName()).build()); 109 | test.get().getModel().setEndTime(getTime(result.getEndMillis())); 110 | } 111 | 112 | public synchronized void onTestFailedButWithinSuccessPercentage(ITestResult result) { 113 | System.out.println(("onTestFailedButWithinSuccessPercentage for " + result.getMethod().getMethodName())); 114 | } 115 | 116 | private Date getTime(long millis) { 117 | Calendar calendar = Calendar.getInstance(); 118 | calendar.setTimeInMillis(millis); 119 | return calendar.getTime(); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/com/qa/opencart/pages/HomePage.java: -------------------------------------------------------------------------------- 1 | package com.qa.opencart.pages; 2 | 3 | import com.microsoft.playwright.Page; 4 | 5 | public class HomePage { 6 | 7 | private Page page; 8 | 9 | // 1. String Locators - OR 10 | private String search = "input[name='search']"; 11 | private String searchIcon = "div#search button"; 12 | private String searchPageHeader = "div#content h1"; 13 | private String loginLink = "a:text('Login')"; 14 | private String myAccountLink = "a[title='My Account']"; 15 | 16 | 17 | // 2. page constructor: 18 | public HomePage(Page page) { 19 | this.page = page; 20 | } 21 | 22 | // 3. page actions/methods: 23 | public String getHomePageTitle() { 24 | String title = page.title(); 25 | System.out.println("page title: " + title); 26 | return title; 27 | } 28 | 29 | public String getHomePageURL() { 30 | String url = page.url(); 31 | System.out.println("page url : " + url); 32 | return url; 33 | } 34 | 35 | public String doSearch(String productName) { 36 | page.fill(search, productName); 37 | page.click(searchIcon); 38 | String header = page.textContent(searchPageHeader); 39 | System.out.println("search header: " + header); 40 | return header; 41 | } 42 | 43 | public LoginPage navigateToLoginPage() { 44 | page.click(myAccountLink); 45 | page.click(loginLink); 46 | return new LoginPage(page); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/qa/opencart/pages/LoginPage.java: -------------------------------------------------------------------------------- 1 | package com.qa.opencart.pages; 2 | 3 | import com.microsoft.playwright.Page; 4 | 5 | public class LoginPage { 6 | 7 | private Page page; 8 | 9 | // 1. String Locators - OR 10 | private String emailId = "//input[@id='input-email']"; 11 | private String password = "//input[@id='input-password']"; 12 | private String loginBtn = "//input[@value='Login']"; 13 | private String forgotPwdLink = "//div[@class='form-group']//a[normalize-space()='Forgotten Password']"; 14 | private String logoutLink = "//a[@class='list-group-item'][normalize-space()='Logout']"; 15 | 16 | // 2. page constructor: 17 | public LoginPage(Page page) { 18 | this.page = page; 19 | } 20 | 21 | // 3. page actions/methods: 22 | public String getLoginPageTitle() { 23 | return page.title(); 24 | } 25 | 26 | public boolean isForgotPwdLinkExist() { 27 | return page.isVisible(forgotPwdLink); 28 | } 29 | 30 | public boolean doLogin(String appUserName, String appPassword) { 31 | System.out.println("App creds: " + appUserName + ":" + appPassword); 32 | page.fill(emailId, appUserName); 33 | page.fill(password, appPassword); 34 | page.click(loginBtn); 35 | page.locator(logoutLink).waitFor(); 36 | if(page.locator(logoutLink).isVisible()) { 37 | System.out.println("user is logged in successfully...."); 38 | return true; 39 | }else { 40 | System.out.println("user is not logged in successfully...."); 41 | return false; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/com/qa/opencart/base/BaseTest.java: -------------------------------------------------------------------------------- 1 | package com.qa.opencart.base; 2 | 3 | import java.util.Properties; 4 | 5 | import org.testng.annotations.AfterTest; 6 | import org.testng.annotations.BeforeTest; 7 | import org.testng.annotations.Parameters; 8 | 9 | import com.microsoft.playwright.Page; 10 | import com.qa.opencart.factory.PlaywrightFactory; 11 | import com.qa.opencart.pages.HomePage; 12 | import com.qa.opencart.pages.LoginPage; 13 | 14 | public class BaseTest { 15 | 16 | PlaywrightFactory pf; 17 | Page page; 18 | protected Properties prop; 19 | 20 | protected HomePage homePage; 21 | protected LoginPage loginPage; 22 | 23 | @Parameters({ "browser" }) 24 | @BeforeTest 25 | public void setup(String browserName) { 26 | pf = new PlaywrightFactory(); 27 | 28 | prop = pf.init_prop(); 29 | 30 | if (browserName != null) { 31 | prop.setProperty("browser", browserName); 32 | } 33 | 34 | page = pf.initBrowser(prop); 35 | homePage = new HomePage(page); 36 | } 37 | 38 | @AfterTest 39 | public void tearDown() { 40 | page.context().browser().close(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/qa/opencart/tests/HomePageTest.java: -------------------------------------------------------------------------------- 1 | package com.qa.opencart.tests; 2 | 3 | import org.testng.Assert; 4 | import org.testng.annotations.DataProvider; 5 | import org.testng.annotations.Test; 6 | 7 | import com.qa.opencart.base.BaseTest; 8 | import com.qa.opencart.constants.AppConstants; 9 | 10 | public class HomePageTest extends BaseTest { 11 | 12 | @Test 13 | public void homePageTitleTest() { 14 | String actualTitle = homePage.getHomePageTitle(); 15 | Assert.assertEquals(actualTitle, AppConstants.HOME_PAGE_TITLE); 16 | } 17 | 18 | @Test 19 | public void homePageURLTest() { 20 | String actualURL = homePage.getHomePageURL(); 21 | Assert.assertEquals(actualURL, prop.getProperty("url")); 22 | } 23 | 24 | @DataProvider 25 | public Object[][] getProductData() { 26 | return new Object[][] { 27 | { "Macbook" }, 28 | { "iMac" }, 29 | { "Samsung" } 30 | }; 31 | } 32 | 33 | @Test(dataProvider = "getProductData") 34 | public void searchTest(String productName) throws InterruptedException { 35 | Thread.sleep(5000); 36 | String actualSearchHeader = homePage.doSearch(productName); 37 | Assert.assertEquals(actualSearchHeader, "Search - " + productName); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/com/qa/opencart/tests/LoginPageTest.java: -------------------------------------------------------------------------------- 1 | package com.qa.opencart.tests; 2 | 3 | import org.testng.Assert; 4 | import org.testng.annotations.Test; 5 | 6 | import com.qa.opencart.base.BaseTest; 7 | import com.qa.opencart.constants.AppConstants; 8 | 9 | public class LoginPageTest extends BaseTest { 10 | 11 | @Test(priority = 1) 12 | public void loginPageNavigationTest() { 13 | loginPage = homePage.navigateToLoginPage(); 14 | String actLoginPageTitle = loginPage.getLoginPageTitle(); 15 | System.out.println("page act title: " + actLoginPageTitle); 16 | Assert.assertEquals(actLoginPageTitle, AppConstants.LOGIN_PAGE_TITLE); 17 | } 18 | 19 | @Test(priority = 2) 20 | public void forgotPwdLinkExistTest() { 21 | Assert.assertTrue(loginPage.isForgotPwdLinkExist()); 22 | } 23 | 24 | @Test(priority = 3) 25 | public void appLoginTest() { 26 | Assert.assertTrue(loginPage.doLogin(prop.getProperty("username").trim(), prop.getProperty("password").trim())); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/resources/config/config.properties: -------------------------------------------------------------------------------- 1 | browser = chrome 2 | url = https://naveenautomationlabs.com/opencart/ 3 | 4 | username = naveenanimation20@gmail.com 5 | password = Selenium@12345 6 | 7 | headless = false -------------------------------------------------------------------------------- /src/test/resources/testrunners/testng_regressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 34 | 35 | 41 | 42 | 43 | 44 | 45 | --------------------------------------------------------------------------------