ditty 0.8.0 → 0.10.2

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