{"action":"created","comment":{"url":"https://api.github.com/repos/fiverr/passable/pulls/comments/219403373","pull_request_review_id":157564945,"id":219403373,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIxOTQwMzM3Mw==","diff_hunk":"@@ -1,16 +1,63 @@\n # The `test` function\n-The test function is a single test in your validations. It is similar to unit tests `it` or `test` function. `test` accepts the name of the test, the error message and the actual test function. If you explicitly return true, or if your enforce function passed correctly, it is assumed that the test did not fail.\n+The test function is a single test in your validations. It is similar to unit tests `it` or `test` function. `test` accepts the name of the test, the error message and the actual test logic. Tests can either be sync or async.","path":"documentation/test/index.md","position":3,"original_position":3,"commit_id":"347da3fb559dec66f4a945de6287cb10faa45d32","original_commit_id":"347da3fb559dec66f4a945de6287cb10faa45d32","user":{"login":"raphaelboukara","id":6442236,"node_id":"MDQ6VXNlcjY0NDIyMzY=","avatar_url":"https://avatars0.githubusercontent.com/u/6442236?v=4","gravatar_id":"","url":"https://api.github.com/users/raphaelboukara","html_url":"https://github.com/raphaelboukara","followers_url":"https://api.github.com/users/raphaelboukara/followers","following_url":"https://api.github.com/users/raphaelboukara/following{/other_user}","gists_url":"https://api.github.com/users/raphaelboukara/gists{/gist_id}","starred_url":"https://api.github.com/users/raphaelboukara/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/raphaelboukara/subscriptions","organizations_url":"https://api.github.com/users/raphaelboukara/orgs","repos_url":"https://api.github.com/users/raphaelboukara/repos","events_url":"https://api.github.com/users/raphaelboukara/events{/privacy}","received_events_url":"https://api.github.com/users/raphaelboukara/received_events","type":"User","site_admin":false},"body":"\"It is similar to unit tests `it` or `test` function.\" are you sur you want to expose this parallel?","created_at":"2018-09-21T07:18:27Z","updated_at":"2018-09-21T07:35:13Z","html_url":"https://github.com/fiverr/passable/pull/100#discussion_r219403373","pull_request_url":"https://api.github.com/repos/fiverr/passable/pulls/100","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/fiverr/passable/pulls/comments/219403373"},"html":{"href":"https://github.com/fiverr/passable/pull/100#discussion_r219403373"},"pull_request":{"href":"https://api.github.com/repos/fiverr/passable/pulls/100"}}},"pull_request":{"url":"https://api.github.com/repos/fiverr/passable/pulls/100","id":216932453,"node_id":"MDExOlB1bGxSZXF1ZXN0MjE2OTMyNDUz","html_url":"https://github.com/fiverr/passable/pull/100","diff_url":"https://github.com/fiverr/passable/pull/100.diff","patch_url":"https://github.com/fiverr/passable/pull/100.patch","issue_url":"https://api.github.com/repos/fiverr/passable/issues/100","number":100,"state":"open","locked":false,"title":"[Minor] Async test support + done callback chaining","user":{"login":"ealush","id":11255103,"node_id":"MDQ6VXNlcjExMjU1MTAz","avatar_url":"https://avatars1.githubusercontent.com/u/11255103?v=4","gravatar_id":"","url":"https://api.github.com/users/ealush","html_url":"https://github.com/ealush","followers_url":"https://api.github.com/users/ealush/followers","following_url":"https://api.github.com/users/ealush/following{/other_user}","gists_url":"https://api.github.com/users/ealush/gists{/gist_id}","starred_url":"https://api.github.com/users/ealush/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ealush/subscriptions","organizations_url":"https://api.github.com/users/ealush/orgs","repos_url":"https://api.github.com/users/ealush/repos","events_url":"https://api.github.com/users/ealush/events{/privacy}","received_events_url":"https://api.github.com/users/ealush/received_events","type":"User","site_admin":false},"body":"<!--\r\nBefore creating a pull request, please read our contributing guidelines:\r\n\r\nCONTRIBUTING.md\r\n\r\nRemember: Unless it is an urgent bugfix, please use `next` as the base for your PR\r\n\r\nPlease fill the following form (leave what's relevant)\r\n-->\r\n\r\n| Q                | A\r\n| ---------------- | ---\r\n| Bug fix?         | no\r\n| New feature?     | yes\r\n| Breaking change? | no\r\n| Deprecations?    | no\r\n| Documentation?   | yes\r\n| Tests added?     | yes\r\n| Fixed issues     | https://github.com/fiverr/passable/issues/10\r\n\r\n<!-- Describe your changes below in detail. -->\r\n\r\n# Update \r\nThe reasoning behind the api decisions made in this update can be found here: https://github.com/fiverr/passable/issues/10#issuecomment-423355641\r\n\r\n## Asynchronous Tests\r\nSometimes you would want to validate data with information from the server, for example - username availability. In these cases, you should add an async test to your suite, reaching the server before going in and performing the validation. An async validation is a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) object. When it *resolves*, the test passes, and when it *rejects* the test fails. An async test will not complete unless either happens.\r\n\r\n```js\r\ntest('name',  'must be unique', new Promise((resolve, reject) => {\r\n    fetch(`/userExists?name=${name}`)\r\n        .then(res => res.json)\r\n        .then(data => {\r\n            if (data.exists) {\r\n                reject(); // rejects and marks the test as failing\r\n            } else {\r\n                resolve(); // completes. doesn't mark the test as failing\r\n            }\r\n        }\r\n}));\r\n```\r\n\r\n## The `.done()` function\r\n\r\nThe `.done()` function is a function that can be chaind to a passable suite. It accepts a function to be run whenever the suite completes running all [tests](../test/index.md) (both sync, and async - if present), regardless of whether they passed or [failed](../test/how_to_fail.md).\r\n\r\n`.done` calls can be infinitely chained to one another, and as the passable suite completes - they will all run synchronously - meaning that if there is an async action being performed in one of the callbacks, the next `.done` call will *not* wait for it to complete before starting.\r\n\r\nWhen running, the `done` function passes down to its callback function the final passable result object, so you do not have to store it in an external variable.\r\n\r\n```js\r\nimport passable, { enforce } from 'passable';\r\nconst email_regex = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}/gi;\r\n\r\npassable('SendEmailForm', (test) => {\r\n\r\n  test('UserEmail', 'must be a valid email', () => {\r\n    enforce(data.email).matches(email_email_regex);\r\n  });\r\n\r\n  test('UserName', 'must not be blacklisted', new Promise((resolve, reject) => {\r\n    fetch(`/isBlacklisted?name=${data.name}`).then(...).then((data) => {\r\n      if (data.blackListed) {\r\n        reject();\r\n      } else {\r\n        resolve();\r\n      }\r\n    });\r\n  }));\r\n\r\n  test('Content', 'must be between 5 and 500 chars', () => {\r\n    enforce(data.content).largerThan(4).smallerThan(501);\r\n  });\r\n}).done((res) => {\r\n  if (res.hasValidationErrors) {\r\n    showValidationErrors(res.errors)\r\n  }\r\n}).done(reportToServer).done(promptUserQuestionnaire);\r\n```\r\n","created_at":"2018-09-20T11:10:06Z","updated_at":"2018-09-21T07:35:12Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3e90421de82ee5333103a6832e44371056104c40","assignee":null,"assignees":[],"requested_reviewers":[{"login":"omrilotan","id":516342,"node_id":"MDQ6VXNlcjUxNjM0Mg==","avatar_url":"https://avatars0.githubusercontent.com/u/516342?v=4","gravatar_id":"","url":"https://api.github.com/users/omrilotan","html_url":"https://github.com/omrilotan","followers_url":"https://api.github.com/users/omrilotan/followers","following_url":"https://api.github.com/users/omrilotan/following{/other_user}","gists_url":"https://api.github.com/users/omrilotan/gists{/gist_id}","starred_url":"https://api.github.com/users/omrilotan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/omrilotan/subscriptions","organizations_url":"https://api.github.com/users/omrilotan/orgs","repos_url":"https://api.github.com/users/omrilotan/repos","events_url":"https://api.github.com/users/omrilotan/events{/privacy}","received_events_url":"https://api.github.com/users/omrilotan/received_events","type":"User","site_admin":false},{"login":"sahariko","id":9280709,"node_id":"MDQ6VXNlcjkyODA3MDk=","avatar_url":"https://avatars0.githubusercontent.com/u/9280709?v=4","gravatar_id":"","url":"https://api.github.com/users/sahariko","html_url":"https://github.com/sahariko","followers_url":"https://api.github.com/users/sahariko/followers","following_url":"https://api.github.com/users/sahariko/following{/other_user}","gists_url":"https://api.github.com/users/sahariko/gists{/gist_id}","starred_url":"https://api.github.com/users/sahariko/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sahariko/subscriptions","organizations_url":"https://api.github.com/users/sahariko/orgs","repos_url":"https://api.github.com/users/sahariko/repos","events_url":"https://api.github.com/users/sahariko/events{/privacy}","received_events_url":"https://api.github.com/users/sahariko/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/fiverr/passable/pulls/100/commits","review_comments_url":"https://api.github.com/repos/fiverr/passable/pulls/100/comments","review_comment_url":"https://api.github.com/repos/fiverr/passable/pulls/comments{/number}","comments_url":"https://api.github.com/repos/fiverr/passable/issues/100/comments","statuses_url":"https://api.github.com/repos/fiverr/passable/statuses/347da3fb559dec66f4a945de6287cb10faa45d32","head":{"label":"fiverr:async-test-support","ref":"async-test-support","sha":"347da3fb559dec66f4a945de6287cb10faa45d32","user":{"login":"fiverr","id":807499,"node_id":"MDEyOk9yZ2FuaXphdGlvbjgwNzQ5OQ==","avatar_url":"https://avatars0.githubusercontent.com/u/807499?v=4","gravatar_id":"","url":"https://api.github.com/users/fiverr","html_url":"https://github.com/fiverr","followers_url":"https://api.github.com/users/fiverr/followers","following_url":"https://api.github.com/users/fiverr/following{/other_user}","gists_url":"https://api.github.com/users/fiverr/gists{/gist_id}","starred_url":"https://api.github.com/users/fiverr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fiverr/subscriptions","organizations_url":"https://api.github.com/users/fiverr/orgs","repos_url":"https://api.github.com/users/fiverr/repos","events_url":"https://api.github.com/users/fiverr/events{/privacy}","received_events_url":"https://api.github.com/users/fiverr/received_events","type":"Organization","site_admin":false},"repo":{"id":81592021,"node_id":"MDEwOlJlcG9zaXRvcnk4MTU5MjAyMQ==","name":"passable","full_name":"fiverr/passable","private":false,"owner":{"login":"fiverr","id":807499,"node_id":"MDEyOk9yZ2FuaXphdGlvbjgwNzQ5OQ==","avatar_url":"https://avatars0.githubusercontent.com/u/807499?v=4","gravatar_id":"","url":"https://api.github.com/users/fiverr","html_url":"https://github.com/fiverr","followers_url":"https://api.github.com/users/fiverr/followers","following_url":"https://api.github.com/users/fiverr/following{/other_user}","gists_url":"https://api.github.com/users/fiverr/gists{/gist_id}","starred_url":"https://api.github.com/users/fiverr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fiverr/subscriptions","organizations_url":"https://api.github.com/users/fiverr/orgs","repos_url":"https://api.github.com/users/fiverr/repos","events_url":"https://api.github.com/users/fiverr/events{/privacy}","received_events_url":"https://api.github.com/users/fiverr/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/fiverr/passable","description":"An isomorphic data model validations engine","fork":false,"url":"https://api.github.com/repos/fiverr/passable","forks_url":"https://api.github.com/repos/fiverr/passable/forks","keys_url":"https://api.github.com/repos/fiverr/passable/keys{/key_id}","collaborators_url":"https://api.github.com/repos/fiverr/passable/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/fiverr/passable/teams","hooks_url":"https://api.github.com/repos/fiverr/passable/hooks","issue_events_url":"https://api.github.com/repos/fiverr/passable/issues/events{/number}","events_url":"https://api.github.com/repos/fiverr/passable/events","assignees_url":"https://api.github.com/repos/fiverr/passable/assignees{/user}","branches_url":"https://api.github.com/repos/fiverr/passable/branches{/branch}","tags_url":"https://api.github.com/repos/fiverr/passable/tags","blobs_url":"https://api.github.com/repos/fiverr/passable/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/fiverr/passable/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/fiverr/passable/git/refs{/sha}","trees_url":"https://api.github.com/repos/fiverr/passable/git/trees{/sha}","statuses_url":"https://api.github.com/repos/fiverr/passable/statuses/{sha}","languages_url":"https://api.github.com/repos/fiverr/passable/languages","stargazers_url":"https://api.github.com/repos/fiverr/passable/stargazers","contributors_url":"https://api.github.com/repos/fiverr/passable/contributors","subscribers_url":"https://api.github.com/repos/fiverr/passable/subscribers","subscription_url":"https://api.github.com/repos/fiverr/passable/subscription","commits_url":"https://api.github.com/repos/fiverr/passable/commits{/sha}","git_commits_url":"https://api.github.com/repos/fiverr/passable/git/commits{/sha}","comments_url":"https://api.github.com/repos/fiverr/passable/comments{/number}","issue_comment_url":"https://api.github.com/repos/fiverr/passable/issues/comments{/number}","contents_url":"https://api.github.com/repos/fiverr/passable/contents/{+path}","compare_url":"https://api.github.com/repos/fiverr/passable/compare/{base}...{head}","merges_url":"https://api.github.com/repos/fiverr/passable/merges","archive_url":"https://api.github.com/repos/fiverr/passable/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/fiverr/passable/downloads","issues_url":"https://api.github.com/repos/fiverr/passable/issues{/number}","pulls_url":"https://api.github.com/repos/fiverr/passable/pulls{/number}","milestones_url":"https://api.github.com/repos/fiverr/passable/milestones{/number}","notifications_url":"https://api.github.com/repos/fiverr/passable/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/fiverr/passable/labels{/name}","releases_url":"https://api.github.com/repos/fiverr/passable/releases{/id}","deployments_url":"https://api.github.com/repos/fiverr/passable/deployments","created_at":"2017-02-10T18:04:04Z","updated_at":"2018-08-13T11:32:26Z","pushed_at":"2018-09-20T11:10:07Z","git_url":"git://github.com/fiverr/passable.git","ssh_url":"git@github.com:fiverr/passable.git","clone_url":"https://github.com/fiverr/passable.git","svn_url":"https://github.com/fiverr/passable","homepage":"https://fiverr.github.io/passable/","size":2831,"stargazers_count":27,"watchers_count":27,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":4,"mirror_url":null,"archived":false,"open_issues_count":8,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":4,"open_issues":8,"watchers":27,"default_branch":"master"}},"base":{"label":"fiverr:next","ref":"next","sha":"15d4ab2fcb1a3085a5d6dd7f3b210acbaaf10b1b","user":{"login":"fiverr","id":807499,"node_id":"MDEyOk9yZ2FuaXphdGlvbjgwNzQ5OQ==","avatar_url":"https://avatars0.githubusercontent.com/u/807499?v=4","gravatar_id":"","url":"https://api.github.com/users/fiverr","html_url":"https://github.com/fiverr","followers_url":"https://api.github.com/users/fiverr/followers","following_url":"https://api.github.com/users/fiverr/following{/other_user}","gists_url":"https://api.github.com/users/fiverr/gists{/gist_id}","starred_url":"https://api.github.com/users/fiverr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fiverr/subscriptions","organizations_url":"https://api.github.com/users/fiverr/orgs","repos_url":"https://api.github.com/users/fiverr/repos","events_url":"https://api.github.com/users/fiverr/events{/privacy}","received_events_url":"https://api.github.com/users/fiverr/received_events","type":"Organization","site_admin":false},"repo":{"id":81592021,"node_id":"MDEwOlJlcG9zaXRvcnk4MTU5MjAyMQ==","name":"passable","full_name":"fiverr/passable","private":false,"owner":{"login":"fiverr","id":807499,"node_id":"MDEyOk9yZ2FuaXphdGlvbjgwNzQ5OQ==","avatar_url":"https://avatars0.githubusercontent.com/u/807499?v=4","gravatar_id":"","url":"https://api.github.com/users/fiverr","html_url":"https://github.com/fiverr","followers_url":"https://api.github.com/users/fiverr/followers","following_url":"https://api.github.com/users/fiverr/following{/other_user}","gists_url":"https://api.github.com/users/fiverr/gists{/gist_id}","starred_url":"https://api.github.com/users/fiverr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fiverr/subscriptions","organizations_url":"https://api.github.com/users/fiverr/orgs","repos_url":"https://api.github.com/users/fiverr/repos","events_url":"https://api.github.com/users/fiverr/events{/privacy}","received_events_url":"https://api.github.com/users/fiverr/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/fiverr/passable","description":"An isomorphic data model validations engine","fork":false,"url":"https://api.github.com/repos/fiverr/passable","forks_url":"https://api.github.com/repos/fiverr/passable/forks","keys_url":"https://api.github.com/repos/fiverr/passable/keys{/key_id}","collaborators_url":"https://api.github.com/repos/fiverr/passable/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/fiverr/passable/teams","hooks_url":"https://api.github.com/repos/fiverr/passable/hooks","issue_events_url":"https://api.github.com/repos/fiverr/passable/issues/events{/number}","events_url":"https://api.github.com/repos/fiverr/passable/events","assignees_url":"https://api.github.com/repos/fiverr/passable/assignees{/user}","branches_url":"https://api.github.com/repos/fiverr/passable/branches{/branch}","tags_url":"https://api.github.com/repos/fiverr/passable/tags","blobs_url":"https://api.github.com/repos/fiverr/passable/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/fiverr/passable/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/fiverr/passable/git/refs{/sha}","trees_url":"https://api.github.com/repos/fiverr/passable/git/trees{/sha}","statuses_url":"https://api.github.com/repos/fiverr/passable/statuses/{sha}","languages_url":"https://api.github.com/repos/fiverr/passable/languages","stargazers_url":"https://api.github.com/repos/fiverr/passable/stargazers","contributors_url":"https://api.github.com/repos/fiverr/passable/contributors","subscribers_url":"https://api.github.com/repos/fiverr/passable/subscribers","subscription_url":"https://api.github.com/repos/fiverr/passable/subscription","commits_url":"https://api.github.com/repos/fiverr/passable/commits{/sha}","git_commits_url":"https://api.github.com/repos/fiverr/passable/git/commits{/sha}","comments_url":"https://api.github.com/repos/fiverr/passable/comments{/number}","issue_comment_url":"https://api.github.com/repos/fiverr/passable/issues/comments{/number}","contents_url":"https://api.github.com/repos/fiverr/passable/contents/{+path}","compare_url":"https://api.github.com/repos/fiverr/passable/compare/{base}...{head}","merges_url":"https://api.github.com/repos/fiverr/passable/merges","archive_url":"https://api.github.com/repos/fiverr/passable/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/fiverr/passable/downloads","issues_url":"https://api.github.com/repos/fiverr/passable/issues{/number}","pulls_url":"https://api.github.com/repos/fiverr/passable/pulls{/number}","milestones_url":"https://api.github.com/repos/fiverr/passable/milestones{/number}","notifications_url":"https://api.github.com/repos/fiverr/passable/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/fiverr/passable/labels{/name}","releases_url":"https://api.github.com/repos/fiverr/passable/releases{/id}","deployments_url":"https://api.github.com/repos/fiverr/passable/deployments","created_at":"2017-02-10T18:04:04Z","updated_at":"2018-08-13T11:32:26Z","pushed_at":"2018-09-20T11:10:07Z","git_url":"git://github.com/fiverr/passable.git","ssh_url":"git@github.com:fiverr/passable.git","clone_url":"https://github.com/fiverr/passable.git","svn_url":"https://github.com/fiverr/passable","homepage":"https://fiverr.github.io/passable/","size":2831,"stargazers_count":27,"watchers_count":27,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":4,"mirror_url":null,"archived":false,"open_issues_count":8,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":4,"open_issues":8,"watchers":27,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/fiverr/passable/pulls/100"},"html":{"href":"https://github.com/fiverr/passable/pull/100"},"issue":{"href":"https://api.github.com/repos/fiverr/passable/issues/100"},"comments":{"href":"https://api.github.com/repos/fiverr/passable/issues/100/comments"},"review_comments":{"href":"https://api.github.com/repos/fiverr/passable/pulls/100/comments"},"review_comment":{"href":"https://api.github.com/repos/fiverr/passable/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/fiverr/passable/pulls/100/commits"},"statuses":{"href":"https://api.github.com/repos/fiverr/passable/statuses/347da3fb559dec66f4a945de6287cb10faa45d32"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"raphaelboukara"}}