mongo_browser 0.1.3 → 0.2.0.rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. data/.gitignore +3 -0
  2. data/.travis.yml +3 -3
  3. data/README.md +1 -25
  4. data/Rakefile +0 -1
  5. data/app/assets/images/background.png +0 -0
  6. data/app/assets/javascripts/app/controllers/alerts.js.coffee +12 -0
  7. data/app/assets/javascripts/app/controllers/breadcrumbs.js.coffee +25 -0
  8. data/app/assets/javascripts/app/controllers/collections.js.coffee +40 -0
  9. data/app/assets/javascripts/app/controllers/databases.js.coffee +39 -0
  10. data/app/assets/javascripts/app/controllers/documents.js.coffee +49 -0
  11. data/app/assets/javascripts/app/controllers/main.js.coffee +10 -0
  12. data/app/assets/javascripts/app/controllers/server_info.js.coffee +14 -0
  13. data/app/assets/javascripts/app/controllers.js.coffee +2 -0
  14. data/app/assets/javascripts/app/directives.js.coffee +20 -0
  15. data/app/assets/javascripts/app/filters.js.coffee +48 -0
  16. data/app/assets/javascripts/app/modules/dialogs.js.coffee +29 -0
  17. data/app/assets/javascripts/app/modules/pager.js.coffee +87 -0
  18. data/app/assets/javascripts/app/modules/table_filter.js.coffee +27 -0
  19. data/app/assets/javascripts/app/resources.js.coffee +22 -0
  20. data/app/assets/javascripts/app/services.js.coffee +36 -0
  21. data/app/assets/javascripts/app.js.coffee +8 -0
  22. data/app/assets/javascripts/application.js.coffee +35 -6
  23. data/app/assets/javascripts/templates/.gitkeep +0 -0
  24. data/app/assets/javascripts/templates.js.coffee +1 -0
  25. data/app/assets/javascripts/vendor.js.coffee +5 -0
  26. data/app/assets/stylesheets/application.css.scss +46 -3
  27. data/app/assets/templates/collections.html +53 -0
  28. data/app/assets/templates/databases.html +32 -0
  29. data/app/assets/templates/documents.html +45 -0
  30. data/app/assets/templates/pager.html +13 -0
  31. data/app/{views/server_info.erb → assets/templates/server_info.html} +5 -7
  32. data/app/assets/templates/table_filter.html +10 -0
  33. data/bin/mongo_browser +8 -45
  34. data/config-e2e.ru +20 -0
  35. data/grunt.js +36 -0
  36. data/lib/mongo_browser/application.rb +143 -64
  37. data/lib/mongo_browser/middleware/sprockets_base.rb +11 -0
  38. data/lib/mongo_browser/middleware/sprockets_sinatra.rb +3 -7
  39. data/lib/mongo_browser/middleware/sprockets_specs.rb +18 -0
  40. data/lib/mongo_browser/models/collection.rb +67 -0
  41. data/lib/mongo_browser/models/database.rb +52 -0
  42. data/lib/mongo_browser/models/document.rb +17 -0
  43. data/lib/mongo_browser/models/pager.rb +30 -0
  44. data/lib/mongo_browser/models/server.rb +51 -0
  45. data/lib/mongo_browser/version.rb +1 -1
  46. data/lib/mongo_browser.rb +10 -5
  47. data/mongo_browser.gemspec +4 -11
  48. data/public/index.html +47 -0
  49. data/script/ci_all +21 -0
  50. data/script/ci_e2e +11 -0
  51. data/script/ci_javascripts +4 -0
  52. data/script/ci_rspec +3 -0
  53. data/spec/features/collections_list_spec.rb +6 -49
  54. data/spec/features/documents_list_spec.rb +15 -14
  55. data/spec/features/server_info_spec.rb +3 -3
  56. data/spec/javascripts/app/controllers/alerts_spec.js.coffee +36 -0
  57. data/spec/javascripts/app/controllers/breadcrumbs_spec.js.coffee +28 -0
  58. data/spec/javascripts/app/controllers/collections_spec.js.coffee +78 -0
  59. data/spec/javascripts/app/controllers/databases_spec.js.coffee +55 -0
  60. data/spec/javascripts/app/controllers/documents_spec.js.coffee +62 -0
  61. data/spec/javascripts/app/controllers/main_spec.js.coffee +20 -0
  62. data/spec/javascripts/app/controllers/server_info_spec.js.coffee +21 -0
  63. data/spec/javascripts/app/directives_spec.js.coffee +58 -0
  64. data/spec/javascripts/app/filters_spec.js.coffee +99 -0
  65. data/spec/javascripts/app/modules/dialogs_spec.js.coffee +51 -0
  66. data/spec/javascripts/app/modules/pager_spec.js.coffee +104 -0
  67. data/spec/javascripts/app/modules/table_filter_spec.js.coffee +76 -0
  68. data/spec/javascripts/app/services_spec.js.coffee +83 -0
  69. data/spec/javascripts/config/testacular-e2e.conf.js +19 -0
  70. data/spec/javascripts/config/testacular.conf.js +43 -0
  71. data/spec/javascripts/e2e/collections_scenario.js.coffee +49 -0
  72. data/spec/javascripts/e2e/databases_scenario.js.coffee +74 -0
  73. data/spec/javascripts/e2e/documents_scenario.js.coffee +18 -0
  74. data/spec/javascripts/e2e/server_info_scenario.js.coffee +12 -0
  75. data/spec/javascripts/helpers/matchers.js.coffee +5 -0
  76. data/spec/javascripts/helpers/mocks.js.coffee +7 -0
  77. data/spec/javascripts/helpers_e2e/app_element.js.coffee +6 -0
  78. data/spec/javascripts/lib/angular-mocks.js +1740 -0
  79. data/spec/javascripts/lib/angular-scenario.js +26147 -0
  80. data/spec/javascripts/lib/jasmine-html.js +681 -0
  81. data/spec/javascripts/lib/jasmine.css +82 -0
  82. data/spec/javascripts/lib/jasmine.js +2600 -0
  83. data/spec/javascripts/runner.html +54 -0
  84. data/spec/javascripts/runner_e2e.html +10 -0
  85. data/spec/javascripts/spec.js.coffee +2 -0
  86. data/spec/javascripts/spec_e2e.js.coffee +2 -0
  87. data/spec/lib/models/collection_spec.rb +80 -0
  88. data/spec/lib/models/database_spec.rb +75 -0
  89. data/spec/lib/models/document_spec.rb +17 -0
  90. data/spec/lib/models/pager_spec.rb +64 -0
  91. data/spec/lib/models/server_spec.rb +76 -0
  92. data/spec/lib/mongo_browser_spec.rb +1 -1
  93. data/spec/spec_helper.rb +2 -19
  94. data/spec/support/feature_example_group.rb +8 -3
  95. data/spec/support/fixtures/databases.json +8 -0
  96. data/spec/support/fixtures.rb +20 -3
  97. data/spec/support/matchers/have_flash_message.rb +1 -1
  98. data/spec/support/mongod.rb +37 -21
  99. data/spec/support/mongodb.conf +47 -0
  100. data/vendor/assets/javascripts/angular/angular-bootstrap.js +166 -0
  101. data/vendor/assets/javascripts/angular/angular-resource.js +435 -0
  102. data/vendor/assets/javascripts/angular/angular-sanitize.js +535 -0
  103. data/vendor/assets/javascripts/angular/angular.js +14531 -0
  104. data/vendor/assets/javascripts/underscore.js +1200 -0
  105. metadata +136 -148
  106. data/app/assets/javascripts/app/table_filter.js.coffee +0 -50
  107. data/app/assets/javascripts/ujs.js.coffee +0 -23
  108. data/app/views/collections/index.erb +0 -59
  109. data/app/views/databases/index.erb +0 -29
  110. data/app/views/documents/index.erb +0 -61
  111. data/app/views/layout/_flash_messages.erb +0 -10
  112. data/app/views/layout/_navbar.erb +0 -22
  113. data/app/views/layout.erb +0 -20
  114. data/app/views/shared/_filter.erb +0 -14
  115. data/features/mongo_browser.feature +0 -18
  116. data/features/step_definitions/mongo_browser_steps.rb +0 -1
  117. data/features/support/env.rb +0 -18
  118. data/spec/features/databases_list_spec.rb +0 -65
@@ -0,0 +1,83 @@
1
+ describe "services", ->
2
+ beforeEach module("mb.services")
3
+
4
+ describe "alerts", ->
5
+ it "is defined", inject (alerts) ->
6
+ expect(alerts).toBeDefined()
7
+
8
+ describe "#nextId", ->
9
+ it "return the next id for the new flash message", inject (alerts) ->
10
+ expect(alerts.nextId()).toEqual(1)
11
+ _(4).times -> alerts.nextId()
12
+ expect(alerts.nextId()).toEqual(6)
13
+
14
+ describe "#push", ->
15
+ beforeEach inject (alerts) ->
16
+ spyOn(alerts, "delayedDispose")
17
+
18
+ it "returns an id for the new flash message", inject (alerts) ->
19
+ expect(alerts.push("info", "Test..")).toEqual(1)
20
+ expect(alerts.delayedDispose).toHaveBeenCalledWith(1)
21
+
22
+ expect(alerts.push("error", "Test error..")).toEqual(2)
23
+ expect(alerts.delayedDispose).toHaveBeenCalledWith(2)
24
+
25
+ describe "#info", ->
26
+ it "pushesh the given message", inject (alerts) ->
27
+ # Given
28
+ testMessage = "This is a test message!"
29
+ otherTestMessage = "This is a second test message!"
30
+
31
+ # When
32
+ alerts.info(testMessage)
33
+ expect(alerts.delayedDispose).toHaveBeenCalledWith(1)
34
+
35
+ alerts.info(otherTestMessage)
36
+ expect(alerts.delayedDispose).toHaveBeenCalledWith(2)
37
+
38
+ # Then
39
+ expect(alerts.messages).toContain(id: 1, type: "info", text: testMessage)
40
+ expect(alerts.messages).toContain(id: 2, type: "info", text: otherTestMessage)
41
+
42
+ describe "#error", ->
43
+ it "pushesh the given message", inject (alerts) ->
44
+ # Given
45
+ testMessage = "This is a test message!"
46
+
47
+ # When
48
+ alerts.error(testMessage)
49
+ expect(alerts.delayedDispose).toHaveBeenCalledWith(1)
50
+
51
+ # Then
52
+ expect(alerts.messages).toContain(id: 1, type: "error", text: testMessage)
53
+
54
+ describe "#dispose", ->
55
+ it "removes a message with the given id", inject (alerts) ->
56
+ # Given
57
+ alerts.info("First message")
58
+ alerts.info("Second message")
59
+ alerts.info("Third message")
60
+ alerts.error("Error message")
61
+
62
+ # When
63
+ alerts.dispose(2)
64
+
65
+ # Then
66
+ expect(alerts.messages).toContain(id: 1, type: "info", text: "First message")
67
+ expect(alerts.messages).not.toContain(id: 2, type: "info", text: "Second message")
68
+ expect(alerts.messages).toContain(id: 3, type: "info", text: "Third message")
69
+ expect(alerts.messages).toContain(id: 4, type: "error", text: "Error message")
70
+
71
+ describe "#delayedDispose", ->
72
+ it "removes a message after the given time", inject (alerts, $timeout) ->
73
+ # Given
74
+ alerts.info("First message")
75
+
76
+ # When
77
+ alerts.delayedDispose(1)
78
+ expect(alerts.messages).toContain(id: 1, type: "info", text: "First message")
79
+
80
+ $timeout.flush()
81
+
82
+ # Then
83
+ expect(alerts.messages).toEqual([])
@@ -0,0 +1,19 @@
1
+ basePath = "../../../";
2
+
3
+ files = [
4
+ ANGULAR_SCENARIO,
5
+ ANGULAR_SCENARIO_ADAPTER,
6
+ "spec/javascripts/helpers_e2e/**/*.js.coffee",
7
+ "spec/javascripts/e2e/**/*.js.coffee"
8
+ ];
9
+
10
+ reporters = ["dots"];
11
+ browsers = ["PhantomJS"];
12
+
13
+ autoWatch = false;
14
+ singleRun = true;
15
+
16
+ urlRoot = '/__testacular/';
17
+ proxies = {
18
+ "/": "http://localhost:3001/"
19
+ };
@@ -0,0 +1,43 @@
1
+ basePath = "../../../";
2
+
3
+ files = [
4
+ JASMINE,
5
+ JASMINE_ADAPTER,
6
+
7
+ // Libraries
8
+ "vendor/assets/javascripts/jquery.js",
9
+ "vendor/assets/javascripts/angular/angular.js",
10
+ "vendor/assets/javascripts/angular/angular-resource.js",
11
+ "vendor/assets/javascripts/angular/angular-sanitize.js",
12
+ "vendor/assets/javascripts/angular/angular-bootstrap.js",
13
+ "vendor/assets/javascripts/*.js",
14
+
15
+ // The app
16
+ "app/assets/javascripts/app/controllers.js.coffee",
17
+ "app/assets/javascripts/app/**/*.js.coffee",
18
+ "app/assets/javascripts/application.js.coffee",
19
+
20
+ // Specs
21
+ "spec/javascripts/lib/angular-mocks.js",
22
+
23
+ "spec/javascripts/helpers/**/*.js.coffee",
24
+ "spec/javascripts/**/*_spec.js.coffee",
25
+ "spec/javascripts/**/*_spec.js.coffee",
26
+
27
+ // Templates
28
+ "app/assets/javascripts/templates/*.html.js"
29
+ ];
30
+
31
+ preprocessors = {
32
+ "**/*.js.coffee": "coffee",
33
+ "**/*.html": "html2js"
34
+ };
35
+
36
+ // Test results reporter to use
37
+ // possible values: dots || progress
38
+ reporters = ["dots"];
39
+
40
+ browsers = ["PhantomJS"];
41
+
42
+ autoWatch = true;
43
+ singleRun = false;
@@ -0,0 +1,49 @@
1
+ describe "collections 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
+
8
+ it "navigates to the valid url", ->
9
+ expect(browser().location().url()).toBe("/databases/first_database/collections")
10
+
11
+ it "displays a valid section title", ->
12
+ title = element("h2").text()
13
+ expect(title).toEqual("first_database collections")
14
+
15
+ it "displays available collections ordered by name", ->
16
+ expect(repeater("table.collections tbody tr").column("collection.name"))
17
+ .toEqual(["first_collection", "second_collection", "system.indexes", "third_collection"])
18
+
19
+ it "filters the collections list", ->
20
+ input("value").enter("")
21
+ expect(repeater("table.collections tbody tr").count()).toBe(4)
22
+ expect(repeater("table.collections tbody tr").column("collection.name"))
23
+ .toEqual(["first_collection", "second_collection", "system.indexes", "third_collection"])
24
+
25
+ input("value").enter("first")
26
+ expect(repeater("table.collections tbody tr").count()).toBe(1)
27
+ expect(repeater("table.collections tbody tr").column("collection.name"))
28
+ .toEqual(["first_collection"])
29
+
30
+ input("value").enter("second")
31
+ expect(repeater("table.collections tbody tr").count()).toBe(1)
32
+ expect(repeater("table.collections tbody tr").column("collection.name"))
33
+ .toEqual(["second_collection"])
34
+
35
+ input("value").enter("collection")
36
+ expect(repeater("table.collections tbody tr").count()).toBe(3)
37
+ expect(repeater("table.collections tbody tr").column("collection.name"))
38
+ .toEqual(["first_collection", "second_collection", "third_collection"])
39
+
40
+ input("value").enter("not existing")
41
+ expect(repeater("table.collections tbody tr").count()).toBe(0)
42
+ expect(element(".filter.alert:visible").text()).toMatch(/Nothing has been found./)
43
+
44
+ element("button:contains('Clear')").click()
45
+ expect(repeater("table.collections tbody tr").count()).toBe(4)
46
+
47
+ it "displays a tab with database stats", ->
48
+ element(".tabbable a:contains('Database stats')").click()
49
+ expect(repeater("table tbody tr").count()).toBeGreaterThan(0)
@@ -0,0 +1,74 @@
1
+ describe "databases list page", ->
2
+ beforeEach ->
3
+ browser().navigateTo("/e2e/load_fixtures")
4
+ browser().navigateTo("/")
5
+
6
+ it "navigates to the valid url", ->
7
+ expect(browser().location().url()).toBe("/")
8
+
9
+ it "displays a valid section title", ->
10
+ title = element("h2").text()
11
+ expect(title).toEqual("localhost databases")
12
+
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
+ describe "filtering by database name", ->
18
+ it "displays all databases when the filter is not provided", ->
19
+ 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"])
23
+
24
+ it "filters by database name", ->
25
+ 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"])
29
+
30
+ 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"])
34
+
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./)
38
+
39
+ it "displays all records when the filter is cleared", ->
40
+ 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"])
44
+
45
+ describe "delete a database", ->
46
+ 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?")
49
+
50
+ describe "when the dialog was disposed", ->
51
+ beforeEach ->
52
+ appElement "div.modal .modal-footer a:contains('Cancel')", ($element) ->
53
+ $element.click()
54
+
55
+ 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"])
59
+
60
+ describe "when the dialog was confirmed", ->
61
+ beforeEach ->
62
+ appElement "div.bootbox a:contains('OK')", ($element) ->
63
+ $element.click()
64
+
65
+ # TODO figure out how to test it
66
+ xit "shows the alert", ->
67
+ expect(repeater("aside#alerts .alert").count()).toBe(1)
68
+ expect(repeater("aside#alerts .alert").column("message.text"))
69
+ .toContain("Database third_database has been deleted.")
70
+
71
+ 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"])
@@ -0,0 +1,18 @@
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
+
9
+ it "shows the documents page", ->
10
+ expect(browser().location().url())
11
+ .toBe("/databases/first_database/collections/first_collection/documents")
12
+
13
+ title = element("h2").text()
14
+ expect(title).toEqual("first_collection documents")
15
+
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)
@@ -0,0 +1,12 @@
1
+ describe "server info page", ->
2
+ beforeEach ->
3
+ browser().navigateTo("/")
4
+ element("a:contains('Server Info')").click()
5
+
6
+ it "displays details about the server", ->
7
+ expect(browser().location().url()).toBe("/server_info")
8
+
9
+ title = element("h2").text()
10
+ expect(title).toEqual("server info")
11
+
12
+ expect(repeater("table tbody tr").count()).toBeGreaterThan(0)
@@ -0,0 +1,5 @@
1
+ beforeEach ->
2
+ @addMatchers
3
+ toHaveCssClass: (klass) ->
4
+ @message = -> "Expected '#{angular.mock.dump(@actual)}' to have class '#{klass}'"
5
+ @actual.hasClass(klass)
@@ -0,0 +1,7 @@
1
+ # Create a mock for dialogsHandler
2
+ angular.module("mocks", []).config ($provide) ->
3
+ $provide.factory "dialogsHandler", ->
4
+ confirm: (message, callback) ->
5
+ @callback = callback
6
+ confirmed: -> @callback(true)
7
+ disposed: -> @callback(false)
@@ -0,0 +1,6 @@
1
+ # Access to iframe's jQuery, see: https://gist.github.com/1700488
2
+ angular.scenario.dsl "appElement", ->
3
+ (selector, fn) ->
4
+ @addFutureAction "element " + selector, ($window, $document, done) ->
5
+ fn.call this, $window.angular.element(selector)
6
+ done()