{"id":19888926,"url":"https://github.com/paypal/nemo-view","last_synced_at":"2025-05-02T17:32:52.032Z","repository":{"id":17064180,"uuid":"19828911","full_name":"paypal/nemo-view","owner":"paypal","description":"View interface for the Nemo automation framework","archived":false,"fork":false,"pushed_at":"2023-11-23T19:49:14.000Z","size":603,"stargazers_count":26,"open_issues_count":18,"forks_count":48,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-04-13T19:27:13.942Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paypal.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","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,"publiccode":null,"codemeta":null}},"created_at":"2014-05-15T17:37:24.000Z","updated_at":"2024-06-18T18:27:35.159Z","dependencies_parsed_at":"2024-06-18T18:27:30.834Z","dependency_job_id":"340bf379-6caa-4e1c-96f6-96f21694931a","html_url":"https://github.com/paypal/nemo-view","commit_stats":null,"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paypal%2Fnemo-view","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paypal%2Fnemo-view/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paypal%2Fnemo-view/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paypal%2Fnemo-view/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paypal","download_url":"https://codeload.github.com/paypal/nemo-view/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224324456,"owners_count":17292521,"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":[],"created_at":"2024-11-12T18:08:39.737Z","updated_at":"2024-11-12T18:08:40.363Z","avatar_url":"https://github.com/paypal.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## nemo-view\n\nView Interface for nemo views.\n\n[![Build Status](https://travis-ci.org/paypal/nemo-view.svg?branch=master)](https://travis-ci.org/paypal/nemo-view) [![Greenkeeper badge](https://badges.greenkeeper.io/paypal/nemo-view.svg)](https://greenkeeper.io/)\n\n\n### Installation\n\n1. Add dependencies to your `package.json` file and install\n\n```javascript\n\t...\n    \"nemo\": \"^2.0.0\",\n    \"nemo-view\": \"^2.0.0\",\n\t...\n```\n\n2. Add `nemo-view` to your plugins nemo config\n\n```javascript\n{\n  \"driver\": {\n    ...\n  },\n  \"plugins\": {\n    \"view\": {\n      \"module\": \"nemo-view\",\n      \"arguments\": [\"path:locator\"]\n    }\n  },\n  \"data\": {\n    ...\n  }\n}\n```\n\n### locatorDefinition\n\nThe `locatorDefinition` can either be a JSON object like this:\n\n```\n{\n  \"locator\": \".myClass\",\n  \"type\": \"css\"\n}\n```\n\nWhere `type` is any of the [selenium locator strategies](http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/by_exports_By.html). A `locator` or `type` CANNOT be empty/blank/absent in JSON object representation of `locatorDefinition`. An error will be thrown during the setup of nemo-view. If `type` under `locatorDefinition` is invalid (not amongst [allowed types](http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/by_exports_By.html)) then an error is thrown as well.\n\n\nOr `locatorDefinition` can be a string like this:\n\n```\n\"css:.myClass\"\n```\nString of the form `\u003ctype\u003e:\u003clocator\u003e` or `\u003clocator\u003e` (where `\u003ctype\u003e` will be assumed as css)\n\n\n### Writing a locator file\n\nThe locator JSON file describes elements and the locator strategy used for each one. The most common use case is to store\nall your locator files in the `nemoBaseDir` + /locator directory. The below example uses the JSON style `locatorDefinition`.\n\n#### textBox.json\n\n```javascript\n{\n\t\"fooText\": {\n\t\t\"locator\": \"#foo input.texty\",\n\t\t\"type\": \"css\"\n\t},\n\t\"fooButton\": {\n\t\t\"locator\": \"#foo input[type='button']\",\n\t\t\"type\": \"css\"\n\t},\n\t\"barText\": {\n\t\t\"locator\": \"#bar input.texty\",\n\t\t\"type\": \"css\"\n\t},\n\t\"barButton\": {\n\t\t\"locator\": \"#bar input[type='button']\",\n\t\t\"type\": \"css\"\n\t},\n\t\"bingText\": {\n\t\t\"locator\": \"#bing input.texty\",\n\t\t\"type\": \"css\"\n\t},\n\t\"bingButton\": {\n\t\t\"locator\": \"#bing input[type='button']\",\n\t\t\"type\": \"css\"\n\t},\n\t\"bangText\": {\n\t\t\"locator\": \"#bang input.texty\",\n\t\t\"type\": \"css\"\n\t},\n\t\"bangButton\": {\n\t\t\"locator\": \"#bang input[type='button']\",\n\t\t\"type\": \"css\"\n\t},\n\t\"outBox\": {\n\t\t\"locator\": \"outy\",\n\t\t\"type\": \"id\"\n\t}\n}\n```\n\n`nemo-view` supports for adding JavaScript-style comments in your json files as each file is processed by using [shush](https://github.com/krakenjs/shush)\n\n### Using views\n\n_Note: code snippets are minus the require blocks for the sake of brevity. Please see unit tests for full files_\n\n#### Without locator files\n\nIf you don't have any locator files, or don't configure nemo-view to find locator files, you will still get back convenience methods on the nemo object:\n\n```\nnemo.view._find\nnemo.view._finds\nnemo.view._present\nnemo.view._visible\nnemo.view._wait\nnemo.view._waitVisible\nnemo.view._optionValue\nnemo.view._optionText\nnemo.view._firstVisible\n\n```\n\nWhich can be used as follows:\n\n```javascript\ndescribe('nemo-view @verySimple@', function () {\n  before(function (done) {\n    nemo = Nemo(done);\n  });\n\n  after(function (done) {\n    nemo.driver.quit().then(done);\n  });\n\n  beforeEach(function (done) {\n    nemo.driver.get(nemo.data.baseUrl);\n    util.waitForJSReady(nemo).then(util.doneSuccess(done), util.doneError(done));\n  });\n\n  it('should use the form view to enter values and write to outy div @useView@', function (done) {\n    nemo.view._find('css:#outy').getTagName().then(function (tn) {\n      assert.equal(tn.toLowerCase(), 'div');\n    });\n    nemo.view._finds('body').then(function (bodyArray) {\n      return bodyArray[0].getTagName();\n    }).then(function (tn) {\n      assert.equal(tn.toLowerCase(), 'body');\n    }).then(done, util.doneError(done));\n  });\n});\n```\n\nThese generic - or \"underbar\" - methods are defined below.\n\n#### With locator files\n\nIf you've configured nemo-view properly, and have the following locator files:\n\n```\n\u003cnemoBaseDir\u003e\n   |- locator\n      |- form.json\n      |- formElementList.json\n      |- select.json\n      |- simple.json\n      |- sub\n         |- form.json\n```\n\nYou will get back the following views on the nemo object:\n\n```\nnemo.view.form\nnemo.view.formElementList\nnemo.view.select\nnemo.view.simple\nnemo.view.sub.form\n```\n\nEach including a set of helper methods for each locator as documented below. And usable as follows:\n\n```javascript\ndescribe('nemo-view @simpleViewSuite@', function () {\n  before(function(done) {\n    nemo = Nemo(done);\n  });\n\n  after(function(done) {\n    nemo.driver.quit().then(done);\n  });\n\n  beforeEach(function (done) {\n    nemo.driver.get(nemo.data.baseUrl);\n    util.waitForJSReady(nemo).then(util.doneSuccess(done), util.doneError(done));\n  });\n\n  it('should use the form view to enter values and write to outy div @useView@', function (done) {\n    nemo.view.form.fooText().sendKeys('foo');\n    nemo.driver.sleep(300);\n    nemo.view.form.fooButton().click();\n    nemo.view.form.barText().sendKeys('bar');\n    nemo.view.form.barButton().click();\n    nemo.view.form.bingText().sendKeys('bing');\n    nemo.view.form.bingButton().click();\n    nemo.view.form.bangText().sendKeys('bang');\n    nemo.view.form.bangButton().click();\n    nemo.driver.sleep(3000);\n    nemo.view.form.outBox().getText().then(function (outText) {\n      assert.equal(outText, 'foobarbingbang');\n      done();\n    }, util.doneError(done));\n  });\n});\n```\n\n### Combining methods from with and without locator files\n\nYou can pass locators from `[locatorName]By` to underscore methods like `_find` or `_finds` etc. For example,\n\n```javascript\nnemo.view._finds(nemo.view.paypal.languageBy()).then(function(languages){\n    languages.forEach(function(language){\n        //do stuff\n    });\n });\n```\n\nFinding elements under another element\n\n```javascript\nnemo.view._finds('div.fielder', nemo.view.simple.parentBanner()).then(function (divs) {\n      //do stuff\n});\n```\n\n\n### Creating nemo plugins with self contained views and flows\n\nYou may want to publish complete flows as a nemo plugin. That way you can import the functionality and access as a plugin. The following is an example of that.\n\nPlease see the `test/contained-functionality.js` test file and `test/plugin/shared-fn-plugin.js` plugin file for an example of this.\n\n\n\n\n## View features\n\n### Generic/underbar methods\n\nThe following generic methods are added to `nemo.view`\n\n#### _find(locatorDefinition[, parentWebElement])\n\n`@argument locatorDefinition {String|Object}` - Please see `locatorDefinition` above\n\n`@argument parentWebElement {WebElement} (optional, default driver)` - parent WebElement to search elements underneath\n\n`@returns {Promise}` resolves to a WebElement or rejected\n\n#### _finds(locatorDefinition[, parentWebElement])\n\n`@argument locatorDefinition {String|Object}` - Please see `locatorDefinition` above\n\n`@argument parentWebElement {WebElement} (optional, default driver)` - parent WebElement to search elements underneath\n\n`@returns {Promise}` resolves to an array of WebElements or rejected\n\n\n#### _present(locatorDefinition[, parentWebElement])\n\n`@argument locatorDefinition {String|Object}` - Please see `locatorDefinition` above\n\n`@argument parentWebElement {WebElement} (optional, default driver)` - parent WebElement to search elements underneath\n\n`@returns {Promise}` resolves to true or false\n\n#### _visible(locatorDefinition[, parentWebElement])\n\n`@argument locatorDefinition {String|Object}` - Please see `locatorDefinition` above\n\n`@argument parentWebElement {WebElement} (optional, default driver)` - parent WebElement to search elements underneath\n\n`@returns {Promise}` resolves to true or false.  Rejected if element is not found\n\n#### _wait(locatorDefinition[, timeout [, msg]])\n\n`@argument locatorDefinition {String|Object}` - Please see `locatorDefinition` above\n\n`@argument timeout {Integer} (optional, default 5000)` - ms to wait until rejecting\n\n`@argument msg {String} (optional)` - Message to accompany error in failure case`\n\n`@returns {Promise}` resolves to true or rejected\n\n#### _waitVisible(locatorDefinition[, timeout [, msg]])\n\n`@argument locatorDefinition {String|Object}` - Please see `locatorDefinition` above\n\n`@argument timeout {Integer} (optional, default 5000)` - ms to wait until rejecting\n\n`@argument msg {String} (optional)` - Message to accompany error in failure case`\n\n`@returns {Promise}` resolves to true or rejected\n\n#### _optionValue(locatorDefinition, value [, parentWebElement])\n\n`@argument locatorDefinition {String|Object}}` - Please see `locatorDefinition` above\n\n`@argument value {String}`  - the value attribute of the option you wish to select\n\n`@argument parentWebElement {WebElement} (optional, default driver)` - parent WebElement to search elements underneath\n\n#### _optionText(locatorDefinition, text [, parentWebElement])\n\n`@argument locatorDefinition {String|Object}}` - Please see `locatorDefinition` above\n\n`@argument text {String}`  - The text in the option you wish to select\n\n`@argument parentWebElement {WebElement} (optional, default driver)` - parent WebElement to search elements underneath\n\n#### _firstVisible(locatorObject[, timeout])\n\n`@argument locatorObject {Object}` - Object of key/value pairs where the key describes the element to find and the\nvalue is a `locatorDefinition` (see above). Example would be:\n\n```javascript\n{\n  'loginerror': '.notification.notification-critical',\n  'profile': '#contents[role=main]'\n }\n```\n\n`@argument timeout {Integer} (optional, default 5000)` - ms to wait until rejecting\n\n`@returns {Promise}` resolves to the found key (e.g. 'loginerror' or 'profile' from above example) or rejected\n\n### addView method\n\nThe addView method will be added to the nemo.view namespace with the following signature:\n`nemo.view.addView(viewSpec, addToNamespace);`\n\n__viewSpec__ {String|JSON} will be either a string, or a JSON object to define the view/locator.\n__addToNamespace__ {boolean} (optional, defaults to true) if `false` nemo-view will not attach the view to the `nemo.view` namespace\n\nUsing the addView method, you can add a view at any time using the same formats and conventions as if you are adding them in the Nemo.setup() method. Examples:\n\n```javascript\n//add using a locator in the autoBaseDir/locator directory\nvar myPage = nemo.view.addView('myPage');\nvar login = nemo.view.addView({\n\t\"name\": \"login\",\n\t\"locator\": \"path:locator/loggedOut/login\"\n});\nvar addCard = nemo.view.addView({\n\t\"name\": \"addCard\",\n\t\"locator\": \"module:nemo-paypal-locators/addCard\"\n});\n\nThe addView method will return the view object. It will also dedupe to prevent extra cycles adding the same view multiple times, or overwriting of a view with another of the same name.\n\n```\n\n### locator methods\nThe view will create the following methods for each locator object:\n\n#### [locatorName]\n\n* arguments: none\n* returns: Promise which resolves to a WebElement or to a list if a *list locator* is used. Rejects if an error occurs.\n\n##### The list locator\nThis is a special locator, which let's you find lists of related elements. For example, given the locator file `formElementList.json`:\n\n```json\n{\n  \"inputGroup\": {\n    \"locator\": \"div.fielder\",\n    \"type\": \"css\",\n    \"Elements\": {\n      \"text\": \"input.texty\",\n      \"button\": \"input[type='button']\"\n    }\n  }\n}\n```\n\nYou will get a list of items, each with two properties `text` and `button` which themselves return WebElements when called.\n\n\n```js\n  nemo.view.formElementList\n    .inputGroup()\n    .then((elements) =\u003e {\n      elements.forEach(function (el) {\n        el.text().sendKeys('abcd');\n        el.button().click();\n      })\n    });\n```\n\n#### [locatorName]By or [locatorName].by\n\n* arguments: none\n* returns: JSON locator object. You can use this, for example, to pass to selenium-webdriver until statements\n\n#### [locatorName]Present or [locatorName].present\n\n* arguments: none\n* returns: Promise which resolves to true or false\n\n#### [locatorName]Wait or [locatorName].wait\n\n* arguments\n  * timeout {Number} time to wait in milliseconds\n  * msg {String} optional. Message to accompany error in failure case\n* returns: Promise which resolves to WebElement when element is present, or reject\n\n#### [locatorName]WaitVisible or [locatorName].waitVisible\n\n* arguments\n  * timeout {Number} time to wait in milliseconds\n  * msg {String} optional. Message to accompany error in failure case\n* returns: A promise which resolves to WebElement when element is both found and visible, or reject\n\n#### [locatorName]Visible or [locatorName].visible\n\n* arguments: none\n* returns: Promise which resolves to true or false when element is present, or rejected if element is not present\n\n#### [locatorName]OptionText or [locatorName].optionText\n\n* arguments\n  * text: the text in the option you wish to select\n* returns: Promise which resolves to true when option is selected\n\n#### [locatorName]OptionValue or [locatorName].optionValue\n\n* arguments\n  * value: the value attribute of the option you wish to select\n* returns: Promise which resolves to true when option is selected\nAny method in the view object's prototype will also be available for use\nOther than that, the nemo-view uses nemo-locatex internally, so if you change your locator files and set LOCALE, nemo-view will handle the rest!\n\n#### [locatorName]TextEquals or [locatorName].textEquals\n\n* arguments\n  * value: the expected value for the element\n* returns: Promise which resolves to true when the expected text matches, or rejects when it doesn't\n\n#### [locatorName]AttrEquals or [locatorName].attrEquals\n\n* arguments\n  * attribute: attribute value to check\n  * value: the expected value for the element\n* returns: Promise which resolves to true when the expected text matches, or rejects when it doesn't\n\n## Using locator specialization\n\nYou can specify different locator strings/strategies based on the `data.locale` configuration value.\nTo do so, first modify the entry you wish to be specialized:\n\n```js\n{\n  \"myLocator\": {\n    \"type\": \"css\",\n    \"locator\": \".myLocator\"\n  }\n}\n```\n\nchanges to\n\n```js\n{\n  \"myLocator\": {\n    \"default\": {\n       \"type\": \"css\",\n       \"locator\": \".myLocator\"\n     },\n    \"DE\": {\n      \"type\": \"css\",\n      \"locator\": \".meinLocator\"\n    }\n  }\n}\n```\n\nYou can set the `data.locale` property as follows:\n\n```js\nnemo._config.set('data:locale', 'DE');\n```\n\nFor a working example, refer to the unit tests for the locale feature (found in `test/locale.js`) in this module.\n\n_NOTE: This feature is a carry-over from earlier versions of nemo-view. It is understood now that the above feature does\nnot actually represent \"locale\" specificity as defined by bcp47 (https://tools.ietf.org/html/bcp47). See discussion\n[here](https://github.com/paypal/nemo-view/pull/32) and issue [here](https://github.com/paypal/nemo-view/issues/33).\nFollow along as we discuss a backwards compatible way to resolve this unfortunate nomenclature error.\n\n## Unit Tests\n\n* Unit tests run by default using headless browser [PhantomJS](http://phantomjs.org/). To run unit tests out of box, You must have PhantomJS installed on your system and must be present in the path\n    * Download PhantomJS from [here](http://phantomjs.org/download.html)\n    * On OSX, you can optionally use `brew` to install PhantomJS like `brew install phantomjs`\n    * PhantomJS installation detailed guide on Ubuntu can be found [here](https://gist.github.com/julionc/7476620)\n\n* If you want to run unit tests on your local browser, like lets say Firefox, you need to update browser in unit test\nconfiguration, for example the browser section under `test/config/config.json` like [here](https://github.com/paypal/nemo-view/blob/master/test/config/config.json#L14)\n\n* How to run unit tests?\n  * `npm run test:unit` will just run unit tests\n  * `npm test` - default grunt task will run linting as well as unit tests\n  * To run directly using mocha assuming its globally installed on your system `mocha -t 60s`\n  * Run using mocha on a specific test,  `mocha --grep @_visible@withParent@negative@ -t 60s`\n  * Or post `npm install` on nemo-view module, you can run `node_modules/.bin/mocha --grep @_visible@withParent@negative@ -t 60s`\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaypal%2Fnemo-view","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaypal%2Fnemo-view","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaypal%2Fnemo-view/lists"}