DEV Community

Cover image for How To Work With Tables In Selenium PHP?
himanshuseth004 for LambdaTest

Posted on • Updated on • Originally published at lambdatest.com

How To Work With Tables In Selenium PHP?

Web tables or data tables are a common sight in many web-based applications. And these tables are predominantly used for displaying information in a tabular format. Rows and columns are the key identifiers of web tables in Selenium. If you’re using tables in Selenium PHP, you can perform several operations on the table, e.g., fetching data from a specific row-column combination, searching for a particular key string in the table, etc. Selenium web automation should be used for automating the operations on the web tables.

A simple yet effective usage of web tables can be seen in e-commerce websites where detailed product information is displayed in a tabular format since it offers better readability. The information in the table can either be static or dynamically populated through some scripts.

In this Selenium WebDriver PHP Tutorial, we deep dive into the usage of web tables in Selenium PHP and how Selenium web automation can be used for automating various operations on web tables.

What Are Web Tables In Selenium?

Web Table is a type of web element primarily used for displaying information in a tabular format. Popular web elements like radio boxes, drop-down menus, checkboxes, etc., have data available in each cell of the web table that can be accessed using the WebElement functions.

As web tables in Selenium PHP comprise rows and columns, the WebElement functions are used along with the locators that identify the corresponding row (and/or column) on which Selenium test automation operation has to be performed.

Shown below is a web table with (8*3) configuration, i.e., number of rows = 8 and number of columns = 3.

jenins vs gitlabcicd

Here are some of the important HTML tags that are used in the construction of tables in Selenium PHP:

HTML Tag Description
Table Defines a Table in HTML
th Contains the information related to the Header in the table
tr Defines a Row in the table
td Defines a Column in the table

As seen below, the content inside the th tag defines the Header. Hence, the headers in the table are FEATURE, JENKINS, and GITLAB CI/CD.

Here is an example usage of where we have highlighted the contents of:

First row? R-1, C-0: Open-Source or Commercial, R-1, C-1: Open Source, and R-1, C-2: Open Source.

Second row?R-2, C-0: Product Type, R-2, C-1: Self-hosted/On-Premise, and R-2, C-2: Self-hosted/On-Premise.

Here is a sample usage of td where we have highlighted the contents of Row 1 and Column 1, i.e., R – 1, C – 1 ? Open-Source or Commercial

The content of Row 2 and Column 1, i.e., R – 2, C – 0 ? Product Type.

LambdaTest inspect

Handling Web Tables In Selenium PHP

There are two broad categories of web tables in Selenium – Static Table and Dynamic Table. Static Web Table is where the data (or information) in the table is static (i.e., it is not fetched dynamically via queries or other mechanisms). We showcased an example of a Static Web Table in the previous section.

On the other hand, the content in a Dynamic Web Table is not fixed. For example, when buying a laptop on an e-commerce website, the table’s contents (that shows the configuration) will change depending on the user’s configuration ‘customized.’

For demonstrating the handling of web tables in Selenium PHP, we would be using these web tables. You might face cross browser issues when dealing with web tables, particularly with the browser versions where there is no support for handling HTML Table APIs.

In the upcoming sections of this Selenium WebDriver PHP tutorial, we look at some of the widely used operations on web tables in Selenium PHP. The HTML code of the web table used for demonstration is available here.

We would be using the PHPUnit framework for executing the tests. The necessary packages (or dependencies) have to be downloaded before we move ahead with the implementation. For downloading the dependencies, we create composer.json in the project root folder.

{
   "require":{
      "php":">=7.1",
      "phpunit/phpunit":"^9",
      "phpunit/phpunit-selenium": "*",
      "php-webdriver/webdriver":"1.8.0",
      "symfony/symfony":"4.4",
      "brianium/paratest": "dev-master"
   }
}
Enter fullscreen mode Exit fullscreen mode

Run the following command on the terminal to download the dependencies.

composer require
Enter fullscreen mode Exit fullscreen mode

Press the ‘Enter’ button twice to proceed with the installation of the downloaded packages.

After the download and installation process, the PHPUnit framework will be present in the vendor\bin folder. With the completion of the basic setup, we proceed with the demonstration of handling web tables in Selenium PHP.

The tests are executed on LambdaTest’s cloud-based Selenium Grid. These web tables will be used for all the demonstrations.

How To Compute The Number Of Rows and Columns In A Web Table?

The tr tag in HTML indicates rows and td tag indicates columns in a web table. The row tag i.e. tr is used for getting information about the number of rows in the table.

We used the POM Builder extension in Chrome instead of the Inspect tool for getting information about the required web element (i.e., R-1, C- 1). Hence, the XPath [//*[@id=’customers’]/tbody/tr[2]/td] is used for calculating the number of columns in the table.

The th tag can be used for calculating the number of columns in the table. The XPath //*[@id=’customers’]/tbody/tr/th is used for computing the number of columns in the table.

Alternatively, the XPath //table//th can also be used for computing the columns since all column headings are marked with the th tag.

Implementation

<?php
require 'vendor/autoload.php';

use PHPUnit\Framework\TestCase;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverBy;

$GLOBALS['LT_USERNAME'] = "user-name";
$GLOBALS['LT_APPKEY'] = "access-key";

class WebTable_Get_Rows_ColsTest extends TestCase
{
  protected $webDriver;

  public function build_browser_capabilities(){
    /* $capabilities = DesiredCapabilities::chrome(); */
    $capabilities = array(
      "build" => "[PHP-1] Counting number of rows and columns in WebTable",
      "name" => "[PHP-1] Counting number of rows and columns in WebTable",
      "platform" => "Windows 10",
      "browserName" => "Chrome",
      "version" => "85.0"
    );
    return $capabilities;
  }

  public function setUp(): void
  {
    $url = "https://". $GLOBALS['LT_USERNAME'] .":" . $GLOBALS['LT_APPKEY'] ."@hub.lambdatest.com/wd/hub";
    $capabilities = $this->build_browser_capabilities();
    /* $this->webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub', $capabilities); */
    $this->webDriver = RemoteWebDriver::create($url, $capabilities);
  }

  public function tearDown(): void
  {
    $this->webDriver->quit();
  }
  /*
  * @test
  */ 
  public function test_SwitchToNewWindow()
  {
    $test_url = "https://www.w3schools.com/html/html_tables.asp";
    $title = "HTML Tables";

    $this->webDriver->get($test_url);
    $this->webDriver->manage()->window()->maximize();
    sleep(5);

    $driver = $this->webDriver;
    $this->webDriver->wait()->until(
      function () use ($driver) {
      $elements = $this->webDriver->findElements(WebDriverBy::className('w3-example'));
          return count($elements) > 0;
      },
      'Error locating W3 example element'
    );

    $num_rows = count ($this->webDriver->findElements(WebDriverBy::xpath("//*[@id='customers']/tbody/tr")));
    echo ("\nRows in table are " . $num_rows);

    $num_cols = count ($this->webDriver->findElements(WebDriverBy::xpath("//*[@id='customers']/tbody/tr[2]/td")));
    print("\nColumns in table are " . $num_cols);

    $this->assertEquals($title, $this->webDriver->getTitle());
  }
}
?>
Enter fullscreen mode Exit fullscreen mode

Code WalkThrough

Lines (4 – 7): Import (or use) all the necessary classes (or packages) whose methods would be used in the code.

use PHPUnit\Framework\TestCase;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverBy;
Enter fullscreen mode Exit fullscreen mode

Lines (9 – 11): Two global variables are used to store user-name and access-key. Username and access key are available in your profile section on LambdaTest.

$GLOBALS['LT_USERNAME'] = "user-name";
# accessKey:  AccessKey can be generated from automation dashboard or profile section
$GLOBALS['LT_APPKEY'] = "access-key";
Enter fullscreen mode Exit fullscreen mode

Lines (17 – 27): The browser capabilities array that was generated using the LambdaTest capabilities generator is used for testing.

public function build_browser_capabilities(){
    /* $capabilities = DesiredCapabilities::chrome(); */
    $capabilities = array(
      "build" =&gt; "[PHP-1] Counting number of rows and columns in WebTable",
      "name" =&gt; "[PHP-1] Counting number of rows and columns in WebTable",
      "platform" =&gt; "Windows 10",
      "browserName" =&gt; "Chrome",
      "version" =&gt; "85.0"
    );
    return $capabilities;
  }
Enter fullscreen mode Exit fullscreen mode

Line (34): The create method of the RemoteWebDriver class takes two parameters – LambdaTest Grid URL, i.e. [@hub.lambdatest.com/wd/hub] and browser capabilities.

$this-&gt;webDriver = RemoteWebDriver::create($url, $capabilities);
Enter fullscreen mode Exit fullscreen mode

Lines (53 – 60): An explicit wait is triggered for ensuring the loading of the web table with CLASS_NAME = w3-example. The default wait duration is 30 seconds, post which Selenium framework raises an ElementNotVisibleException exception.

If the element is loaded within the designated time-frame, the count operation will return a non-zero value.

$driver = $this-&gt;webDriver;
$this-&gt;webDriver-&gt;wait()-&gt;until(
function () use ($driver) {
      $elements = $this-&gt;webDriver-&gt;findElements(WebDriverBy::className('w3-example'));
          return count($elements) &gt; 0;
},
'Error locating W3 example element'
);
Enter fullscreen mode Exit fullscreen mode

Lines (62 – 63): The XPath [//*[@id=’customers’]/tbody/tr] is used to get details about the number of rows in the table. Instead of the XPath used in the code, the XPath [//table//tr] can also be used to get all tr elements in the table.

$num_rows = count ($this-&gt;webDriver-&gt;findElements(WebDriverBy::xpath("//*[@id='customers']/tbody/tr")));
echo ("\nRows in table are " . $num_rows);
Enter fullscreen mode Exit fullscreen mode

Lines (65 – 66): The XPath [//*[@id=’customers’]/tbody/tr[2]/td] is used to get details about the number of columns in the table. Alternatively, the //table//th XPATH can also be used to get the number of columns.

$num_cols = count ($this-&gt;webDriver-&gt;findElements(WebDriverBy::xpath("//*[@id='customers']/tbody/tr[2]/td")));
echo("\nColumns in table are " . $num_cols);
Enter fullscreen mode Exit fullscreen mode

Execution

For counting the number of rows and columns in Selenium PHP, run the following command on the terminal:

vendor\bin\phpunit WebTable_Get_Rows_ColsTest.php
Enter fullscreen mode Exit fullscreen mode

Here is the execution snapshot which outputs the number of rows (i.e., 7) and columns (i.e., 3) present in the table:

How To Print The Content Of Web Tables In Selenium PHP?

We iterate through the rows (i.e., tr) in the table for accessing the contents in each row and column of the web table. Post this, the tags under the corresponding row (tr) are also iterated.

Since the number of rows and columns are dynamic, they are computed dynamically. The following XPaths are used for accessing the data available in specific (row + column) combination:

  • XPath for accessing R:2, C:1 – //*[@id=”customers”]/tbody/tr[2]/td[1]
  • XPath for accessing R:3, C:2 – //*[@id=”customers”]/tbody/tr[3]/td[1]

Implementation

<?php
require 'vendor/autoload.php';

use PHPUnit\Framework\TestCase;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverBy;

$GLOBALS['LT_USERNAME'] = "user-name";
$GLOBALS['LT_APPKEY'] = "access-key";

class WebTable_Print_Rows_ColsTest extends TestCase
{
  protected $webDriver;

  public function build_browser_capabilities(){
    /* $capabilities = DesiredCapabilities::chrome(); */
    $capabilities = array(
      "build" => "[PHP-2] Print the data available in rows and columns",
      "name" => "[PHP-2] Print the data available in rows and columns",
      "platform" => "Windows 10",
      "browserName" => "Chrome",
      "version" => "85.0"
    );
    return $capabilities;
  }

  public function setUp(): void
  {
    $url = "https://". $GLOBALS['LT_USERNAME'] .":" . $GLOBALS['LT_APPKEY'] ."@hub.lambdatest.com/wd/hub";
    $capabilities = $this->build_browser_capabilities();
    $this->webDriver = RemoteWebDriver::create($url, $capabilities);
  }

  public function tearDown(): void
  {
    $this->webDriver->quit();
  }
  /*
  * @test
  */ 
  public function test_SwitchToNewWindow()
  {
    $test_url = "https://www.w3schools.com/html/html_tables.asp";
    $title = "HTML Tables";
    $before_XPath = "//*[@id='customers']/tbody/tr[";
    $aftertd_XPath = "]/td[";
    $aftertr_XPath = "]";

    $this->webDriver->get($test_url);
    $this->webDriver->manage()->window()->maximize();
    sleep(5);

    $driver = $this->webDriver;
    $this->webDriver->wait()->until(
    function () use ($driver) {
        $elements = $this->webDriver->findElements(WebDriverBy::className('w3-example'));
        return count($elements) > 0;
    },
    'Error locating W3 example element'
    );

    $rows = count ($this->webDriver->findElements(WebDriverBy::xpath("//*[@id='customers']/tbody/tr")));
    echo ("\nRows in table are " . $rows);

    $columns = count ($this->webDriver->findElements(WebDriverBy::xpath("//*[@id='customers']/tbody/tr[2]/td")));
    echo("\nColumns in table are " . $columns);
    echo("\n");
    echo("\n");

    for($t_row = 2; $t_row <= $rows; $t_row++)
    {
        for($t_column = 1; $t_column <= $columns; $t_column++)
        {
            $FinalXPath = $before_XPath .$t_row. $aftertd_XPath .$t_column. $aftertr_XPath;
            $cell = $this->webDriver->findElement(WebDriverBy::xpath($FinalXPath));
            $cell_text = $cell->getText();
            echo($cell_text);
            echo("\n");
        }
        echo("\n");
    }
    $this->assertEquals($title, $this->webDriver->getTitle());
  }
}
?>
Enter fullscreen mode Exit fullscreen mode

Code WalkThrough

Most of the implementation is the same as the one used in the previous example.

The test method test_SwitchToNewWindow contains the implementation for printing the data available in each cell of the table.

Lines (46 – 48): The XPath for accessing a specific row and column has two variables (i.e., row number and column number).

The XPath (//*[@id=”customers”]/tbody/tr[row-number]/td[column-number]) is subdivided into multiple strings to accommodate static (i.e. unchanged) and dynamic (i.e. combination of row and column) properties in the XPath.

$before_XPath = "//*[@id='customers']/tbody/tr[";
$aftertd_XPath = "]/td[";
$aftertr_XPath = "]";
Enter fullscreen mode Exit fullscreen mode

Lines (71 – 83): The sample table has 7 rows and 3 columns. Hence, a nested for loop is executed with rows ranging from 2..7 and columns ranging from 1..3

The final XPath used for fetching the data available in a specific cell (i.e., a combination of row and column) is created using a combination of fixed Path and variable factors like row & column whose data has to be read.

for($t_row = 2; $t_row &lt;= $rows; $t_row++)
{
  for($t_column = 1; $t_column &lt;= $columns; $t_column++) { $FinalXPath = $before_XPath .$t_row. $aftertd_XPath .$t_column. $aftertr_XPath; $cell = $this-&gt;webDriver-&gt;findElement(WebDriverBy::xpath($FinalXPath));
    $cell_text = $cell-&gt;getText();
    echo($cell_text);
    echo(" ");
  }
  echo("\n");
}
Enter fullscreen mode Exit fullscreen mode

The XPath for reading data in any cell is formed using the following combination:

"//*[@id='customers']/tbody/tr[" .$t_row. "]/td[" .$t_column. "]"
Enter fullscreen mode Exit fullscreen mode

This is how the XPaths for different cells are generated:

  • XPath for (2 , 1) ? //*[@id=”customers”]/tbody/tr[2]/td[1]
  • XPath for (2, 3) ? //*[@id=”customers”]/tbody/tr[2]/td[3]
  • XPath for (7 , 2) ? //*[@id=”customers”]/tbody/tr[7]/td[2] and so on…

We start the reading from the 2nd row since the first row contains the title and is skipped from the read operation.

Execution

As seen in the execution snapshot, the data in every cell is read and printed on the terminal:

How To Read Data From Rows Of Web Tables In Selenium PHP?

In this section of the Selenium WebDriver PHP Tutorial, we demonstrate how to read the data row-wise from web tables. As we are reading row-wise, rows () would be variable, whereas columns () would remain constant.

Here are the sample XPaths for accessing the information available in (R2, C1), (R2, C2), and (R2, C3).

  • XPath for accessing R:2, C:1 – //*[@id=”customers”]/tbody/tr[2]/td[1]
  • XPath for accessing R:2, C:2 – //*[@id=”customers”]/tbody/tr[2]/td[2]
  • XPath for accessing R:3, C:2 – //*[@id=”customers”]/tbody/tr[3]/td[2]

Since the first row is the title, we start reading from row – 2. A for loop is executed with values ranging from 2..7, with 7 signifying the number of rows in the table. The corresponding column numbers are added to the row numbers to form a row-column (RC) combination.

Here is the XPath that is used for reading data from a particular row:

"//*[@id='customers']/tbody/tr[" .$t_row. "]/td[column_number]"
Enter fullscreen mode Exit fullscreen mode

For reading the complete data from Row-2, $t_row will be 2, and the column_number will vary from 1..3. Here are the XPaths for reading data from Row-2:

Row and Column number XPath
R – 2, C – 1 //*[@id=’customers’]/tbody/tr[2]/td[1]
R – 2, C – 2 //*[@id=’customers’]/tbody/tr[2]/td[2]
R – 2, C – 3 //*[@id=’customers’]/tbody/tr[2]/td[3]

Implementation

<?php
require 'vendor/autoload.php';

use PHPUnit\Framework\TestCase;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverBy;

$GLOBALS['LT_USERNAME'] = "user-name";
$GLOBALS['LT_APPKEY'] = "access-key";

class WebTable_Get_Rows_DataTest extends TestCase
{
  protected $webDriver;

  public function build_browser_capabilities(){
    /* $capabilities = DesiredCapabilities::chrome(); */
    $capabilities = array(
      "build" => "[PHP-3] Read data in the rows of a web table",
      "name" => "[PHP-3] Read data in the rows of a web table",
      "platform" => "Windows 10",
      "browserName" => "Chrome",
      "version" => "85.0"
    );
    return $capabilities;
  }

  public function setUp(): void
  {
    $url = "https://". $GLOBALS['LT_USERNAME'] .":" . $GLOBALS['LT_APPKEY'] ."@hub.lambdatest.com/wd/hub";
    $capabilities = $this->build_browser_capabilities();
    $this->webDriver = RemoteWebDriver::create($url, $capabilities);
  }

  public function tearDown(): void
  {
    $this->webDriver->quit();
  }
  /*
  * @test
  */ 
  public function test_SwitchToNewWindow()
  {
    $test_url = "https://www.w3schools.com/html/html_tables.asp";
    $title = "HTML Tables";
    $before_XPath = "//*[@id='customers']/tbody/tr[";
    $aftertd_XPath_1 = "]/td[1]";
    $aftertd_XPath_2 = "]/td[2]";
    $aftertd_XPath_3 = "]/td[3]";

    $this->webDriver->get($test_url);
    $this->webDriver->manage()->window()->maximize();
    sleep(5);

    $driver = $this->webDriver;
    $this->webDriver->wait()->until(
    function () use ($driver) {
        $elements = $this->webDriver->findElements(WebDriverBy::className('w3-example'));
        return count($elements) > 0;
    },
    'Error locating W3 example element'
    );

    $rows = count ($this->webDriver->findElements(WebDriverBy::xpath("//*[@id='customers']/tbody/tr")));
    echo ("\nRows in table are " . $rows);
    echo("\n");

    $cols = count ($this->webDriver->findElements(WebDriverBy::xpath("//*[@id='customers']/tbody/tr[2]/td")));
    print("\nColumns in table are " . $cols);
    echo("\n\n");

    $this->assertEquals($title, $this->webDriver->getTitle());

    echo("Data present in Rows, Col - 1\n");
    echo("-----------------------------\n");
    echo("\n");

    for($t_row = 2; $t_row <= ($rows); $t_row++)
    {
        $FinalXPath = $before_XPath .$t_row. $aftertd_XPath_1;
        $cell = $this->webDriver->findElement(WebDriverBy::xpath($FinalXPath));
        $cell_text = $cell->getText();
        echo($cell_text);
        echo("\n");
    }
    echo("\n\n");
    echo("Data present in Rows, Col - 2\n");
    echo("-----------------------------\n");
    echo("\n");

    for($t_row = 2; $t_row <= ($rows); $t_row++)
    {
       $FinalXPath = $before_XPath .$t_row. $aftertd_XPath_2;
        $cell = $this->webDriver->findElement(WebDriverBy::xpath($FinalXPath));
        $cell_text = $cell->getText();
        echo($cell_text);
        echo("\n");
    }

    echo("\n\n");
    echo("Data present in Rows, Col - 3\n");
    echo("-----------------------------\n");
    echo("\n");

    for($t_row = 2; $t_row <= ($rows); $t_row++)
    {
        $FinalXPath = $before_XPath .$t_row. $aftertd_XPath_3;
        $cell = $this->webDriver->findElement(WebDriverBy::xpath($FinalXPath));
        $cell_text = $cell->getText();
        echo($cell_text);
        echo("\n");
    }
    echo("\n\n");
    echo("Fetched all the records from the table\n");   
  }
}
?>
Enter fullscreen mode Exit fullscreen mode

Code WalkThrough

Lines (47 – 50): $before_XPath holds the static part of the XPath. As mentioned earlier, the $before_XPath will be appended with the Row number (which in our case ranges from 2..7).

The newly formed string will be appended to the XPath of the corresponding column number (i.e. “]/td[1]” for Column-1, “]/td[2]” for Column-2, and so on).

$before_XPath = "//*[@id='customers']/tbody/tr[";
$aftertd_XPath_1 = "]/td[1]";
$aftertd_XPath_2 = "]/td[2]";
$aftertd_XPath_3 = "]/td[3]";
Enter fullscreen mode Exit fullscreen mode

Lines (79 – 86): Here is the implementation for printing values available in rows (2..7) and column (1), i.e. (R-2, C-1), (R-3, C-1), (R-3, C-1) and so on…

In the code shown below, XPath for the column – 1 (i.e., td[1]) is appended to the computed XPath.

for($t_row = 2; $t_row &lt;= ($rows); $t_row++) { $FinalXPath = $before_XPath .$t_row. $aftertd_XPath_1; $cell = $this-&gt;webDriver-&gt;findElement(WebDriverBy::xpath($FinalXPath));
    $cell_text = $cell-&gt;getText();
    echo($cell_text);
    echo("\n");
}
Enter fullscreen mode Exit fullscreen mode

The for loop will be executed with rows ranging from 2..7. The corresponding column values (td[1]/td[2]/td[3]) are appended depending on the column that has to be accessed.

Execution

As seen in the execution snapshot, a ‘row-wise’ read is performed on every cell in the table.

How to read data from Columns of web tables in Selenium PHP?

In the previous section, we performed a ‘row-wise’ read of the web table. In this section of the Selenium WebDriver PHP Tutorial, we would perform a ‘column-wise’ read operation. For column-wise read, rows would remain constant, whereas the column number is the variable factor (i.e., column number is computed dynamically).

Here are the XPaths used for accessing the information with ‘constant’ rows and ‘variable’ columns:

  • XPath for accessing R:2, C:2 – //*[@id=”customers”]/tbody/tr[2]/td[2]
  • XPath for accessing R:2, C:3 – //*[@id=”customers”]/tbody/tr[2]/td[3]
  • XPath for accessing R:2, C:4 – //*[@id=”customers”]/tbody/tr[2]/td[4]

Shown below is the sample XPath used for reading data from Row-2 and all the columns [i.e. (2,1), (2,2), (2,3)… (2,7)].

"//*[@id='customers']/tbody/tr[2]/th[".$t_column. "]"
Enter fullscreen mode Exit fullscreen mode

For reading the complete data from Column-1, $t_column will be 1, and the row_number will vary from 1..3. Here are the XPaths for reading data from Row-2:

Row and Column number XPath
R – 2, C – 1 //*[@id=’customers’]/tbody/tr[2]/td[1]
R – 3, C – 1 //*[@id=’customers’]/tbody/tr[3]/td[1]
R – 4, C – 1 //*[@id=’customers’]/tbody/tr[4]/td[1]

Implementation

<?php
require 'vendor/autoload.php';

use PHPUnit\Framework\TestCase;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverBy;

$GLOBALS['LT_USERNAME'] = "user-name";
$GLOBALS['LT_APPKEY'] = "access-key";

class WebTable_Get_Cols_DataTest extends TestCase
{
  protected $webDriver;

  public function build_browser_capabilities(){
    /* $capabilities = DesiredCapabilities::chrome(); */
    $capabilities = array(
      "build" => "[PHP-4] Read data in the columns of a web table",
      "name" => "[PHP-4] Read data in the columns of a web table",
      "platform" => "Windows 10",
      "browserName" => "Chrome",
      "version" => "85.0"
    );
    return $capabilities;
  }

  public function setUp(): void
  {
    $url = "https://". $GLOBALS['LT_USERNAME'] .":" . $GLOBALS['LT_APPKEY'] ."@hub.lambdatest.com/wd/hub";
    $capabilities = $this->build_browser_capabilities();
    /* $this->webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub', $capabilities); */
    $this->webDriver = RemoteWebDriver::create($url, $capabilities);
  }

  public function tearDown(): void
  {
    $this->webDriver->quit();
  }
  /*
  * @test
  */ 
  public function test_SwitchToNewWindow()
  {
    $test_url = "https://www.w3schools.com/html/html_tables.asp";
    $title = "HTML Tables";
    $before_XPath_1 = "//*[@id='customers']/tbody/tr[1]/th[";
    $before_XPath_2 = "//*[@id='customers']/tbody/tr[2]/td[";
    $after_XPath = "]";

    $this->webDriver->get($test_url);
    $this->webDriver->manage()->window()->maximize();
    sleep(5);

    $driver = $this->webDriver;
    $this->webDriver->wait()->until(
    function () use ($driver) {
        $elements = $this->webDriver->findElements(WebDriverBy::className('w3-example'));
        return count($elements) > 0;
    },
    'Error locating W3 example element'
    );

    $rows = count ($this->webDriver->findElements(WebDriverBy::xpath("//*[@id='customers']/tbody/tr")));
    echo ("Rows in table are " . $rows);

    $columns = count ($this->webDriver->findElements(WebDriverBy::xpath("//*[@id='customers']/tbody/tr[2]/td")));
    echo("\nColumns in table are " . $columns);
    echo("\n");
    echo("\n");

    $this->assertEquals($title, $this->webDriver->getTitle());

    echo("\n\n");
    echo("Data present in Col - 1 i.e. Title\n");
    echo("-----------------------------\n");
    echo("\n");

    for($t_col = 1; $t_col <= $columns; $t_col++)
    {
        $FinalXPath = $before_XPath_1 .$t_col. $after_XPath;
        $cell = $this->webDriver->findElement(WebDriverBy::xpath($FinalXPath));
        $cell_text = $cell->getText();
        echo($cell_text);
        echo("\n");
    }

    echo("\n\n");
    echo("Data present in Col - 2\n");
    echo("-----------------------\n");
    echo("\n");

    for($t_col = 1; $t_col <= $columns; $t_col++)
    {
        $FinalXPath = $before_XPath_2 .$t_col. $after_XPath;
        $cell = $this->webDriver->findElement(WebDriverBy::xpath($FinalXPath));
        $cell_text = $cell->getText();
        echo($cell_text);
        echo("\n");
    }   
    echo("\n\n");
    echo("Fetched all the records from the table\n");
  }
}
?>
Enter fullscreen mode Exit fullscreen mode

Code WalkThrough

Lines (47 – 49): $before_XPath_1 holds the static part of the XPath for row 1 (i.e., row with the Header). The variable $before_XPath_2 has the static part of the XPath for row 2.

As mentioned earlier, the column-number will be appended to the XPaths to form the resultant XPath, which will be used to navigate the appropriate cell.

$before_XPath_1 = "//*[@id='customers']/tbody/tr[1]/th["; 
$before_XPath_2 = "//*[@id='customers']/tbody/tr[2]/td["; 
$after_XPath = "]";
Enter fullscreen mode Exit fullscreen mode

Lines (79 – 86): Here is the implementation for printing values available in columns (1..3) with row number being constant (i.e., row number = 1).

In the code shown below, XPath for row – 1 (i.e., tr[1]) is appended to the computed XPath.

for($t_col = 1; $t_col <= ($columns); $t_col++) 
{ 
$FinalXPath = $before_XPath_1 .$t_col. $after_XPath; 
$cell = $this->webDriver->findElement(WebDriverBy::xpath($FinalXPath)); $cell_text = $cell->getText(); 
echo($cell_text); 
echo("\n"); }
Enter fullscreen mode Exit fullscreen mode

The for loop will be executed with columns ranging from 1..3. The corresponding row values (tr[1]/tr[2]/tr[3]… tr[7]) are appended depending on the row that has to be accessed.

Execution

As seen in the execution snapshot, a ‘column-wise’ read is performed on every cell in the table.

How To Locate An Element In Web Tables In Selenium PHP?

In this test, we look for an element in the table and alert whether the element is present or not. The content in each cell is read, and a case insensitive search is performed to check the element’s presence.

Implementation

<?php
require 'vendor/autoload.php';

use PHPUnit\Framework\TestCase;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverBy;

$GLOBALS['LT_USERNAME'] = "user-name";
$GLOBALS['LT_APPKEY'] = "access-key";

class WebTable_Search_DataTest extends TestCase
{
  protected $webDriver;

  public function build_browser_capabilities(){
    /* $capabilities = DesiredCapabilities::chrome(); */
    $capabilities = array(
      "build" => "[PHP-5] Perform a search for an element in the web table",
      "name" => "[PHP-5] Perform a search for an element in the web table",
      "platform" => "Windows 10",
      "browserName" => "Chrome",
      "version" => "85.0"
    );
    return $capabilities;
  }

  public function setUp(): void
  {
    $url = "https://". $GLOBALS['LT_USERNAME'] .":" . $GLOBALS['LT_APPKEY'] ."@hub.lambdatest.com/wd/hub";
    $capabilities = $this->build_browser_capabilities();
    /* $this->webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub', $capabilities); */
    $this->webDriver = RemoteWebDriver::create($url, $capabilities);
  }

  public function tearDown(): void
  {
    $this->webDriver->quit();
  }
  /*
  * @test
  */ 
  public function test_SwitchToNewWindow()
  {
    $test_url = "https://www.w3schools.com/html/html_tables.asp";
    $title = "HTML Tables";
    $before_XPath = "//*[@id='customers']/tbody/tr[";
    $aftertd_XPath = "]/td[";
    $aftertr_XPath = "]";
    $search_text = " Magazzini Alimentari Riuniti";

    $this->webDriver->get($test_url);
    $this->assertEquals($title, $this->webDriver->getTitle());
    $this->webDriver->manage()->window()->maximize();
    sleep(5);

    $driver = $this->webDriver;
    $this->webDriver->wait()->until(
    function () use ($driver) {
        $elements = $this->webDriver->findElements(WebDriverBy::className('w3-example'));
        return count($elements) > 0;
    },
    'Error locating W3 example element'
    );

    $rows = count ($this->webDriver->findElements(WebDriverBy::xpath("//*[@id='customers']/tbody/tr")));
    echo ("\nRows in table are " . $rows);

    $columns = count ($this->webDriver->findElements(WebDriverBy::xpath("//*[@id='customers']/tbody/tr[2]/td")));
    echo("\nColumns in table are " . $columns);
    echo("\n");
    echo("\n");

    $elem_found = False;

    for($t_row = 2; $t_row <= $rows; $t_row++)
    {
        for($t_column = 1; $t_column <= $columns; $t_column++)
        {
            $FinalXPath = $before_XPath . $t_row . $aftertd_XPath . $t_column . $aftertr_XPath;
            $cell = $this->webDriver->findElement(WebDriverBy::xpath($FinalXPath));
            $cell_text = $cell->getText();
            if ((strcasecmp($cell_text, $search_text)) == 0)
            {
                $concat_str = "Search Text " . $search_text . " is present at row " . $t_row . " and column " . $t_column . " in the table";
                echo($concat_str);
                $elem_found = True;
                break;
            }
        }
    }

    if ($elem_found == False)
    {
        echo("Search Text " . $search_text ." not found");
    }
  }
}
?>
Enter fullscreen mode Exit fullscreen mode

Code WalkThrough

Lines (47 – 50): As the search has to be performed on every cell in the web table, the row-numbers and column-numbers would be variable. We break the resultant XPath into three different parts, as shown below:

A nested for loop will be executed for parsing through the contents of the table. Hence, row-number and column-number will be fetched during run-time.

$before_XPath = "//*[@id='customers']/tbody/tr[";
$aftertd_XPath = "]/td[";
$aftertr_XPath = "]";
$search_text = " Magazzini Alimentari Riuniti";
Enter fullscreen mode Exit fullscreen mode

Lines (76 – 80): A nested for loop is used for navigating to every cell in the web table. The outer loop is based on the number of rows (i.e., it executes from 2..7), whereas the inner for loop is based on the number of columns (i.e., it executes from 1..3).

As seen in the previous step, the corresponding row and column are added to the variables used for defining the XPath.

For example, the XPath for the following RC combinations will be:

  • R-2, C-1 : //*[@id=”customers”]/tbody/tr[2]/td[1]
  • R-6, C-2 : //*[@id=”customers”]/tbody/tr[6]/td[2]
for($t_row = 2; $t_row <= $rows; $t_row++) 
{ 
for($t_column = 1; $t_column <= $columns; $t_column++) { $FinalXPath = $before_XPath . $t_row . $aftertd_XPath . $t_column . $aftertr_XPath; ................................ ................................ } }
Enter fullscreen mode Exit fullscreen mode

Lines (81 – 82): Using the getText method provided by Selenium in PHP, we read the text (or data) present in the current cell.

$cell = $this->webDriver->findElement(WebDriverBy::xpath($FinalXPath)); $cell_text = $cell->getText();
Enter fullscreen mode Exit fullscreen mode

Lines (83 – 89): A case-insensitive comparison is performed with the search string, and the cell details are printed if the string present in the current cell matches with the search string. A Boolean variable elem_found is set to True, and the loop is exited.

if ((strcasecmp($cell_text, $search_text)) == 0) 
{ 
$concat_str = "Search Text " . $search_text . " is present at row " . $t_row . " and column " . $t_column . " in the table"; 
echo($concat_str); 
$elem_found = True; 
break; }
Enter fullscreen mode Exit fullscreen mode

Lines (93 – 96): If the search term is not found, the Boolean variable elem_found is False, and we print that the search string is not present in the web table.

if ($elem_found == False) { echo("Search Text " . $search_text ." not found"); }
Enter fullscreen mode Exit fullscreen mode

Execution

We executed the code with two search strings – 1. LambdaTest, and 2. Yoshi tanNamuri.

As seen in the execution snapshot, the search string ‘LambdaTest’ is not present in the table:

Shown below is the execution snapshot where the search string is Magazzini Alimentari Riuniti. The string is present in the cell (7,1) in the table.



Though there are many more operations possible with web tables in Selenium PHP, we have covered the widely used operations in this Selenium PHP tutorial. Check out the most detailed Selenium PHP tutorial (with Examples)

Conclusion

Web tables are commonly used when information has to be displayed in a tabular format. The data in the cells could either be static or dynamic. Whether it is Selenium PHP or Selenium Python, or any other framework-language combination, web tables’ essentials remain unchanged.

You may face cross browser issues (especially with older browser versions and retired browsers like Internet Explorer) with web tables in Selenium PHP. Hence, it is recommended to verify the functionalities of tables on cross browser platforms like LambdaTest that lets you test tables in Selenium PHP across multiple combinations of browsers, devices (or emulators), and platforms.

Have you used web tables for Selenium web automation? If yes, what’s your experience with them? Have you learned anything that I’ve missed in this post? I’d love to benefit from your experience too!

Top comments (0)