@techgirl1908

❝Existing Selenium projects will continue for a long time, but after learning Playwright, I will never start a new E2E test project in Selenium.❞ ~ Andrejs

VS

@AutomationPanda

@techgirl1908

❝I have used both for some time now and can’t wait to see what points both speakers put.❞ ~ Rahul

VS

@AutomationPanda

@techgirl1908

❝I have used both selenium and playwright(js binding). For me playwright is the clear winner. Let the code speak❞ ~ Dushyant

VS

@AutomationPanda

@techgirl1908

@AutomationPanda

❝About time Selenium got a worthy competitor. I've been a WebDriver fan for good 7+ years and can’t wait to see how long will Playwright survive against it 😉❞ ~ Akash

VS

@techgirl1908

@AutomationPanda

❝Sorry Angie. On this one I’m team Andy, my bet is on Playwright❞ ~ Ixchel

VS

@techgirl1908

@AutomationPanda

❝Playwright is absolutely changing the game! Automatic waits, built in device and multiple browser support, available in Python, JS, and more! ❞ ~ Sean

VS

Why compare

Selenium vs Playwright?

@techgirl1908

@AutomationPanda

👩🏽‍💻Selenium WebDriver (Java)

 

🧑🏻‍💻Playwright

(Java)

@techgirl1908

@AutomationPanda

The Battle

@techgirl1908

@AutomationPanda

🥊 10 Rounds
 

💻 Show implementations in Selenium and Playwright
 

🗳 You vote
 

💬 Discuss after each round

Round 1:

Element Interaction

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

Round 1: Playwright

@Test
public void testLogin()
{
    page.navigate("https://demo.applitools.com/");
    page.fill("id=username", "andy");
    page.fill("id=password", "panda<3");
    page.click("id=log-in");
    assertThat(page.locator(".element-header >> nth=0"))
      	.hasText("Financial Overview");
}

@techgirl1908

@AutomationPanda

Round 1: Selenium

@Test
public void testLogin()
{
    driver.get("https://demo.applitools.com/");
    driver.findElement(By.id("username")).sendKeys("angie");
    driver.findElement(By.id("password")).sendKeys("12345");
    driver.findElement(By.id("log-in")).click();
    assertEquals(
            "Financial Overview",
            driver.findElement(By.className("element-header")).getText());
}

Round 1: Selenium vs Playwright

@Test
public void testLogin()
{
    page.navigate("https://demo.applitools.com/");
    page.fill("id=username", "andy");
    page.fill("id=password", "panda<3");
    page.click("id=log-in");
    assertThat(page.locator(".element-header >> nth=0"))
      	.hasText("Financial Overview");
}
@Test
public void testLogin()
{
    driver.get("https://demo.applitools.com/");
    driver.findElement(By.id("username")).sendKeys("angie");
    driver.findElement(By.id("password")).sendKeys("12345");
    driver.findElement(By.id("log-in")).click();
    assertEquals(
            "Financial Overview",
            driver.findElement(By.className("element-header")).getText());
}

Round 2: Dropdowns

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

Round 2: Selenium

@Test
public void testDropdown()
{
    driver.get("https://kitchen.applitools.com/ingredients/select");
    
    Select dropdown = 
        new Select(driver.findElement(By.id("spices-select-single")));
        
    dropdown.selectByValue("ginger");
    
    assertEquals("ginger", 
        dropdown.getAllSelectedOptions().get(0).getAttribute("value"));
}

@techgirl1908

@AutomationPanda

Round 2: Playwright

@Test
public void testDropdown()
{
    page.navigate("https://kitchen.applitools.com/ingredients/select");
    page.selectOption("id=spices-select-single", "ginger");
    
    assertThat(page.locator("id=spices-select-single"))
    	.hasValue("ginger");
}

Round 2: Selenium vs Playwright

@Test
public void testDropdown()
{
    driver.get("https://kitchen.applitools.com/ingredients/select");
    
    Select dropdown = 
        new Select(driver.findElement(By.id("spices-select-single")));
        
    dropdown.selectByValue("ginger");
    
    assertEquals("ginger", 
        dropdown.getAllSelectedOptions().get(0).getAttribute("value"));
}
@Test
public void testDropdown()
{
    page.navigate("https://kitchen.applitools.com/ingredients/select");
    page.selectOption("id=spices-select-single", "ginger");
    
    assertThat(page.locator("id=spices-select-single"))
    	.hasValue("ginger");
}

Round 3:

Uploading Files

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

Round 3: Playwright

@Test
public void testFileUpload()
{
    page.navigate("https://kitchen.applitools.com/ingredients/file-picker");
    page.setInputFiles("id=photo-upload", Paths.get("pic.jpg"));
}

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

Round 3: Selenium

@Test
public void testFileUpload()
{
    driver.get("https://kitchen.applitools.com/ingredients/file-picker");
    driver.findElement(By.id("photo-upload")).sendKeys("/Users/angie/tmp/pic.jpg");
}

Round 3: Selenium vs Playwright

@Test
public void testFileUpload()
{
    driver.get("https://kitchen.applitools.com/ingredients/file-picker");
    driver.findElement(By.id("photo-upload")).sendKeys("/Users/angie/tmp/pic.jpg");
}
@Test
public void testFileUpload()
{
    page.navigate("https://kitchen.applitools.com/ingredients/file-picker");
    page.setInputFiles("id=photo-upload", Paths.get("pic.jpg"));
}

@techgirl1908

@AutomationPanda

Round 4: Frames

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

Round 4: Selenium

@Test
public void testIframe()
{
    driver.get("https://kitchen.applitools.com/ingredients/iframe");
    
    assertTrue(
    	driver.switchTo().frame("the-kitchen-table")
            .findElement(By.id("fruits-vegetables"))
            .isDisplayed());
}

@techgirl1908

Round 4: Playwright

@Test
public void testIframe()
{
    page.navigate("https://kitchen.applitools.com/ingredients/iframe");
    
    assertThat(page
    	.frameLocator("id=the-kitchen-table")
        .locator("id=fruits-vegetables")
    ).isVisible();
}

@AutomationPanda

Round 4: Selenium vs Playwright

@Test
public void testIframe()
{
    driver.get("https://kitchen.applitools.com/ingredients/iframe");
    
    assertTrue(
    	driver.switchTo().frame("the-kitchen-table")
            .findElement(By.id("fruits-vegetables"))
            .isDisplayed());
}
@Test
public void testIframe()
{
    page.navigate("https://kitchen.applitools.com/ingredients/iframe");
    
    assertThat(
    	page.frameLocator("id=the-kitchen-table")
        .locator("id=fruits-vegetables")
    ).isVisible();
}

Round 5: Waiting

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

@techgirl1908

Round 5: Playwright

@Test
public void testWaitForFilter()
{
    page.navigate("https://automationbookstore.dev/");
    page.fill("id=searchBar", "testing");
    
    page.locator("li.ui-screen-hidden >> nth=0").waitFor(
        new Locator.WaitForOptions()
            .setState(WaitForSelectorState.HIDDEN)
            .setTimeout(5000));
    
    assertThat(page.locator("li:not(.ui-screen-hidden)"))
      	.hasCount(1, new LocatorAssertions.HasCountOptions().setTimeout(5000));
}

@AutomationPanda

@techgirl1908

Round 5: Playwright (simplified)

@Test
public void testWaitForFilter()
{
    page.navigate("https://automationbookstore.dev/");
    page.fill("id=searchBar", "testing");
    
    // page.locator("li.ui-screen-hidden >> nth=0").waitFor(
    //    new Locator.WaitForOptions()
    //        .setState(WaitForSelectorState.HIDDEN)
    //        .setTimeout(5000));
    
    assertThat(page.locator("li:not(.ui-screen-hidden)"))
      	.hasCount(1, new LocatorAssertions.HasCountOptions().setTimeout(5000));
}

@AutomationPanda

Explicitly waiting for hidden elements to attach to the DOM is not required.
Waiting for the non-hidden element count to reach 1 inherently covers it.

@techgirl1908

Round 5: Selenium

@Test
public void testWaitForFilter()
{
    driver.get("https://automationbookstore.dev/");
    driver.findElement(By.id("searchBar")).sendKeys("testing");
    
    new WebDriverWait(driver, Duration.ofSeconds(5))
        .until(presenceOfElementLocated(
            By.cssSelector("li.ui-screen-hidden"))
        );
   
    assertEquals(1, 
        driver.findElements(By.cssSelector("li:not(.ui-screen-hidden)"))
            .size());
}

@AutomationPanda

@techgirl1908

Round 5: Selenium vs Playwright

@Test
public void testWaitForFilter()
{
    ...
    new WebDriverWait(driver, Duration.ofSeconds(5))
        .until(presenceOfElementLocated(
            By.cssSelector("li.ui-screen-hidden"))
        );
    ...
}
@Test
public void testWaitForFilter()
{
    ...
    page.locator("li.ui-screen-hidden >> nth=0").waitFor(
        new Locator.WaitForOptions()
            .setState(WaitForSelectorState.HIDDEN)
            .setTimeout(5000));
    ...
}

@AutomationPanda

Round 6: Alerts

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

Round 6: Selenium

@BeforeAll
public static void openAlertsPage(){
    driver.get("https://kitchen.applitools.com/ingredients/alert");
}

@Test
public void testAcceptAlert(){
    driver.findElement(By.id("alert-button")).click();
    driver.switchTo().alert().accept();
}

@Test
public void testDismissAlert(){
    driver.findElement(By.id("confirm-button")).click();
    driver.switchTo().alert().dismiss();
}

@Test
public void testAnswerPrompt(){
    driver.findElement(By.id("prompt-button")).click();
    Alert alert = driver.switchTo().alert();
    alert.sendKeys("nachos");
    alert.accept();
}

@techgirl1908

Round 6: Playwright

@AutomationPanda

@BeforeAll
public static void openAlertsPage(){
    page.navigate("https://kitchen.applitools.com/ingredients/alert");
}

@Test
public void testAcceptAlert(){
    page.onDialog(Dialog::accept);
    page.click("id=alert-button");
}

@Test
public void testDismissAlert(){
    page.onDialog(Dialog::dismiss);
    page.click("id=confirm-button");
}

@Test
public void testAnswerPrompt(){
    page.onDialog(dialog -> dialog.accept("nachos"));
    page.click("id=prompt-button");
}

Round 6: Selenium vs Playwright

@BeforeAll
public static void openAlertsPage(){
    driver.get("https://kitchen.applitools.com/ingredients/alert");
}

@Test
public void testAcceptAlert(){
    driver.findElement(By.id("alert-button")).click();
    driver.switchTo().alert().accept();
}

@Test
public void testDismissAlert(){
    driver.findElement(By.id("confirm-button")).click();
    driver.switchTo().alert().dismiss();
}

@Test
public void testAnswerPrompt(){
    driver.findElement(By.id("prompt-button")).click();
    Alert alert = driver.switchTo().alert();
    alert.sendKeys("nachos");
    alert.accept();
}
@BeforeAll
public static void openAlertsPage(){
    page.navigate("https://kitchen.applitools.com/ingredients/alert");
}

@Test
public void testAcceptAlert(){
    page.onDialog(Dialog::accept);
    page.click("id=alert-button");
}

@Test
public void testDismissAlert(){
    page.onDialog(Dialog::dismiss);
    page.click("id=confirm-button");
}

@Test
public void testAnswerPrompt(){
    page.onDialog(dialog -> dialog.accept("nachos"));
    page.click("id=prompt-button");
}

Round 7: Navigation

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

@techgirl1908

Round 7: Playwright

@Test
public void testNewTab()
{
    page.navigate("https://kitchen.applitools.com/ingredients/links");
    Page newTab = context.waitForPage(
        () -> page.click("id=button-the-kitchen-table"));
    assertThat(newTab.locator("id=fruits-vegetables")).isVisible();
}

@AutomationPanda

@techgirl1908

Round 7: Selenium

@Test
public void testNewTab()
{
    driver.get("https://kitchen.applitools.com/ingredients/links");
    driver.findElement(By.id("button-the-kitchen-table")).click();
    driver.getWindowHandles().forEach(tab->driver.switchTo().window(tab));
    assertTrue(driver.findElement(By.id("fruits-vegetables")).isDisplayed());
}

@AutomationPanda

@techgirl1908

Round 7: Selenium vs Playwright

@Test
public void testNewTab()
{
    driver.get("https://kitchen.applitools.com/ingredients/links");
    driver.findElement(By.id("button-the-kitchen-table")).click();
    driver.getWindowHandles().forEach(tab->driver.switchTo().window(tab));
    assertTrue(driver.findElement(By.id("fruits-vegetables")).isDisplayed());
}

@AutomationPanda

@Test
public void testNewTab()
{
    page.navigate("https://kitchen.applitools.com/ingredients/links");
    Page newTab = context.waitForPage(
        () -> page.click("id=button-the-kitchen-table"));
    assertThat(newTab.locator("id=fruits-vegetables")).isVisible();
}

Round 8: API Requests

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

https://kitchen.applitools.com/api/recipes

@techgirl1908

Round 8: Selenium

😫

@AutomationPanda

@techgirl1908

Round 8: Playwright

@AutomationPanda

Currently, Playwright provides API testing

only for JavaScript and Python.

 

API testing support will come to Java in 1.18.

It will come to .NET thereafter.

😲

@techgirl1908

Round 8: Playwright  (Python)

def test_kitchen_api_recipes(context):
  
  response = context.request.get(
    'https://kitchen.applitools.com/api/recipes')

  body = response.json()
  
  assert response.ok
  assert body['time'] > 0
  assert len(body['data']) > 0
  
  # Include other assertions about body data as appropriate

@AutomationPanda

@techgirl1908

Round 8: Selenium vs Playwright

def test_kitchen_api_recipes(context):
  
  response = context.request.get(
    'https://kitchen.applitools.com/api/recipes')

  body = response.json()
  
  assert response.ok
  assert body['time'] > 0
  assert len(body['data']) > 0
  
  # Include other assertions about body data as appropriate

@AutomationPanda

Round 9: Screenshots

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

@techgirl1908

Round 9: Playwright

@Test
public void testScreenshot()
{
    page.navigate("https://kitchen.applitools.com/ingredients/table");
    page.click("id=column-button-name");
    
    page.screenshot(
        new Page.ScreenshotOptions()
            .setPath(Paths.get("fullPage.png"))
            .setFullPage(true));
}

@AutomationPanda

@techgirl1908

Round 9: Selenium

@Test
public void testScreenshot()
{
    driver.get("https://kitchen.applitools.com/ingredients/table");
    driver.findElement(By.id("column-button-name")).click();
    
    var screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
    
    try{
        Files.move(screenshot, new File("resources/screenshots/test.png"));
    }catch(IOException e){
        e.printStackTrace();
    }
}

@AutomationPanda

@techgirl1908

Round 9: Selenium vs Playwright

@Test
public void testScreenshot(){
    driver.get("https://kitchen.applitools.com/ingredients/table");
    driver.findElement(By.id("column-button-name")).click();
    var screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
    try{
        Files.move(screenshot, new File("resources/screenshots/test.png"));
    }catch(IOException e){
        e.printStackTrace();
    }    
}
@Test
public void testScreenshot()
{
    page.navigate("https://kitchen.applitools.com/ingredients/table");
    page.click("id=column-button-name");
    
    page.screenshot(
        new Page.ScreenshotOptions()
            .setPath(Paths.get("fullPage.png"))
            .setFullPage(true));
}

@AutomationPanda

Round 10: Videos

@techgirl1908

@AutomationPanda

@techgirl1908

@AutomationPanda

@techgirl1908

Round 10: Selenium

@AutomationPanda

Selenium WebDriver does not support

video recording out of the box!

😫

@techgirl1908

Round 10: Playwright

@BeforeEach
public void startPage() {
    context = browser.newContext(
        new Browser.NewContextOptions()
            .setRecordVideoDir(Paths.get("videos/")));
            
    page = context.newPage();
}

@AfterEach
public void closePage() {
    context.close();
}

@Test
public void testLogin() {
    // This is the same code from Round 1
    ...
}

@AutomationPanda

@techgirl1908

Round 10: Selenium vs Playwright

@BeforeEach
public void startPage() {
    context = browser.newContext(
        new Browser.NewContextOptions()
            .setRecordVideoDir(Paths.get("videos/")));
            
    page = context.newPage();
}

@AfterEach
public void closePage() {
    context.close();
}

...

@AutomationPanda

Selenium WebDriver does not support

video recording out of the box!

@techgirl1908

Selenium or Playwright:

 

 

 

 

Who's the Winner?

@AutomationPanda