Proyectos de Subversion Moodle

Rev

Rev 1 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1 Rev 11
Línea 30... Línea 30...
30
use Behat\Gherkin\Node\TableNode;
30
use Behat\Gherkin\Node\TableNode;
31
use Behat\Mink\Element\NodeElement;
31
use Behat\Mink\Element\NodeElement;
32
use Behat\Mink\Exception\DriverException;
32
use Behat\Mink\Exception\DriverException;
33
use Behat\Mink\Exception\ElementNotFoundException;
33
use Behat\Mink\Exception\ElementNotFoundException;
34
use Behat\Mink\Exception\ExpectationException;
34
use Behat\Mink\Exception\ExpectationException;
-
 
35
use Facebook\WebDriver\Exception\NoSuchAlertException;
35
use Facebook\WebDriver\Exception\NoSuchElementException;
36
use Facebook\WebDriver\Exception\NoSuchElementException;
36
use Facebook\WebDriver\Exception\StaleElementReferenceException;
37
use Facebook\WebDriver\Exception\StaleElementReferenceException;
-
 
38
use Facebook\WebDriver\WebDriverAlert;
-
 
39
use Facebook\WebDriver\WebDriverExpectedCondition;
Línea 37... Línea 40...
37
 
40
 
38
/**
41
/**
39
 * Cross component steps definitions.
42
 * Cross component steps definitions.
40
 *
43
 *
Línea 261... Línea 264...
261
        }
264
        }
262
        $this->getSession()->switchToWindow($names[0]);
265
        $this->getSession()->switchToWindow($names[0]);
263
    }
266
    }
Línea 264... Línea 267...
264
 
267
 
-
 
268
    /**
-
 
269
     * Wait for an alert to be displayed.
-
 
270
     *
-
 
271
     * @return WebDriverAlert
-
 
272
     */
-
 
273
    public function wait_for_alert(): WebDriverAlert {
-
 
274
        $webdriver = $this->getSession()->getDriver()->getWebdriver();
-
 
275
        $webdriver->wait()->until(WebDriverExpectedCondition::alertIsPresent());
-
 
276
 
-
 
277
        return $webdriver->switchTo()->alert();
-
 
278
    }
-
 
279
 
265
    /**
280
    /**
266
     * Accepts the currently displayed alert dialog. This step does not work in all the browsers, consider it experimental.
281
     * Accepts the currently displayed alert dialog. This step does not work in all the browsers, consider it experimental.
267
     * @Given /^I accept the currently displayed dialog$/
282
     * @Given /^I accept the currently displayed dialog$/
268
     */
283
     */
269
    public function accept_currently_displayed_alert_dialog() {
284
    public function accept_currently_displayed_alert_dialog() {
-
 
285
        $alert = $this->wait_for_alert();
270
        $this->getSession()->getDriver()->getWebDriver()->switchTo()->alert()->accept();
286
        $alert->accept();
Línea 271... Línea 287...
271
    }
287
    }
272
 
288
 
273
    /**
289
    /**
274
     * Dismisses the currently displayed alert dialog. This step does not work in all the browsers, consider it experimental.
290
     * Dismisses the currently displayed alert dialog. This step does not work in all the browsers, consider it experimental.
275
     * @Given /^I dismiss the currently displayed dialog$/
291
     * @Given /^I dismiss the currently displayed dialog$/
276
     */
292
     */
-
 
293
    public function dismiss_currently_displayed_alert_dialog() {
277
    public function dismiss_currently_displayed_alert_dialog() {
294
        $alert = $this->wait_for_alert();
Línea 278... Línea 295...
278
        $this->getSession()->getDriver()->getWebDriver()->switchTo()->alert()->dismiss();
295
        $alert->dismiss();
279
    }
296
    }
280
 
297
 
281
    /**
298
    /**
282
     * Clicks link with specified id|title|alt|text.
299
     * Clicks link with specified id|title|alt|text.
283
     *
300
     *
284
     * @When /^I follow "(?P<link_string>(?:[^"]|\\")*)"$/
301
     * @When /^I follow "(?P<link_string>(?:[^"]|\\")*)"$/
285
     * @throws ElementNotFoundException Thrown by behat_base::find
302
     * @throws ElementNotFoundException Thrown by behat_base::find
286
     * @param string $link
-
 
287
     */
303
     * @param string $link
288
    public function click_link($link) {
-
 
289
 
304
     */
290
        $linknode = $this->find_link($link);
305
    public function click_link($link) {
Línea 291... Línea 306...
291
        $this->ensure_node_is_visible($linknode);
306
        $linknode = $this->find_link($link);
292
        $linknode->click();
307
        $linknode->click();
Línea 391... Línea 406...
391
     * @When /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)"$/
406
     * @When /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)"$/
392
     * @param string $element Element we look for
407
     * @param string $element Element we look for
393
     * @param string $selectortype The type of what we look for
408
     * @param string $selectortype The type of what we look for
394
     */
409
     */
395
    public function i_click_on($element, $selectortype) {
410
    public function i_click_on($element, $selectortype) {
396
 
-
 
397
        // Gets the node based on the requested selector type and locator.
411
        // Gets the node based on the requested selector type and locator.
398
        $node = $this->get_selected_node($selectortype, $element);
412
        $this->get_selected_node($selectortype, $element)->click();
399
        $this->ensure_node_is_visible($node);
-
 
400
        $node->click();
-
 
401
    }
413
    }
Línea 402... Línea 414...
402
 
414
 
403
    /**
415
    /**
404
     * Sets the focus and takes away the focus from an element, generating blur JS event.
416
     * Sets the focus and takes away the focus from an element, generating blur JS event.
Línea 456... Línea 468...
456
     * @param string $selectortype The type of what we look for
468
     * @param string $selectortype The type of what we look for
457
     * @param string $nodeelement Element we look in
469
     * @param string $nodeelement Element we look in
458
     * @param string $nodeselectortype The type of selector where we look in
470
     * @param string $nodeselectortype The type of selector where we look in
459
     */
471
     */
460
    public function i_click_on_in_the($element, $selectortype, $nodeelement, $nodeselectortype) {
472
    public function i_click_on_in_the($element, $selectortype, $nodeelement, $nodeselectortype) {
461
 
-
 
462
        $node = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement);
473
        $node = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement);
463
        $this->ensure_node_is_visible($node);
-
 
464
        $node->click();
474
        $node->click();
465
    }
475
    }
Línea 466... Línea 476...
466
 
476
 
467
    /**
477
    /**
Línea 500... Línea 510...
500
            default:
510
            default:
501
                throw new \coding_exception("Unknown modifier key '$modifier'}");
511
                throw new \coding_exception("Unknown modifier key '$modifier'}");
502
        }
512
        }
Línea 503... Línea 513...
503
 
513
 
504
        $node = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement);
-
 
Línea 505... Línea 514...
505
        $this->ensure_node_is_visible($node);
514
        $node = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement);
506
 
515
 
507
        // KeyUP and KeyDown require the element to be displayed in the current window.
516
        // KeyUP and KeyDown require the element to be displayed in the current window.
508
        $this->execute_js_on_node($node, '{{ELEMENT}}.scrollIntoView();');
517
        $this->execute_js_on_node($node, '{{ELEMENT}}.scrollIntoView();');
Línea 1421... Línea 1430...
1421
        $tablenode = $this->get_selected_node('table', $table);
1430
        $tablenode = $this->get_selected_node('table', $table);
1422
        $tablexpath = $tablenode->getXpath();
1431
        $tablexpath = $tablenode->getXpath();
Línea 1423... Línea 1432...
1423
 
1432
 
1424
        $rowliteral = behat_context_helper::escape($row);
1433
        $rowliteral = behat_context_helper::escape($row);
1425
        $valueliteral = behat_context_helper::escape($value);
-
 
Línea 1426... Línea -...
1426
        $columnliteral = behat_context_helper::escape($column);
-
 
1427
 
-
 
1428
        if (preg_match('/^-?(\d+)-?$/', $column, $columnasnumber)) {
1434
        $valueliteral = behat_context_helper::escape($value);
1429
            // Column indicated as a number, just use it as position of the column.
-
 
1430
            $columnpositionxpath = "/child::*[position() = {$columnasnumber[1]}]";
-
 
1431
        } else {
-
 
1432
            // Header can be in thead or tbody (first row), following xpath should work.
-
 
1433
            $theadheaderxpath = "thead/tr[1]/th[(normalize-space(.)=" . $columnliteral . " or a[normalize-space(text())=" .
-
 
1434
                    $columnliteral . "] or div[normalize-space(text())=" . $columnliteral . "])]";
-
 
1435
            $tbodyheaderxpath = "tbody/tr[1]/td[(normalize-space(.)=" . $columnliteral . " or a[normalize-space(text())=" .
-
 
1436
                    $columnliteral . "] or div[normalize-space(text())=" . $columnliteral . "])]";
-
 
1437
 
-
 
1438
            // Check if column exists.
-
 
1439
            $columnheaderxpath = $tablexpath . "[" . $theadheaderxpath . " | " . $tbodyheaderxpath . "]";
-
 
1440
            $columnheader = $this->getSession()->getDriver()->find($columnheaderxpath);
-
 
1441
            if (empty($columnheader)) {
-
 
1442
                $columnexceptionmsg = $column . '" in table "' . $table . '"';
-
 
1443
                throw new ElementNotFoundException($this->getSession(), "\n$columnheaderxpath\n\n".'Column', null, $columnexceptionmsg);
-
 
1444
            }
-
 
1445
            // Following conditions were considered before finding column count.
-
 
1446
            // 1. Table header can be in thead/tr/th or tbody/tr/td[1].
-
 
1447
            // 2. First column can have th (Gradebook -> user report), so having lenient sibling check.
-
 
1448
            $columnpositionxpath = "/child::*[position() = count(" . $tablexpath . "/" . $theadheaderxpath .
-
 
Línea 1449... Línea 1435...
1449
                "/preceding-sibling::*) + 1]";
1435
 
1450
        }
1436
        $columnpositionxpath = $this->get_table_column_xpath($table, $column);
1451
 
1437
 
1452
        // Check if value exists in specific row/column.
1438
        // Check if value exists in specific row/column.
Línea 1488... Línea 1474...
1488
            $this->getSession()
1474
            $this->getSession()
1489
        );
1475
        );
1490
    }
1476
    }
Línea 1491... Línea 1477...
1491
 
1477
 
-
 
1478
    /**
-
 
1479
     * Get xpath for a row child that corresponds to the specified column header
-
 
1480
     *
-
 
1481
     * @param string $table table identifier that can be used with 'table' node selector (i.e. table title or CSS class)
-
 
1482
     * @param string $column either text in the column header or the column number, such as -1-, -2-, etc
-
 
1483
     *      When matching the column header it has to be either exact match of the whole header or an exact
-
 
1484
     *      match of a text inside a link in the header.
-
 
1485
     *      For example, to match "<a>First name</a> / <a>Last name</a>" you need to specify either "First name" or "Last name"
-
 
1486
     * @return string
-
 
1487
     */
-
 
1488
    protected function get_table_column_xpath(string $table, string $column): string {
-
 
1489
        $tablenode = $this->get_selected_node('table', $table);
-
 
1490
        $tablexpath = $tablenode->getXpath();
-
 
1491
        $columnliteral = behat_context_helper::escape($column);
-
 
1492
        if (preg_match('/^-?(\d+)-?$/', $column, $columnasnumber)) {
-
 
1493
            // Column indicated as a number, just use it as position of the column.
-
 
1494
            $columnpositionxpath = "/child::*[position() = {$columnasnumber[1]}]";
-
 
1495
        } else {
-
 
1496
            // Header can be in thead or tbody (first row), following xpath should work.
-
 
1497
            $theadheaderxpath = "thead/tr[1]/th[(normalize-space(.)={$columnliteral} or a[normalize-space(text())=" .
-
 
1498
                    $columnliteral . "] or div[normalize-space(text())={$columnliteral}])]";
-
 
1499
            $tbodyheaderxpath = "tbody/tr[1]/td[(normalize-space(.)={$columnliteral} or a[normalize-space(text())=" .
-
 
1500
                    $columnliteral . "] or div[normalize-space(text())={$columnliteral}])]";
-
 
1501
 
-
 
1502
            // Check if column exists.
-
 
1503
            $columnheaderxpath = "{$tablexpath}[{$theadheaderxpath} | {$tbodyheaderxpath}]";
-
 
1504
            $columnheader = $this->getSession()->getDriver()->find($columnheaderxpath);
-
 
1505
            if (empty($columnheader)) {
-
 
1506
                if (strpos($column, '/') !== false) {
-
 
1507
                    // We are not able to match headers consisting of several links, such as "First name / Last name".
-
 
1508
                    // Instead we can match "First name" or "Last name" or "-1-" (column number).
-
 
1509
                    throw new Exception("Column matching locator \"$column\" not found. ".
-
 
1510
                        "If the column header contains multiple links, specify only one of the link texts. ".
-
 
1511
                        "Otherwise, use the column number as the locator");
-
 
1512
                }
-
 
1513
                $columnexceptionmsg = $column . '" in table "' . $table . '"';
-
 
1514
                throw new ElementNotFoundException($this->getSession(), "\n$columnheaderxpath\n\n".'Column',
-
 
1515
                    null, $columnexceptionmsg);
-
 
1516
            }
-
 
1517
            // Following conditions were considered before finding column count.
-
 
1518
            // 1. Table header can be in thead/tr/th or tbody/tr/td[1].
-
 
1519
            // 2. First column can have th (Gradebook -> user report), so having lenient sibling check.
-
 
1520
            $columnpositionxpath = "/child::*[position() = count({$tablexpath}/{$theadheaderxpath}" .
-
 
1521
                "/preceding-sibling::*) + 1]";
-
 
1522
        }
-
 
1523
        return $columnpositionxpath;
-
 
1524
    }
-
 
1525
 
-
 
1526
    /**
-
 
1527
     * Find a table row where each of the specified columns matches and throw exception if not found
-
 
1528
     *
-
 
1529
     * @param string $table table locator
-
 
1530
     * @param array $cells key is the column locator (name or index such as '-1-') and value is the text contents of the table cell
-
 
1531
     */
-
 
1532
    protected function ensure_table_row_exists(string $table, array $cells): void {
-
 
1533
        $tablenode = $this->get_selected_node('table', $table);
-
 
1534
        $tablexpath = $tablenode->getXpath();
-
 
1535
 
-
 
1536
        $columnconditions = [];
-
 
1537
        foreach ($cells as $columnname => $value) {
-
 
1538
            $valueliteral = behat_context_helper::escape($value);
-
 
1539
            $columnpositionxpath = $this->get_table_column_xpath($table, $columnname);
-
 
1540
            $columnconditions[] = '.' . $columnpositionxpath . "[contains(normalize-space(.)," . $valueliteral . ")]";
-
 
1541
        }
-
 
1542
        $rowxpath = $tablexpath . "/tbody/tr[" . join(' and ', $columnconditions) . ']';
-
 
1543
 
-
 
1544
        $rownode = $this->getSession()->getDriver()->find($rowxpath);
-
 
1545
        if (empty($rownode)) {
-
 
1546
            $rowlocator = array_map(fn($k) => "{$k} => {$cells[$k]}", array_keys($cells));
-
 
1547
            throw new ElementNotFoundException($this->getSession(), "\n$rowxpath\n\n".'Table row', null, join(', ', $rowlocator));
-
 
1548
        }
-
 
1549
    }
-
 
1550
 
-
 
1551
    /**
-
 
1552
     * Find a table row where each of the specified columns matches and throw exception if found
-
 
1553
     *
-
 
1554
     * @param string $table table locator
-
 
1555
     * @param array $cells key is the column locator (name or index such as '-1-') and value is the text contents of the table cell
-
 
1556
     */
-
 
1557
    protected function ensure_table_row_does_not_exist(string $table, array $cells): void {
-
 
1558
        try {
-
 
1559
            $this->ensure_table_row_exists($table, $cells);
-
 
1560
            // Throw exception if found.
-
 
1561
        } catch (ElementNotFoundException $e) {
-
 
1562
            // Table row/column doesn't contain this value. Nothing to do.
-
 
1563
            return;
-
 
1564
        }
-
 
1565
        $rowlocator = array_map(fn($k) => "{$k} => {$cells[$k]}", array_keys($cells));
-
 
1566
        throw new ExpectationException('Table row "' . join(', ', $rowlocator) .
-
 
1567
            '" is present in the table "' . $table . '"', $this->getSession()
-
 
1568
        );
-
 
1569
    }
-
 
1570
 
1492
    /**
1571
    /**
1493
     * Checks that the provided value exist in table.
1572
     * Checks that the provided value exist in table.
1494
     *
1573
     *
1495
     * First row may contain column headers or numeric indexes of the columns
1574
     * First row may contain column headers or numeric indexes of the columns
1496
     * (syntax -1- is also considered to be column index). Column indexes are
1575
     * (syntax -1- is also considered to be column index). Column indexes are
Línea 1503... Línea 1582...
1503
     *        | Header 1 | Header 2 | Header 3 |
1582
     *        | Header 1 | Header 2 | Header 3 |
1504
     *        | Value 1 | Value 2 | Value 3|
1583
     *        | Value 1 | Value 2 | Value 3|
1505
     */
1584
     */
1506
    public function following_should_exist_in_the_table($table, TableNode $data) {
1585
    public function following_should_exist_in_the_table($table, TableNode $data) {
1507
        $datahash = $data->getHash();
1586
        $datahash = $data->getHash();
-
 
1587
        if ($datahash && count($data->getRow(0)) != count($datahash[0])) {
-
 
1588
            // Check that the number of columns in the hash is the same as the number of the columns in the first row.
-
 
1589
            throw new coding_exception('Table contains duplicate column headers');
-
 
1590
        }
Línea 1508... Línea 1591...
1508
 
1591
 
1509
        foreach ($datahash as $row) {
-
 
1510
 
-
 
1511
            // Row contains only a single column, just assert it's present in the table.
-
 
1512
            if (count($row) === 1) {
-
 
1513
                $this->execute('behat_general::assert_element_contains_text', [reset($row), $table, 'table']);
-
 
1514
            } else {
-
 
1515
                // Iterate over all columns.
-
 
1516
                $firstcell = null;
1592
        foreach ($datahash as $row) {
1517
                foreach ($row as $column => $value) {
-
 
1518
                    if ($firstcell === null) {
-
 
1519
                        $firstcell = $value;
-
 
1520
                    } else {
-
 
1521
                        $this->row_column_of_table_should_contain($firstcell, $column, $table, $value);
-
 
1522
                    }
-
 
1523
                }
-
 
1524
            }
1593
            $this->ensure_table_row_exists($table, $row);
1525
        }
1594
        }
Línea 1526... Línea 1595...
1526
    }
1595
    }
1527
 
1596
 
1528
    /**
1597
    /**
-
 
1598
     * Checks that the provided values do not exist in a table.
-
 
1599
     *
-
 
1600
     * If there are more than two columns, we check that NEITHER of the columns 2..n match
1529
     * Checks that the provided values do not exist in a table.
1601
     * in the row where the first column matches
1530
     *
1602
     *
1531
     * @Then /^the following should not exist in the "(?P<table_string>[^"]*)" table:$/
1603
     * @Then /^the following should not exist in the "(?P<table_string>[^"]*)" table:$/
1532
     * @throws ExpectationException
1604
     * @throws ExpectationException
1533
     * @param string $table name of table
1605
     * @param string $table name of table
1534
     * @param TableNode $data table with first row as header and following values
1606
     * @param TableNode $data table with first row as header and following values
1535
     *        | Header 1 | Header 2 | Header 3 |
1607
     *        | Header 1 | Header 2 | Header 3 |
1536
     *        | Value 1 | Value 2 | Value 3|
1608
     *        | Value 1 | Value 2 | Value 3|
1537
     */
1609
     */
-
 
1610
    public function following_should_not_exist_in_the_table($table, TableNode $data) {
-
 
1611
        $datahash = $data->getHash();
-
 
1612
        if ($datahash && count($data->getRow(0)) != count($datahash[0])) {
-
 
1613
            // Check that the number of columns in the hash is the same as the number of the columns in the first row.
Línea 1538... Línea 1614...
1538
    public function following_should_not_exist_in_the_table($table, TableNode $data) {
1614
            throw new coding_exception('Table contains duplicate column headers');
1539
        $datahash = $data->getHash();
-
 
1540
 
-
 
1541
        foreach ($datahash as $value) {
1615
        }
1542
 
1616
 
1543
            // Row contains only a single column, just assert it's not present in the table.
-
 
1544
            if (count($value) === 1) {
1617
        foreach ($datahash as $value) {
1545
                $this->execute('behat_general::assert_element_not_contains_text', [reset($value), $table, 'table']);
1618
            if (count($value) > 2) {
1546
            } else {
1619
                // When there are more than two columns, what we really want to check is that for the rows
1547
                // Iterate over all columns.
-
 
1548
                $row = array_shift($value);
1620
                // where the first column matches, NEITHER of the other columns match.
1549
                foreach ($value as $column => $value) {
1621
                $columns = array_keys($value);
1550
                    try {
1622
                for ($i = 1; $i < count($columns); $i++) {
1551
                        $this->row_column_of_table_should_contain($row, $column, $table, $value);
-
 
1552
                        // Throw exception if found.
-
 
1553
                    } catch (ElementNotFoundException $e) {
-
 
1554
                        // Table row/column doesn't contain this value. Nothing to do.
-
 
1555
                        continue;
-
 
1556
                    }
1623
                    $this->ensure_table_row_does_not_exist($table, [
1557
                    throw new ExpectationException('"' . $column . '" with value "' . $value . '" is present in "' .
1624
                        $columns[0] => $value[$columns[0]],
-
 
1625
                        $columns[$i] => $value[$columns[$i]],
-
 
1626
                    ]);
1558
                        $row . '"  row for table "' . $table . '"', $this->getSession()
1627
                }
1559
                    );
1628
            } else {
1560
                }
1629
                $this->ensure_table_row_does_not_exist($table, $value);
Línea 1561... Línea 1630...
1561
            }
1630
            }