{"id":27771634,"url":"https://github.com/webreinvent/vaah-webdriverio","last_synced_at":"2026-07-03T21:01:32.525Z","repository":{"id":41813011,"uuid":"391327763","full_name":"webreinvent/vaah-webdriverio","owner":"webreinvent","description":"Helpful classes to reduce code \u0026 accelerate speed for writing test cases for WebDriver.io ","archived":false,"fork":false,"pushed_at":"2025-01-06T11:19:05.000Z","size":187,"stargazers_count":0,"open_issues_count":3,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-29T22:44:47.031Z","etag":null,"topics":["testing"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/webreinvent.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-07-31T10:46:11.000Z","updated_at":"2021-12-06T08:34:07.000Z","dependencies_parsed_at":"2023-01-21T20:48:29.375Z","dependency_job_id":null,"html_url":"https://github.com/webreinvent/vaah-webdriverio","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/webreinvent%2Fvaah-webdriverio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webreinvent%2Fvaah-webdriverio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webreinvent%2Fvaah-webdriverio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webreinvent%2Fvaah-webdriverio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webreinvent","download_url":"https://codeload.github.com/webreinvent/vaah-webdriverio/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251596613,"owners_count":21615014,"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":["testing"],"created_at":"2025-04-29T22:44:50.316Z","updated_at":"2025-10-24T02:23:06.790Z","avatar_url":"https://github.com/webreinvent.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# vaah-webdriverio\nHelpful classes to reduce code \u0026amp; accelerate speed for writing test cases for WebDriver.io \n\n## Objectives\n- Reduce code for `selecting` elements and verifying `asserts`\n- Generate unique `page id`, `group id` and `test case id`\n- Run `test cases` based on `page id`, `group id` or `test id`\n- Generate a well `formated` report\n\n## Setup\n##### Step 1: Clone or add as this repo as submodule to root of `webdriverio` tests folder with folder name `vaah-webdriverio`\nDemo: https://img-v3.getdemo.dev/screenshot/spjG338m6A.mp4\n\n\n##### Step 2: Configure `wdio.env.sample.js`\n- Rename `wdio.env.sample.js` to `wdio.env.js`\n- Move `wdio.env.js` to the `root` folder of your project or where `wdio.conf.js` exist\n\nDemo: https://img-v3.getdemo.dev/screenshot/HwjLwZEoOk.mp4\n\n\n##### Step 3: Include `wdio.env.js`\nIn `wdio.conf.js`, include `wdio.env.js` and update following variables:\n\n```js\nconst env = require('./wdio.env');\n\nexports.config = {\n    ...\n    env: env,\n    baseUrl: env.base_url,\n    ...\n}\n\n```\nDemo: https://img-v3.getdemo.dev/screenshot/eNboGGqmrh.mp4\n\n\nIn `env.js` tester should set the base URL based on their test environment. // Make sure that the URL ends with '/'.\n````js\ncase 'localhost':\n        params.base_url = null // Instead of null insert your base URL inside \" \".\n        break;\n````\nDemo: https://img-v3.getdemo.dev/screenshot/BiI0D6ygq3.mp4\n\n\n\n##### Step 4: Extend `pageobjects` and variables in `constructor`\nExtend all your `pageobjects` to `const Page = require('./../vaah-webdriverio/Page');`, \n\nExample: `pageobjects/Login.page.js`: \n```js\nconst Page = require('./../vaah-webdriverio/Page');\n\nclass Login extends Page {\n\n    constructor() {\n        super();\n        this.page.id = \"LI\"; // Page ID, Please keep this unique for all the pages.\n        this.page.name = \"Login\";\n        this.page.path = \"login\";\n        this.page.url = this.base_url + this.page.path;\n    }\n\n    open (url=null) {\n        if(url)\n        {\n            this.page.url = url\n        }\n        return super.open(this.page.url);\n    }\n    \n}\nmodule.exports = new Login();\n```\nDemo: https://img-v3.getdemo.dev/screenshot/iTSi72u1p3.mp4\n\n#### step 5: All the methods present in Assert class under Assets in vaah-webdriverio should be prefixed with \"async\" to run the methods in async mode in the test scripts.\nExample:\n```js\nconst env = require('./../../../wdio.env');\n\nclass Assert{\n\n    async pause()\n    {\n        if(env.is_human)\n        {\n            browser.pause(env.is_human_pause*1000);\n        }\n    }\n\n    async pageTitle(text)\n    {\n        return expect(browser).toHaveTitleContaining(text);\n\n    }\n\n    async text(selector, text) {\n        await expect(selector).toHaveTextContaining(text);\n        await this.pause();\n    }\n    \n};\n\nmodule.exports = new Assert()\n```` \n\n##### Step 6: Writing test cases\nIn `specs` folder create a file `login.e2e.js` and write following code for example:\n```js\nconst sl = require('../vaah-webdriverio/Selector');\nconst assert = require('../vaah-webdriverio/Assert');\nconst login = require('../pageobjects/login.page');\n\nlogin.group.count = 1; // Group counter which will be used to generate Group ID\nlogin.group.name = 'Login';\n\ndescribe(login.groupId(), () =\u003e {\n    //-----------------------------------------------------------\n    login.test = {\n        count: 1.1, // Test counter which will be used to generate Test ID\n        name: 'Tester should be ble to run login test successfully',\n        expect: \"Alert message 'You logged into a secure area!' should appear\",\n        data: \"You logged into a secure area!\",\n    }\n\n    it(login.testId(), async () =\u003e {\n        login.open();\n        browser.maximizeWindow();\n        await assert.pageTitle(\"The Internet\");\n        sl.name(\"username\", \"tomsmith\"); \n        // This will select the element with attribute as name='username' and will also insert the value \"tomsmith\".\n        sl.name(\"password\", \"SuperSecretPassword!\");\n        sl.class('radius').click();\n        await assert.text(sl.id('flash'), login.test.data);\n    });\n    //-----------------------------------------------------------\n \n});\n````   \nDemo: https://img-v3.getdemo.dev/screenshot/OdRIb4yXIr.mp4\n\nNote: This is just an example of where to write the test script. The test script may differ.\n\n\n| Selector | In Selector.js|Use|Description|\n|--|--|--|--|\n|testid|`testid(name,value=null) { let el = this.attr('data-testid', name); if(value) { el.setValue(value) } return el; }`|`sl.testid(\"royal_email\", \"demo@test.com\")`|This will select the element having attribute `data-testid='royal_email'` and then will insert the value as \"demo@test.com\" in it.|\n|id|`id(id)  {  return $(\"#\"+id);  } `|`sl.id(\"submit\").click;`|This will select the element with attribute id='submit' and will click on it.|\n|class|`class(name) { return $(\".\"+name); }`|`sl.class(\"submit\").click;`|This will select the element with attribute `id='submit'` and will click on it.\n|$|`$(selector){return $(selector);}`|`sl.$(\"h1\");`|This will select the element having attribute as `h1`. Mostly used during assertion.|\n|attr|`attr(attribute, value){return$('['+attribute+'=\"'+value+'\"]'); }`|`sl.attr('href','#/forgot-password' ).click();`|This will select the element having attribute as `href` and its value as `#/forgot-password`.\n|name|`name(name,value=null) { let el = this.attr('name', name); if(value) { el.setValue(value) } return el; }`|`sl.name(\"username\", \"tomsmith\");`|This will select the element with attribute `name=\"username\"` and will insert value \"tomsmith\" in it.|\n|wdio|`wdio(name,value=null) { let el = this.attr('data-wdio', name); if(value) { el.setValue(value) } return el; }`|`sl.wdio(\"username\", \"tomsmith\")`|This will select the element having attribute `data-wdio='username'` and then will insert the value as \"tomsmith\" in it. Note: If you are not able to find data-wdio attribute associated with the element in that case either you can add it by yourself or you can ask the developer to add this attribute.|\n|dusk|`dusk(name,value=null) { let el = this.attr('dusk', name); if(value) { el.setValue(value) } return el; }`|`sl.dusk(\"username\", \"tomsmith\")`|This will select the element having attribute `dusk='username'` and then will insert the value as \"tomsmith\" in it.|\n|role|`role(name) { return this.attr('role', name); }`|`sl.role(\"navigation\").click()`|This will select the element having attribute `role=\"navigation\"` and will click on it.|\n\n\nPage object model will help you to store the element's attribute value at one place so that if there is a change in the value then we have to change it at one page rather then changing it at every instance.\n\nTo implement page object we need to to create a file to store these values. Inside the tests folder go to wdio folder and then go inside data folder (if the folder does not exist you can create one). Then inside the data folder create a javascript file elements.js and paste the below mentioned code.\n\nDemo: https://img-v3.getdemo.dev/screenshot/37DZHpTEcH.mp4\n\nNote: Due to limitations this section is not showing in tabular format. Please copy and paste the section in https://stackedit.io/ to view the tabular form.\n\n```js\n class Elements {  \n    constructor() {  \n        this.login= {\n          signin_email: \"signin-email_or_username\",  \n          signin_password: \"signin-password\",\n          button_signin: \"signin-signin\",\n          remember_me_checkbox: \"checkbox\",\n }}}\n module.exports = new Elements();\n```\n`this.login={}` block contains all the attributes values used in for the login value. If you are testing any other page you can create a seperate block and add the attributes used in that block. An example is mentioned below: \n \n Demo: https://img-v3.getdemo.dev/screenshot/bt9XOVsbUS.mp4\n\n\n ```js\n class Elements {  \n    constructor() {  \n        this.login= {\n          signin_email: \"signin-email_or_username\",  \n          signin_password: \"signin-password\",\n          button_signin: \"signin-signin\",\n          remember_me_checkbox: \"checkbox\",\n        }\n        this.home={\n          main_heading:\"h1\",\n          sub_heading:\"h2\",\n        }\n }}\n module.exports = new Elements();\n```\n\n\nWhen using the above pageobject then you can write the selectors in the following manner:\n\n\n\n| Selector | In Selector.js | Use with pageobject |\n|--|--|--|\n|testid|`testid(name,value=null) { let el = this.attr('data-testid', name); if(value) { el.setValue(value) } return el; }`|`sl.testid(\"royal_email\", \"demo@test.com\");` or `sl.testid(\"royal_email\").setValue(\"demo@test.com\")`|\n|id|`id(id) { return $(\"#\"+id); }`|`sl.id(elements.login.button_signin).click();`|\n|class|`class(name) { return $(\".\"+name); }`|`sl.class(elements.login.button_signin).click();`|\n|$|`$(selector){return $(selector);}`|`expect(sl.$(elements.login.remember_me_checkbox)).toBeSelected();`|\n|attr|`attr(attribute, value){return$('['+attribute+'=\"'+value+'\"]'); }`|`sl.attr(\"class\", elements.login.button_signin).click();`\n|name|`name(name,value=null) { let el = this.attr('name', name); if(value) { el.setValue(value) } return el; }`|`sl.name(elements.login.signin_email, \"tomsmith\");` or `sl.name(elements.login.signin_email).setValue(\"tomsmith\");`|\n|wdio|`wdio(name,value=null) { let el = this.attr('data-wdio', name); if(value) { el.setValue(value) } return el; }`|`sl.wdio(elements.login.signin_email, \"tomsmith\");` or `sl.wdio(elements.login.signin_email).setValue(\"tomsmith\")`|\n|dusk|`dusk(name,value=null) { let el = this.attr('dusk', name); if(value) { el.setValue(value) } return el; }`|`sl.dusk(elements.login.signin_password, \"SuperSecretPassword\")` or `sl.dusk(elements.login.signin_password).setValue(\"SuperSecretPassword\");`|\n|role|`role(name) { return this.attr('role', name); }`|`sl.role(elements.login.button_signin).click();`|\n\n\n\nDemo: https://img-v3.getdemo.dev/screenshot/F0Q3bDNA9K.mp4\n ```\nNote:\n\n1.For selector 'testid', if attribute or locator \"data-testid\" is present in the html code when we are inspecting or locating an element then we should give the first priority to the locator or attribute 'data-testid'.\n   e.g. sl.testid(\"royal_email\", \"demo@test.com\");\n\n2.Due to limitations this section is not showing in tabular format. Please copy and paste the section in https://stackedit.io/ to view the tabular form.\n```\nDemo(1): https://img-v4.getdemo.dev/screenshot/chrome_revNZwwQcK.mp4\n\nI have written an example on how to write a test script for logging in using the page object:\n\n ```js\nconst sl = require('../vaah-webdriverio/Selector');\nconst assert = require('../vaah-webdriverio/Assert');\nconst login = require('../pageobjects/login.page');  \nconst elements = require('../data/elements');\nlogin.group.count = 1; // Group counter which will be used to generate Group IDlogin.group.name = 'Login';  \n\ndescribe(login.groupId(), () =\u003e {  \n    login.test = {  \n        count: 1, // Test counter which will be used to generate Test ID  \n        name: 'Tester should be ble to run login test successfully',  \n        expect: \"Alert message 'You logged into a secure area!' should appear\",  \n        data: \"You logged into a secure area!\",\n    };\n\n    it(login.testId(), async () =\u003e {  \n        login.open();  \n        browser.maximizeWindow();\n        await assert.pageTitle(\"The Internet\");  \n        sl.wdio(elements.login.signin_email, \"tomsmith\"); \n        /*This will select the element with attribute as `data-wdio='signin-email_or_username'`which is stored in the elements.js \n          as `signin_email` and will also insert the value \"tomsmith\".*/  \n        sl.dusk(elements.login.signin_password, \"SuperSecretPassword\"); \n        sl.class(elements.login.button_signin).click();  \n        await assert.text(sl.id('flash'), login.test.data);  \n    }); \n});\n```\n\nDemo: https://img-v3.getdemo.dev/screenshot/RU2Tp6h1qo.mp4\n\n\nNote: The test_count_id should be unique so that there will be no conflict between the test scripts.\nExample:\n ```js\nconst sl = require('../vaah-webdriverio/Selector');\nconst assert = require('../vaah-webdriverio/Assert');\nconst page = require('../pageobjects/about-us.page');\nconst elements = require('../data/elements');\nconst assert_data = require('../data/assert-data');\n\n\nlet params = page.params;\n\nparams.group.count = 1;\nparams.group.name = 'About-Us';\n\ndescribe(page.groupId(params), () =\u003e {\n\n//----------------------------------------------------------------------------------------\n\n    params.test = {\n        count: 1.1,\n        name: \"Visit About Us page and check for title\",\n        expect: \"Main heading should be '\" + assert_data.about_us_page_title.title + \"'\",\n    };\n    it(page.testId(params), async () =\u003e {\n        page.open();\n        browser.maximizeWindow();\n        await assert.text(sl.$(elements.about_us.heading), assert_data.about_us_page_title.title);\n    });\n\n    params.test = {\n        count: 1.2,\n        name: \"Validating seems interesting button\",\n        expect: \"After clicking the button should reveal the rest of story '\" + assert_data.about_us_page_title.last_story + \"'\",\n    };\n    it(page.testId(params), async () =\u003e {\n        page.open();\n        browser.maximizeWindow();\n        await assert.text(sl.$(elements.about_us.heading), assert_data.about_us_page_title.title);\n        sl.wdio(elements.about_us.button_interesting).click();\n        await assert.text(sl.wdio(elements.about_us.last_story), assert_data.about_us_page_title.last_story);\n    });\n});\n``` \nDemo: https://img-v4.getdemo.dev/screenshot/phpstorm64_KzTsODht7l.mp4\n\n##### Step 7: Run test \nNow, you can run the test via:\n```sh\nnpx wdio --spec ./tests/wdio/specs/login.e2e.js\n```\nDemo: https://img-v4.getdemo.dev/screenshot/chrome_uNW2UpI0dH.mp4\n\n\nor run all tests via:\n\n```shell\nnpx wdio run ./wdio.conf.js\n```\nDemo: https://img-v3.getdemo.dev/screenshot/AWcVR496IG.mp4\n\nThe Demo shows how a passed and failed test cases will be represented.\n\n##### Step 8: Result\n\n\u003cimg src=\"https://user-images.githubusercontent.com/114494381/193214928-bc3bed84-65ca-4f4c-bf68-9f39ff8ab089.png\" width=\"70%\" style=\"max-width: 100%;\"\u003e\n\n\nIt contains:\n```\n[PAGE ID: LI]\n[GROUP ID: LI_1]\n[TEST ID: LI_1_1.1]\n```\nDemo: https://img-v4.getdemo.dev/screenshot/phpstorm64_0r5SfdxoR8.mp4\n\nIf you need to run tests based on `page id`, `group id` or `test id`, you can use following command:\n\n```shell\nnpx wdio --mochaOpts.grep \u003cpage id\u003e \ne.g. npx wdio --mochaOpts.grep LI // This will run all the test cases under the Page with Page ID LI_1\nDemo:https://img-v3.getdemo.dev/screenshot/jqNYsEBnhT.mp4\n\nnpx wdio --mochaOpts.grep \u003cgroup id\u003e\ne.g. npx wdio --mochaOpts.grep LI_1 // This will run all the test cases under the Group with Group ID LI_1\nDemo:https://img-v3.getdemo.dev/screenshot/b54baoyxkZ.mp4\n\nnpx wdio --mochaOpts.grep \u003ctest id\u003e\ne.g. npx wdio --mochaOpts.grep LI_1_1.1 // This will run all the test cases under the Page ID LI having Group ID 1 and Test ID starting with 1.1\nDemo:https://img-v4.getdemo.dev/screenshot/phpstorm64_NhXad1pY4Z.mp4\n// Note: If you have test case with test ID as LI_1_11, LI_1_12... LI_1_19, these tests will also run if you provide the test ID as LI_1_1\n// To avoid this situation you can use a keyword to run a single test, but make sure to keep the keyword unique otherwise all the test cases having that keyword will run while executing tests. \n```\nor you can even run the test cases based on a specific keyword:\n```npx wdio --mochaOpts.grep \u003cany keyword\u003e\ne.g. npx wdio --mochaOpts.grep smoke\nDemo: https://img-v3.getdemo.dev/screenshot/vju9IYLTiO.mp4\n```\n##### Possible error\n ```\n@wdio/runner: Error: Failed to create session.\nsession not created: This version of ChromeDriver only supports Chrome version 96\n```\nIf this error occurrs that means your `wdio-chromedriver-service` and `chromedriver` dependencies are outdated and those need to be updated.\nEasiest way to update the dependency is provided in the demo.\n\nDemo: https://img-v3.getdemo.dev/screenshot/xL5B0R3Gar.mp4\n\n  \n \n\u003cbr/\u003e\n\n## Support us\n\nPlease consider starring the project to show your :heart: and support.\n\n[WebReinvent](https://webreinvent.com) is a web agency based in Delhi, India. You'll find an overview of all our open source projects [on github](https://github.com/webreinvent).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebreinvent%2Fvaah-webdriverio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebreinvent%2Fvaah-webdriverio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebreinvent%2Fvaah-webdriverio/lists"}