mongo_browser 0.1.3 → 0.2.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
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()