mongo_browser 0.2.0.rc2 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/.gitignore +3 -1
  2. data/.rspec +1 -1
  3. data/.travis.yml +6 -1
  4. data/CHANGELOG.md +15 -0
  5. data/{grunt.js → Gruntfile.js} +10 -8
  6. data/Procfile +1 -0
  7. data/README.md +44 -2
  8. data/Rakefile +1 -12
  9. data/app/assets/images/ajax-loader.gif +0 -0
  10. data/app/assets/javascripts/app/controllers/{breadcrumbs.js.coffee → breadcrumbs_controller.js.coffee} +4 -7
  11. data/app/assets/javascripts/app/controllers/collections/index_controller.js.coffee +38 -0
  12. data/app/assets/javascripts/app/controllers/collections/stats_controller.js.coffee +17 -0
  13. data/app/assets/javascripts/app/controllers/{databases.js.coffee → databases/index_controller.js.coffee} +11 -15
  14. data/app/assets/javascripts/app/controllers/databases/stats_controller.js.coffee +15 -0
  15. data/app/assets/javascripts/app/controllers/documents/index_controller.js.coffee +54 -0
  16. data/app/assets/javascripts/app/controllers/documents/show_controller.js.coffee +38 -0
  17. data/app/assets/javascripts/app/controllers/main_controller.js.coffee +15 -0
  18. data/app/assets/javascripts/app/controllers/servers/show_controller.js.coffee +17 -0
  19. data/app/assets/javascripts/app/directives.js.coffee +23 -0
  20. data/app/assets/javascripts/app/filters.js.coffee +14 -1
  21. data/app/assets/javascripts/app/modules/alerts.js.coffee +58 -0
  22. data/app/assets/javascripts/app/modules/pager.js.coffee +2 -2
  23. data/app/assets/javascripts/app/modules/spinner.js.coffee +29 -0
  24. data/app/assets/javascripts/app/modules/table_filter.js.coffee +4 -4
  25. data/app/assets/javascripts/app/resources.js.coffee +14 -8
  26. data/app/assets/javascripts/app/services.js.coffee +11 -33
  27. data/app/assets/javascripts/application.js.coffee +62 -34
  28. data/app/assets/javascripts/application.test.js.coffee +5 -0
  29. data/app/assets/javascripts/compiled_templates.js.coffee +1 -0
  30. data/app/assets/javascripts/vendor.js.coffee +0 -1
  31. data/app/assets/stylesheets/application.css.scss +36 -18
  32. data/{public/index.html → app/views/index.erb} +8 -8
  33. data/bin/mongo_browser +2 -13
  34. data/config.ru +3 -1
  35. data/lib/mongo_browser.rb +1 -0
  36. data/lib/mongo_browser/api.rb +11 -0
  37. data/lib/mongo_browser/api/collections.rb +34 -0
  38. data/lib/mongo_browser/api/databases.rb +32 -0
  39. data/lib/mongo_browser/api/documents.rb +37 -0
  40. data/lib/mongo_browser/api/mongo.rb +41 -0
  41. data/lib/mongo_browser/application.rb +8 -174
  42. data/lib/mongo_browser/application/development.rb +32 -0
  43. data/lib/mongo_browser/cli.rb +48 -0
  44. data/lib/mongo_browser/entities.rb +43 -0
  45. data/lib/mongo_browser/models/collection.rb +7 -12
  46. data/lib/mongo_browser/models/document.rb +5 -1
  47. data/lib/mongo_browser/models/pager.rb +22 -9
  48. data/lib/mongo_browser/version.rb +1 -1
  49. data/mongo_browser.gemspec +22 -15
  50. data/package.json +30 -0
  51. data/public/ng/templates/alerts.html +6 -0
  52. data/public/ng/templates/collections/index.html +39 -0
  53. data/public/ng/templates/collections/stats.html +18 -0
  54. data/public/ng/templates/databases/index.html +35 -0
  55. data/public/ng/templates/databases/stats.html +18 -0
  56. data/public/ng/templates/documents/index.html +40 -0
  57. data/public/ng/templates/documents/show.html +17 -0
  58. data/{app/assets → public/ng}/templates/pager.html +0 -0
  59. data/{app/assets/templates/server_info.html → public/ng/templates/server/show.html} +1 -1
  60. data/{app/assets → public/ng}/templates/table_filter.html +0 -0
  61. data/script/ci_all +5 -1
  62. data/script/ci_e2e +5 -2
  63. data/script/ci_javascripts +1 -1
  64. data/script/ci_rspec +1 -1
  65. data/spec/javascripts/app/controllers/{breadcrumbs_spec.js.coffee → breadcrumbs_controller_spec.js.coffee} +1 -1
  66. data/spec/javascripts/app/controllers/collections/index_controller_spec.js.coffee +95 -0
  67. data/spec/javascripts/app/controllers/collections/stats_controller_spec.js.coffee +34 -0
  68. data/spec/javascripts/app/controllers/databases/index_controller_spec.js.coffee +93 -0
  69. data/spec/javascripts/app/controllers/databases/stats_controller_spec.js.coffee +30 -0
  70. data/spec/javascripts/app/controllers/documents/index_controller_spec.js.coffee +108 -0
  71. data/spec/javascripts/app/controllers/documents/show_controller_spec.js.coffee +94 -0
  72. data/spec/javascripts/app/controllers/{main_spec.js.coffee → main_controller_spec.js.coffee} +2 -2
  73. data/spec/javascripts/app/controllers/{server_info_spec.js.coffee → server/show_controller_spec.js.coffee} +5 -6
  74. data/spec/javascripts/app/directives_spec.js.coffee +108 -24
  75. data/spec/javascripts/app/filters_spec.js.coffee +31 -5
  76. data/spec/javascripts/app/modules/alerts_spec.js.coffee +138 -0
  77. data/spec/javascripts/app/modules/dialogs_spec.js.coffee +1 -2
  78. data/spec/javascripts/app/modules/pager_spec.js.coffee +0 -1
  79. data/spec/javascripts/app/modules/spinner_spec.js.coffee +65 -0
  80. data/spec/javascripts/app/modules/table_filter_spec.js.coffee +9 -9
  81. data/spec/javascripts/app/resources_spec.js.coffee +99 -0
  82. data/spec/javascripts/app/services_spec.js.coffee +31 -71
  83. data/spec/javascripts/config/{testacular-e2e.conf.js → karma-e2e.conf.js} +1 -1
  84. data/spec/javascripts/config/{testacular.conf.js → karma.conf.js} +2 -3
  85. data/spec/javascripts/e2e/collection_stats_scenario.js.coffee +12 -0
  86. data/spec/javascripts/e2e/collections_scenario.js.coffee +59 -20
  87. data/spec/javascripts/e2e/database_stats_scenario.js.coffee +11 -0
  88. data/spec/javascripts/e2e/databases_scenario.js.coffee +37 -36
  89. data/spec/javascripts/e2e/document_show_scenario.js.coffee +31 -0
  90. data/spec/javascripts/e2e/documents_pagination_scenario.js.coffee +33 -0
  91. data/spec/javascripts/e2e/documents_scenario.js.coffee +43 -4
  92. data/spec/javascripts/e2e/server_info_scenario.js.coffee +8 -2
  93. data/spec/javascripts/helpers/mocks.js.coffee +2 -0
  94. data/spec/javascripts/helpers_e2e/dsl.js.coffee +20 -0
  95. data/spec/javascripts/lib/angular-mocks.js +64 -16
  96. data/spec/javascripts/lib/angular-scenario.js +724 -561
  97. data/spec/javascripts/runner.html +5 -5
  98. data/spec/lib/api/collections_spec.rb +62 -0
  99. data/spec/lib/api/databases_spec.rb +58 -0
  100. data/spec/lib/api/documents_spec.rb +135 -0
  101. data/spec/lib/api/mongo_spec.rb +27 -0
  102. data/spec/lib/cli_spec.rb +19 -0
  103. data/spec/lib/entities_spec.rb +39 -0
  104. data/spec/lib/models/collection_spec.rb +16 -10
  105. data/spec/lib/models/database_spec.rb +4 -4
  106. data/spec/lib/models/document_spec.rb +5 -5
  107. data/spec/lib/models/pager_spec.rb +20 -11
  108. data/spec/spec_helper.rb +7 -15
  109. data/spec/support/api_example_group.rb +45 -0
  110. data/spec/support/fixtures.rb +10 -6
  111. data/spec/support/matchers/expose.rb +18 -0
  112. data/vendor/assets/javascripts/angular/angular-bootstrap.js +1 -1
  113. data/vendor/assets/javascripts/angular/angular-resource.js +78 -56
  114. data/vendor/assets/javascripts/angular/angular-sanitize.js +3 -1
  115. data/vendor/assets/javascripts/angular/angular.js +720 -404
  116. metadata +323 -183
  117. data/app/assets/javascripts/app.js.coffee +0 -8
  118. data/app/assets/javascripts/app/controllers.js.coffee +0 -2
  119. data/app/assets/javascripts/app/controllers/alerts.js.coffee +0 -12
  120. data/app/assets/javascripts/app/controllers/collections.js.coffee +0 -40
  121. data/app/assets/javascripts/app/controllers/documents.js.coffee +0 -49
  122. data/app/assets/javascripts/app/controllers/main.js.coffee +0 -10
  123. data/app/assets/javascripts/app/controllers/server_info.js.coffee +0 -14
  124. data/app/assets/javascripts/templates.js.coffee +0 -1
  125. data/app/assets/javascripts/templates/.gitkeep +0 -0
  126. data/app/assets/templates/collections.html +0 -53
  127. data/app/assets/templates/databases.html +0 -32
  128. data/app/assets/templates/documents.html +0 -45
  129. data/config-e2e.ru +0 -20
  130. data/spec/features/collections_list_spec.rb +0 -64
  131. data/spec/features/documents_list_spec.rb +0 -139
  132. data/spec/features/server_info_spec.rb +0 -23
  133. data/spec/javascripts/app/controllers/alerts_spec.js.coffee +0 -36
  134. data/spec/javascripts/app/controllers/collections_spec.js.coffee +0 -78
  135. data/spec/javascripts/app/controllers/databases_spec.js.coffee +0 -55
  136. data/spec/javascripts/app/controllers/documents_spec.js.coffee +0 -62
  137. data/spec/javascripts/helpers_e2e/app_element.js.coffee +0 -6
  138. data/spec/support/feature_example_group.rb +0 -53
  139. data/spec/support/matchers/have_flash_message.rb +0 -16
  140. data/spec/support/mongod.rb +0 -91
  141. data/spec/support/mongodb.conf +0 -47
@@ -0,0 +1,11 @@
1
+ describe "database stats page", ->
2
+
3
+ beforeEach ->
4
+ browser().navigateTo("/e2e/load_fixtures")
5
+ browser().navigateTo("/")
6
+
7
+ element("table.databases tbody tr a:contains('first_database')").click()
8
+ element("a.btn:contains('Database stats')").click()
9
+
10
+ it "displays database stats", ->
11
+ expect(repeater("table tbody tr").count()).toBeGreaterThan(0)
@@ -1,74 +1,75 @@
1
1
  describe "databases list page", ->
2
+ databasesList = null
3
+
4
+ shouldShowDatabase = (name) ->
5
+ expect(databasesList.column("database.name")).toContain(name)
6
+
7
+ shouldShowAllDatabases = ->
8
+ shouldShowDatabase("first_database")
9
+ shouldShowDatabase("second_database")
10
+ shouldShowDatabase("third_database")
11
+
2
12
  beforeEach ->
3
13
  browser().navigateTo("/e2e/load_fixtures")
4
14
  browser().navigateTo("/")
5
15
 
16
+ databasesList = repeater("table.databases tbody tr")
17
+
6
18
  it "navigates to the valid url", ->
7
19
  expect(browser().location().url()).toBe("/")
8
20
 
21
+ it "shows the breadcrumbs", ->
22
+ link = element(".container a.brand")
23
+ expect(link.text()).toEqual("Mongo Browser")
24
+ expect(link.attr("href")).toEqual("/")
25
+
9
26
  it "displays a valid section title", ->
10
27
  title = element("h2").text()
11
28
  expect(title).toEqual("localhost databases")
12
29
 
13
- it "displays available databases ordered by name", ->
14
- expect(repeater("table.databases tbody tr").column("database.name"))
15
- .toEqual(["first_database", "second_database", "third_database"])
16
-
17
30
  describe "filtering by database name", ->
18
31
  it "displays all databases when the filter is not provided", ->
19
32
  input("value").enter("")
20
- expect(repeater("table.databases tbody tr").count()).toBe(3)
21
- expect(repeater("table.databases tbody tr").column("database.name"))
22
- .toEqual(["first_database", "second_database", "third_database"])
33
+ shouldShowAllDatabases()
23
34
 
24
35
  it "filters by database name", ->
25
36
  input("value").enter("first")
26
- expect(repeater("table.databases tbody tr").count()).toBe(1)
27
- expect(repeater("table.databases tbody tr").column("database.name"))
28
- .toEqual(["first_database"])
37
+ shouldShowDatabase("first_database")
29
38
 
30
39
  input("value").enter("second")
31
- expect(repeater("table.databases tbody tr").count()).toBe(1)
32
- expect(repeater("table.databases tbody tr").column("database.name"))
33
- .toEqual(["second_database"])
40
+ shouldShowDatabase("second_database")
34
41
 
35
- input("value").enter("not existing")
36
- expect(repeater("table.databases tbody tr").count()).toBe(0)
37
- expect(element(".filter.alert:visible").text()).toMatch(/Nothing has been found./)
42
+ input("value").enter("not existing database")
43
+ expect(databasesList.count()).toBe(0)
44
+ expect(element(".alert:visible").text()).toMatch(/Nothing has been found./)
38
45
 
39
46
  it "displays all records when the filter is cleared", ->
40
47
  element("button:contains('Clear')").click()
41
- expect(repeater("table.databases tbody tr").count()).toBe(3)
42
- expect(repeater("table.databases tbody tr").column("database.name"))
43
- .toEqual(["first_database", "second_database", "third_database"])
48
+ shouldShowAllDatabases()
44
49
 
45
50
  describe "delete a database", ->
51
+ deleteDatabase = (name) ->
52
+ element("table.databases tbody tr:contains('#{name}') td:last-child a:contains('Delete')")
53
+ .click()
54
+
46
55
  beforeEach ->
47
- element("table.databases tbody tr:contains('third_database') td.actions a:contains('Delete')").click()
48
- expect(element("div.modal .modal-body").text()).toContain("Deleting third_database. Are you sure?")
56
+ deleteDatabase("third_database")
57
+ expect(element("div.modal .modal-body").text())
58
+ .toContain("Deleting third_database. Are you sure?")
49
59
 
50
60
  describe "when the dialog was disposed", ->
51
- beforeEach ->
52
- appElement "div.modal .modal-footer a:contains('Cancel')", ($element) ->
53
- $element.click()
61
+ beforeEach -> disposeDialog()
54
62
 
55
63
  it "does nothig", ->
56
- expect(repeater("table.databases tbody tr").count()).toBe(3)
57
- expect(repeater("table.databases tbody tr").column("database.name"))
58
- .toEqual(["first_database", "second_database", "third_database"])
64
+ shouldShowAllDatabases()
59
65
 
60
66
  describe "when the dialog was confirmed", ->
61
- beforeEach ->
62
- appElement "div.bootbox a:contains('OK')", ($element) ->
63
- $element.click()
67
+ beforeEach -> confirmDialog()
64
68
 
65
- # TODO figure out how to test it
66
- xit "shows the alert", ->
69
+ it "shows the alert", ->
67
70
  expect(repeater("aside#alerts .alert").count()).toBe(1)
68
71
  expect(repeater("aside#alerts .alert").column("message.text"))
69
- .toContain("Database third_database has been deleted.")
72
+ .toContain("Database third_database has been deleted.")
70
73
 
71
74
  it "deletes a database", ->
72
- expect(repeater("table.databases tbody tr").count()).toBe(2)
73
- expect(repeater("table.databases tbody tr").column("database.name"))
74
- .toEqual(["first_database", "second_database"])
75
+ expect(databasesList.column("database.name")).not().toContain("third_database")
@@ -0,0 +1,31 @@
1
+ describe "documents list page", ->
2
+ beforeEach ->
3
+ browser().navigateTo("/e2e/load_fixtures")
4
+ browser().navigateTo("/")
5
+
6
+ element("table.databases tbody tr a:contains('first_database')").click()
7
+ element("table.collections tbody tr a:contains('first_collection')").click()
8
+ element("table.documents tbody tr:first td span.id a").click()
9
+
10
+ it "shows the document page", ->
11
+ expect(browser().location().url()).toMatch(/\/databases\/first_database\/collections\/first_collection\/documents\/.+/)
12
+
13
+ it "shows the alerts when the document has been refreshed", ->
14
+ element("a:contains('Refresh')").click()
15
+
16
+ expect(repeater("aside#alerts .alert").count()).toBe(1)
17
+ expect(repeater("aside#alerts .alert").column("message.text"))
18
+ .toContain("Document was refreshed")
19
+
20
+ describe "when the document has not been found", ->
21
+ beforeEach ->
22
+ notExistingDocumentId = "50f486f1dac5d50540000003"
23
+ browser().navigateTo("/databases/first_database/collections/first_collection/documents/#{notExistingDocumentId}")
24
+
25
+ it "redirects to the documents list page", ->
26
+ expect(browser().location().url()).toEqual("/databases/first_database/collections/first_collection/documents")
27
+
28
+ it "sets the flash error message", ->
29
+ expect(repeater("aside#alerts .alert").count()).toBe(1)
30
+ expect(repeater("aside#alerts .alert").column("message.text"))
31
+ .toEqual(["Document not found"])
@@ -0,0 +1,33 @@
1
+ describe "documents list page", ->
2
+ documentsList = null
3
+
4
+ beforeEach ->
5
+ browser().navigateTo("/e2e/load_fixtures")
6
+ browser().navigateTo("/")
7
+
8
+ element("table.databases tbody tr a:contains('first_database')").click()
9
+ element("table.collections tbody tr a:contains('second_collection')").click()
10
+
11
+ documentsList = repeater("table.documents tbody tr")
12
+
13
+ describe "pagination", ->
14
+ it "displays the pager", ->
15
+ expect(documentsList.count()).toEqual(25)
16
+ expect(repeater("div.pagination:first li").count()).toEqual(5)
17
+
18
+ # TODO extend this spec
19
+ it "paginate documents", ->
20
+ element("div.pagination:first li a:contains('Next')").click()
21
+ expect(documentsList.count()).toEqual(25)
22
+ expect(browser().location().url())
23
+ .toBe("/databases/first_database/collections/second_collection/documents?page=2")
24
+
25
+ element("div.pagination:first li a:contains('Next')").click()
26
+ expect(documentsList.count()).toEqual(20)
27
+ expect(browser().location().url())
28
+ .toBe("/databases/first_database/collections/second_collection/documents?page=3")
29
+
30
+ element("div.pagination:first li a:contains('1')").click()
31
+ expect(documentsList.count()).toEqual(25)
32
+ expect(browser().location().url())
33
+ .toBe("/databases/first_database/collections/second_collection/documents")
@@ -1,4 +1,6 @@
1
1
  describe "documents list page", ->
2
+ documentsList = null
3
+
2
4
  beforeEach ->
3
5
  browser().navigateTo("/e2e/load_fixtures")
4
6
  browser().navigateTo("/")
@@ -6,13 +8,50 @@ describe "documents list page", ->
6
8
  element("table.databases tbody tr a:contains('first_database')").click()
7
9
  element("table.collections tbody tr a:contains('first_collection')").click()
8
10
 
11
+ documentsList = repeater("table.documents tbody tr")
12
+
9
13
  it "shows the documents page", ->
10
14
  expect(browser().location().url())
11
- .toBe("/databases/first_database/collections/first_collection/documents")
15
+ .toBe("/databases/first_database/collections/first_collection/documents")
12
16
 
13
17
  title = element("h2").text()
14
18
  expect(title).toEqual("first_collection documents")
15
19
 
16
- it "displays a tab with collection stats", ->
17
- element(".tabbable a:contains('Collection stats')").click()
18
- expect(repeater("table tbody tr").count()).toBeGreaterThan(0)
20
+ it "shows the breadcrumbs", ->
21
+ link = element(".container a.brand")
22
+ expect(link.text()).toEqual("Mongo Browser")
23
+ expect(link.attr("href")).toEqual("/")
24
+
25
+ dbLink = element(".container .breadcrumbs li:nth-child(1) a")
26
+ expect(dbLink.text()).toEqual("first_database")
27
+ expect(dbLink.attr("href")).toEqual("/databases/first_database/collections")
28
+
29
+ collectionLink = element(".container .breadcrumbs li:nth-child(2) a")
30
+ expect(collectionLink.text()).toEqual("first_collection")
31
+ expect(collectionLink.attr("href"))
32
+ .toEqual("/databases/first_database/collections/first_collection/documents")
33
+
34
+ describe "delete a document", ->
35
+ beforeEach ->
36
+ element("table.documents tbody tr:first td:last-child a:contains('Delete')")
37
+ .click()
38
+
39
+ expect(element("div.modal .modal-body").text())
40
+ .toContain("Are you sure?")
41
+
42
+ describe "when the dialog was disposed", ->
43
+ beforeEach -> disposeDialog()
44
+
45
+ it "does nothig", ->
46
+ expect(documentsList.count()).toBe(2)
47
+
48
+ describe "when the dialog was confirmed", ->
49
+ beforeEach -> confirmDialog()
50
+
51
+ it "shows the alert", ->
52
+ expect(repeater("aside#alerts .alert").count()).toBe(1)
53
+ expect(repeater("aside#alerts .alert").column("message.text"))
54
+ .toMatch(/Document \w+ has been deleted./)
55
+
56
+ it "deletes a database", ->
57
+ expect(documentsList.count()).toBe(1)
@@ -3,10 +3,16 @@ describe "server info page", ->
3
3
  browser().navigateTo("/")
4
4
  element("a:contains('Server Info')").click()
5
5
 
6
- it "displays details about the server", ->
6
+ it "navigates to the valid url", ->
7
7
  expect(browser().location().url()).toBe("/server_info")
8
8
 
9
+ it "displays a valid section title", ->
9
10
  title = element("h2").text()
10
11
  expect(title).toEqual("server info")
11
12
 
12
- expect(repeater("table tbody tr").count()).toBeGreaterThan(0)
13
+ it "displays details about the server", ->
14
+ list = repeater("table tbody tr")
15
+ expect(list.count()).toBeGreaterThan(0)
16
+
17
+ for property in ["version", "gitVersion", "sysInfo", "versionArray", "bits", "debug", "maxBsonObjectSize", "ok"]
18
+ expect(list.column("property")).toContain(property)
@@ -1,5 +1,7 @@
1
1
  # Create a mock for dialogsHandler
2
2
  angular.module("mocks", []).config ($provide) ->
3
+ $provide.value("alertTimeout", 3000)
4
+
3
5
  $provide.factory "dialogsHandler", ->
4
6
  confirm: (message, callback) ->
5
7
  @callback = callback
@@ -0,0 +1,20 @@
1
+ dsl = angular.scenario.dsl
2
+
3
+ # Access to iframe's jQuery, see: https://gist.github.com/1700488
4
+ dsl "appElement", ->
5
+ (selector, fn) ->
6
+ @addFutureAction "element " + selector, ($window, $document, done) ->
7
+ fn.call this, $window.angular.element(selector)
8
+ done()
9
+
10
+ dsl "confirmDialog", ->
11
+ ->
12
+ @addFutureAction "confirm dialog", ($window, $document, done) ->
13
+ $window.angular.element("div.bootbox a:contains('OK')").click()
14
+ done()
15
+
16
+ dsl "disposeDialog", ->
17
+ ->
18
+ @addFutureAction "confirm dialog", ($window, $document, done) ->
19
+ $window.angular.element("div.bootbox a:contains('Cancel')").click()
20
+ done()
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.0.3
2
+ * @license AngularJS v1.0.7
3
3
  * (c) 2010-2012 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  *
@@ -202,6 +202,30 @@ angular.mock.$Browser.prototype = {
202
202
  * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
203
203
  * into it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
204
204
  * information.
205
+ *
206
+ *
207
+ * <pre>
208
+ * describe('$exceptionHandlerProvider', function() {
209
+ *
210
+ * it('should capture log messages and exceptions', function() {
211
+ *
212
+ * module(function($exceptionHandlerProvider) {
213
+ * $exceptionHandlerProvider.mode('log');
214
+ * });
215
+ *
216
+ * inject(function($log, $exceptionHandler, $timeout) {
217
+ * $timeout(function() { $log.log(1); });
218
+ * $timeout(function() { $log.log(2); throw 'banana peel'; });
219
+ * $timeout(function() { $log.log(3); });
220
+ * expect($exceptionHandler.errors).toEqual([]);
221
+ * expect($log.assertEmpty());
222
+ * $timeout.flush();
223
+ * expect($exceptionHandler.errors).toEqual(['banana peel']);
224
+ * expect($log.log.logs).toEqual([[1], [2], [3]]);
225
+ * });
226
+ * });
227
+ * });
228
+ * </pre>
205
229
  */
206
230
 
207
231
  angular.mock.$ExceptionHandlerProvider = function() {
@@ -217,11 +241,11 @@ angular.mock.$ExceptionHandlerProvider = function() {
217
241
  *
218
242
  * @param {string} mode Mode of operation, defaults to `rethrow`.
219
243
  *
220
- * - `rethrow`: If any errors are are passed into the handler in tests, it typically
244
+ * - `rethrow`: If any errors are passed into the handler in tests, it typically
221
245
  * means that there is a bug in the application or test, so this mock will
222
246
  * make these tests fail.
223
- * - `log`: Sometimes it is desirable to test that an error is throw, for this case the `log` mode stores the
224
- * error and allows later assertion of it.
247
+ * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log` mode stores an
248
+ * array of errors in `$exceptionHandler.errors`, to allow later assertion of them.
225
249
  * See {@link ngMock.$log#assertEmpty assertEmpty()} and
226
250
  * {@link ngMock.$log#reset reset()}
227
251
  */
@@ -298,7 +322,13 @@ angular.mock.$LogProvider = function() {
298
322
  * @propertyOf ngMock.$log
299
323
  *
300
324
  * @description
301
- * Array of logged messages.
325
+ * Array of messages logged using {@link ngMock.$log#log}.
326
+ *
327
+ * @example
328
+ * <pre>
329
+ * $log.log('Some Log');
330
+ * var first = $log.log.logs.unshift();
331
+ * </pre>
302
332
  */
303
333
  $log.log.logs = [];
304
334
  /**
@@ -307,7 +337,13 @@ angular.mock.$LogProvider = function() {
307
337
  * @propertyOf ngMock.$log
308
338
  *
309
339
  * @description
310
- * Array of logged messages.
340
+ * Array of messages logged using {@link ngMock.$log#warn}.
341
+ *
342
+ * @example
343
+ * <pre>
344
+ * $log.warn('Some Warning');
345
+ * var first = $log.warn.logs.unshift();
346
+ * </pre>
311
347
  */
312
348
  $log.warn.logs = [];
313
349
  /**
@@ -316,7 +352,13 @@ angular.mock.$LogProvider = function() {
316
352
  * @propertyOf ngMock.$log
317
353
  *
318
354
  * @description
319
- * Array of logged messages.
355
+ * Array of messages logged using {@link ngMock.$log#info}.
356
+ *
357
+ * @example
358
+ * <pre>
359
+ * $log.info('Some Info');
360
+ * var first = $log.info.logs.unshift();
361
+ * </pre>
320
362
  */
321
363
  $log.info.logs = [];
322
364
  /**
@@ -325,7 +367,13 @@ angular.mock.$LogProvider = function() {
325
367
  * @propertyOf ngMock.$log
326
368
  *
327
369
  * @description
328
- * Array of logged messages.
370
+ * Array of messages logged using {@link ngMock.$log#error}.
371
+ *
372
+ * @example
373
+ * <pre>
374
+ * $log.log('Some Error');
375
+ * var first = $log.error.logs.unshift();
376
+ * </pre>
329
377
  */
330
378
  $log.error.logs = [];
331
379
  };
@@ -406,7 +454,7 @@ angular.mock.$LogProvider = function() {
406
454
  *
407
455
  * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
408
456
  *
409
- * Mock of the Date type which has its timezone specified via constroctor arg.
457
+ * Mock of the Date type which has its timezone specified via constructor arg.
410
458
  *
411
459
  * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
412
460
  * offset, so that we can test code that depends on local timezone settings without dependency on
@@ -561,7 +609,7 @@ angular.mock.$LogProvider = function() {
561
609
 
562
610
  /**
563
611
  * @ngdoc function
564
- * @name angular.mock.debug
612
+ * @name angular.mock.dump
565
613
  * @description
566
614
  *
567
615
  * *NOTE*: this is not an injectable instance, just a globally available function.
@@ -629,10 +677,10 @@ angular.mock.dump = function(object) {
629
677
  * @ngdoc object
630
678
  * @name ngMock.$httpBackend
631
679
  * @description
632
- * Fake HTTP backend implementation suitable for unit testing application that use the
680
+ * Fake HTTP backend implementation suitable for unit testing applications that use the
633
681
  * {@link ng.$http $http service}.
634
682
  *
635
- * *Note*: For fake http backend implementation suitable for end-to-end testing or backend-less
683
+ * *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less
636
684
  * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}.
637
685
  *
638
686
  * During unit testing, we want our unit tests to run quickly and have no external dependencies so
@@ -744,7 +792,7 @@ angular.mock.dump = function(object) {
744
792
  }
745
793
 
746
794
  // testing controller
747
- var $http;
795
+ var $httpBackend;
748
796
 
749
797
  beforeEach(inject(function($injector) {
750
798
  $httpBackend = $injector.get('$httpBackend');
@@ -1629,7 +1677,7 @@ window.jasmine && (function(window) {
1629
1677
  * @name angular.mock.module
1630
1678
  * @description
1631
1679
  *
1632
- * *NOTE*: This is function is also published on window for easy access.<br>
1680
+ * *NOTE*: This function is also published on window for easy access.<br>
1633
1681
  * *NOTE*: Only available with {@link http://pivotal.github.com/jasmine/ jasmine}.
1634
1682
  *
1635
1683
  * This function registers a module configuration code. It collects the configuration information
@@ -1663,7 +1711,7 @@ window.jasmine && (function(window) {
1663
1711
  * @name angular.mock.inject
1664
1712
  * @description
1665
1713
  *
1666
- * *NOTE*: This is function is also published on window for easy access.<br>
1714
+ * *NOTE*: This function is also published on window for easy access.<br>
1667
1715
  * *NOTE*: Only available with {@link http://pivotal.github.com/jasmine/ jasmine}.
1668
1716
  *
1669
1717
  * The inject function wraps a function into an injectable function. The inject() creates new
@@ -1729,7 +1777,7 @@ window.jasmine && (function(window) {
1729
1777
  try {
1730
1778
  injector.invoke(blockFns[i] || angular.noop, this);
1731
1779
  } catch (e) {
1732
- if(e.stack) e.stack += '\n' + errorForStack.stack;
1780
+ if(e.stack && errorForStack) e.stack += '\n' + errorForStack.stack;
1733
1781
  throw e;
1734
1782
  } finally {
1735
1783
  errorForStack = null;