{"action":"created","comment":{"url":"https://api.github.com/repos/DevExpress/testcafe/pulls/comments/44763938","id":44763938,"diff_hunk":"@@ -80,44 +82,82 @@ Runner.prototype._onActionRun = function () {\n     transport.asyncServiceMsg(msg);\n };\n \n-Runner.prototype._onError = function (err) {\n-    var runner = this;\n+Runner.prototype._beforeScreenshot = function () {\n+    this.stepIterator.suspend();\n+    this.eventEmitter.emit(RunnerBase.SCREENSHOT_CREATING_STARTED_EVENT, {});\n+    this.savedDocumentTitle = document.title;\n \n-    if (this.stopped)\n-        return;\n+    var assignedTitle = `[ ${window.location.toString()} ]`;\n \n-    //NOTE: we should stop stepIterator to prevent playback after an error is occurred\n-    this.stepIterator.stop();\n+    // NOTE: we should keep the page url in the\n+    // document.title while screenshot creating run\n+    this.checkTitleIntervalId = window.setInterval(() => {\n+        if (document.title !== assignedTitle) {\n+            this.savedDocumentTitle = document.title;\n+            document.title          = assignedTitle;\n+        }\n+    }, 50);\n \n-    RunnerBase.prototype._onError.call(this, err);\n+    document.title = assignedTitle;\n+\n+    return new Promise(resolve => window.setTimeout(resolve), APPLY_DOCUMENT_TITLE_TIMEOUT);\n+};\n+\n+Runner.prototype._afterScreenshot = function () {\n+    window.clearInterval(this.checkTitleIntervalId);\n+\n+    document.title            = this.savedDocumentTitle;\n+    this.checkTitleIntervalId = null;\n+    this.savedDocumentTitle   = null;\n+\n+    this.eventEmitter.emit(RunnerBase.SCREENSHOT_CREATING_FINISHED_EVENT, {});\n+    this.stepIterator.resume();\n+\n+    return new Promise(resolve => window.setTimeout(resolve), RESTORE_DOCUMENT_TITLE_TIMEOUT);\n+};\n \n-    if (!SETTINGS.get().TAKE_SCREENSHOT_ON_FAILS) {\n-        this.stopped = true;\n-        transport.fail(err, Runner.checkStatus);\n+Runner.prototype._onTestFail = function (err, isAssertion) {\n+    // NOTE: we should not create several screenshots for a step. Create a screenshot\n+    // if it's the first error in the step or it's a error on page initialization.\n+    err.pageUrl            = document.location.toString();\n+    err.screenshotRequired = SETTINGS.get().TAKE_SCREENSHOTS && SETTINGS.get().TAKE_SCREENSHOT_ON_FAILS &&\n+                             this.stepIterator.state.curStepErrors.length < 2;\n+\n+    return new Promise(resolve => {\n+        if (err.screenshotRequired)\n+            return this._beforeScreenshot().then(resolve);\n+\n+        resolve();\n+    })\n+        .then(() => new Promise(resolve => {\n+            if (isAssertion)\n+                transport.assertionFailed(err, resolve);\n+            else\n+                transport.fail(err, resolve);\n+        }))\n+        .then(() => new Promise(resolve => {\n+            if (err.screenshotRequired)\n+                return this._afterScreenshot().then(resolve);\n+\n+            resolve();\n+        }));\n+};","path":"src/client/runner/runner.js","position":103,"original_position":103,"commit_id":"7f3228e84be6ff64a1233605e14c077727df4ab3","original_commit_id":"7f3228e84be6ff64a1233605e14c077727df4ab3","user":{"login":"inikulin","id":453071,"avatar_url":"https://avatars.githubusercontent.com/u/453071?v=3","gravatar_id":"","url":"https://api.github.com/users/inikulin","html_url":"https://github.com/inikulin","followers_url":"https://api.github.com/users/inikulin/followers","following_url":"https://api.github.com/users/inikulin/following{/other_user}","gists_url":"https://api.github.com/users/inikulin/gists{/gist_id}","starred_url":"https://api.github.com/users/inikulin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/inikulin/subscriptions","organizations_url":"https://api.github.com/users/inikulin/orgs","repos_url":"https://api.github.com/users/inikulin/repos","events_url":"https://api.github.com/users/inikulin/events{/privacy}","received_events_url":"https://api.github.com/users/inikulin/received_events","type":"User","site_admin":false},"body":"The whole promise can be rewritten:\r\n```js\r\nvar errorProcessingChain = Promise.resolve();\r\n\r\nif (err.screenshotRequired)\r\n   errorProcessingChain.then(() => this._beforeScreenshot());\r\n\r\nerrorProcessingChain.then(() => this._reportErrorToServer(isAssertion));\r\n\r\nif (err.screenshotRequired)\r\n   errorProcessingChain.then(() => this._afterScreenshot());\r\n\r\nreturn errorProcessingChain;\r\n```","created_at":"2015-11-13T09:32:55Z","updated_at":"2015-11-13T09:32:55Z","html_url":"https://github.com/DevExpress/testcafe/pull/130#discussion_r44763938","pull_request_url":"https://api.github.com/repos/DevExpress/testcafe/pulls/130","_links":{"self":{"href":"https://api.github.com/repos/DevExpress/testcafe/pulls/comments/44763938"},"html":{"href":"https://github.com/DevExpress/testcafe/pull/130#discussion_r44763938"},"pull_request":{"href":"https://api.github.com/repos/DevExpress/testcafe/pulls/130"}}},"pull_request":{"url":"https://api.github.com/repos/DevExpress/testcafe/pulls/130","id":48587916,"html_url":"https://github.com/DevExpress/testcafe/pull/130","diff_url":"https://github.com/DevExpress/testcafe/pull/130.diff","patch_url":"https://github.com/DevExpress/testcafe/pull/130.patch","issue_url":"https://api.github.com/repos/DevExpress/testcafe/issues/130","number":130,"state":"open","locked":false,"title":"Enable screenshot functionality (closes #104)","user":{"login":"AlexanderMoskovkin","id":12047804,"avatar_url":"https://avatars.githubusercontent.com/u/12047804?v=3","gravatar_id":"","url":"https://api.github.com/users/AlexanderMoskovkin","html_url":"https://github.com/AlexanderMoskovkin","followers_url":"https://api.github.com/users/AlexanderMoskovkin/followers","following_url":"https://api.github.com/users/AlexanderMoskovkin/following{/other_user}","gists_url":"https://api.github.com/users/AlexanderMoskovkin/gists{/gist_id}","starred_url":"https://api.github.com/users/AlexanderMoskovkin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AlexanderMoskovkin/subscriptions","organizations_url":"https://api.github.com/users/AlexanderMoskovkin/orgs","repos_url":"https://api.github.com/users/AlexanderMoskovkin/repos","events_url":"https://api.github.com/users/AlexanderMoskovkin/events{/privacy}","received_events_url":"https://api.github.com/users/AlexanderMoskovkin/received_events","type":"User","site_admin":false},"body":"We have client tests for this and server tests for reporting with screenshots now. Also I've created the functional tests locally, but we will commit them when we implement the https://github.com/superroma/testcafe-phoenix/issues/52 issue, because we need something like `functional-tests-harness`\r\n\r\n/cc @inikulin @helen-dikareva ","created_at":"2015-10-23T14:39:29Z","updated_at":"2015-11-13T09:32:55Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a9bcb146ffdd42d2634d5030c2bb8c2f7464176e","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/DevExpress/testcafe/pulls/130/commits","review_comments_url":"https://api.github.com/repos/DevExpress/testcafe/pulls/130/comments","review_comment_url":"https://api.github.com/repos/DevExpress/testcafe/pulls/comments{/number}","comments_url":"https://api.github.com/repos/DevExpress/testcafe/issues/130/comments","statuses_url":"https://api.github.com/repos/DevExpress/testcafe/statuses/7f3228e84be6ff64a1233605e14c077727df4ab3","head":{"label":"AlexanderMoskovkin:enable-screenshots-functionality","ref":"enable-screenshots-functionality","sha":"7f3228e84be6ff64a1233605e14c077727df4ab3","user":{"login":"AlexanderMoskovkin","id":12047804,"avatar_url":"https://avatars.githubusercontent.com/u/12047804?v=3","gravatar_id":"","url":"https://api.github.com/users/AlexanderMoskovkin","html_url":"https://github.com/AlexanderMoskovkin","followers_url":"https://api.github.com/users/AlexanderMoskovkin/followers","following_url":"https://api.github.com/users/AlexanderMoskovkin/following{/other_user}","gists_url":"https://api.github.com/users/AlexanderMoskovkin/gists{/gist_id}","starred_url":"https://api.github.com/users/AlexanderMoskovkin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AlexanderMoskovkin/subscriptions","organizations_url":"https://api.github.com/users/AlexanderMoskovkin/orgs","repos_url":"https://api.github.com/users/AlexanderMoskovkin/repos","events_url":"https://api.github.com/users/AlexanderMoskovkin/events{/privacy}","received_events_url":"https://api.github.com/users/AlexanderMoskovkin/received_events","type":"User","site_admin":false},"repo":{"id":40255267,"name":"testcafe-phoenix","full_name":"AlexanderMoskovkin/testcafe-phoenix","owner":{"login":"AlexanderMoskovkin","id":12047804,"avatar_url":"https://avatars.githubusercontent.com/u/12047804?v=3","gravatar_id":"","url":"https://api.github.com/users/AlexanderMoskovkin","html_url":"https://github.com/AlexanderMoskovkin","followers_url":"https://api.github.com/users/AlexanderMoskovkin/followers","following_url":"https://api.github.com/users/AlexanderMoskovkin/following{/other_user}","gists_url":"https://api.github.com/users/AlexanderMoskovkin/gists{/gist_id}","starred_url":"https://api.github.com/users/AlexanderMoskovkin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AlexanderMoskovkin/subscriptions","organizations_url":"https://api.github.com/users/AlexanderMoskovkin/orgs","repos_url":"https://api.github.com/users/AlexanderMoskovkin/repos","events_url":"https://api.github.com/users/AlexanderMoskovkin/events{/privacy}","received_events_url":"https://api.github.com/users/AlexanderMoskovkin/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/AlexanderMoskovkin/testcafe-phoenix","description":"","fork":true,"url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix","forks_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/forks","keys_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/teams","hooks_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/hooks","issue_events_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/issues/events{/number}","events_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/events","assignees_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/assignees{/user}","branches_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/branches{/branch}","tags_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/tags","blobs_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/git/refs{/sha}","trees_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/statuses/{sha}","languages_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/languages","stargazers_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/stargazers","contributors_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/contributors","subscribers_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/subscribers","subscription_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/subscription","commits_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/commits{/sha}","git_commits_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/git/commits{/sha}","comments_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/comments{/number}","issue_comment_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/issues/comments{/number}","contents_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/contents/{+path}","compare_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/merges","archive_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/downloads","issues_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/issues{/number}","pulls_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/pulls{/number}","milestones_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/milestones{/number}","notifications_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/labels{/name}","releases_url":"https://api.github.com/repos/AlexanderMoskovkin/testcafe-phoenix/releases{/id}","created_at":"2015-08-05T16:08:05Z","updated_at":"2015-08-05T16:08:06Z","pushed_at":"2015-11-13T08:30:14Z","git_url":"git://github.com/AlexanderMoskovkin/testcafe-phoenix.git","ssh_url":"git@github.com:AlexanderMoskovkin/testcafe-phoenix.git","clone_url":"https://github.com/AlexanderMoskovkin/testcafe-phoenix.git","svn_url":"https://github.com/AlexanderMoskovkin/testcafe-phoenix","homepage":null,"size":24364,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"DevExpress:master","ref":"master","sha":"36ead6b39a7dcc7a3ffb10b9c208c3b718bafcb5","user":{"login":"DevExpress","id":4243232,"avatar_url":"https://avatars.githubusercontent.com/u/4243232?v=3","gravatar_id":"","url":"https://api.github.com/users/DevExpress","html_url":"https://github.com/DevExpress","followers_url":"https://api.github.com/users/DevExpress/followers","following_url":"https://api.github.com/users/DevExpress/following{/other_user}","gists_url":"https://api.github.com/users/DevExpress/gists{/gist_id}","starred_url":"https://api.github.com/users/DevExpress/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DevExpress/subscriptions","organizations_url":"https://api.github.com/users/DevExpress/orgs","repos_url":"https://api.github.com/users/DevExpress/repos","events_url":"https://api.github.com/users/DevExpress/events{/privacy}","received_events_url":"https://api.github.com/users/DevExpress/received_events","type":"Organization","site_admin":false},"repo":{"id":34262857,"name":"testcafe","full_name":"DevExpress/testcafe","owner":{"login":"DevExpress","id":4243232,"avatar_url":"https://avatars.githubusercontent.com/u/4243232?v=3","gravatar_id":"","url":"https://api.github.com/users/DevExpress","html_url":"https://github.com/DevExpress","followers_url":"https://api.github.com/users/DevExpress/followers","following_url":"https://api.github.com/users/DevExpress/following{/other_user}","gists_url":"https://api.github.com/users/DevExpress/gists{/gist_id}","starred_url":"https://api.github.com/users/DevExpress/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DevExpress/subscriptions","organizations_url":"https://api.github.com/users/DevExpress/orgs","repos_url":"https://api.github.com/users/DevExpress/repos","events_url":"https://api.github.com/users/DevExpress/events{/privacy}","received_events_url":"https://api.github.com/users/DevExpress/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/DevExpress/testcafe","description":"","fork":false,"url":"https://api.github.com/repos/DevExpress/testcafe","forks_url":"https://api.github.com/repos/DevExpress/testcafe/forks","keys_url":"https://api.github.com/repos/DevExpress/testcafe/keys{/key_id}","collaborators_url":"https://api.github.com/repos/DevExpress/testcafe/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/DevExpress/testcafe/teams","hooks_url":"https://api.github.com/repos/DevExpress/testcafe/hooks","issue_events_url":"https://api.github.com/repos/DevExpress/testcafe/issues/events{/number}","events_url":"https://api.github.com/repos/DevExpress/testcafe/events","assignees_url":"https://api.github.com/repos/DevExpress/testcafe/assignees{/user}","branches_url":"https://api.github.com/repos/DevExpress/testcafe/branches{/branch}","tags_url":"https://api.github.com/repos/DevExpress/testcafe/tags","blobs_url":"https://api.github.com/repos/DevExpress/testcafe/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/DevExpress/testcafe/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/DevExpress/testcafe/git/refs{/sha}","trees_url":"https://api.github.com/repos/DevExpress/testcafe/git/trees{/sha}","statuses_url":"https://api.github.com/repos/DevExpress/testcafe/statuses/{sha}","languages_url":"https://api.github.com/repos/DevExpress/testcafe/languages","stargazers_url":"https://api.github.com/repos/DevExpress/testcafe/stargazers","contributors_url":"https://api.github.com/repos/DevExpress/testcafe/contributors","subscribers_url":"https://api.github.com/repos/DevExpress/testcafe/subscribers","subscription_url":"https://api.github.com/repos/DevExpress/testcafe/subscription","commits_url":"https://api.github.com/repos/DevExpress/testcafe/commits{/sha}","git_commits_url":"https://api.github.com/repos/DevExpress/testcafe/git/commits{/sha}","comments_url":"https://api.github.com/repos/DevExpress/testcafe/comments{/number}","issue_comment_url":"https://api.github.com/repos/DevExpress/testcafe/issues/comments{/number}","contents_url":"https://api.github.com/repos/DevExpress/testcafe/contents/{+path}","compare_url":"https://api.github.com/repos/DevExpress/testcafe/compare/{base}...{head}","merges_url":"https://api.github.com/repos/DevExpress/testcafe/merges","archive_url":"https://api.github.com/repos/DevExpress/testcafe/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/DevExpress/testcafe/downloads","issues_url":"https://api.github.com/repos/DevExpress/testcafe/issues{/number}","pulls_url":"https://api.github.com/repos/DevExpress/testcafe/pulls{/number}","milestones_url":"https://api.github.com/repos/DevExpress/testcafe/milestones{/number}","notifications_url":"https://api.github.com/repos/DevExpress/testcafe/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/DevExpress/testcafe/labels{/name}","releases_url":"https://api.github.com/repos/DevExpress/testcafe/releases{/id}","created_at":"2015-04-20T13:43:28Z","updated_at":"2015-11-09T11:58:28Z","pushed_at":"2015-11-13T08:30:14Z","git_url":"git://github.com/DevExpress/testcafe.git","ssh_url":"git@github.com:DevExpress/testcafe.git","clone_url":"https://github.com/DevExpress/testcafe.git","svn_url":"https://github.com/DevExpress/testcafe","homepage":null,"size":25011,"stargazers_count":4,"watchers_count":4,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":10,"mirror_url":null,"open_issues_count":35,"forks":10,"open_issues":35,"watchers":4,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/DevExpress/testcafe/pulls/130"},"html":{"href":"https://github.com/DevExpress/testcafe/pull/130"},"issue":{"href":"https://api.github.com/repos/DevExpress/testcafe/issues/130"},"comments":{"href":"https://api.github.com/repos/DevExpress/testcafe/issues/130/comments"},"review_comments":{"href":"https://api.github.com/repos/DevExpress/testcafe/pulls/130/comments"},"review_comment":{"href":"https://api.github.com/repos/DevExpress/testcafe/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/DevExpress/testcafe/pulls/130/commits"},"statuses":{"href":"https://api.github.com/repos/DevExpress/testcafe/statuses/7f3228e84be6ff64a1233605e14c077727df4ab3"}}}}