rogerxu / rogerxu.github.io

Roger Xu's Blog
3 stars 2 forks source link

Selenium #131

Open rogerxu opened 7 years ago

rogerxu commented 7 years ago

Selenium - Web Browser Automation

rogerxu commented 7 years ago

WebDriver

Selenium WebDriver — Selenium Documentation

Install

Ardesco/selenium-standalone-server-plugin: A Maven plugin that will download the WebDriver stand alone server executables for use in your mavenised Selenium project.

Ardesco/Selenium-Maven-Template: A maven template for Selenium that will let you check out and go.

<plugin>
    <groupId>com.lazerycode.selenium</groupId>
    <artifactId>driver-binary-downloader-maven-plugin</artifactId>
    <version>1.0.14</version>
    <executions>
        <execution>
            <id>install-webdriver</id>
            <phase>pre-integration-test</phase>
            <goals>
                <goal>selenium</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <rootStandaloneServerDirectory>${project.build.directory}/webdriver</rootStandaloneServerDirectory>
        <downloadedZipFileDirectory>${project.build.directory}/downloads</downloadedZipFileDirectory>
        <onlyGetDriversForHostOperatingSystem>true</onlyGetDriversForHostOperatingSystem>
        <getSpecificExecutableVersions>
            <googlechrome>2.29</googlechrome>
            <!-- <marionette>0.15.0</marionette> -->
            <!-- <edge>3.14393</edge> -->
            <internetexplorer>3.3.0</internetexplorer>
        </getSpecificExecutableVersions>
    </configuration>
</plugin>

PhantomJSInstaller.java

import java.io.File;
import java.text.MessageFormat;
import java.util.logging.Level;
import java.util.logging.Logger;

import net.anthavio.phanbedder.Phanbedder;

public class PhantomJSInstaller {

    /** the logger instance */
    private static final Logger LOGGER = Logger.getLogger(PhantomJSInstaller.class.getName());

    /**
     * System property/capability that defines the location of the PhantomJS executable.
     */
    public static final String PHANTOMJS_EXECUTABLE_PATH_PROPERTY = "phantomjs.binary.path";

    public static void main(String[] args) {
        File phantomjs = Phanbedder.unpack();
        String phantomjsBinaryPath = phantomjs.getAbsolutePath();
        System.setProperty(PHANTOMJS_EXECUTABLE_PATH_PROPERTY, phantomjsBinaryPath);
        LOGGER.log(Level.INFO, MessageFormat.format("Set system property {0}={1}", PHANTOMJS_EXECUTABLE_PATH_PROPERTY, phantomjsBinaryPath));
    }
}

DesiredCapabilities

DesiredCapabilities · SeleniumHQ/selenium Wiki

capabilities.json

{
  "internet explorer": {
    "ignoreProtectedModeSettings": true,
    "ie.ensureCleanSession": false
  },
  "phantomjs": {
    "phantomjs.page.settings.resourceTimeout": 300000,
    "phantomjs.page.settings.localToRemoteUrlAccessEnabled": true,
    "phantomjs.page.settings.webSecurityEnabled": false,
    "phantomjs.service.settings.start": true,
    "phantomjs.cli.args": [
      "--webdriver-loglevel=WARN",
      "--local-to-remote-url-access=true",
      "--web-security=false",
      "--ignore-ssl-errors=true",
      "--disk-cache=false",
      "--proxy-type=http",
      "--proxy=proxy:8080"
    ]
  }
}

WebDriver API

By locator

WebElement

wait until

ChromeDriver

ChromeDriver · SeleniumHQ/selenium Wiki

webdriver.chrome.driver

Set one of the following options

PhantomJSDriver

Built-in in Selenium webdriver API

phantom.binary.path

GeckoDriver

mozilla/geckodriver: WebDriver <-> Marionette proxy

webdriver.gecko.driver

FirefoxDriver

FirefoxDriver · SeleniumHQ/selenium Wiki

webdriver.firefox.driver

Firefox driver is included in the selenium-server-stanalone.jar available in the downloads.

EdgeDriver

webdriver.edge.driver

InternetExplorerDriver

InternetExplorerDriver · SeleniumHQ/selenium Wiki

webdriver.ie.driver

rogerxu commented 7 years ago

FirefoxDriver

Firefox driver is included in the selenium-server-stanalone.jar available in the downloads.

FirefoxDriver · SeleniumHQ/selenium Wiki

System Properties

Firefox 46.0.1

Download https://ftp.mozilla.org/pub/firefox/releases/46.0.1/

selenium - Difference between webdriver.firefox.marionette & webdriver.gecko.driver - Stack Overflow

Up to version 47, the driver used to automate Firefox was an extension included with each client. But this extension was dropped, probably due to the change of policy which now requires all the extensions to be signed by Mozilla.

Marionette is the new driver that is shipped/included with Firefox. This driver has it's own protocol which is not directly compatible with the Selenium/WebDriver protocol.

The Gecko driver (previously named wires) is an application server implementing the Selenium/WebDriver protocol. It translates the Selenium commands and forwards them to the Marionette driver.

For the Java client, the default behavior is to use the Gecko driver, but it can be overridden to use the legacy extension as a driver with the webdriver.firefox.marionette property:

System.setProperty("webdriver.firefox.marionette", "false");
WebDriver driver = new FirefoxDriver();

or with the marionette capability through FirefoxOptions:

FirefoxOptions options = new FirefoxOptions()
  .setLegacy(true);

WebDriver driver = new FirefoxDriver(options);
// or with a remote server
WebDriver driver = new RemoteWebDriver(remoteUrl, options.toDesiredCapabilities());

or directly with the DesiredCapabilities:

DesiredCapabilities capabilities = DesiredCapabilities.firefox();
capabilities.setCapability("marionette", false);

WebDriver driver = new FirefoxDriver(capabilities);
// or with a remote server
WebDriver driver = new RemoteWebDriver(remoteUrl, capabilities);

Portable Firefox

Using Portable Firefox 46 with WebDriver » Selenium Simplified

Proxy

Firefox maintains its proxy configuration in a profile. You can preset the proxy in a profile and use that Firefox Profile or you can set it on profile that is created on the fly as is shown in the following example.

String PROXY = "localhost:8080";

org.openqa.selenium.Proxy proxy = new org.openqa.selenium.Proxy();
proxy.setHttpProxy(PROXY)
     .setFtpProxy(PROXY)
     .setSslProxy(PROXY);

DesiredCapabilities capabilities = DesiredCapabilities.firefox();
capabilities.setCapability(CapabilityType.PROXY, proxy);
WebDriver driver = new FirefoxDriver(capabilities);
rogerxu commented 7 years ago

Java

Maven

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.demo</groupId>
    <artifactId>selenium-test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.11</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.5.3</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.6.1</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

TestNG

package org.demo;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;
import org.testng.annotations.Test;

/**
 * Unit test for simple App.
 */
public class AppTest {

    @Test
    public void testApp() {
        // Create a new instance of the Firefox driver
        // Notice that the remainder of the code relies on the interface,
        // not the implementation.
        WebDriver driver = getWebDriver();

        // And now use this to visit Google
        driver.get("http://www.google.com");
        // Alternatively the same thing can be done like this
        // driver.navigate().to("http://www.google.com");

        // Find the text input element by its name
        WebElement element = driver.findElement(By.name("q"));

        // Enter something to search for
        element.sendKeys("Cheese!");

        // Now submit the form. WebDriver will find the form for us from the element
        element.submit();

        // Check the title of the page
        System.out.println("Page title is: " + driver.getTitle());

        // Google's search is rendered dynamically with JavaScript.
        // Wait for the page to load, timeout after 10 seconds
        (new WebDriverWait(driver, 10))
            .until((ExpectedCondition<Boolean>) webDriver -> webDriver.getTitle().toLowerCase().startsWith("cheese!"));

        // Should see: "cheese! - Google Search"
        System.out.println("Page title is: " + driver.getTitle());

        // Close the browser
        driver.quit();

        Assert.assertTrue(true);
    }
}
rogerxu commented 7 years ago

GeckoDriver

WebDriver - Mozilla | MDN

mozilla/geckodriver: WebDriver <-> Marionette proxy

System.setProperty("webdriver.gecko.driver", "C:\\geckodriver.exe");
private WebDriver getGeckoDriver(boolean isRemoteServer) {
    WebDriver driver = null;
    DesiredCapabilities capabilities = DesiredCapabilities.firefox();

    // proxy
    if (isUseProxy()) {
        String proxyHost = settings.getProperty("selenium.browser.proxy.host");
        int proxyPort = Integer.parseInt(settings.getProperty("selenium.browser.proxy.port"), 10);

        JsonObject json = new JsonObject();
        json.addProperty("proxyType", "MANUAL");
        json.addProperty("httpProxy", proxyHost);
        json.addProperty("httpProxyPort", proxyPort);
        json.addProperty("sslProxy", proxyHost);
        json.addProperty("sslProxyPort", proxyPort);

        capabilities.setCapability(CapabilityType.PROXY, json);
    }

    if (isRemoteServer) {
        driver = getRemoteDriver(capabilities);
    } else {
        driver = new FirefoxDriver(capabilities);
    }

    return driver;
}
rogerxu commented 7 years ago

Node.js

selenium-webdriver

API Index

package.json

{
  "scripts": {
    "test": "mocha",
    "test:debug": "mocha --inspect"
  },
  "devDependencies": {
    "chai": "^4.2.0",
    "chromedriver": "^76.0.1",
    "edgedriver": "^4.15063.0",
    "geckodriver": "^1.8.1",
    "mocha": "^6.2.0",
    "selenium-webdriver": "^3.6.0"
  }
}

test/example.js

require('chromedriver');
const { describe, it, before, beforeEach, after, afterEach } = require('mocha');
const { expect } = require('chai');
const { By, Key, until } = require('selenium-webdriver');
const { suite } = require('selenium-webdriver/testing');

suite(function (env) {

  describe('Test Suite', function () {
    this.timeout(30000);

    let driver;

    before(async function () {
      console.log('before');
      driver = await env.builder().build();
    });

    after(async function () {
      console.log('after');

      await driver.quit();
    });

    beforeEach(function () {
      console.log('beforeEach');
    });

    afterEach(function () {
      console.log('afterEach');
    });

    it('Test 1', function () {
      console.log('test 1');
      expect(1 + 1).to.equal(2);
    });

    it('async', async function () {
      console.log('async');

      await driver.get('https://www.google.com/ncr');
      await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN);
      await driver.wait(until.titleContains('webdriver'), 1000);

      const resultStats = await driver.findElement(By.id('resultStats'));
      const results = await driver.wait(async function () {
        return await resultStats.getText();
      }, 5000);

      console.log('results.length:', results.length);
      expect(results.length).to.be.above(10);
    });
  });
});

Promise with async/await

WebDriverJs · SeleniumHQ/selenium Wiki

rogerxu commented 7 years ago

RemoteDriver

RemoteWebDriver · SeleniumHQ/selenium Wiki

Grid Platforms · SeleniumHQ/selenium Wiki

private WebDriver getRemoteDriver() {
    DesiredCapabilities capabilities = DesiredCapabilities.firefox();

    // proxy
    Proxy proxy = getProxy();
    capabilities.setCapability(CapabilityType.PROXY, proxy);

    // use legacy firefox < 47
    capabilities.setCapability("marionette", false);

    // remote driver settings
    capabilities.setPlatform(Platform.LINUX);
    capabilities.setCapability(CapabilityType.APPLICATION_NAME, settings.getProperty("selenium.applicationName"));

    String seleniumGridServer = settings.getProperty("selenium.grid.url");
    WebDriver driver = null;
    try {
        driver = new RemoteWebDriver(new URL(seleniumGridServer), capabilities);
    } catch (MalformedURLException e) {
        LOG.error("Invalid selenium grid server: {0}", seleniumGridServer);
    }

    return driver;
}

.env

SELENIUM_BROWSER=chrome
SELENIUM_REMOTE_URL=http://localhost:4444/wd/hub
SELENIUM_GRID_APPLICATION_NAME=app-debug-5901

test/remote.js

require('dotenv').config();

const { describe, it, before, beforeEach, after, afterEach } = require('mocha');
const { expect } = require('chai');
const { By, Key, until } = require('selenium-webdriver');
const { suite } = require('selenium-webdriver/testing');

const seleniumUrl = process.env['SELENIUM_REMOTE_URL'];
console.log('seleniumUrl :', seleniumUrl);

suite(function (env) {

  describe('Test Suite', function () {
    this.timeout(30000);

    let driver;

    before(async function () {
      console.log('before');
      const builder = await env.builder();

      if (process.env.SELENIUM_GRID_APPLICATION_NAME) {
        builder.withCapabilities({
          applicationName: process.env.SELENIUM_GRID_APPLICATION_NAME
        });
      }

      driver = builder.build();
    });

    after(async function () {
      console.log('after');

      await driver.quit();
    });

    beforeEach(function () {
      console.log('beforeEach');
    });

    afterEach(function () {
      console.log('afterEach');
    });

    it('Test', async function () {
      console.log('Test bing.com');

      await driver.get('https://www.bing.com/');
      await driver.findElement(By.name('q')).sendKeys('webdriver');
      await driver.findElement(By.id('sb_form_go')).click();

      console.log('enter results page');
      await driver.wait(until.titleContains('webdriver'), 10000);
      const searchbox = await driver.findElement(By.name('q'));
      const query = await driver.wait(async function () {
        return await searchbox.getAttribute('value');
      }, 5000);

      expect(query).to.equal('webdriver');
    });
  });
});
rogerxu commented 7 years ago

PhantomJS

Built-in in Selenium webdriver API

phantom.binary.path

detro/ghostdriver: Ghost Driver is an implementation of the Remote WebDriver Wire protocol, using PhantomJS as back-end

private WebDriver getPhantomJSDriver() {
    WebDriver driver = null;
    DesiredCapabilities capabilities = DesiredCapabilities.phantomjs();
    driver = new PhantomJSDriver(capabilities);

    return driver;
}
rogerxu commented 7 years ago

Page Objects

PageObjects · SeleniumHQ/selenium Wiki