mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 12:32:08 +02:00
Merge branch 'MDL-82373-401' of https://github.com/andrewnicols/moodle into MOODLE_401_STABLE
This commit is contained in:
commit
c12d07d9d4
2
admin/tool/usertours/amd/build/tour.min.js
vendored
2
admin/tool/usertours/amd/build/tour.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -36,6 +36,7 @@ import {dispatchEvent} from 'core/event_dispatcher';
|
||||
import {eventTypes} from './events';
|
||||
import {get_string as getString} from 'core/str';
|
||||
import {prefetchStrings} from 'core/prefetch';
|
||||
import PendingPromise from 'core/pending';
|
||||
|
||||
/**
|
||||
* The minimum spacing for tour step to display.
|
||||
@ -485,14 +486,22 @@ const Tour = class {
|
||||
return this.endTour();
|
||||
}
|
||||
|
||||
const pendingPromise = new PendingPromise(`tool_usertours/tour:_gotoStep-${stepConfig.stepNumber}`);
|
||||
|
||||
if (typeof stepConfig.delay !== 'undefined' && stepConfig.delay && !stepConfig.delayed) {
|
||||
stepConfig.delayed = true;
|
||||
window.setTimeout(this._gotoStep.bind(this), stepConfig.delay, stepConfig, direction);
|
||||
window.setTimeout(function(stepConfig, direction) {
|
||||
this._gotoStep(stepConfig, direction);
|
||||
pendingPromise.resolve();
|
||||
}, stepConfig.delay, stepConfig, direction);
|
||||
|
||||
return this;
|
||||
} else if (!stepConfig.orphan && !this.isStepActuallyVisible(stepConfig)) {
|
||||
let fn = direction == -1 ? 'getPreviousStepNumber' : 'getNextStepNumber';
|
||||
return this.gotoStep(this[fn](stepConfig.stepNumber), direction);
|
||||
const fn = direction == -1 ? 'getPreviousStepNumber' : 'getNextStepNumber';
|
||||
this.gotoStep(this[fn](stepConfig.stepNumber), direction);
|
||||
|
||||
pendingPromise.resolve();
|
||||
return this;
|
||||
}
|
||||
|
||||
this.hide();
|
||||
@ -503,6 +512,7 @@ const Tour = class {
|
||||
this.dispatchEvent(eventTypes.stepRendered, {stepConfig});
|
||||
}
|
||||
|
||||
pendingPromise.resolve();
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -820,12 +830,14 @@ const Tour = class {
|
||||
left: 0,
|
||||
});
|
||||
|
||||
const pendingPromise = new PendingPromise(`tool_usertours/tour:addStepToPage-${stepConfig.stepNumber}`);
|
||||
animationTarget
|
||||
.animate({
|
||||
scrollTop: this.calculateScrollTop(stepConfig),
|
||||
}).promise().then(function() {
|
||||
this.positionStep(stepConfig);
|
||||
this.revealStep(stepConfig);
|
||||
pendingPromise.resolve();
|
||||
return;
|
||||
}.bind(this))
|
||||
.catch(function() {
|
||||
@ -897,6 +909,7 @@ const Tour = class {
|
||||
*/
|
||||
revealStep(stepConfig) {
|
||||
// Fade the step in.
|
||||
const pendingPromise = new PendingPromise(`tool_usertours/tour:revealStep-${stepConfig.stepNumber}`);
|
||||
this.currentStepNode.fadeIn('', $.proxy(function() {
|
||||
// Announce via ARIA.
|
||||
this.announceStep(stepConfig);
|
||||
@ -910,6 +923,7 @@ const Tour = class {
|
||||
if (this.currentStepNode) {
|
||||
this.currentStepNode.focus();
|
||||
}
|
||||
pendingPromise.resolve();
|
||||
}, this), 100);
|
||||
|
||||
}, this));
|
||||
@ -1157,6 +1171,7 @@ const Tour = class {
|
||||
return this;
|
||||
}
|
||||
|
||||
const pendingPromise = new PendingPromise('tool_usertours/tour:hide');
|
||||
if (this.currentStepNode && this.currentStepNode.length) {
|
||||
this.currentStepNode.hide();
|
||||
if (this.currentStepPopper) {
|
||||
@ -1191,17 +1206,22 @@ const Tour = class {
|
||||
this.currentStepConfig = null;
|
||||
}
|
||||
|
||||
let fadeTime = 0;
|
||||
if (transition) {
|
||||
fadeTime = 400;
|
||||
}
|
||||
|
||||
// Remove the backdrop features.
|
||||
$('[data-flexitour="step-background"]').remove();
|
||||
$('[data-flexitour="step-backdrop"]').removeAttr('data-flexitour');
|
||||
$('[data-flexitour="backdrop"]').fadeOut(fadeTime, function() {
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
const backdrop = $('[data-flexitour="backdrop"]');
|
||||
if (backdrop.length) {
|
||||
if (transition) {
|
||||
const backdropRemovalPromise = new PendingPromise('tool_usertours/tour:hide:backdrop');
|
||||
backdrop.fadeOut(400, function() {
|
||||
$(this).remove();
|
||||
backdropRemovalPromise.resolve();
|
||||
});
|
||||
} else {
|
||||
backdrop.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove aria-describedby and tabindex attributes.
|
||||
if (this.currentStepNode && this.currentStepNode.length) {
|
||||
@ -1222,6 +1242,8 @@ const Tour = class {
|
||||
|
||||
this.currentStepNode = null;
|
||||
this.currentStepPopper = null;
|
||||
|
||||
pendingPromise.resolve();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -12,17 +12,7 @@ Feature: Delete H5P file from the content bank
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
And I am on site homepage
|
||||
And I turn editing mode on
|
||||
And the following config values are set as admin:
|
||||
| unaddableblocks | | theme_boost|
|
||||
And I add the "Navigation" block if not present
|
||||
And I configure the "Navigation" block
|
||||
And I set the following fields to these values:
|
||||
| Page contexts | Display throughout the entire site |
|
||||
And I press "Save changes"
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
And I am on the "Content bank" page
|
||||
And I click on "Upload" "link"
|
||||
And I click on "Choose a file..." "button"
|
||||
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
|
||||
@ -32,14 +22,16 @@ Feature: Delete H5P file from the content bank
|
||||
And I click on "Save changes" "button"
|
||||
|
||||
Scenario: Admins can delete content from the content bank
|
||||
Given I click on "More" "button"
|
||||
Given I wait "2" seconds
|
||||
And I click on "More" "button"
|
||||
And I should see "Delete"
|
||||
And I click on "Delete" "link" in the ".cb-toolbar-container" "css_element"
|
||||
And I click on "Delete" "link"
|
||||
And I should see "Are you sure you want to delete the content 'content2delete.h5p'"
|
||||
And I should not see "The content will only be deleted from the content bank"
|
||||
And I click on "Cancel" "button" in the "Delete content" "dialogue"
|
||||
Then I should see "content2delete.h5p"
|
||||
And I click on "More" "button"
|
||||
And I wait "2" seconds
|
||||
And I click on "More" "button"
|
||||
And I click on "Delete" "link" in the ".cb-toolbar-container" "css_element"
|
||||
And I click on "Delete" "button" in the "Delete content" "dialogue"
|
||||
And I wait until the page is ready
|
||||
@ -61,20 +53,21 @@ Feature: Delete H5P file from the content bank
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/find-the-words.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
When I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
When I am on the "Content bank" page
|
||||
And I should see "content2delete.h5p"
|
||||
And I follow "content2delete.h5p"
|
||||
And I wait "2" seconds
|
||||
And I click on "More" "button"
|
||||
Then I should not see "Delete"
|
||||
And I click on "Content bank" "link"
|
||||
And I am on the "Content bank" page
|
||||
And I click on "Upload" "link"
|
||||
And I click on "Choose a file..." "button"
|
||||
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
|
||||
And I click on "find-the-words.h5p" "link"
|
||||
And I click on "Select this file" "button"
|
||||
And I click on "Save changes" "button"
|
||||
And I click on "More" "button"
|
||||
And I wait "2" seconds
|
||||
And I click on "More" "button"
|
||||
And I should see "Delete"
|
||||
|
||||
Scenario: The number of times a content is used is displayed before removing it
|
||||
@ -86,10 +79,10 @@ Feature: Delete H5P file from the content bank
|
||||
And I click on "Link to the file" "radio"
|
||||
And I click on "Select this file" "button"
|
||||
And I click on "Save changes" "button"
|
||||
When I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Content bank" "link" in the "Navigation" "block"
|
||||
And I am on the "Content bank" page
|
||||
And I follow "content2delete.h5p"
|
||||
And I click on "More" "button"
|
||||
And I wait "2" seconds
|
||||
And I click on "More" "button"
|
||||
And I click on "Delete" "link" in the ".cb-toolbar-container" "css_element"
|
||||
Then I should see "Are you sure you want to delete the content 'content2delete.h5p'"
|
||||
And I should see "The content will only be deleted from the content bank"
|
||||
|
@ -55,6 +55,7 @@ Feature: We can use Single view
|
||||
And the following config values are set as admin:
|
||||
| fullnamedisplay | firstnamephonetic,lastnamephonetic |
|
||||
| alternativefullnameformat | middlename, alternatename, firstname, lastname |
|
||||
And I change window size to "large"
|
||||
And I am on the "Course 1" "grades > Grader report > View" page logged in as "teacher1"
|
||||
|
||||
Scenario: I can update grades, add feedback and exclude grades.
|
||||
|
@ -645,7 +645,6 @@ trait behat_session_trait {
|
||||
* @return void Throws an exception if it times out without the element being visible
|
||||
*/
|
||||
protected function ensure_node_is_visible($node) {
|
||||
|
||||
if (!$this->running_javascript()) {
|
||||
return;
|
||||
}
|
||||
@ -715,7 +714,6 @@ trait behat_session_trait {
|
||||
* @return NodeElement Throws an exception if it times out without being visible
|
||||
*/
|
||||
protected function ensure_element_is_visible($element, $selectortype) {
|
||||
|
||||
if (!$this->running_javascript()) {
|
||||
return;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
namespace Moodle\BehatExtension\Driver;
|
||||
|
||||
use Behat\Mink\Exception\DriverException;
|
||||
use OAndreyev\Mink\Driver\WebDriver as UpstreamDriver;
|
||||
|
||||
// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod
|
||||
@ -79,4 +80,14 @@ class WebDriver extends UpstreamDriver {
|
||||
public function post_key($key, $xpath) {
|
||||
throw new \Exception('No longer used - please use keyDown and keyUp');
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function stop(): void {
|
||||
try {
|
||||
parent::stop();
|
||||
} catch (DriverException $e) {
|
||||
error_log($e->getMessage());
|
||||
$this->webDriver = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +138,10 @@ M.util.CollapsibleRegion = function(Y, id, userpref, strtooltip) {
|
||||
from: {height:height}
|
||||
});
|
||||
|
||||
animation.on('start', () => M.util.js_pending('CollapsibleRegion'));
|
||||
animation.on('resume', () => M.util.js_pending('CollapsibleRegion'));
|
||||
animation.on('pause', () => M.util.js_complete('CollapsibleRegion'));
|
||||
|
||||
// Handler for the animation finishing.
|
||||
animation.on('end', function() {
|
||||
this.div.toggleClass('collapsed');
|
||||
@ -152,6 +156,8 @@ M.util.CollapsibleRegion = function(Y, id, userpref, strtooltip) {
|
||||
} else {
|
||||
this.icon.set('src', M.util.image_url('t/expanded', 'moodle'));
|
||||
}
|
||||
|
||||
M.util.js_complete('CollapsibleRegion');
|
||||
}, this);
|
||||
|
||||
// Hook up the event handler.
|
||||
|
@ -62,7 +62,6 @@ class behat_action_menu extends behat_base {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->ensure_node_is_visible($node);
|
||||
$node->click();
|
||||
}
|
||||
|
||||
@ -80,7 +79,6 @@ class behat_action_menu extends behat_base {
|
||||
// Gets the node based on the requested selector type and locator.
|
||||
$menuselector = ".moodle-actionmenu .dropdown.show .dropdown-menu";
|
||||
$node = $this->get_node_in_container("link", $menuitemstring, "css_element", $menuselector);
|
||||
$this->ensure_node_is_visible($node);
|
||||
$node->click();
|
||||
}
|
||||
|
||||
|
@ -738,7 +738,6 @@ class behat_forms extends behat_base {
|
||||
public function i_expand_the_autocomplete($field) {
|
||||
$csstarget = '.form-autocomplete-downarrow';
|
||||
$node = $this->get_node_in_container('css_element', $csstarget, 'form_row', $field);
|
||||
$this->ensure_node_is_visible($node);
|
||||
$node->click();
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,11 @@ use Behat\Mink\Element\NodeElement;
|
||||
use Behat\Mink\Exception\DriverException;
|
||||
use Behat\Mink\Exception\ElementNotFoundException;
|
||||
use Behat\Mink\Exception\ExpectationException;
|
||||
use Facebook\WebDriver\Exception\NoSuchAlertException;
|
||||
use Facebook\WebDriver\Exception\NoSuchElementException;
|
||||
use Facebook\WebDriver\Exception\StaleElementReferenceException;
|
||||
use Facebook\WebDriver\WebDriverAlert;
|
||||
use Facebook\WebDriver\WebDriverExpectedCondition;
|
||||
|
||||
/**
|
||||
* Cross component steps definitions.
|
||||
@ -262,12 +265,25 @@ class behat_general extends behat_base {
|
||||
$this->getSession()->switchToWindow($names[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for an alert to be displayed.
|
||||
*
|
||||
* @return WebDriverAlert
|
||||
*/
|
||||
public function wait_for_alert(): WebDriverAlert {
|
||||
$webdriver = $this->getSession()->getDriver()->getWebdriver();
|
||||
$webdriver->wait()->until(WebDriverExpectedCondition::alertIsPresent());
|
||||
|
||||
return $webdriver->switchTo()->alert();
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the currently displayed alert dialog. This step does not work in all the browsers, consider it experimental.
|
||||
* @Given /^I accept the currently displayed dialog$/
|
||||
*/
|
||||
public function accept_currently_displayed_alert_dialog() {
|
||||
$this->getSession()->getDriver()->getWebDriver()->switchTo()->alert()->accept();
|
||||
$alert = $this->wait_for_alert();
|
||||
$alert->accept();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -275,7 +291,8 @@ class behat_general extends behat_base {
|
||||
* @Given /^I dismiss the currently displayed dialog$/
|
||||
*/
|
||||
public function dismiss_currently_displayed_alert_dialog() {
|
||||
$this->getSession()->getDriver()->getWebDriver()->switchTo()->alert()->dismiss();
|
||||
$alert = $this->wait_for_alert();
|
||||
$alert->dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -286,9 +303,7 @@ class behat_general extends behat_base {
|
||||
* @param string $link
|
||||
*/
|
||||
public function click_link($link) {
|
||||
|
||||
$linknode = $this->find_link($link);
|
||||
$this->ensure_node_is_visible($linknode);
|
||||
$linknode->click();
|
||||
}
|
||||
|
||||
@ -393,11 +408,8 @@ class behat_general extends behat_base {
|
||||
* @param string $selectortype The type of what we look for
|
||||
*/
|
||||
public function i_click_on($element, $selectortype) {
|
||||
|
||||
// Gets the node based on the requested selector type and locator.
|
||||
$node = $this->get_selected_node($selectortype, $element);
|
||||
$this->ensure_node_is_visible($node);
|
||||
$node->click();
|
||||
$this->get_selected_node($selectortype, $element)->click();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -458,10 +470,56 @@ class behat_general extends behat_base {
|
||||
* @param string $nodeselectortype The type of selector where we look in
|
||||
*/
|
||||
public function i_click_on_in_the($element, $selectortype, $nodeelement, $nodeselectortype) {
|
||||
$node = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement);
|
||||
$node->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on the element with some modifier key pressed (alt, shift, meta or control).
|
||||
*
|
||||
* It is important to note that not all HTML elements are compatible with this step because
|
||||
* the webdriver limitations. For example, alt click on checkboxes with a visible label will
|
||||
* produce a normal checkbox click without the modifier.
|
||||
*
|
||||
* @When I :modifier click on :element :selectortype in the :nodeelement :nodeselectortype
|
||||
* @param string $modifier the extra modifier to press (for example, alt+shift or shift)
|
||||
* @param string $element Element we look for
|
||||
* @param string $selectortype The type of what we look for
|
||||
* @param string $nodeelement Element we look in
|
||||
* @param string $nodeselectortype The type of selector where we look in
|
||||
*/
|
||||
public function i_key_click_on_in_the($modifier, $element, $selectortype, $nodeelement, $nodeselectortype) {
|
||||
behat_base::require_javascript_in_session($this->getSession());
|
||||
|
||||
$key = null;
|
||||
switch (strtoupper(trim($modifier))) {
|
||||
case '':
|
||||
break;
|
||||
case 'SHIFT':
|
||||
$key = behat_keys::SHIFT;
|
||||
break;
|
||||
case 'CTRL':
|
||||
$key = behat_keys::CONTROL;
|
||||
break;
|
||||
case 'ALT':
|
||||
$key = behat_keys::ALT;
|
||||
break;
|
||||
case 'META':
|
||||
$key = behat_keys::META;
|
||||
break;
|
||||
default:
|
||||
throw new \coding_exception("Unknown modifier key '$modifier'}");
|
||||
}
|
||||
|
||||
$node = $this->get_node_in_container($selectortype, $element, $nodeselectortype, $nodeelement);
|
||||
$this->ensure_node_is_visible($node);
|
||||
|
||||
// KeyUP and KeyDown require the element to be displayed in the current window.
|
||||
$this->execute_js_on_node($node, '{{ELEMENT}}.scrollIntoView();');
|
||||
$node->keyDown($key);
|
||||
$node->click();
|
||||
// Any click action can move the scroll. Ensure the element is still displayed.
|
||||
$this->execute_js_on_node($node, '{{ELEMENT}}.scrollIntoView();');
|
||||
$node->keyUp($key);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -725,6 +725,15 @@ class behat_navigation extends behat_base {
|
||||
case 'Admin notifications':
|
||||
return new moodle_url('/admin/');
|
||||
|
||||
case 'Content bank':
|
||||
return new moodle_url('/contentbank/');
|
||||
|
||||
case 'My private files':
|
||||
return new moodle_url('/user/files.php');
|
||||
|
||||
case 'System logs report':
|
||||
return new moodle_url('/report/log/index.php');
|
||||
|
||||
default:
|
||||
throw new Exception('Unrecognised core page type "' . $name . '."');
|
||||
}
|
||||
|
@ -96,6 +96,7 @@ Feature: In a lesson activity, students can not re-attempt a question more than
|
||||
And I press the "back" button in the browser
|
||||
And I press the "back" button in the browser
|
||||
And I press the "back" button in the browser
|
||||
And I reload the page
|
||||
And I should see "Paper is made from trees"
|
||||
And I set the following fields to these values:
|
||||
| True | 1 |
|
||||
@ -117,6 +118,7 @@ Feature: In a lesson activity, students can not re-attempt a question more than
|
||||
And I press "Submit"
|
||||
And I should see "Wrong"
|
||||
And I press the "back" button in the browser
|
||||
And I reload the page
|
||||
And I set the following fields to these values:
|
||||
| True | 1 |
|
||||
When I press "Submit"
|
||||
@ -141,6 +143,7 @@ Feature: In a lesson activity, students can not re-attempt a question more than
|
||||
And I press "Submit"
|
||||
And I should see "Correct"
|
||||
And I press the "back" button in the browser
|
||||
And I reload the page
|
||||
And I set the following fields to these values:
|
||||
| False | 1 |
|
||||
And I press "Submit"
|
||||
|
@ -143,6 +143,9 @@ class behat_mod_quiz extends behat_question_base {
|
||||
return new moodle_url('/mod/quiz/review.php', ['attempt' => $attempt->id]);
|
||||
|
||||
case 'question bank':
|
||||
// The question bank does not handle fields at the edge of the viewport well.
|
||||
// Increase the size to avoid this.
|
||||
$this->execute('behat_general::i_change_window_size_to', ['window', 'large']);
|
||||
return new moodle_url('/question/edit.php', [
|
||||
'cmid' => $this->get_cm_by_quiz_name($identifier)->id,
|
||||
]);
|
||||
@ -579,7 +582,6 @@ class behat_mod_quiz extends behat_question_base {
|
||||
public function i_click_on_shuffle_for_section($heading) {
|
||||
$xpath = $this->get_xpath_for_shuffle_checkbox($heading);
|
||||
$checkbox = $this->find('xpath', $xpath);
|
||||
$this->ensure_node_is_visible($checkbox);
|
||||
$checkbox->click();
|
||||
}
|
||||
|
||||
|
@ -68,8 +68,12 @@ class behat_core_question extends behat_question_base {
|
||||
protected function resolve_page_instance_url(string $type, string $identifier): moodle_url {
|
||||
switch (strtolower($type)) {
|
||||
case 'course question bank':
|
||||
return new moodle_url('/question/edit.php',
|
||||
['courseid' => $this->get_course_id($identifier)]);
|
||||
// The question bank does not handle fields at the edge of the viewport well.
|
||||
// Increase the size to avoid this.
|
||||
$this->execute('behat_general::i_change_window_size_to', ['window', 'large']);
|
||||
return new moodle_url('/question/edit.php', [
|
||||
'courseid' => $this->get_course_id($identifier),
|
||||
]);
|
||||
|
||||
case 'course question categories':
|
||||
return new moodle_url('/question/bank/managecategories/category.php',
|
||||
|
@ -289,7 +289,6 @@ class behat_filepicker extends behat_base {
|
||||
}
|
||||
|
||||
$selectfilebutton = $this->find_button(get_string('getfile', 'repository'));
|
||||
$this->ensure_node_is_visible($selectfilebutton);
|
||||
$selectfilebutton->click();
|
||||
|
||||
// We wait for all the JS to finish as it is performing an action.
|
||||
@ -297,7 +296,6 @@ class behat_filepicker extends behat_base {
|
||||
|
||||
if ($overwriteaction !== false) {
|
||||
$overwritebutton = $this->find_button($overwriteaction);
|
||||
$this->ensure_node_is_visible($overwritebutton);
|
||||
$overwritebutton->click();
|
||||
|
||||
// We wait for all the JS to finish.
|
||||
|
@ -175,7 +175,6 @@ class behat_repository_upload extends behat_base {
|
||||
|
||||
if ($overwriteaction !== false) {
|
||||
$overwritebutton = $this->find_button($overwriteaction);
|
||||
$this->ensure_node_is_visible($overwritebutton);
|
||||
$overwritebutton->click();
|
||||
|
||||
// We wait for all the JS to finish.
|
||||
|
Loading…
x
Reference in New Issue
Block a user