protected function getElementAssociatedWithLabelElement($labelElement, $labelText)
{
// shorthand
$topElement = $this->getTopElement();
// what are we doing?
$log = usingLog()->startAction("find elements associated with label '{$labelText}'");
$inputElementId = null;
try {
$inputElementId = $log->addStep("determine id of corresponding input element", function () use($labelElement) {
return $labelElement->attribute('for');
});
} catch (Exception $e) {
usingLog()->writeToLog("label '{$labelText}' is missing the 'for' attribute");
// this is NOT fatal - the element might be nested
}
// what do we do next?
if ($inputElementId !== null) {
// where does the 'for' attribute go?
try {
$inputElement = $log->addStep("find the input element with the id '{$inputElementId}'", function () use($topElement, $inputElementId) {
return $topElement->getElement('id', $inputElementId);
});
// all done
$log->endAction();
return $inputElement;
} catch (Exception $e) {
$log->endAction("could not find element with id '{$inputElementId}'; does markup use 'name' when it should 'id'?");
// report the failure
throw new E5xx_ActionFailed(__METHOD__);
}
}
// if we get here, then the label doesn't say which element it is 'for'
//
// let's hope (assume?) that the input is inside the element
try {
// build up the xpath to use
$xpathList = ['descendant::label[normalize-space(text()) = "' . $labelText . '"]/input'];
// search using the xpath
$elements = $this->getElementsByXpath($xpathList);
// find the first one that the user can see
$inputElement = $this->returnNthVisibleElement(0, $elements);
// if we get here, we're good
$log->endAction();
return $inputElement;
} catch (Exception $e) {
$log->endAction("cound not find input element associated with label '{$labelText}'");
throw new E5xx_ActionFailed(__METHOD__);
}
}