{"id":22360363,"url":"https://github.com/sergueik/skdf","last_synced_at":"2025-07-30T13:31:49.829Z","repository":{"id":41219284,"uuid":"105801316","full_name":"sergueik/SKDF","owner":"sergueik","description":"Yet another implementation of keyword driven framework for Selenium and Protractor","archived":false,"fork":false,"pushed_at":"2024-02-01T00:00:09.000Z","size":6442,"stargazers_count":4,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-02-01T00:36:25.651Z","etag":null,"topics":["keyword-driven-framework","poi","selenium"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sergueik.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2017-10-04T18:08:48.000Z","updated_at":"2023-09-12T05:52:01.000Z","dependencies_parsed_at":"2024-02-01T00:44:33.883Z","dependency_job_id":null,"html_url":"https://github.com/sergueik/SKDF","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergueik%2FSKDF","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergueik%2FSKDF/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergueik%2FSKDF/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergueik%2FSKDF/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sergueik","download_url":"https://codeload.github.com/sergueik/SKDF/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228144705,"owners_count":17876160,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["keyword-driven-framework","poi","selenium"],"created_at":"2024-12-04T16:15:59.113Z","updated_at":"2025-07-30T13:31:49.812Z","avatar_url":"https://github.com/sergueik.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿### About SKDF\r\n\r\n![TestCase.xls](https://github.com/sergueik/skdf/blob/master/images/testcase_selenium.png)\r\n\r\nThis directory contains a skeleton [Keyword-Driven Framework](http://toolsqa.com/selenium-webdriver/keyword-driven-framework/introduction/) project based on\r\n[ashokkhape/automation_framework_selenium](https://github.com/ashokkhape/automation_framework_selenium) and [selenium-webdriver-software-testing/keyword-driven-framework](https://github.com/selenium-webdriver-software-testing/keyword-driven-framework)\r\n\r\nThe project builds two runnable jars (`com.github.sergueik.jprotractor` and `com.github.sergueik.ngwebdriver` group id namespaces):\r\n```bash\r\ncp TestCase.xls ~/Desktop\r\npushd jprotractor\r\nmvn  -Pdevelop -DskipTests -Dmaven.test.skip=true install\r\nREM java -jar target/skdf_jprotractor-develop.jar\r\nREM alternatively\r\njava -cp target\\skdf_jprotractor-develop.jar;target\\lib\\* com.github.sergueik.jprotractor.Launcher\r\npopd\r\npushd ngwebdriver\r\nmvn clean install\r\nREM java -jar target/skdf_ngwebdriver-develop.jar\r\njava -cp target\\skdf_ngwebdriver-develop.jar;target\\lib\\* com.github.sergueik.ngwebdriver.Launcher\r\npopd\r\n```\r\nThe launcher uses reflection to associate _keywords_ with *class methods*\r\n```java\r\nprivate static Map\u003cString, String\u003e methodTable = new HashMap\u003c\u003e();\r\nstatic {\r\n  methodTable.put(\"CLICK\", \"clickButton\");\r\n  methodTable.put(\"CLICK_BUTTON\", \"clickButton\");\r\n...\r\n\r\n```\r\n- a single method may have several keywords pointing to it;\r\n```java\r\nString methodName = methodTable.get(keyword);\r\ntry {\r\n  Class\u003c?\u003e _class = Class.forName(\"com.github.sergueik.ngwebdriver.KeywordLibrary\");\r\n  Method _method = _class.getMethod(methodName, Map.class);\r\n  System.out.println(keyword + \" call method: \" + methodName + \" with \"\r\n\t\t\t+ String.join(\",\", params.values()));\r\n  // for static methods\r\n  _method.invoke(null, params);\r\n  // or when using instances methods\r\n  Object _object = _class.newInstance();\r\n  _method.invoke(_object, params);\r\n```\r\nSimilar approach is used to define Selector strategies, most of which are static methods of the appropriate core  Selenium class:\r\n```java\r\n    locatorTable.put(\"className\",\r\n        By.class.getMethod(\"className\", String.class));\r\n    locatorTable.put(\"css\", By.class.getMethod(\"cssSelector\", String.class));\r\n    locatorTable.put(\"id\", By.class.getMethod(\"id\", String.class));\r\n    locatorTable.put(\"linkText\",\r\n        By.class.getMethod(\"linkText\", String.class));\r\n    locatorTable.put(\"name\", By.class.getMethod(\"name\", String.class));\r\n    locatorTable.put(\"tagName\", By.class.getMethod(\"tagName\", String.class));\r\n    locatorTable.put(\"xpath\", By.class.getMethod(\"xpath\", String.class));\r\n```\r\n\r\nwith few \"synthetic\" strategies, notably  the __TEXT__:\r\n\r\n```java\r\n// put synthetic selectors explicitly\r\n  locatorTable.put(\"text\", methodMissing);\r\n```\r\nimplemented e.g. through `xpath`:\r\n\r\n```java\r\n  String amendedSelectorValue = String.format(\r\n      \"//%s[contains(normalize-space(text()),'%s')]\",\r\n      (selectorTagName != null) ? selectorTagName : \"*\", selectorValue);\r\n  _element = _wait.until(new ExpectedCondition\u003cWebElement\u003e() {\r\n    @Override\r\n    public WebElement apply(WebDriver d) {\r\n      return d.findElements(By.xpath(amendedSelectorValue)).stream()\r\n          .filter(o -\u003e {\r\n            return (Boolean) (o.getText().contains(selectorValue));\r\n          }).findFirst().get();\r\n    }\r\n  });\r\n```\r\n\r\nThe test step arguments are passed as hash of parameters.  That is done so one does not care about the method signature.\r\nAlso the [AngularJS](https://angularjs.org/) introduced `NgBy` locators which fequently require (multiple) additional arguments like e.g.\r\n```java\r\n@FindBy(how = How.REPEATER_COLUMN, using = \"row in rows\", column = \"name\")\r\nprivate List\u003cWebElement\u003e friendNames;\r\n```\r\nThe step status is returned via `params[\"status\"]` entry, the step result (if any) is returned via `params[\"result\"]`\r\n\r\n### Adding Tests to the Spreadsheet\r\nTo add a test case, put its name into the `Index` sheet and mark it with `Yes` to be executed\r\n![index](https://github.com/sergueik/skdf/blob/master/images/testcase_index.png)\r\n\r\nNext, add the steps. Making the cell border visible will ensure the blank cells are not getting skipped:\r\n![demoqa](https://github.com/sergueik/skdf/blob/master/images/testcase_demoqa.png)\r\n\r\n### Adding jProtractor\r\n\r\nOne can explore additional selectors with jProtractor.\r\n\r\n![TestCase.xls](https://github.com/sergueik/skdf/blob/master/images/testcase_protractor.png)\r\n\r\n[jProtractor](https://github.com/sergueik/jProtractor) is not available in maven central, therefore to use it with framework one needs do build it from source and\r\ninstall it into current user's `.m2` repo:\r\n\r\n```cmd\r\ngit clone https://github.com/sergueik/jProtractor.git\r\npushd jProtractor\r\nmvn -Dmaven.test.skip=true clean install\r\n```\r\nwhich will install the jar:\r\n```cmd\r\n[INFO] Installing C:\\developer\\sergueik\\selenium_java\\protractor\\target\\jprotractor-1.2-SNAPSHOT.jar to C:\\Users\\Serguei\\.m2\\repository\\com\\jprotractor\\jprotractor\\1.2-SNAPSHOT\\jprotractor-1.2-SNAPSHOT.jar\r\n[INFO] Installing C:\\developer\\sergueik\\selenium_java\\protractor\\pom.xml to C:\\Users\\Serguei\\.m2\\repository\\com\\jprotractor\\jprotractor\\1.2-SNAPSHOT\\jprotractor-1.2-SNAPSHOT.pom\r\n```\r\nThis will add about 10 AngularJS-specific `NgBy` locators:\r\n\r\n![NgBy methods](https://github.com/sergueik/skdf/blob/master/images/ngby_methods.png)\r\n\r\n* `options`\r\n* `input`\r\n* `selectedOption`\r\n* `repeater`\r\n* `model`\r\n* `binding`\r\n* `repeaterElement`\r\n* `repeaterRows`\r\n* `buttonText`\r\n* `repeaterColumn`\r\n* `cssContainingText`\r\n* `selectedRepeaterOption`\r\n* `partialButtonText`\r\n\r\n### Adding ngWebDriver\r\n\r\nAnother implementation of Protractor selectors is [ngWebDriver](https://github.com/paul-hammant/ngWebDriver).\r\n\r\n![ByAngular methods](https://github.com/sergueik/skdf/blob/master/images/byangular_methods.png)\r\n\r\nMost Protractor-specific locators are the same (the class is `ByAngular`):\r\n\r\n* `options`\r\n* `repeater`\r\n* `model`\r\n* `binding`\r\n* `buttonText`\r\n* `cssContainingText`\r\n* `partialButtonText`\r\n\r\nFew method signatures of are different:\r\n\r\n* `repeaterCell`\r\n* `repeaterRow`\r\n* `repeaterColumn`\r\n\r\nThe implementation of the correspondent keyword methods is through chaining the\r\nngWebDriver methods e.g.\r\n\r\n```java\r\ncase \"repeaterColumn\":\r\n  ngDriver.waitForAngularRequestsToFinish();\r\n  ByAngularRepeater _elementRepeater = ByAngular.repeater(selectorValue);\r\n  ByAngularRepeaterColumn _elementRepeaterColumn = _elementRepeater.column(selectorColumn);\r\n  _element = driver.findElement(_elementRepeaterColumn);\r\n  return _element;\r\n\r\n```\r\nSome methods are unique to jProtracror, they do not exist in ngWebDriver:\r\n\r\n* `selectedOption`\r\n* `selectedRepeaterOption`\r\n\r\n\r\nIn addition the \"text\" keyword is recognized with the usual implementation through `xpath` locator:\r\n```java\r\nString.format(\"//%s[contains(normalize-space(text()), '%s')]\", (selectorTagName != null) ? selectorTagName : \"*\", selectorValue);\r\n```\r\nalternatively if the `selectorTagName` is provided, the Java 8 stream based impplementation is possible:\r\n```java\r\n_element = driver.findElements(By.tagName(selectorTagName)).stream()\r\n  .filter(o -\u003e o.getText().contains(selectorValue)).findFirst().get();\r\n```\r\n\r\n### Introduction\r\n\r\nThe original Keyword Driven Framework [suggests](http://toolsqa.com/selenium-webdriver/keyword-driven-framework/introduction/)\r\nidentifying few columns (not necessarily exactly four, though).\r\n\r\n  * __Summary__: *brief description of the step*\r\n  * __Target__: *name of the Web Page object/element, like \"Link\" or \"Input\"*\r\n  * __Action__: *name of the action, which will be performed on Target Element such as click, open browser, input text etc.*\r\n  * __Data__: *any value which is needed by the Object to perform any action, like text value for input field.*\r\n\r\n\r\nIt is very likely inspired by\r\n![selenium_ide](https://github.com/sergueik/skdf/blob/master/images/selenium_ide.png)\r\n\r\n[Selenium IDE Firefox Add-On](https://addons.mozilla.org/en-US/firefox/addon/selenium-ide/)\r\nCommand, Target, Value columns, with significanylty narrowed choice of commands (Keywords).\r\nThe advantages from taking such approach are discussed many times:\r\n\r\n  * __Less Technical Expertise__:  manual testers or non technical testers can easily write test scripts for automation using the Framework than code straight.\r\n  * __Easy To Understand__: With no coding is exposed, the test flow is easy to read and understand. Keywords \u0026 actions are descriptive.\r\n  * __Early Start__: One can start building Keyword Driven test cases immediately deferring more challenging tasks like Page Object model to a later stage. Keyword steps are quick to identify from requirements documentation or manual test.\r\n  * __Re-usability__: With implementing modularization in Keyword Driven, Re-usability can be further increased. Equipped with a stable and powerful Execution Engine in Keyword Driven Framework, it encourage extreme code re-usability.\r\n  * __Automation__: Excel file is (a lot) easier to produce by a recording tool than a full blown program.\r\n\r\n### Work in Progress\r\n\r\nAdding \r\n\r\n* [ahajamit/chrome-devtools-webdriver-integration](https://github.com/sahajamit/chrome-devtools-webdriver-integration) Selenium 3.x compatible Chrome Devtool Selenium extension project that exposes whole set of [Chrome DevTools Protocol automation API](https://chromedevtools.github.io/devtools-protocol/) to Selenium in similar fashion Selenium 4 is doing (Selenum 4 is currently in alpha) as __cdp\\_integration__\r\n* [sukgu/shadow-automation-selenium](https://github.com/sukgu/shadow-automation-selenium) shadow ROOT DOM automation javascript API wrapper project, which offrs custom API as __shadow\\_automation__\r\n\r\nNo keywords defined for any of those yet.\r\n\r\n### Note\r\n\r\nthe urls `http://www.seleniumeasy.com/test/basic-first-form-demo.html` and `https://www.seleniumeasy.com/test/input-form-demo.html` no longer exist on `http://www.seleniumeasy.com` though the former is still referenced in documentation for Python testers.\r\n\r\nThese pages were apparently mirrored on `https://demo.anhtester.com`\r\nThe directory `http://www.seleniumeasy.com/test/` is also gone and there is no mirror\r\nThe update of test material is a work in progress. The sheets `KeywordFramework` are curently disabled.\r\nThe `Alert` sheet is updated and enabled (it had a typo in the custom method name for processing the alert popup)\r\n\r\n### See Also\r\n\r\n * [qaf](https://github.com/qmetry/qaf)\r\n * [NPOI](https://github.com/dotnetcore/NPOI)\r\n * [ExcelDataReader (.net)](https://github.com/ExcelDataReader/ExcelDataReader)\r\n * [LinqToExcel](https://github.com/paulyoder/LinqToExcel)\r\n * [save-selenium-webdriver-testng-result-excel](http://www.techbeamers.com/save-selenium-webdriver-testng-result-excel/)\r\n * [DataProvider - Data Driven Testing with Selenium and TestNG](http://functionaltestautomation.blogspot.in/2009/10/dataprovider-data-driven-testing-with.html)\r\n * [Excel Java poi helpers](https://github.com/Crab2died/Excel4J) \r\n * [Fast Excel poi-clean Java implementation](https://github.com/dhatim/fastexcel)\r\n\r\n### License\r\nThis project is licensed under the terms of the MIT license.\r\n\r\n### Author\r\n[Serguei Kouzmine](kouzmine_serguei@yahoo.com)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsergueik%2Fskdf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsergueik%2Fskdf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsergueik%2Fskdf/lists"}