{"id":13527980,"url":"https://github.com/admc/wd","last_synced_at":"2025-05-13T21:12:35.639Z","repository":{"id":1440505,"uuid":"1669923","full_name":"admc/wd","owner":"admc","description":"A node.js client for webdriver/selenium 2.","archived":false,"fork":false,"pushed_at":"2024-02-13T19:26:36.000Z","size":3989,"stargazers_count":1525,"open_issues_count":73,"forks_count":402,"subscribers_count":51,"default_branch":"master","last_synced_at":"2025-04-28T17:04:32.572Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/admc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.APACHE2","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":"2011-04-27T09:45:05.000Z","updated_at":"2025-03-16T06:48:13.000Z","dependencies_parsed_at":"2024-04-15T04:13:35.196Z","dependency_job_id":"0f19d8c5-cd71-4ce3-91fa-67f1dcc930ae","html_url":"https://github.com/admc/wd","commit_stats":{"total_commits":1609,"total_committers":111,"mean_commits":"14.495495495495495","dds":0.3095090118085767,"last_synced_commit":"e74df30db9f452ab188371c5eb9a53d2fcd58895"},"previous_names":[],"tags_count":108,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/admc%2Fwd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/admc%2Fwd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/admc%2Fwd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/admc%2Fwd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/admc","download_url":"https://codeload.github.com/admc/wd/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254029008,"owners_count":22002284,"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-08-01T06:02:09.156Z","updated_at":"2025-05-13T21:12:30.620Z","avatar_url":"https://github.com/admc.png","language":"JavaScript","readme":"# WD.js\n\n[![NPM version](http://img.shields.io/npm/v/wd.svg)](https://npmjs.org/package/wd)\n[![Downloads](http://img.shields.io/npm/dm/wd.svg)](https://npmjs.org/package/wd)\n[![Dependency Status](https://david-dm.org/admc/wd.svg)](https://david-dm.org/admc/wd)\n[![devDependency Status](https://david-dm.org/admc/wd/dev-status.svg)](https://david-dm.org/admc/wd#info=devDependencies)\n[![Build Status](https://secure.travis-ci.org/admc/wd.png?branch=master)](http://travis-ci.org/admc/wd)\n[![Selenium Test Status](https://saucelabs.com/buildstatus/wdjs)](https://saucelabs.com/u/wdjs)\n\n[![Selenium Test Status](https://saucelabs.com/browser-matrix/wdjs.svg)](https://saucelabs.com/u/wdjs)\n\n**node.js Webdriver/Selenium 2 client**\n\n- [Site](http://admc.io/wd/)\n- [Mailing List](https://groups.google.com/forum/#!forum/wdjs)\n\nThis library is designed to be a maleable implementation of the webdriver protocol in Node, exposing functionality via a number of programming paradigms. If you are looking for a more polished, opinionated and active library - I would suggest [webdriver.io](http://webdriver.io/).\n\n## Release Notes\n[here](https://github.com/admc/wd/blob/master/doc/release-notes.md)\n\n## Install\n\n```\nnpm install wd\n```\n\nNote: WD.js does not start the selenium server. You may use the  [selenium-standalone](https://www.npmjs.com/package/selenium-standalone) package\nto install and start a selenium server.\n\n## Authors\n\n  - Adam Christian ([admc](http://github.com/admc))\n  - Ruben Daniels ([javruben](https://github.com/javruben))\n  - Peter Braden ([peterbraden](https://github.com/peterbraden))\n  - Seb Vincent ([sebv](https://github.com/sebv))\n  - Peter 'Pita' Martischka ([pita](https://github.com/Pita))\n  - Jonathan Lipps ([jlipps](https://github.com/jlipps))\n  - Phil Sarin ([pdsarin](https://github.com/pdsarin))\n  - Mathieu Sabourin ([OniOni](https://github.com/OniOni))\n  - Bjorn Tipling ([btipling](https://github.com/btipling))\n  - Santiago Suarez Ordonez ([santiycr](https://github.com/santiycr))\n  - Bernard Kobos ([bernii](https://github.com/bernii))\n  - Jason Carr ([maudineormsby](https://github.com/maudineormsby))\n  - Matti Schneider ([MattiSG](https://github.com/MattiSG))\n\n## License\n\n  * License - Apache 2: http://www.apache.org/licenses/LICENSE-2.0\n\n## Usage\n\n### Q promises + chaining\n\n```js\n...\n\nbrowser\n  .init({browserName:'chrome'})\n  .get(\"http://admc.io/wd/test-pages/guinea-pig.html\")\n  .title()\n    .should.become('WD Tests')\n  .elementById('i am a link')\n  .click()\n  .eval(\"window.location.href\")\n    .should.eventually.include('guinea-pig2')\n  .back()\n  .elementByCss('#comments').type('Bonjour!')\n  .getValue().should.become('Bonjour!')\n  .fin(function() { return browser.quit(); })\n  .done();\n```\n[full code here](https://github.com/admc/wd/blob/master/examples/promise/chrome.js)\n\n\n### Pure async\n\n```js\n...\n\nbrowser.init({browserName:'chrome'}, function() {\n  browser.get(\"http://admc.io/wd/test-pages/guinea-pig.html\", function() {\n    browser.title(function(err, title) {\n      title.should.include('WD');\n      browser.elementById('i am a link', function(err, el) {\n        browser.clickElement(el, function() {\n          browser.eval(\"window.location.href\", function(err, href) {\n            href.should.include('guinea-pig2');\n            browser.quit();\n          });\n        });\n      });\n    });\n  });\n});\n```\n[full code here](https://github.com/admc/wd/blob/master/examples/async/chrome.js)\n\n\n### Q promises without chaining\n\nSee example [here](https://github.com/admc/wd/blob/master/examples/promise/no-chain.js).\n\n## Generators api\n\n### Yiewd\n\n[Yiewd](https://github.com/jlipps/yiewd) is a wrapper around Wd.js that uses\ngenerators in order to avoid nested callbacks, like so:\n\n```js\nwd.remote(function*() {\n  yield this.init(desiredCaps);\n  yield this.get(\"http://mysite.com\");\n  el = yield this.elementById(\"someId\");\n  yield el.click();\n  el2 = yield this.elementById(\"anotherThing\")\n  text = yield el2.text();\n  text.should.equal(\"What the text should be\");\n  yield this.quit();\n});\n```\n## Mocha integration\n\n```js\n...\n\ndescribe(\"using promises and chai-as-promised\", function() {\n  var browser;\n\n  before(function() {\n    browser = wd.promiseChainRemote();\n    ...\n\n    return browser.init({browserName:'chrome'});\n  });\n\n  beforeEach(function() {\n    return browser.get(\"http://admc.io/wd/test-pages/guinea-pig.html\");\n  });\n\n  after(function() {\n    return browser.quit();\n  });\n\n  it(\"should retrieve the page title\", function() {\n    return browser.title().should.become(\"WD Tests\");\n  });\n\n  it(\"submit element should be clicked\", function() {\n    return browser.elementById(\"submit\").click().eval(\"window.location.href\")\n      .should.eventually.include(\"\u0026submit\");\n  });\n});\n```\n\n[example here](https://github.com/admc/wd/blob/master/examples/promise/mocha-specs.js)\n\n\n## Repl\n\n\nIf wd was installed via npm run:\n```\n./node_modules/.bin/wd shell\n```\n\nOr for local install run:\n```\nnode lib/bin.js shell\n```\n\nThen within the shell:\n```\n): wd shell\n\u003e x = wd.remote() or wd.remote(\"ondemand.saucelabs.com\", 80, \"username\", \"apikey\") or wd.remote(\"hub.browserstack.com\", 80, \"username\", \"apikey\") or wd.remote(\"hub.testingbot.com\", 80, \"key\", \"secret\")\n\n\u003e x.init() or x.init({desired capabilities override})\n\u003e x.get(\"http://www.url.com\")\n\u003e x.eval(\"window.location.href\", function(e, o) { console.log(o) })\n\u003e x.quit()\n```\n\n## Doc\n\n### Api\n\n[jsonwire mapping + api doc](doc/api.md)\n\n[full jsonwire mapping](doc/jsonwire-full-mapping.md)\n\n### JsonWireProtocol\n\nWD is simply implementing the Selenium JsonWireProtocol, for more details see the official docs:\n - \u003ca href=\"http://code.google.com/p/selenium/wiki/JsonWireProtocol\"\u003ehttp://code.google.com/p/selenium/wiki/JsonWireProtocol\u003c/a\u003e\n\nWD is incrementally implementing the Mobile JsonWireProtocol draft, see proposal docs:\n - \u003ca href=\"https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile\"\u003ehttps://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile\u003c/a\u003e\n\nCheck which Mobile JsonWire Protocol methods are supported in [/doc/jsonwire-mobile.md](doc/jsonwire-mobile.md)\n\n### Browser initialization\n\n#### Indexed parameters\n\n```js\nvar browser = wd.remote();\n// or\nvar browser = wd.remote('localhost');\n// or\nvar browser = wd.remote('localhost', 8888);\n// or\nvar browser = wd.remote(\"ondemand.saucelabs.com\", 80, \"username\", \"apikey\");\n// or\nvar browser = wd.remote(\"hub.browserstack.com\", 80, \"username\", \"apikey\");\n// or\nvar browser = wd.remote(\"hub.testingbot.com\", 80, \"key\", \"secret\");\n```\n#### Named parameters\n\nThe parameters used are similar to those in the [url](http://nodejs.org/docs/latest/api/url.html) module.\n\n```js\nvar browser = wd.remote()\n// or\nvar browser = wd.remote({\n  hostname: '127.0.0.1',\n  port: 4444,\n  user: 'username',\n  pwd: 'password',\n});\n// or\nvar browser = wd.remote({\n  hostname: '127.0.0.1',\n  port: 4444,\n  auth: 'username:password',\n});\n```\n\nThe following parameters may also be used (as in earlier versions):\n\n```js\nvar browser = wd.remote({\n  host: '127.0.0.1',\n  port: 4444,\n  username: 'username',\n  accessKey: 'password',\n});\n```\n#### Url string\n\n```js\nvar browser = wd.remote('http://localhost:4444/wd/hub');\n// or\nvar browser = wd.remote('http://user:apiKey@ondemand.saucelabs.com/wd/hub');\n// or\nvar browser = wd.remote('http://user:apiKey@hub.browserstack.com/wd/hub');\n// or\nvar browser = wd.remote('http://key:secret@hub.testingbot.com/wd/hub');\n// or\nvar browser = wd.remote('https://user:apiKey@api.kobiton.com/wd/hub');\n```\n\n#### Url object created via url.parse\n\n[URL module documentation](http://nodejs.org/docs/v0.10.0/api/url.html#url_url)\n\n```js\nvar url = require('url');\nvar browser = wd.remote(url.parse('http://localhost:4444/wd/hub'));\n// or\nvar browser = wd.remote(url.parse('http://user:apiKey@ondemand.saucelabs.com:80/wd/hub'));\n// or\nvar browser = wd.remote(url.parse('http://user:apiKey@hub.browserstack.com:80/wd/hub'));\n// or\nvar browser = wd.remote(url.parse('http://key:secret@hub.testingbot.com:80/wd/hub'));\n// or\nvar browser = wd.remote(url.parse('https://user:apiKey@api.kobiton.com/wd/hub'));\n```\n\n#### Defaults\n\n```js\n{\n    protocol: 'http:'\n    hostname: '127.0.0.1',\n    port: '4444'\n    path: '/wd/hub'\n}\n```\n\n#### Specifying driver type in remote\n\nYou may pass `async`,`promise` or `promiseChain` to `remote` to specify the driver type instead of\ncalling the driver specific method.\n\n```js\nvar browser = wd.remote('promiseChain')\n// or\nvar browser = wd.remote('localhost', 8888, 'promise');\n// or\nvar browser = wd.remote('localhost', 'promiseChain');\n// or\nvar browser = wd.remote({\n  hostname: '127.0.0.1',\n  port: 4444,\n  user: 'username',\n  pwd: 'password',\n}, 'promise');\n// or\nvar browser = wd.remote({\n  hostname: '127.0.0.1',\n  port: 4444,\n  auth: 'username:password',\n}, 'promiseChain');\n```\n\n#### Attach to an already-existing session\n\nInstead of calling 'init' use 'attach' using the WebDriver session ID. Use `detach`\nto detach from the session (callbacks are optional).\n\n```js\nvar browser = wd.remote('http://localhost:4444/wd/hub');\nbrowser.attach('df606fdd-f4b7-4651-aaba-fe37a39c86e3', function(err, capabilities) {\n  // The 'capabilities' object as returned by sessionCapabilities\n  if (err) { /* that session doesn't exist */ }\n  else {\n    browser.elementByCss(\"button.groovy-button\", function(err, el) {\n      ...\n    });\n  }\n});\n...\nbrowser.detach();\n\n```\n\n### Capabilities\n\n[doc here](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities).\n\n### Element function chaining (using promise chains)\n\nWith the promise chain api the method from the `browser` prototype and the\n`element` prototype are all available within the `browser` instance, so it might\nbe confusing at first. However we tried to keep the logic as simple as possible\nusing the principles below:\n\n- There is no state passed between calls, except for what the method returns.\n- If the method returns an element the element scope is propagated.\n- If the method returns nothing (click, type etc...) we make the method return the current element, so the element scope is propagated.\n- If the method returns something (text, getAttribute...), the element scope is lost.\n- You may use \"\u003c\" as the first parameter to get out of the element scope.\n- You may use \"\u003e\" as the first parameter to force the call to be done within the current context (mainly used to retrieve subelements).\n- By default element(s) methods are always executed in the global context, because this is the most common use case, but you may use \"\u003e\" to retrieve subelements. If you want to change the default use `browser.defaultChainingScope = 'element';`.\n\nIf you need to do something more complicated, like reusing an element for 2 calls, then\ncan either Q promise functionality (like then, Q.all or Q sequences), or retrieve your\nelement twice (since the promise chain api is very terse, this is usually acceptable).\n\nElement function chaining example [here](https://github.com/admc/wd/blob/master/examples/promise/chained-el-func-call.js)\n\n### Waiting for something\n\nBelow are the methods to use to wait for a condition:\n\n- `browser.waitFor(asserter, timeout, pollFreq, cb) -\u003e cb(err, value)`: generic wait method, the return value is provided by the asserter when the condition is satisfied.\n- `browser.waitForElementBy???(value ,asserter, timeout, pollFreq, cb) -\u003e cb(err, el)`: waits for a element then a\ncondition, then returns the element.\n- `browser.waitForConditionInBrowser(conditionExpr, timeout, pollFreq, cb) -\u003e cb(err, boolean)`: waits for a js condition within a browser, then returns a boolean.\n\n**NOTE:** When using `waitForConditionInBrowser` you must first set the async script timeout using `setAsyncScriptTimeout()`.  For instance:\n\n```js\n// init phase\nbrowser\n  .init()\n  .setAsyncScriptTimeout(30000);\n// test\nbrowser\n  .waitForConditionInBrowser(\"document.querySelectorAll('.foo').length \u003e 0\", 10000);\n```\n\nYou should be able to use [ready to use asserters](https://github.com/admc/wd/blob/master/lib/asserters.js),\nin most cases. [Here](https://github.com/admc/wd/blob/master/examples/promise/wait-for-simple.js) is a simple\nexample.\nPlease refer to the asserter category in the api doc [here](https://github.com/admc/wd/blob/master/doc/api.md).\n\nCustom asserters should be written using either models below . `target` may be `browser` and/or `element` depending on the context.\n\n```js\n// async\nvar asyncAsserter = new Asserter(\n  function(target,cb) {\n    ...\n    cb(err, satisfied, value);\n  }\n);\n\n// promise\nvar promiseAsserter = new Asserter(\n  function(target) {\n    ...\n    return promise; // promise resolved with the wait_for return value.\n\n    // Promise asserter should throw errors marked with `err.retriable=true`\n    // when the condition is not satisfied.\n  }\n);\n\n```\n\n[Here](https://github.com/admc/wd/blob/master/examples/promise/wait-for-custom.js) is a custom asserter example.\n\n### Adding custom methods\n\n- `wd.addAsyncMethod(name, method)`: This is for regular async methods with callback as the last argument. This will not only add the method to the async browser prototype, but also wrap the method and add it to the promise and promiseChain prototypes.\n- `wd.addPromiseMethod(name, method)`: This is for promise returning methods NOT USING CHAIN internally. This will not only add the method to the promise browser prototype, but also wrap the method and add it to the promiseChain prototype (but not to the async prototype).\n- `wd.addPromiseChainMethod(name, method)`: This is for promise returning methods USING CHAIN internally. This will only add the method to the promiseChain browser prototype (but neither to async nor to promise browser prototypes).\n\nIf you are only using the promise chain api, you should probably stick with `wd.addPromiseChainMethod`.\n\nCustom methods may be removed with `wd.removeMethod(name)`. That will remove the method from the 3 prototypes.\n\nPlease refer to the following examples:\n\n- [promise chain](https://github.com/admc/wd/blob/master/examples/promise/add-method.js).\n- [async method used by promise chain](https://github.com/admc/wd/blob/master/examples/promise/add-method-async.js).\n- [promise no-chain](https://github.com/admc/wd/blob/master/examples/promise/add-method-no-chain.js).\n- [async](https://github.com/admc/wd/blob/master/examples/async/add-method.js).\n\nNote: No need to call rewrap anymore.\n\n### Promise helpers\n\nThis is an alternative to adding custom methods.\nSee example [here](https://github.com/admc/wd/blob/master/examples/promise/helper.js).\n\n### Starting the promise chain\n\nThe `browser` and `element` object are not themselves promises (cause that would lead to chaos), so you\ncannot call Q core methods on them. However you may call one of the method below to initiate the promise\nchain:\n\n- `browser.chain()`\n- `browser.noop()`\n- `browser.resolve(promise)`\n- `element.chain()`\n- `element.noop()`\n- `element.resolve(promise)`\n\nThe `resolve` methods work like `Q` `thenResolve`.\n\n### Extra promise methods:\n\n- `at(i)`: get element from list (starting at 0).\n- `nth(i)`: get element from list (starting at 1).\n- `first()`: get the first element.\n- `second()`: get the second element.\n- `third()`: get the third element.\n- `last()`: get the last element.\n- `printError(prepend)`: print the previous error, prepend optional\n- `print(prepend)`: print the previous promise result, prepend optional\n\n**NOTE:** When using functions such as `nth()`, `first()`, `second()` you must use the \"plural\" versions of the `get` functions.\n\n### Working with external promise libraries\n\n`wd` uses `Q` internally, but you may use promises from other libraries with the following methods:\n\n- `browser.resolve(externalPromise)`\n- `wd.addPromiseChainMethod(name, externalPromise)`\n- `wd.addPromiseMethod(name, externalPromise)`\n\nThe external promise will be automatically wrapped within a Q promise using `new Q(externalPromise)`.\n\nSee example [here](https://github.com/admc/wd/blob/master/examples/promise/external-promise.js).\n\n### Http configuration / base url\n\nHttp behaviour and base url may be configured via the `configureHttp` method as\nin the code below:\n\n```js\n// global config\nwd.configureHttp({\n  timeout: 60000,\n  retries: 3,\n  retryDelay: 100,\n  baseUrl: 'http://example.com/'\n});\n// per browser config\nbrowser.configureHttp({\n  timeout: 60000,\n  retries: 3,\n  retryDelay: 100,\n  baseUrl: 'http://example.com/'\n});\n```\n\n- timeout: http timeout in ms, default is `undefined` (uses the server timeout,\n  usually 60 seconds). Use `'default'` or `undefined` for server default.\n- retries: Number of reconnection attempts in case the connection is dropped.\n  Default is `3`. Pass `0` or `always` to keep trying. Pass `-1` or `never` to disable.\n- retryDelay: the number of ms to wait before reconnecting. Default is `15`.\n- baseUrl: the base url use by the `get` method. The destination url is computed using\n`url.resolve`. Default is empty.\n- proxy: proxy configuration, as used in [request](https://github.com/mikeal/request). Default is empty.\n- If a field is not specified, the current configuration for this field is\n  unchanged.\n\n### Environment variables for Saucelabs\n\nWhen connecting to Saucelabs, the `user` and `pwd` fields can also be set through the `SAUCE_USERNAME` and `SAUCE_ACCESS_KEY` environment variables.\n\nThe following helper are also available to update sauce jobs: `sauceJobUpdate` and `sauceJobStatus`.\n\n### Safe Methods\n\nThe `safeExecute` and `safeEval` methods are equivalent to `execute` and `eval` but the code is\nexecuted within a `eval` block. They are safe in the sense that eventual\ncode syntax issues are tackled earlier returning as syntax error and\navoiding browser hanging in some cases.\n\nAn example below of expression hanging Chrome:\n\n```js\nbrowser.eval(\"wrong!!!\", function(err, res) { // hangs\nbrowser.safeEval(\"wrong!!!\", function(err, res) { // returns\nbrowser.execute(\"wrong!!!\", function(err, res) { //hangs\nbrowser.safeExecute(\"wrong!!!\", function(err, res) { //returns\n```\n\n## Working with mobile device emulators\n\nIt is possible to use `wd` to test mobile devices using either Selenium or Appium. However\nin either case the full JsonWire protocol is not supported (or is buggy).\n\nExamples [here](https://github.com/appium/sample-code/tree/master/sample-code/examples/node).\n\n### Selenium\n\nBoth Android (using AndroidDriver) and ios (using ios-driver) are supported, locally or using\nSauce Labs cloud.\n\n### Appium\n\nAndroid and iOS work locally and on [Sauce Labs](https://saucelabs.com/platforms/appium) or [BrowserStack](https://www.browserstack.com/automate).\n\n## Run the tests!\n\n```\n# Install the Selenium server, Chromedriver connect\nnode_modules/.bin/install_selenium\nnode_modules/.bin/install_chromedriver\n# NOTE: You may need to upgrade /tmp/sv-selenium/chromedriver to match your Chrome version!\n\n#Run the selenium server with chromedriver:\nnode_modules/.bin/start_selenium_with_chromedriver\n\n#Run the test\ngulp test\n\n//TODO: better doc + sauce test doc\n```\n\n## Adding new method / Contributing\n\nIf the method you want to use is not yet implemented, that should be\neasy to add it to `lib/webdriver.js`. You can use the `doubleclick`\nmethod as a template for methods not returning data, and `getOrientation`\nfor methods which returns data. No need to modify README as the doc\ngeneration is automated. Other contributions are welcomed.\n\n## Generating doc\n\nThe JsonWire mappings in the README and mapping files are generated from code\ncomments using [dox](https://github.com/visionmedia/dox).\n\nTo update the mappings run the following commands:\n\n```\nmake mapping \u003e doc/api.md\nmake full_mapping \u003e doc/jsonwire-full-mapping.md\nmake unsupported_mapping \u003e doc/jsonwire-unsupported-mapping.md\n```\n\n## Publishing\n\n```\nnpm version [patch|minor|major]\ngit push origin master\ngit push --tags\nnpm publish\n```\n\n## Test Coverage\n\n[test coverage](http://admc.io/wd/istanbul/coverage/lcov-report/lib/index.html)\n","funding_links":[],"categories":["JavaScript","Resources"],"sub_categories":["Tools"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadmc%2Fwd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadmc%2Fwd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadmc%2Fwd/lists"}