{"id":23328818,"url":"https://github.com/tonybranfort/ngpo","last_synced_at":"2026-04-30T09:38:19.878Z","repository":{"id":65458294,"uuid":"51611702","full_name":"tonybranfort/ngpo","owner":"tonybranfort","description":"Simple template to create page objects for AngularJs Protractor tests","archived":false,"fork":false,"pushed_at":"2017-09-11T16:02:52.000Z","size":45,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-24T12:57:32.890Z","etag":null,"topics":["angularjs","pageobject","pageobject-pattern","protractor","protractor-tests"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/tonybranfort.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-02-12T19:39:49.000Z","updated_at":"2017-08-11T15:45:37.000Z","dependencies_parsed_at":"2023-01-24T13:15:27.988Z","dependency_job_id":null,"html_url":"https://github.com/tonybranfort/ngpo","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/tonybranfort/ngpo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonybranfort%2Fngpo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonybranfort%2Fngpo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonybranfort%2Fngpo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonybranfort%2Fngpo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tonybranfort","download_url":"https://codeload.github.com/tonybranfort/ngpo/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonybranfort%2Fngpo/sbom","scorecard":{"id":893876,"data":{"date":"2025-08-11","repo":{"name":"github.com/tonybranfort/ngpo","commit":"33e0c653d09bde73230ff2983af3c3a6855b9366"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/29 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-24T12:55:50.844Z","repository_id":65458294,"created_at":"2025-08-24T12:55:50.844Z","updated_at":"2025-08-24T12:55:50.844Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32460781,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T22:27:22.272Z","status":"online","status_checked_at":"2026-04-30T02:00:05.929Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["angularjs","pageobject","pageobject-pattern","protractor","protractor-tests"],"created_at":"2024-12-20T21:17:41.426Z","updated_at":"2026-04-30T09:38:19.864Z","avatar_url":"https://github.com/tonybranfort.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ngpo\nCreate page objects with helper functions for [AngularJs Protractor](http://www.protractortest.org/#/) tests using a simple object template.\n\n### I want: \n* Protractor tests as quick to write, easy to read and ignorant of the page elements as possible.\n* Simple and consistent protractor page objects which can be nested.  \n* Consistent Protractor test methods across applicable elements and html widgets including: \n  - [enterValue](#enterValue) `clientPo.name.enterValue('franky');` \n  - [getValue](#getValue) `expect(clientPo.name.getValue()).toBe('franky');`\n  - [isVisible](#isVisible) (true if both isPresent and isDisplayed) `expect(clientPo.name.isVisible()).toBe(true);` \n  - No impact to existing protractor methods (unless explicitly intended)\n* Simple and consistent way of accessing repeating and nested page elements `expect(clientPo.payments.getRow(1).amount.getValue()).toBe('423');`\n* Ability to easily attach custom functions to page objects.\n* Ability to easily incorporate other html widgets into ngpo. \n* Page Object code that's not repeated.  \n\nInstall with `npm install ngpo`.  \n\n**ngpo v2.x**: requires nodejs 6.x or greater (no breaking api changes from ngpo v1.x).  Tested with angularJS v1.5.0 \u0026 1.6.5, Protractor v5.1.2, Chrome v60.0, and chromedriver 2.31. \n\n**ngpo v1.x**: Tested with Protractor versions 2.5 and 5.1.\n\n## Examples \n\nSee [test\\test.js](https://github.com/tonybranfort/ngpo/blob/master/test/test.js) and [test\\client.po.js](https://github.com/tonybranfort/ngpo/blob/master/test/client.po.js) for a full set of examples. \n\n#### Create a page object of Input, Dropdown \u0026 Button elements using [jsfiddle ngpo example](https://jsfiddle.net/tbmpls/vm6sL9zv/). \n```javascript\nvar ngpo = require('ngpo'); \n\nvar els = {\n  nameInput: {\n    locator: by.model('client.name'),\n    po: ngpo.makeInputPo},\n  name: {\n    locator: by.binding('client.name'),\n    po: ngpo.makeTextPo},\n  clearNameButton: {\n    locator: by.id('clear-name-button'),\n    po: ngpo.makeButtonPo},\n  typeDd: {\n    locator: by.model('client.type'),\n    po: ngpo.makeDdSelectPo}\n};\n\nvar pos = ngpo.makePos(els); \n\n```\nAnd run a protractor test with those elements.  \n```javascript\nvar clientPo = require('client.po.js');\n\ndescribe('client', function() {\n\n    it('should allow name to be modified', function() {\n      clientPo.nameInput.enterValue('franky'); \n      expect(clientPo.nameInput.getValue()).toBe('franky'); \n      expect(clientPo.name.getValue()).toBe('franky');\n\n    it('should clear the name', function() {\n      clientPo.clearNameButton.click();\n      expect(clientPo.name.getValue()).toBe('');\n      expect(clientPo.nameInput.getValue()).toBe('');\n    });\n\n    it('should allow client type to be selected', function() {\n      clientPo.typeDd.enterValue('cranky'); \n      expect(clientPo.typeDd.getValue()).toBe('cranky'); \n      expect(clientPo.type.getValue()).toBe('cranky'); \n    });\n\n});\n\n```\n\n#### Create a list page object using [jsfiddle ngpo example](https://jsfiddle.net/tbmpls/vm6sL9zv/).\n```javascript\nvar ngpo = require('ngpo'); \n\n//Nest the list elements as another 'els' object in the list object ('payments' here): \nvar els = {\n  addPaymentButton: {\n    locator: by.id('add-payment-button'),\n    po: ngpo.makeButtonPo},\n  payments: {\n    locator: by.repeater('payment in payments'),\n    po: ngpo.makeListPo,\n    els: {\n      amountInput: {\n        locator: by.model('payment.amount'),\n        po: ngpo.makeInputPo},\n      amount: {\n        locator: by.binding('payment.amount'),\n        po: ngpo.makeTextPo},\n    },\n  }\n};\n\nvar pos = ngpo.makePos(els); \n\n```\n\nRun the protractor test. \n```javascript\nvar clientPo = require('client.po.js');\n\ndescribe('client', function() {\n\n    it('should have working payment inputs', function() {\n      expect(clientPo.payments.count()).toBe(0);\n\n      clientPo.addPaymentButton.click()\n      .then(() =\u003e {\n        expect(clientPo.payments.count()).toBe(1);\n        // getRow() is the ngpo method to retrieve the row's nested elements.  \n        // ngpo uses getRow() so as to not overwrite the get() method. \n        return clientPo.payments.getRow(0).amountInput.enterValue(5);\n      })\n      .then(() =\u003e {\n        expect(clientPo.payments.getRow(0).amountInput.getValue()).toBe('5'); \n        expect(clientPo.payments.getRow(0).amount.getValue()).toBe('5'); \n      \n        return clientPo.addPaymentButton.click();\n      })\n      .then(() =\u003e {\n        expect(clientPo.payments.count()).toBe(2);\n        expect(clientPo.payments.getRow(0).amount.getValue()).toBe('5'); \n        return clientPo.payments.getRow(1).amountInput.enterValue('423');\n      })\n      .then(() =\u003e {\n        expect(clientPo.payments.getRow(1).amountInput.getValue()).toBe('423'); \n        expect(clientPo.payments.getRow(1).amount.getValue()).toBe('423'); \n      }); \n\n    });\n\n});\n\n```\n\n\n## Documentation\n\n### ngpo Functions available:  \n* [`makePos`](#makePos)\n* Make page object functions and the functions attached (in addition to all expected Protractoor functions): \n  * [`makeDefaultPo`](#makeDefaultPo)\n      - [isVisible](#isVisible)\n  * [`makeTextPo`](#makeTextPo)\n      - [getValue](#getValue)\n      - [getValueTrim](#getValueTrim)  \n      - [isVisible](#isVisible)\n  * [`makeInputPo`](#makeInputPo)\n      - [enterValue](#enterValue)\n      - [getValue](#getValue)\n      - [getValueTrim](#getValueTrim)  \n      - [isVisible](#isVisible)\n  * [`makeDateInputPo`](#makeDateInputPo)\n      - [enterValue](#enterValue)\n      - [getValue](#getValue)\n      - [getValueTrim](#getValueTrim)  \n      - [isVisible](#isVisible)\n      - getValueMmddyyyy\n      - getValueYyyymmdd\n  * [`makeButtonPo`](#makeButtonPo)\n      - [isVisible](#isVisible)\n  * [`makeButtonWithPausePo`](#makeButtonWithPausePo) (**deprecated**)\n  * [`makeDdSelectPo`](#makeDdSelectPo)\n      - [enterValue](#enterValue)\n      - [getValue](#getValue)\n      - [getValueTrim](#getValueTrim)  \n      - [isVisible](#isVisible)\n      - clear (selects first item in dd list)\n  * [`makeParentPo`](#makeParentPo)\n      - [getValue](#getValue)\n      - subPo.poFn()\n  * [`makeListPo`](#makeListPo)\n      - getRow\n      - getRow(n).subPo.poFn()\n      - getCount\n      - getValue\n* poFns  (optional fns that can be attached to page objects; see [Append custom functions to page object elements](#custom-fns))\n    - `hasClass`, `makeHasClassFn` : `expect(clientPo.deleteHobbyButton.hasClass('yada')).toBe(true)`\n    - `clearByBs`, `makeHasClearByBs`  (use to clear date field in Chrome; Protractor issue #562) : `clientPo.dobInput.clearByBs()`\n    - `clickWithPause` (**deprecated**)\n    - `getAttributeValue`\n* Other functions\n  * pause\n  * acceptAlert\n  * dismissAlert\n\n\n#### How to \n* [Append custom functions to page object elements](#custom-fns)\n* Clear a date field in Chrome (Protractor Issue [#562](https://github.com/angular/protractor/issues/562)) - Use `poFns.clearByBs`.  See example in [Append custom functions to page object elements](#custom-fns).\n* [Nest ngpo page objects](#nesting-page-objects).\n* Create your own _makePo_ functions: See [`makeDefaultPo`](#makeDefaultPo).  And github/npm it: See [ngpo-ui-select](https://www.npmjs.com/package/ngpo-ui-select). \n\n\n### ngpo functions attached to page objects \n#### \u003ca name=\"enterValue\"\u003eenterValue()\u003c/a\u003e\nEnters a value into a page element and returns a Promise. How value is entered depends on the page element.  Input elements use: \n```javascript\n  return el\n    .click()\n    .clear()\n    .sendKeys(value)\n    .sendKeys(protractor.Key.TAB);\n\n```\nExample: \n``` javascript\nclientPo.nameInput.enterValue('franky'); \nexpect(clientPo.nameInput.getValue()).toBe('franky'); \n```\n\n#### \u003ca name=\"getValue\"\u003egetValue()\u003c/a\u003e\nReturns the value of the pageObject as a Promise. How value is retrieved depends on the page element: \n* makeTextPo() uses Protractor getText()\n* input POs (makeInputPo, makeDateInputPo) use Protractor `getAttribute('value')`\n* makeDdSelectPo uses el.$('option:checked').getText()\n``` javascript\nclientPo.nameInput.enterValue('franky'); \nexpect(clientPo.nameInput.getValue()).toBe('franky'); // input\nexpect(clientPo.name.getValue()).toBe('franky'); // text by.binding\n```\n\n#### \u003ca name=\"getValueTrim\"\u003egetValueTrim()\u003c/a\u003e\nReturns pageObject.getValue() to a string.trim() as a Promise.\n```javascript\nclientPo.nameInput.enterValue('  b o bb y '); \nexpect(clientPo.nameInput.getValueTrim()).toBe('b o bb y'); \n\n```\n\n#### \u003ca name=\"isVisible\"\u003eisVisible()\u003c/a\u003e\nReturns true as a Promise if isPresent and isDisplayed.\n```javascript\nexpect(clientPo.showme.isPresent()).toBe(true);\nexpect(clientPo.showme.isDisplayed()).toBe(true);\nexpect(clientPo.showme.isVisible()).toBe(true);\n// hide showme element\nclientPo.showmeButton.click()\n.then(function() {\n  expect(clientPo.showme.isPresent()).toBe(true);\n  expect(clientPo.showme.isDisplayed()).toBe(false);\n  expect(clientPo.showme.isVisible()).toBe(false);\n});\n```\n\n### ngpo api functions\n#### \u003ca name=\"makePos\"\u003emakePos(els)\u003c/a\u003e\nReturns a Page Object: An object-literal of Protractor ElementFinder objects possibly with methods appended.  Methods appended are based on the els object passed in. \n\n`makePos` calls the function assigned to the `po` property for every object in the `els` object.  The `po` function is called with (1) the `locator` and (2) the respective els object.  \n\n`els` is an object of the form : \n```javascript\nvar els {\n  poName1: {\n    locator: protractorLocator //  Req'd. eg; by.model('client.city')\n    po: makePoFn  //Req'd. the function to append helper functions and return a protractor ElementFinder\n    els: {...}    // optional nested object of same form els for list or parent pos\n    fns: {fnName: function}  // optional object of custom functions that will be appended to this ElementFinder\n    yourParam: value  // optional; any other parameter may be included for use in custom fns\n  },\n  poName2: ...\n}\n```\n\nExample\n```javascript\nvar ngpo = require('ngpo'); \n\nvar els = {\n  nameInput: {\n    locator: by.model('client.name'),\n    po: ngpo.makeInputPo,\n    myOption: 'abc'},\n};\n\nvar pos = ngpo.makePos(els); \n\n```\n\nIn the above example, when `makePos` is called, `makeInputPo` will be called with \n```javascript\nmakeInputPo(\n  by.model('clientName'),\n  {locator: by.model('client.name'),\n   po: ngpo.makeInputPo\n  myOption: 'abc'}  \n)\n```\n\nAnd return an object with the property `nameInput` which would be a protractor ElementFinder with getValue and enterValue methods appended (from makeInputPo).  \n\n#### \u003ca name=\"makeDefaultPo\"\u003emakeDefaultPo(elOrLoc, options)\u003c/a\u003e\nReturns a Protractor ElementFinder with only the `isVisible` ngpo function appended.  \n\nDetermines if `elOrLoc` is a Protractor ElementFinder or locator.  If it is a locator, creates an ElementFinder from it and returns that ElementFinder.  Otherwise, returns ElementFinder as-is.  `options` is the els object for the page object being created;  eg, `{locator: by.binding('client.name'), po: ngpo.makeTextPo}`. \n\nEvery makeXxxPo function calls this function first.  Custom makeXxxPo functions should also call this function first as well which will ensure that it will work as a 'sub' PO in list and parent elements.\n\nExample\n```javascript\nfunction myCustomPo(elOrLoc, options) {\n  var el = makeDefaultPo(elOrLoc); \n\n  var yank = options \u0026\u0026 options.yank ? options.yank : '';   \n\n  el.isBlada() = function() {\n    return el.getAttribute('blada') === yank; \n  }\n\n  return el; \n}\n\nvar els = {\n  berl: {\n    locator: by.model('something.what'),\n    po: myCustomPo,\n    yank: 'green'\n  }\n}\n\n```\n\n#### \u003ca name=\"makeTextPo\"\u003emakeTextPo(elOrLoc, options)\u003c/a\u003e\nReturns a Protractor ElementFinder with one appended function: \n  * getValue - returns element.getText()\n\nArguments: See [`makeDefaultPo`](#makeDefaultPo) and [`makePos`](#makePos).\n\nWould typically be used with by.binding.  \n\n```javascript\nvar ngpo = require('ngpo'); \n\nvar els = {\n  name: {\n    locator: by.binding('client.name'),\n    po: ngpo.makeTextPo}\n};\n\nvar pos = ngpo.makePos(els); \n\n```\n\n#### \u003ca name=\"makeInputPo\"\u003emakeInputPo(elOrLoc, options)\u003c/a\u003e\nReturns a Protractor ElementFinder for html ```\u003cinput\u003e``` with these appended functions: \n  * getValue - returns element.getText()\n  * enterValue(value) : returns ```element.click().clear().sendKeys(value).sendKeys(protractor.Key.TAB)```\n\nArguments: See [`makeDefaultPo`](#makeDefaultPo) and [`makePos`](#makePos).\n\nExample\n```javascript\nvar ngpo = require('ngpo'); \n\nvar els = {\n  nameInput: {\n    locator: by.model('client.name'),\n    po: ngpo.makeInputPo}\n};\n\nvar clientPo = ngpo.makePos(els); \n\n// test example\n  clientPo.nameInput.enterValue('franky'); \n  expect(clientPo.nameInput.getValue()).toBe('franky'); \n\n```\n\n\n#### \u003ca name=\"makeDateInputPo\"\u003emakeDateInputPo(elOrLoc, options)\u003c/a\u003e\nReturns a Protractor ElementFinder for html ```\u003cinput type=date\u003e``` tags with these appended functions: \n  * getValue - See [`makeInputPo`](#makeInputPo)\n  * enterValue(value) - See `makeInputPo`\n  * getValueMmddyyyy - getValue() as string mm/dd/yyyy format\n  * getValueYyyymmdd - getValue() as string yyyy-mm-dd format\n\nArguments: See [`makeDefaultPo`](#makeDefaultPo) and [`makePos`](#makePos).\n\nExample\n```javascript\nvar ngpo = require('ngpo'); \n\nvar els = {\n  dobInput: {\n    locator: by.model('client.dob'),\n    po: ngpo.makeDateInputPo}\n};\n\nvar clientPo = ngpo.makePos(els); \n\n// test example\n  clientPo.dobInput.enterValue('01/01/1939'); \n  expect(clientPo.dobInput.getValue()).toBe('1939-01-01');\n  expect(clientPo.dobInput.getValueMmddyyyy()).toBe('01/01/1939');\n\n```\n\n#### \u003ca name=\"makeButtonPo\"\u003emakeButtonPo(elOrLoc, options)\u003c/a\u003e\nReturns a Protractor ElementFinder with no appended functions. \n\nArguments: See [`makeDefaultPo`](#makeDefaultPo) and [`makePos`](#makePos).\n\nExample\n```javascript\nvar ngpo = require('ngpo'); \n\nvar els = {\n  deleteCityButton: {\n    locator: by.id('delete-city-button'),\n    po: ngpo.makeButtonPo}\n};\n\nvar clientPo = ngpo.makePos(els); \n\n// test example\n  clientPo.deleteCityButton.click(); \n\n```\n\n\n#### \u003ca name=\"makeButtonWithPausePo\"\u003emakeButtonWithPausePo(elOrLoc, options)\u003c/a\u003e\nReturns a Protractor ElementFinder with this amended function.\n  - `click()` : sleeps for `options.pause` milleseconds after click()\n    ```element.click().then(function() {pause(options.pause);});``` \n\nArguments: See [`makeDefaultPo`](#makeDefaultPo) and [`makePos`](#makePos).\n\nOriginal ElementFinder click() method is available via element.p.click(). \n\nExample\n```javascript\nvar ngpo = require('ngpo'); \n\nvar els = {\n  deleteHobbyButton: {\n    locator: by.id('delete-hobby-button'),\n    po: ngpo.makeButtonWithPausePo,\n    pause: 5000}\n};\n\nvar clientPo = ngpo.makePos(els); \n\n// test example\n  clientPo.deleteHobbyButton.click(); // pauses 5 seconds after click()\n\n```\n\n#### \u003ca name=\"makeDdSelectPo\"\u003emakeDdSelectPo(elOrLoc, options)\u003c/a\u003e\nReturns a Protractor ElementFinder for html ```\u003cselect\u003e``` tags\nwith these appended functions : \n  * getValue - returns ```element.$('option:checked').getText()```\n  * enterValue(value) : returns ```element.click().sendKeys(value).sendKeys(protractor.Key.TAB)```\n\nArguments: See [`makeDefaultPo`](#makeDefaultPo) and [`makePos`](#makePos).\n\nExample\n```javascript\nvar ngpo = require('ngpo'); \n\nvar els = {\n  nameInput: {\n    locator: by.model('client.name'),\n    po: ngpo.makeInputPo}\n};\n\nvar clientPo = ngpo.makePos(els); \n\n// test example\n  clientPo.nameInput.enterValue('franky'); \n  expect(clientPo.nameInput.getValue()).toBe('franky'); \n\n```\n\n#### \u003ca name=\"makeParentPo\"\u003emakeParentPo(elOrLoc, options)\u003c/a\u003e\nReturns a Protractor ElementFinder which can have sub-ElementFinders on it. \n\nArguments: See [`makeDefaultPo`](#makeDefaultPo) and [`makePos`](#makePos).\n\nExample\n```javascript\nvar ngpo = require('ngpo'); \n\nvar els = {\n  request: {\n    locator: by.id('request'),\n    po: ngpo.makeParentPo,\n    els: {\n      rInput: {\n        locator: by.model('client.request'),\n        po: ngpo.makeInputPo},\n      rText: {\n        locator: by.binding('client.request'),\n        po: ngpo.makeTextPo},\n    }\n  },\n};\n\nvar clientPo = ngpo.makePos(els); \n\n// test example\n  clientPo.request.rInput.enterValue('be nice'); \n  expect(clientPo.request.rInput.getValue()).toBe('be nice'); \n  expect(clientPo.request.rText.getValue()).toBe('be nice'); \n\n```\n\n#### \u003ca name=\"makeListPo\"\u003emakeListPo(elOrLoc, options)\u003c/a\u003e\nReturns a Protractor element.all object with nested protractor ElementFinders.  It has these appended functions: \n  * getRow(n) \n  * getRow(n).subPo.poFn()\n  * getCount\n  * getValue\n\nArguments: See [`makeDefaultPo`](#makeDefaultPo) and [`makePos`](#makePos).\n\nExample\n```javascript\nvar ngpo = require('ngpo'); \n\nvar els = {\n  payments: {\n    locator: by.repeater('payment in payments'),\n    po: ngpo.makeListPo,\n    els: {\n      amountInput: {\n        locator: by.model('payment.amount'),\n        po: ngpo.makeInputPo},\n      amount: {\n        locator: by.binding('payment.amount'),\n        po: ngpo.makeTextPo},\n    }\n};\n\nvar clientPo = ngpo.makePos(els); \n\n// test example\n  expect(clientPo.payments.getCount()).toBe(1);\n  clientPo.payments.getRow(0).amountInput.enterValue(5);\n  expect(clientPo.payments.getRow(0).amountInput.getValue()).toBe('5'); \n  expect(clientPo.payments.getRow(0).amount.getValue()).toBe('5'); \n\n```\n\n#### \u003ca name=\"nesting-page-objects\"\u003eHow to Nest Page Objects\u003c/a\u003e\n\nExample to nest the transportation page object into a client page object. \n\n```javascript\n// transportation.po.js\nvar ngpo = require('../lib/index.js'); \n\nvar els = {\n  transportationInput: {\n    locator: by.model('client.transportation'),\n    po: ngpo.makeInputPo},\n  transportation: {\n    locator: by.binding('client.transportation'),\n    po: ngpo.makeTextPo},\n\n}; \n\nvar pos = ngpo.makePos(els); \n\nmodule.exports = pos; \n\n```\n\nThere are 2 ways to nest the above transportation page object. \n```javascript\n// client.po.js\nvar ngpo = require('ngpo'); \nvar transPo = require('./transportation.po.js');\n\n// (1) directly in the client po els object\nvar els = {\n  transportationParent: {\n    locator: by.id('trans-parent'),\n    po: ngpo.makeParentPo, \n    els: transPo.els},   \n}; \n\n// (2) append the transportation page objects elements directly to the  client po object \nvar pos = ngpo.makePos(els); \npos = ngpo.makePos(transPo.els, pos);\n\n```\n\nThe protractor tests would refer to these like this: \n```javascript\n// #1 above would be called using transportationParent: \n  clientPo.transportationParent.transportationInput.enterValue('strides'); \n  expect(clientPo.transportationParent.transportationInput.getValue()).toBe('strides');\n\n// #2 would allow the transportation page object elements to be called directly from the client po\n  clientPo.transportationInput.enterValue('unicycle'); \n  expect(clientPo.transportationInput.getValue()).toBe('unicycle');\n\n\n```\n\n#### \u003ca name=\"custom-fns\"\u003eHow to append custom functions to page object elements\u003c/a\u003e\nCustom functions can be included in the els `fns` property object.  Custom functions are called with the ElementFinder and the options object (see [makeDefaultPo](#makeDefaultPo)), so that you can refer to them in the custom function, and the arguments that you call the function with from the protractor script.  \n\nExample\n```javascript\n\nvar els = {\n  hobbyInput: {\n    locator: by.model('client.hobby'),\n    po: ngpo.makeInputPo,\n    pause: 5000,\n    fns: {\n      getClasses: function(el, options) {return el.getAttribute('class');},\n      clickWithPause: function(el, options) {\n        return el.click().then(function() {browser.sleep(options.pause);})\n      }}\n  },\n  funnyInput: {\n    locator: by.model('client.funny'),\n    po: ngpo.makeInputPo,\n    fns: {\n      inputAddedVals: (funnyInputEl, options, val1, val2) =\u003e {\n        var addedVals = val1 + val2; \n        return funnyInputEl.enterValue(addedVals);\n      }\n    }\n  },\n  dobInput: {\n    locator: by.model('client.dob'),\n    po: ngpo.makeDateInputPo,\n    // override clear() fn with poFns.clearByBs b/c Protractor Issue #562\n    fns: {clear: ngpo.poFns.clearByBs}},\n}; \n\n// test example\n  expect(clientPo.hobbyInput.getClasses()).toContain('yada');\n  clientPo.hobbyInput.clickWithPause();  // pauses 5 seconds after click()\n\n  clientPo.funnyInput.inputAddedVals(3,4)\n  .then(function(){\n    expect(clientPo.funnyInput.getValue()).toBe('7');\n  });\n\n  clientPo.dobInput.enterValue('01/02/1987')\n  .then(() =\u003e {\n    expect(clientPo.dobInput.getValue()).toBe('1987-01-02');\n    clientPo.dobInput.clear();  // using poFns.clearByBs\n    expect(clientPo.dobInput.getValue()).toBe(''); \n  }); \n\n\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftonybranfort%2Fngpo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftonybranfort%2Fngpo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftonybranfort%2Fngpo/lists"}