{"action":"created","comment":{"url":"https://api.github.com/repos/learningequality/ka-lite/pulls/comments/27531737","id":27531737,"diff_hunk":"@@ -0,0 +1,142 @@\n+\"\"\"\n+These methods will probably be used again and again in behave tests.\n+We'll make a few assumptions: every function here takes a behave context\n+as the first positional argument, and should assert what it expects from \n+that context in order to function (instead of just silently failing).\n+\"\"\"\n+import httplib\n+import json\n+\n+from selenium.common.exceptions import TimeoutException\n+from selenium.webdriver.common.by import By\n+from selenium.webdriver.support.ui import WebDriverWait\n+from selenium.webdriver.support import expected_conditions as EC\n+from urlparse import urljoin\n+\n+from django.contrib.auth.models import User\n+from django.core.urlresolvers import reverse\n+\n+# Use these for now, so that we don't DROurselves, but eventually\n+# we'll want to move away from mixins.\n+from kalite.testing.mixins.browser_mixins import BrowserActionMixins\n+from kalite.testing.mixins.django_mixins import CreateAdminMixin\n+\n+\n+# Maximum time to wait when trying to find elements\n+MAX_WAIT_TIME = 1\n+\n+\n+def find_css_class_with_wait(context, css_class, **kwargs):\n+    \"\"\" Tries to find an element with given css class with an explicit timeout.","path":"kalite/testing/behave_helpers.py","position":30,"original_position":30,"commit_id":"5ba8153db0167bcbaa6434f1c4e6781dfebb625c","original_commit_id":"5ba8153db0167bcbaa6434f1c4e6781dfebb625c","user":{"login":"rtibbles","id":1680573,"avatar_url":"https://avatars.githubusercontent.com/u/1680573?v=3","gravatar_id":"","url":"https://api.github.com/users/rtibbles","html_url":"https://github.com/rtibbles","followers_url":"https://api.github.com/users/rtibbles/followers","following_url":"https://api.github.com/users/rtibbles/following{/other_user}","gists_url":"https://api.github.com/users/rtibbles/gists{/gist_id}","starred_url":"https://api.github.com/users/rtibbles/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rtibbles/subscriptions","organizations_url":"https://api.github.com/users/rtibbles/orgs","repos_url":"https://api.github.com/users/rtibbles/repos","events_url":"https://api.github.com/users/rtibbles/events{/privacy}","received_events_url":"https://api.github.com/users/rtibbles/received_events","type":"User","site_admin":false},"body":":+1: for doc strings.","created_at":"2015-03-31T23:02:49Z","updated_at":"2015-03-31T23:02:49Z","html_url":"https://github.com/learningequality/ka-lite/pull/3405#discussion_r27531737","pull_request_url":"https://api.github.com/repos/learningequality/ka-lite/pulls/3405","_links":{"self":{"href":"https://api.github.com/repos/learningequality/ka-lite/pulls/comments/27531737"},"html":{"href":"https://github.com/learningequality/ka-lite/pull/3405#discussion_r27531737"},"pull_request":{"href":"https://api.github.com/repos/learningequality/ka-lite/pulls/3405"}}},"pull_request":{"url":"https://api.github.com/repos/learningequality/ka-lite/pulls/3405","id":31886112,"html_url":"https://github.com/learningequality/ka-lite/pull/3405","diff_url":"https://github.com/learningequality/ka-lite/pull/3405.diff","patch_url":"https://github.com/learningequality/ka-lite/pull/3405.patch","issue_url":"https://api.github.com/repos/learningequality/ka-lite/issues/3405","number":3405,"state":"open","locked":false,"title":"Behave proof of concept - BDD integration tests","user":{"login":"MCGallaspy","id":8888020,"avatar_url":"https://avatars.githubusercontent.com/u/8888020?v=3","gravatar_id":"","url":"https://api.github.com/users/MCGallaspy","html_url":"https://github.com/MCGallaspy","followers_url":"https://api.github.com/users/MCGallaspy/followers","following_url":"https://api.github.com/users/MCGallaspy/following{/other_user}","gists_url":"https://api.github.com/users/MCGallaspy/gists{/gist_id}","starred_url":"https://api.github.com/users/MCGallaspy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MCGallaspy/subscriptions","organizations_url":"https://api.github.com/users/MCGallaspy/orgs","repos_url":"https://api.github.com/users/MCGallaspy/repos","events_url":"https://api.github.com/users/MCGallaspy/events{/privacy}","received_events_url":"https://api.github.com/users/MCGallaspy/received_events","type":"User","site_admin":false},"body":"What's in here:\r\n* A management command (`run_behave_tests`) which searches out `behave` tests in the project directory and runs them.\r\n* A stubbed-out test for the learn tab \r\n* My thoughts on where it's appropriate to use integration tests vs. unit tests\r\n\r\nWhat's coming:\r\n* A better example test\r\n\r\nMy thoughts:\r\n\r\nThis is still a work in progress. I wanted to write a nontrivial (as in not just `pass` statements) integration test for the `/learn/` page, but I encountered a few stumbling blocks.\r\n\r\nFirst, because it takes so dang long to load the content cache *et al* into memory on my machine, tests which try to load pages that use cached variables (like through ajax requests) time out. Secondly, the learn tab is not easily testable as a single-page JS app because it's hard to avoid race conditions -- this problem is carried over from our existing test suite and is a \"feature\" of the app itself.\r\n\r\nFor the learn page (and for other single-page JS features we develop in the future), we need to carefully distinguish between what should be tested using a front-end testing framework with unit tests, and what should be tested using integration tests. For example, some existing tests for the learn page are:\r\n\r\n* Test that watching videos increases points\r\n* Test that the displayed points are updated correctly\r\n* Test various interactions with exercises                \r\n                  \r\nNone of which are appropriate as integration tests, because they can be tested much more easily as unit tests on our Backbone views.\r\n\r\nFor the learn page some tests which *are* appropriate as integration tests since they test client-server interaction through API requests and responses (and might've been helpful during development using BDD but now would only serve as regression tests) are:\r\n\r\n* Test that navigating the sidebar prior to a terminal choice gives you a blank content area.\r\n* Test that navigating to an available content item loads that content item.\r\n* Test that navigating to an unavailable content item displays an appropriate error.\r\n\r\nThe lesson here for single-page JS apps is that if we're purely testing *client-side* behavior let's make it a unit test, but if we're testing the server's response to user actions let's make it an integration test, and spec it out beforehand so we can use BDD. (This may be obvious to you guys, but I've only finally managed to fully grok it. :/ )\r\n\r\n**Finally** I'm putting this PR and my novel-length comment up for review, but I'd also like to write a non-trivial test for another feature. (Which I am presently doing.)","created_at":"2015-03-25T01:27:22Z","updated_at":"2015-03-31T23:02:49Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a8321c811fa380e8d81eb7ec11030a83357cc9b3","assignee":{"login":"rtibbles","id":1680573,"avatar_url":"https://avatars.githubusercontent.com/u/1680573?v=3","gravatar_id":"","url":"https://api.github.com/users/rtibbles","html_url":"https://github.com/rtibbles","followers_url":"https://api.github.com/users/rtibbles/followers","following_url":"https://api.github.com/users/rtibbles/following{/other_user}","gists_url":"https://api.github.com/users/rtibbles/gists{/gist_id}","starred_url":"https://api.github.com/users/rtibbles/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rtibbles/subscriptions","organizations_url":"https://api.github.com/users/rtibbles/orgs","repos_url":"https://api.github.com/users/rtibbles/repos","events_url":"https://api.github.com/users/rtibbles/events{/privacy}","received_events_url":"https://api.github.com/users/rtibbles/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/learningequality/ka-lite/milestones/41","html_url":"https://github.com/learningequality/ka-lite/milestones/0.14.0","labels_url":"https://api.github.com/repos/learningequality/ka-lite/milestones/41/labels","id":795036,"number":41,"title":"0.14.0","description":"","creator":{"login":"aronasorman","id":191955,"avatar_url":"https://avatars.githubusercontent.com/u/191955?v=3","gravatar_id":"","url":"https://api.github.com/users/aronasorman","html_url":"https://github.com/aronasorman","followers_url":"https://api.github.com/users/aronasorman/followers","following_url":"https://api.github.com/users/aronasorman/following{/other_user}","gists_url":"https://api.github.com/users/aronasorman/gists{/gist_id}","starred_url":"https://api.github.com/users/aronasorman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aronasorman/subscriptions","organizations_url":"https://api.github.com/users/aronasorman/orgs","repos_url":"https://api.github.com/users/aronasorman/repos","events_url":"https://api.github.com/users/aronasorman/events{/privacy}","received_events_url":"https://api.github.com/users/aronasorman/received_events","type":"User","site_admin":false},"open_issues":97,"closed_issues":59,"state":"open","created_at":"2014-09-18T21:53:07Z","updated_at":"2015-03-31T22:05:32Z","due_on":"2015-07-01T07:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/learningequality/ka-lite/pulls/3405/commits","review_comments_url":"https://api.github.com/repos/learningequality/ka-lite/pulls/3405/comments","review_comment_url":"https://api.github.com/repos/learningequality/ka-lite/pulls/comments{/number}","comments_url":"https://api.github.com/repos/learningequality/ka-lite/issues/3405/comments","statuses_url":"https://api.github.com/repos/learningequality/ka-lite/statuses/5ba8153db0167bcbaa6434f1c4e6781dfebb625c","head":{"label":"MCGallaspy:behave-proof-of-concept","ref":"behave-proof-of-concept","sha":"5ba8153db0167bcbaa6434f1c4e6781dfebb625c","user":{"login":"MCGallaspy","id":8888020,"avatar_url":"https://avatars.githubusercontent.com/u/8888020?v=3","gravatar_id":"","url":"https://api.github.com/users/MCGallaspy","html_url":"https://github.com/MCGallaspy","followers_url":"https://api.github.com/users/MCGallaspy/followers","following_url":"https://api.github.com/users/MCGallaspy/following{/other_user}","gists_url":"https://api.github.com/users/MCGallaspy/gists{/gist_id}","starred_url":"https://api.github.com/users/MCGallaspy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MCGallaspy/subscriptions","organizations_url":"https://api.github.com/users/MCGallaspy/orgs","repos_url":"https://api.github.com/users/MCGallaspy/repos","events_url":"https://api.github.com/users/MCGallaspy/events{/privacy}","received_events_url":"https://api.github.com/users/MCGallaspy/received_events","type":"User","site_admin":false},"repo":{"id":25265236,"name":"ka-lite","full_name":"MCGallaspy/ka-lite","owner":{"login":"MCGallaspy","id":8888020,"avatar_url":"https://avatars.githubusercontent.com/u/8888020?v=3","gravatar_id":"","url":"https://api.github.com/users/MCGallaspy","html_url":"https://github.com/MCGallaspy","followers_url":"https://api.github.com/users/MCGallaspy/followers","following_url":"https://api.github.com/users/MCGallaspy/following{/other_user}","gists_url":"https://api.github.com/users/MCGallaspy/gists{/gist_id}","starred_url":"https://api.github.com/users/MCGallaspy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MCGallaspy/subscriptions","organizations_url":"https://api.github.com/users/MCGallaspy/orgs","repos_url":"https://api.github.com/users/MCGallaspy/repos","events_url":"https://api.github.com/users/MCGallaspy/events{/privacy}","received_events_url":"https://api.github.com/users/MCGallaspy/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/MCGallaspy/ka-lite","description":"KA Lite: lightweight web server for serving core Khan Academy content (videos and exercises) without needing internet connectivity","fork":true,"url":"https://api.github.com/repos/MCGallaspy/ka-lite","forks_url":"https://api.github.com/repos/MCGallaspy/ka-lite/forks","keys_url":"https://api.github.com/repos/MCGallaspy/ka-lite/keys{/key_id}","collaborators_url":"https://api.github.com/repos/MCGallaspy/ka-lite/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/MCGallaspy/ka-lite/teams","hooks_url":"https://api.github.com/repos/MCGallaspy/ka-lite/hooks","issue_events_url":"https://api.github.com/repos/MCGallaspy/ka-lite/issues/events{/number}","events_url":"https://api.github.com/repos/MCGallaspy/ka-lite/events","assignees_url":"https://api.github.com/repos/MCGallaspy/ka-lite/assignees{/user}","branches_url":"https://api.github.com/repos/MCGallaspy/ka-lite/branches{/branch}","tags_url":"https://api.github.com/repos/MCGallaspy/ka-lite/tags","blobs_url":"https://api.github.com/repos/MCGallaspy/ka-lite/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/MCGallaspy/ka-lite/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/MCGallaspy/ka-lite/git/refs{/sha}","trees_url":"https://api.github.com/repos/MCGallaspy/ka-lite/git/trees{/sha}","statuses_url":"https://api.github.com/repos/MCGallaspy/ka-lite/statuses/{sha}","languages_url":"https://api.github.com/repos/MCGallaspy/ka-lite/languages","stargazers_url":"https://api.github.com/repos/MCGallaspy/ka-lite/stargazers","contributors_url":"https://api.github.com/repos/MCGallaspy/ka-lite/contributors","subscribers_url":"https://api.github.com/repos/MCGallaspy/ka-lite/subscribers","subscription_url":"https://api.github.com/repos/MCGallaspy/ka-lite/subscription","commits_url":"https://api.github.com/repos/MCGallaspy/ka-lite/commits{/sha}","git_commits_url":"https://api.github.com/repos/MCGallaspy/ka-lite/git/commits{/sha}","comments_url":"https://api.github.com/repos/MCGallaspy/ka-lite/comments{/number}","issue_comment_url":"https://api.github.com/repos/MCGallaspy/ka-lite/issues/comments{/number}","contents_url":"https://api.github.com/repos/MCGallaspy/ka-lite/contents/{+path}","compare_url":"https://api.github.com/repos/MCGallaspy/ka-lite/compare/{base}...{head}","merges_url":"https://api.github.com/repos/MCGallaspy/ka-lite/merges","archive_url":"https://api.github.com/repos/MCGallaspy/ka-lite/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/MCGallaspy/ka-lite/downloads","issues_url":"https://api.github.com/repos/MCGallaspy/ka-lite/issues{/number}","pulls_url":"https://api.github.com/repos/MCGallaspy/ka-lite/pulls{/number}","milestones_url":"https://api.github.com/repos/MCGallaspy/ka-lite/milestones{/number}","notifications_url":"https://api.github.com/repos/MCGallaspy/ka-lite/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/MCGallaspy/ka-lite/labels{/name}","releases_url":"https://api.github.com/repos/MCGallaspy/ka-lite/releases{/id}","created_at":"2014-10-15T17:21:39Z","updated_at":"2015-02-06T23:45:13Z","pushed_at":"2015-03-31T19:46:21Z","git_url":"git://github.com/MCGallaspy/ka-lite.git","ssh_url":"git@github.com:MCGallaspy/ka-lite.git","clone_url":"https://github.com/MCGallaspy/ka-lite.git","svn_url":"https://github.com/MCGallaspy/ka-lite","homepage":"https://learningequality.org/ka-lite/","size":145822,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":2,"forks":1,"open_issues":2,"watchers":0,"default_branch":"master"}},"base":{"label":"learningequality:develop","ref":"develop","sha":"2d041854b1cf9f3197e0cedc9aaedc30b1ec1d1e","user":{"login":"learningequality","id":3926525,"avatar_url":"https://avatars.githubusercontent.com/u/3926525?v=3","gravatar_id":"","url":"https://api.github.com/users/learningequality","html_url":"https://github.com/learningequality","followers_url":"https://api.github.com/users/learningequality/followers","following_url":"https://api.github.com/users/learningequality/following{/other_user}","gists_url":"https://api.github.com/users/learningequality/gists{/gist_id}","starred_url":"https://api.github.com/users/learningequality/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/learningequality/subscriptions","organizations_url":"https://api.github.com/users/learningequality/orgs","repos_url":"https://api.github.com/users/learningequality/repos","events_url":"https://api.github.com/users/learningequality/events{/privacy}","received_events_url":"https://api.github.com/users/learningequality/received_events","type":"Organization","site_admin":false},"repo":{"id":5741125,"name":"ka-lite","full_name":"learningequality/ka-lite","owner":{"login":"learningequality","id":3926525,"avatar_url":"https://avatars.githubusercontent.com/u/3926525?v=3","gravatar_id":"","url":"https://api.github.com/users/learningequality","html_url":"https://github.com/learningequality","followers_url":"https://api.github.com/users/learningequality/followers","following_url":"https://api.github.com/users/learningequality/following{/other_user}","gists_url":"https://api.github.com/users/learningequality/gists{/gist_id}","starred_url":"https://api.github.com/users/learningequality/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/learningequality/subscriptions","organizations_url":"https://api.github.com/users/learningequality/orgs","repos_url":"https://api.github.com/users/learningequality/repos","events_url":"https://api.github.com/users/learningequality/events{/privacy}","received_events_url":"https://api.github.com/users/learningequality/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/learningequality/ka-lite","description":"KA Lite: lightweight web server for serving core Khan Academy content (videos and exercises) without needing internet connectivity","fork":false,"url":"https://api.github.com/repos/learningequality/ka-lite","forks_url":"https://api.github.com/repos/learningequality/ka-lite/forks","keys_url":"https://api.github.com/repos/learningequality/ka-lite/keys{/key_id}","collaborators_url":"https://api.github.com/repos/learningequality/ka-lite/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/learningequality/ka-lite/teams","hooks_url":"https://api.github.com/repos/learningequality/ka-lite/hooks","issue_events_url":"https://api.github.com/repos/learningequality/ka-lite/issues/events{/number}","events_url":"https://api.github.com/repos/learningequality/ka-lite/events","assignees_url":"https://api.github.com/repos/learningequality/ka-lite/assignees{/user}","branches_url":"https://api.github.com/repos/learningequality/ka-lite/branches{/branch}","tags_url":"https://api.github.com/repos/learningequality/ka-lite/tags","blobs_url":"https://api.github.com/repos/learningequality/ka-lite/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/learningequality/ka-lite/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/learningequality/ka-lite/git/refs{/sha}","trees_url":"https://api.github.com/repos/learningequality/ka-lite/git/trees{/sha}","statuses_url":"https://api.github.com/repos/learningequality/ka-lite/statuses/{sha}","languages_url":"https://api.github.com/repos/learningequality/ka-lite/languages","stargazers_url":"https://api.github.com/repos/learningequality/ka-lite/stargazers","contributors_url":"https://api.github.com/repos/learningequality/ka-lite/contributors","subscribers_url":"https://api.github.com/repos/learningequality/ka-lite/subscribers","subscription_url":"https://api.github.com/repos/learningequality/ka-lite/subscription","commits_url":"https://api.github.com/repos/learningequality/ka-lite/commits{/sha}","git_commits_url":"https://api.github.com/repos/learningequality/ka-lite/git/commits{/sha}","comments_url":"https://api.github.com/repos/learningequality/ka-lite/comments{/number}","issue_comment_url":"https://api.github.com/repos/learningequality/ka-lite/issues/comments{/number}","contents_url":"https://api.github.com/repos/learningequality/ka-lite/contents/{+path}","compare_url":"https://api.github.com/repos/learningequality/ka-lite/compare/{base}...{head}","merges_url":"https://api.github.com/repos/learningequality/ka-lite/merges","archive_url":"https://api.github.com/repos/learningequality/ka-lite/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/learningequality/ka-lite/downloads","issues_url":"https://api.github.com/repos/learningequality/ka-lite/issues{/number}","pulls_url":"https://api.github.com/repos/learningequality/ka-lite/pulls{/number}","milestones_url":"https://api.github.com/repos/learningequality/ka-lite/milestones{/number}","notifications_url":"https://api.github.com/repos/learningequality/ka-lite/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/learningequality/ka-lite/labels{/name}","releases_url":"https://api.github.com/repos/learningequality/ka-lite/releases{/id}","created_at":"2012-09-09T20:01:40Z","updated_at":"2015-03-29T20:46:51Z","pushed_at":"2015-03-31T22:05:35Z","git_url":"git://github.com/learningequality/ka-lite.git","ssh_url":"git@github.com:learningequality/ka-lite.git","clone_url":"https://github.com/learningequality/ka-lite.git","svn_url":"https://github.com/learningequality/ka-lite","homepage":"https://learningequality.org/ka-lite/","size":220917,"stargazers_count":199,"watchers_count":199,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":235,"mirror_url":null,"open_issues_count":235,"forks":235,"open_issues":235,"watchers":199,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/learningequality/ka-lite/pulls/3405"},"html":{"href":"https://github.com/learningequality/ka-lite/pull/3405"},"issue":{"href":"https://api.github.com/repos/learningequality/ka-lite/issues/3405"},"comments":{"href":"https://api.github.com/repos/learningequality/ka-lite/issues/3405/comments"},"review_comments":{"href":"https://api.github.com/repos/learningequality/ka-lite/pulls/3405/comments"},"review_comment":{"href":"https://api.github.com/repos/learningequality/ka-lite/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/learningequality/ka-lite/pulls/3405/commits"},"statuses":{"href":"https://api.github.com/repos/learningequality/ka-lite/statuses/5ba8153db0167bcbaa6434f1c4e6781dfebb625c"}}}}