/** * Returns array of virtual methods (available selenium commands). Array will be sorted by keys (methodName). * * @return array Array of methods in format: ['methodName' => 'returnType'] * @throws \Exception */ public function getAvailableSeleniumCommands() { $methods = $this->_getBaseMethods() + $this->_getAutoGeneratedMethods() + $this->manualAddedMethods; $methods = Helper::filterByKeys($methods, null, $this->manualExcludedMethods); ksort($methods); return $methods; }
/** * Creates method and load data from specified XML nodes. * * * Typical html code that described method: * <pre><code> * <dt> * <strong> * <a name="addLocationStrategy"></a> * addLocationStrategy(strategyName,functionDefinition) * </strong> * </dt> * * <dd>Defines a new function for Selenium to locate elements on the page. * For example, if you define the strategy "foo", and someone runs click("foo=blah"), we'll run your * function, passing you the string "blah", and click on the element that your function returns, or throw an * "Element not found" error if your function returns null. * * We'll pass three arguments to your function: * <ul> * <li>locator: the string the user passed in</li> * <li>inWindow: the currently selected window</li> * <li>inDocument: the currently selected document</li> * </ul> * The function must return null if the element can't be found. * * <p>Arguments:</p> * <ul> * <li>strategyName - the name of the strategy to define; this should use only letters [a-zA-Z] with no * spaces or other punctuation. * </li> * <li>functionDefinition - a string defining the body of a function in JavaScript. For example: * < code >return inDocument.getElementById(locator);< / code > * </li> * </ul> * </dd> * </code></pre> * * @param \SimpleXMLElement $dt XML node, which contain determination * @param \SimpleXMLElement $dd XML node, which contain description * * @return Method */ private function _createMethodFromXML(\SimpleXMLElement $dt, \SimpleXMLElement $dd) { $method = Method::createNew(); // Name $method->name = (string) $dt->xpath('descendant::a[@name]')[0]->attributes()['name']; // Description (without arguments, returnValue, and related commands) $text = $dd->asXML(); if (Helper::contain('Arguments:', $text)) { $assertion = '<p>[\\s]*Arguments:'; } elseif (Helper::contain('Returns:', $text)) { $assertion = '<p>\\s*<dl>'; } elseif (Helper::contain('Related Assertions, automatically generated:', $text)) { $assertion = '<p>Related Assertions,'; } else { $assertion = null; } $regExp = $assertion ? '/<dd>\\s*(?P<description>[\\s\\S]+)(?=' . $assertion . ')/' : '/<dd>\\s*(?P<description>[\\s\\S]+)\\s*<\\/dd>/'; preg_match($regExp, $text, $matches) && array_key_exists('description', $matches) or die('Error at parse method description: ' . $text); $method->description = $matches['description']; // Arguments // arguments from determination preg_match('/([a-zA-Z]+)\\s*\\((?P<args>[a-zA-Z0-9\\,\\s]+)\\)/', $dt->asXML(), $m) && array_key_exists('args', $m) or die('Error at parse args from determination of method: ' . $dt->asXML()); $dtArgs = []; if ($args = trim($m['args'])) { foreach (explode(',', $args) as $arg) { $dtArgs[] = trim($arg); } } // arguments from description $xmlArguments = $dd->xpath("p[normalize-space(text())='Arguments:']/following-sibling::ul[1]/li"); foreach ($xmlArguments as $xmlArgument) { $argument = $this->_createArgumentFromXML($xmlArgument)->setMethod($method); $method->addArgument($argument); } $argsDiff = array_diff($dtArgs, array_keys($method->arguments)); if (!empty($argsDiff)) { echo 'Warning [method = ' . $method->name . ']: not all arguments has been parsed. Problem arguments: ' . join(',', $argsDiff) . Helper::EOL; if (empty($method->arguments)) { // add as arguments with empty description foreach ($argsDiff as $diffArgName) { $argument = Argument::createNew()->setMethod($method); $argument->name = $diffArgName; $argument->type = Argument::DEFAULT_TYPE; $method->addArgument($argument); } echo ' ...added as args with empty description' . Helper::EOL; } else { echo ' ...cannot be added!' . Helper::EOL; } } // Return value $xmlReturnValue = $dd->xpath("descendant::dt[normalize-space(text())='Returns:']/following-sibling::dd"); $method->returnValue = ReturnValue::createNew(); $method->returnValue->description = empty($xmlReturnValue) ? '' : str_replace(['<dd>', '</dd>'], '', $xmlReturnValue[0]->asXML()); // Derivative methods $xmlRelatedAssertions = $dd->xpath("p[normalize-space(text())='Related Assertions, automatically generated:']/following-sibling::ul[1]/li"); foreach ($xmlRelatedAssertions as $xmlRelatedAssertion) { $derivativeMethod = $this->_createDerivativeMethodFromXML($xmlRelatedAssertion); $method->addDerivativeMethod($derivativeMethod); } return $method; }
/** * Returns name of new method, which can be created from current through * {@link CodeGenerator::createNewMethodWithName}. * * @param string $newSubtype * * @return string Name of new method */ function makeNameForSubtype($newSubtype) { // ---- Source method has Accessor type switch ($this->subtype) { case Method::SUBTYPE_ASSERT: case Method::SUBTYPE_ASSERT_NOT: if (in_array($newSubtype, [Method::SUBTYPE_VERIFY, Method::SUBTYPE_VERIFY_NOT])) { return 'verify' . Helper::cutPrefix('assert', $this->name); } else { self::throwException("Incorrect subtype: some cases (may be) not handled."); } break; case Method::SUBTYPE_VERIFY: case Method::SUBTYPE_VERIFY_NOT: if (in_array($newSubtype, [Method::SUBTYPE_ASSERT, Method::SUBTYPE_ASSERT_NOT])) { return 'assert' . Helper::cutPrefix('verify', $this->name); } else { self::throwException("Incorrect subtype: some cases (may be) not handled."); } break; default: self::throwException("Incorrect subtype: some cases (may be) not handled."); } // todo implement and test other cases (other subtypes) }
/** * Adds dot (if not exist) in to end of specified text (completion of sentence). * * @param string $text * * @return string Trimmed text with dot in the end. */ private function _addEndDotIfNotExist($text) { $endSymbols = '[' . join('', Helper::$endOfSentence) . ']'; // symbol class like: [.!?] // find text like: "end</p>", "end </p>", "end </p>" $regExpDotBeforeClosingTag = '/(?<!' . $endSymbols . '|' . $endSymbols . '\\s|' . $endSymbols . '\\s\\s)(?P<tag><\\/\\w+>)\\s*\\Z/'; $testedText = trim(strip_tags($text)); if ($testedText && !Helper::hasPostfix(Helper::$endOfSentence, $testedText)) { $postfix = preg_match($regExpDotBeforeClosingTag, $text, $m) ? $m['tag'] : ''; $text = Helper::cutPostfix($postfix, rtrim($text)) . '.' . $postfix; } return $text; }
switch ($method->type) { case models\Method::TYPE_ACTION: $linkDescription = 'Related Action'; break; case models\Method::TYPE_ACCESSOR: $linkDescription = 'Related Accessor'; break; case models\Method::TYPE_ASSERTION: $linkDescription = 'Related Assertion'; break; } $seeLinks[$method->getNameFQSEN()] = $linkDescription; } foreach ($methodsGroup as $method) { $method->seeLinks += $seeLinks; $method->seeLinks = Helper::filterByKeys($method->seeLinks, null, [$method->getNameFQSEN()]); // delete link to self } } // Make plain array of methods $methods = []; foreach ($methodsByBaseName as $methodBaseName => $methodsGroup) { foreach ($methodsGroup as $method) { $methods[] = $method; } } // Output if (!file_put_contents('SeleniumTestCaseDoc.generated.php', $generator->generate($methods))) { throw new Exception('Error at file write'); } if (!empty($notFounded)) {