ditty 0.8.0 → 0.10.2

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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/.env.test +2 -0
  3. data/.gitignore +3 -0
  4. data/.pryrc +2 -0
  5. data/.rubocop.yml +23 -4
  6. data/.travis.yml +4 -8
  7. data/CNAME +1 -0
  8. data/Dockerfile +18 -0
  9. data/Gemfile.ci +0 -17
  10. data/Rakefile +2 -2
  11. data/_config.yml +1 -0
  12. data/config.ru +4 -4
  13. data/ditty.gemspec +28 -18
  14. data/docs/CNAME +1 -0
  15. data/docs/_config.yml +1 -0
  16. data/docs/index.md +34 -0
  17. data/exe/ditty +2 -0
  18. data/lib/ditty/cli.rb +41 -5
  19. data/lib/ditty/components/{app.rb → ditty.rb} +18 -16
  20. data/lib/ditty/controllers/{application.rb → application_controller.rb} +63 -34
  21. data/lib/ditty/controllers/{audit_logs.rb → audit_logs_controller.rb} +4 -2
  22. data/lib/ditty/controllers/{auth.rb → auth_controller.rb} +22 -18
  23. data/lib/ditty/controllers/{component.rb → component_controller.rb} +23 -20
  24. data/lib/ditty/controllers/{main.rb → main_controller.rb} +6 -2
  25. data/lib/ditty/controllers/roles_controller.rb +23 -0
  26. data/lib/ditty/controllers/user_login_traits_controller.rb +46 -0
  27. data/lib/ditty/controllers/{users.rb → users_controller.rb} +13 -11
  28. data/lib/ditty/db.rb +7 -5
  29. data/lib/ditty/emails/base.rb +37 -32
  30. data/lib/ditty/generators/crud_generator.rb +114 -0
  31. data/lib/ditty/generators/migration_generator.rb +26 -0
  32. data/lib/ditty/generators/project_generator.rb +52 -0
  33. data/lib/ditty/helpers/component.rb +2 -1
  34. data/lib/ditty/helpers/pundit.rb +24 -8
  35. data/lib/ditty/helpers/response.rb +15 -13
  36. data/lib/ditty/helpers/views.rb +28 -6
  37. data/lib/ditty/listener.rb +6 -4
  38. data/lib/ditty/memcached.rb +8 -0
  39. data/lib/ditty/middleware/accept_extension.rb +2 -2
  40. data/lib/ditty/middleware/error_catchall.rb +2 -2
  41. data/lib/ditty/models/base.rb +9 -0
  42. data/lib/ditty/models/identity.rb +11 -7
  43. data/lib/ditty/models/role.rb +1 -0
  44. data/lib/ditty/models/user.rb +23 -2
  45. data/lib/ditty/policies/role_policy.rb +1 -1
  46. data/lib/ditty/policies/user_login_trait_policy.rb +1 -1
  47. data/lib/ditty/policies/user_policy.rb +1 -1
  48. data/lib/ditty/services/authentication.rb +27 -16
  49. data/lib/ditty/services/email.rb +19 -15
  50. data/lib/ditty/services/logger.rb +26 -20
  51. data/lib/ditty/services/pagination_wrapper.rb +7 -5
  52. data/lib/ditty/services/settings.rb +7 -6
  53. data/lib/ditty/tasks/ditty.rake +19 -1
  54. data/lib/ditty/tasks/omniauth-ldap.rake +2 -2
  55. data/lib/ditty/templates/.gitignore +5 -0
  56. data/lib/ditty/templates/.rspec +2 -0
  57. data/lib/ditty/templates/.rubocop.yml +7 -0
  58. data/lib/ditty/templates/Rakefile +12 -0
  59. data/lib/ditty/templates/application.rb +12 -0
  60. data/lib/ditty/templates/config.ru +37 -0
  61. data/lib/ditty/templates/controller.rb.erb +64 -0
  62. data/lib/ditty/templates/env.example +4 -0
  63. data/lib/ditty/templates/lib/project.rb.erb +5 -0
  64. data/lib/ditty/templates/logs/.empty_directory +0 -0
  65. data/lib/ditty/templates/migration.rb.erb +7 -0
  66. data/lib/ditty/templates/model.rb.erb +26 -0
  67. data/lib/ditty/templates/pids/.empty_directory +0 -0
  68. data/lib/ditty/templates/policy.rb.erb +48 -0
  69. data/{public → lib/ditty/templates/public}/browserconfig.xml +0 -0
  70. data/lib/ditty/templates/public/css/sb-admin-2.min.css +10 -0
  71. data/lib/ditty/templates/public/css/styles.css +13 -0
  72. data/lib/ditty/templates/public/favicon.ico +0 -0
  73. data/{public → lib/ditty/templates/public}/images/apple-icon.png +0 -0
  74. data/{public → lib/ditty/templates/public}/images/favicon-16x16.png +0 -0
  75. data/{public → lib/ditty/templates/public}/images/favicon-32x32.png +0 -0
  76. data/{public → lib/ditty/templates/public}/images/launcher-icon-1x.png +0 -0
  77. data/{public → lib/ditty/templates/public}/images/launcher-icon-2x.png +0 -0
  78. data/{public → lib/ditty/templates/public}/images/launcher-icon-4x.png +0 -0
  79. data/{public → lib/ditty/templates/public}/images/mstile-150x150.png +0 -0
  80. data/{public → lib/ditty/templates/public}/images/safari-pinned-tab.svg +0 -0
  81. data/lib/ditty/templates/public/js/sb-admin-2.min.js +7 -0
  82. data/lib/ditty/templates/public/js/scripts.js +1 -0
  83. data/{public/manifest.json → lib/ditty/templates/public/manifest.json.erb} +2 -2
  84. data/lib/ditty/templates/settings.yml.erb +29 -0
  85. data/lib/ditty/templates/sidekiq.rb +18 -0
  86. data/lib/ditty/templates/sidekiq.yml +9 -0
  87. data/lib/ditty/templates/spec_helper.rb +43 -0
  88. data/lib/ditty/templates/type.rb.erb +21 -0
  89. data/lib/ditty/templates/views/display.haml.tt +20 -0
  90. data/lib/ditty/templates/views/edit.haml.tt +10 -0
  91. data/lib/ditty/templates/views/form.haml.tt +11 -0
  92. data/lib/ditty/templates/views/index.haml.tt +29 -0
  93. data/lib/ditty/templates/views/new.haml.tt +10 -0
  94. data/lib/ditty/version.rb +1 -1
  95. data/lib/ditty.rb +6 -4
  96. data/lib/rubocop/cop/ditty/call_services_directly.rb +2 -2
  97. data/migrate/20181209_add_user_login_traits.rb +4 -4
  98. data/migrate/20190220_add_parent_id_to_roles.rb +9 -0
  99. data/spec/ditty/api_spec.rb +51 -0
  100. data/spec/ditty/controllers/roles_spec.rb +67 -0
  101. data/spec/ditty/controllers/user_login_traits_spec.rb +72 -0
  102. data/spec/ditty/controllers/users_spec.rb +72 -0
  103. data/spec/ditty/emails/base_spec.rb +76 -0
  104. data/spec/ditty/emails/forgot_password_spec.rb +20 -0
  105. data/spec/ditty/helpers/component_spec.rb +85 -0
  106. data/spec/ditty/models/user_spec.rb +36 -0
  107. data/spec/ditty/services/email_spec.rb +36 -0
  108. data/spec/ditty/services/logger_spec.rb +68 -0
  109. data/spec/ditty/services/settings_spec.rb +63 -0
  110. data/spec/ditty_spec.rb +9 -0
  111. data/spec/factories.rb +46 -0
  112. data/spec/fixtures/logger.yml +17 -0
  113. data/spec/fixtures/section.yml +3 -0
  114. data/spec/fixtures/settings.yml +8 -0
  115. data/spec/spec_helper.rb +51 -0
  116. data/spec/support/api_shared_examples.rb +250 -0
  117. data/spec/support/crud_shared_examples.rb +145 -0
  118. data/views/403.haml +1 -1
  119. data/views/404.haml +2 -4
  120. data/views/500.haml +11 -0
  121. data/views/audit_logs/index.haml +32 -33
  122. data/views/auth/forgot_password.haml +32 -16
  123. data/views/auth/identity.haml +14 -13
  124. data/views/auth/ldap.haml +2 -2
  125. data/views/auth/login.haml +23 -17
  126. data/views/auth/register.haml +20 -18
  127. data/views/auth/register_identity.haml +27 -12
  128. data/views/auth/reset_password.haml +36 -19
  129. data/views/blank.haml +43 -0
  130. data/views/embedded.haml +17 -11
  131. data/views/index.haml +1 -1
  132. data/views/layout.haml +45 -30
  133. data/views/partials/actions.haml +15 -14
  134. data/views/partials/content_tag.haml +0 -0
  135. data/views/partials/delete_form.haml +1 -1
  136. data/views/partials/filter_control.haml +2 -2
  137. data/views/partials/footer.haml +6 -5
  138. data/views/partials/form_control.haml +19 -12
  139. data/views/partials/form_tag.haml +1 -1
  140. data/views/partials/navitems.haml +42 -0
  141. data/views/partials/notifications.haml +12 -8
  142. data/views/partials/pager.haml +44 -25
  143. data/views/partials/search.haml +15 -11
  144. data/views/partials/sidebar.haml +15 -37
  145. data/views/partials/sort_ui.haml +2 -0
  146. data/views/partials/topbar.haml +53 -0
  147. data/views/partials/user_associations.haml +32 -0
  148. data/views/quick_start.haml +23 -0
  149. data/views/roles/display.haml +27 -6
  150. data/views/roles/edit.haml +3 -3
  151. data/views/roles/form.haml +1 -0
  152. data/views/roles/index.haml +23 -16
  153. data/views/roles/new.haml +2 -2
  154. data/views/user_login_traits/display.haml +4 -4
  155. data/views/user_login_traits/edit.haml +3 -3
  156. data/views/user_login_traits/index.haml +23 -25
  157. data/views/user_login_traits/new.haml +2 -2
  158. data/views/users/display.haml +14 -15
  159. data/views/users/edit.haml +3 -3
  160. data/views/users/form.haml +0 -0
  161. data/views/users/index.haml +31 -24
  162. data/views/users/login_traits.haml +6 -8
  163. data/views/users/new.haml +2 -2
  164. data/views/users/profile.haml +15 -15
  165. data/views/users/user.haml +1 -1
  166. metadata +271 -63
  167. data/lib/ditty/controllers/roles.rb +0 -13
  168. data/lib/ditty/controllers/user_login_traits.rb +0 -18
  169. data/views/partials/navbar.haml +0 -22
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'ditty/emails/forgot_password'
5
+ require 'mail'
6
+
7
+ describe ::Ditty::Emails::ForgotPassword do
8
+ let(:mail) do
9
+ mail = Mail.new
10
+ allow(mail).to receive(:deliver!)
11
+ mail
12
+ end
13
+
14
+ describe '.new' do
15
+ it 'defaults to base options' do
16
+ expect(subject.options).to include subject: 'Request to reset password', from: 'no-reply@ditty.io',
17
+ view: :forgot_password
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'ditty/controllers/component_controller'
5
+ require 'ditty/helpers/component'
6
+ require 'ditty/models/user'
7
+
8
+ class DummyComponentController < ::Ditty::ComponentController
9
+ set model_class: Ditty::User
10
+
11
+ FILTERS = [{ name: :email }].freeze
12
+ SEARCHABLE = %i[name email].freeze
13
+ end
14
+
15
+ describe ::Ditty::Helpers::Component do
16
+ def app
17
+ DummyComponentController
18
+ end
19
+
20
+ let(:user) { create(:super_admin_user) }
21
+ let(:model) { create(app.model_class.name.to_sym) }
22
+ let(:create_data) do
23
+ group = described_class.model_class.to_s.demodulize.underscore
24
+ identity = build(:identity).to_hash
25
+ identity['password_confirmation'] = identity['password'] = 'som3Password!'
26
+ {
27
+ group => build(described_class.model_class.name.to_sym).to_hash,
28
+ 'identity' => identity
29
+ }
30
+ end
31
+ let(:update_data) do
32
+ group = described_class.model_class.to_s.demodulize.underscore
33
+ { group => build(described_class.model_class.name.to_sym).to_hash }
34
+ end
35
+ let(:invalid_create_data) do
36
+ group = described_class.model_class.to_s.demodulize.underscore
37
+ { group => { email: 'invalidemail' } }
38
+ end
39
+ let(:invalid_update_data) do
40
+ group = described_class.model_class.to_s.demodulize.underscore
41
+ { group => { email: 'invalidemail' } }
42
+ end
43
+
44
+ before do
45
+ env 'rack.session', 'user_id' => user.id
46
+ create(:user, email: 'bruce@wayne.com')
47
+ create(:user, email: 'tony@stark.com')
48
+ end
49
+
50
+ describe 'filters' do
51
+ it 'returns the matching items' do
52
+ header 'Accept', 'application/json'
53
+ get '/', email: 'bruce@wayne.com'
54
+
55
+ response = JSON.parse last_response.body
56
+ expect(response['count']).to eq(1)
57
+ end
58
+
59
+ it 'returns no items' do
60
+ header 'Accept', 'application/json'
61
+ get '/', email: 'not found'
62
+
63
+ response = JSON.parse last_response.body
64
+ expect(response['count']).to eq(0)
65
+ end
66
+ end
67
+
68
+ describe 'search' do
69
+ it 'returns the matching items' do
70
+ header 'Accept', 'application/json'
71
+ get '/', q: 'wayne'
72
+
73
+ response = JSON.parse last_response.body
74
+ expect(response['count']).to eq(1)
75
+ end
76
+
77
+ it 'returns no items' do
78
+ header 'Accept', 'application/json'
79
+ get '/', q: 'not found'
80
+
81
+ response = JSON.parse last_response.body
82
+ expect(response['count']).to eq(0)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'ditty/models/user'
5
+
6
+ describe ::Ditty::User, type: :model do
7
+ let(:super_admin_role) { create(:role, name: 'super_admin') }
8
+ let(:admin_role) { create(:role, name: 'admin', parent_id: super_admin_role.id) }
9
+ let!(:user_role) { create(:role, name: 'user', parent_id: admin_role.id) }
10
+ let(:super_admin) { create(:user) }
11
+ let(:user) { create(:user) }
12
+
13
+ before { super_admin.add_role(super_admin_role) }
14
+
15
+ describe '#role?(check)' do
16
+ context 'when a user has a role without a parent' do
17
+ it 'returns true only for specific role' do
18
+ expect(user).to be_role('user')
19
+ end
20
+
21
+ it 'returns false for other roles' do
22
+ %w[admin super_admin].each do |role|
23
+ expect(user).not_to be_role(role)
24
+ end
25
+ end
26
+ end
27
+
28
+ context 'when a user has a role with descendants' do
29
+ it 'returns true for all descendants' do
30
+ %w[user admin super_admin].each do |role|
31
+ expect(super_admin).to be_role(role)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'ditty/services/email'
5
+
6
+ describe ::Ditty::Services::Email do
7
+ after do
8
+ described_class.config = nil
9
+ end
10
+
11
+ context 'config!' do
12
+ it 'configures the Mail gem' do
13
+ expect(Mail).to receive(:defaults)
14
+ described_class.config!
15
+ end
16
+
17
+ it 'uses the default settings' do
18
+ expect(described_class).to receive(:default).and_call_original
19
+ described_class.config!
20
+ end
21
+ end
22
+
23
+ context 'deliver!' do
24
+ it 'autoloads a ditty email from a symbol' do
25
+ mail = Mail.new
26
+ expect(mail).to receive(:deliver!)
27
+ described_class.deliver(:base, 'test@mail.com', locals: { content: 'content' }, mail: mail)
28
+ end
29
+
30
+ it 'sends a mail object' do
31
+ mail = Mail.new
32
+ expect(mail).to receive(:deliver!)
33
+ described_class.deliver(mail)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+ require 'spec_helper'
5
+ require 'ditty/services/logger'
6
+
7
+ class TestLogger
8
+ WARN = 2
9
+ attr_accessor :level
10
+
11
+ def initialize(options = {})
12
+ @options = options
13
+ end
14
+ end
15
+
16
+ describe ::Ditty::Services::Logger, type: :service do
17
+ let(:subject) { described_class.clone }
18
+ let(:config_file) { File.read('./spec/fixtures/logger.yml') }
19
+
20
+ context 'initialize' do
21
+ it '.instance always refers to the same instance' do
22
+ expect(subject.instance).to eq subject.instance
23
+ end
24
+
25
+ it "creates default logger if config file does't exist" do
26
+ expect(subject.instance.loggers[0]).to be_instance_of Logger
27
+ end
28
+
29
+ it 'reads config from file and creates an array of loggers' do
30
+ ::Ditty::Services::Settings.values = nil
31
+ allow(File).to receive(:file?).and_return(false)
32
+ allow(File).to receive(:file?).with('./config/logger.yml').and_return(true)
33
+ allow(File).to receive(:read).and_return(config_file)
34
+
35
+ expect(subject.instance.loggers.size).to eq 4
36
+ expect(subject.instance.loggers[0]).to be_instance_of Logger
37
+ expect(subject.instance.loggers[1]).to be_instance_of TestLogger
38
+ end
39
+
40
+ it 'sets the correct logging level' do
41
+ ::Ditty::Services::Settings.values = nil
42
+ allow(File).to receive(:file?).and_return(false)
43
+ allow(File).to receive(:file?).with('./config/logger.yml').and_return(true)
44
+ allow(File).to receive(:read).and_return(config_file)
45
+ expect(subject.instance.loggers[0].level).to eq Logger::DEBUG
46
+ expect(subject.instance.loggers[2].level).to eq Logger::INFO
47
+ expect(subject.instance.loggers[3].level).to eq Logger::WARN
48
+ end
49
+ end
50
+
51
+ context 'send messages' do
52
+ it 'receives message and passes it to the loggers' do
53
+ ::Ditty::Services::Settings.values = nil
54
+ allow(File).to receive(:file?).and_return(false)
55
+ allow(File).to receive(:file?).with('./config/logger.yml').and_return(true)
56
+ allow(File).to receive(:read).and_return(config_file)
57
+ allow(Logger).to receive(:warn).with('Some message')
58
+ allow(TestLogger).to receive(:warn).with('Some message')
59
+
60
+ expect(subject.instance.loggers[0]).to receive(:warn).with('Some message')
61
+ expect(subject.instance.loggers[1]).to receive(:warn).with('Some message')
62
+ expect($stdout).to receive(:write).with(/Some message$/)
63
+ expect($stderr).to receive(:write).with(/Some message$/)
64
+
65
+ subject.instance.warn 'Some message'
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'ditty/services/settings'
5
+
6
+ describe ::Ditty::Services::Settings do
7
+ def setup_files
8
+ settings = File.read('./spec/fixtures/settings.yml')
9
+ section = File.read('./spec/fixtures/section.yml')
10
+
11
+ allow(File).to receive(:file?).and_return(false)
12
+ allow(File).to receive(:file?).with('./config/settings.yml').and_return(true)
13
+ allow(File).to receive(:file?).with('./config/section.yml').and_return(true)
14
+
15
+ allow(File).to receive(:read).with('./config/settings.yml').and_return(settings)
16
+ allow(File).to receive(:read).with('./config/section.yml').and_return(section)
17
+ end
18
+
19
+ describe '#[]' do
20
+ before do
21
+ setup_files
22
+ described_class.values = nil
23
+ end
24
+
25
+ it 'returns the specified values from the global settings' do
26
+ expect(described_class[:option_a]).to eq 1
27
+ end
28
+
29
+ it 'allows access to sectional settings' do
30
+ expect(described_class[:no_file_section]).to include(section_1: 2, section_2: 'set')
31
+ end
32
+
33
+ it 'allows using dots to travers' do
34
+ expect(described_class['nested.option']).to eq 'value'
35
+ end
36
+ end
37
+
38
+ describe '#values' do
39
+ context 'uses the global file' do
40
+ before do
41
+ setup_files
42
+ end
43
+
44
+ it 'to return global settings' do
45
+ expect(described_class.values).to include(option_a: 1, option_b: 'value')
46
+ end
47
+
48
+ it 'to return sectional settings' do
49
+ expect(described_class.values(:no_file_section)).to include(section_1: 2, section_2: 'set')
50
+ end
51
+ end
52
+
53
+ context 'uses the sectional file' do
54
+ before do
55
+ setup_files
56
+ end
57
+
58
+ it 'prefers the sectional settings file' do
59
+ expect(described_class.values(:section)).to include(section_1: 3, section_2: 'section')
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ::Ditty do
6
+ it 'has a version number' do
7
+ expect(Ditty::VERSION).not_to be nil
8
+ end
9
+ end
data/spec/factories.rb ADDED
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faker'
4
+ require 'ditty/models/user'
5
+ require 'ditty/models/identity'
6
+ require 'ditty/models/role'
7
+ require 'ditty/models/user_login_trait'
8
+
9
+ FactoryBot.define do
10
+ to_create(&:save)
11
+
12
+ sequence(:email) { |n| "person-#{n}@example.com" }
13
+ sequence(:name) { |n| "Name-#{n}" }
14
+
15
+ factory :user, class: 'Ditty::User', aliases: [:'Ditty::User'] do
16
+ email
17
+
18
+ after(:create) do |user, _evaluator|
19
+ create(:identity, user: user)
20
+ end
21
+
22
+ factory :super_admin_user do
23
+ after(:create) do |user, _evaluator|
24
+ user.add_role(Ditty::Role.find_or_create(name: 'super_admin'))
25
+ end
26
+ end
27
+ end
28
+
29
+ factory :identity, class: 'Ditty::Identity', aliases: [:'Ditty::Identity'] do
30
+ username { generate :email }
31
+ crypted_password { 'som3Password!' }
32
+ end
33
+
34
+ factory :role, class: 'Ditty::Role', aliases: [:'Ditty::Role'] do
35
+ name { "Role #{generate(:name)}" }
36
+ parent_id { nil }
37
+ end
38
+
39
+ factory :user_login_trait, class: 'Ditty::UserLoginTrait', aliases: [:'Ditty::UserLoginTrait'] do
40
+ association :user, strategy: :create, factory: :user
41
+ ip_address { Faker::Internet.ip_v4_address }
42
+ platform { Faker::Device.platform }
43
+ device { Faker::Device.model_name }
44
+ browser { 'Firefox' }
45
+ end
46
+ end
@@ -0,0 +1,17 @@
1
+ loggers:
2
+ - name: file
3
+ class: Logger
4
+ level: 'DEBUG'
5
+ - name: ES
6
+ class: TestLogger
7
+ options:
8
+ url: 'http://logging.ditty.io:9200'
9
+ log: false
10
+ - name: stdout
11
+ class: Logger
12
+ options: '$stdout'
13
+ level: INFO
14
+ - name: stderr
15
+ class: Logger
16
+ options: '$stderr'
17
+ level: WARN
@@ -0,0 +1,3 @@
1
+ ---
2
+ section_1: 3
3
+ section_2: section
@@ -0,0 +1,8 @@
1
+ ---
2
+ option_a: 1
3
+ option_b: value
4
+ no_file_section:
5
+ section_1: 2
6
+ section_2: set
7
+ nested:
8
+ option: value
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dotenv'
4
+ Dotenv.load('.env.test')
5
+ Dotenv.overload('.env.test.local')
6
+
7
+ ENV['APP_ENV'] ||= 'test'
8
+ ENV['RACK_ENV'] ||= 'test'
9
+ require 'simplecov'
10
+ SimpleCov.start
11
+
12
+ ENV['DATABASE_URL'] ||= 'sqlite::memory:'
13
+
14
+ require 'ditty'
15
+ require 'ditty/db'
16
+ require 'rspec'
17
+ require 'rack/test'
18
+ require 'factory_bot'
19
+ require 'database_cleaner'
20
+ require 'timecop'
21
+
22
+ if ENV['DATABASE_URL'] == 'sqlite::memory:'
23
+ folder = File.expand_path("#{File.dirname(__FILE__)}/../migrate")
24
+ Sequel.extension :migration
25
+ Sequel::Migrator.apply(DB, folder)
26
+
27
+ # Seed the DB
28
+ require 'ditty/seed'
29
+ end
30
+
31
+ Ditty.component :ditty
32
+ RSpec.configure do |config|
33
+ config.include Rack::Test::Methods
34
+ config.include FactoryBot::Syntax::Methods
35
+
36
+ config.alias_example_to :fit, focus: true
37
+ config.filter_run focus: true
38
+ config.run_all_when_everything_filtered = true
39
+
40
+ config.before(:suite) do
41
+ DatabaseCleaner.strategy = :transaction
42
+ FactoryBot.find_definitions
43
+ Timecop.freeze
44
+ end
45
+
46
+ config.around do |example|
47
+ DatabaseCleaner.cleaning do
48
+ example.run
49
+ end
50
+ end
51
+ end