rolemodel-rails 0.26.0
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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +161 -0
- data/Rakefile +6 -0
- data/lib/generators/rolemodel/README.md +29 -0
- data/lib/generators/rolemodel/USAGE +5 -0
- data/lib/generators/rolemodel/all_generator.rb +29 -0
- data/lib/generators/rolemodel/base_generator.rb +14 -0
- data/lib/generators/rolemodel/editors/README.md +9 -0
- data/lib/generators/rolemodel/editors/USAGE +9 -0
- data/lib/generators/rolemodel/editors/editors_generator.rb +30 -0
- data/lib/generators/rolemodel/editors/vscode_helpers.rb +22 -0
- data/lib/generators/rolemodel/github/README.md +23 -0
- data/lib/generators/rolemodel/github/USAGE +9 -0
- data/lib/generators/rolemodel/github/github_generator.rb +43 -0
- data/lib/generators/rolemodel/good_job/README.md +13 -0
- data/lib/generators/rolemodel/good_job/USAGE +5 -0
- data/lib/generators/rolemodel/good_job/good_job_generator.rb +73 -0
- data/lib/generators/rolemodel/good_job/templates/config/initializers/active_job.rb +17 -0
- data/lib/generators/rolemodel/good_job/templates/config/initializers/good_job.rb +24 -0
- data/lib/generators/rolemodel/heroku/README.md +8 -0
- data/lib/generators/rolemodel/heroku/USAGE +9 -0
- data/lib/generators/rolemodel/heroku/heroku_generator.rb +52 -0
- data/lib/generators/rolemodel/heroku/templates/Procfile +2 -0
- data/lib/generators/rolemodel/heroku/templates/app.json.tt +30 -0
- data/lib/generators/rolemodel/kaminari/README.md +14 -0
- data/lib/generators/rolemodel/kaminari/USAGE +5 -0
- data/lib/generators/rolemodel/kaminari/kaminari_generator.rb +17 -0
- data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_first_page.html.slim +9 -0
- data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_gap.html.slim +8 -0
- data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_last_page.html.slim +9 -0
- data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_next_page.html.slim +12 -0
- data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_page.html.slim +10 -0
- data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_paginator.html.slim +19 -0
- data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_prev_page.html.slim +12 -0
- data/lib/generators/rolemodel/linters/README.md +32 -0
- data/lib/generators/rolemodel/linters/USAGE +5 -0
- data/lib/generators/rolemodel/linters/all_generator.rb +14 -0
- data/lib/generators/rolemodel/linters/eslint/README.md +5 -0
- data/lib/generators/rolemodel/linters/eslint/USAGE +8 -0
- data/lib/generators/rolemodel/linters/eslint/eslint_generator.rb +33 -0
- data/lib/generators/rolemodel/linters/eslint/templates/eslint.config.js +92 -0
- data/lib/generators/rolemodel/linters/rubocop/README.md +7 -0
- data/lib/generators/rolemodel/linters/rubocop/USAGE +9 -0
- data/lib/generators/rolemodel/linters/rubocop/rubocop_generator.rb +23 -0
- data/lib/generators/rolemodel/linters/rubocop/templates/lib/cops/form_error_response.rb +54 -0
- data/lib/generators/rolemodel/linters/rubocop/templates/lib/cops/no_chrome_tag.rb +45 -0
- data/lib/generators/rolemodel/lograge/README.md +10 -0
- data/lib/generators/rolemodel/lograge/USAGE +8 -0
- data/lib/generators/rolemodel/lograge/lograge_generator.rb +15 -0
- data/lib/generators/rolemodel/lograge/templates/config/initializers/lograge.rb +16 -0
- data/lib/generators/rolemodel/mailers/README.md +13 -0
- data/lib/generators/rolemodel/mailers/USAGE +22 -0
- data/lib/generators/rolemodel/mailers/mailers_generator.rb +99 -0
- data/lib/generators/rolemodel/mailers/templates/app/assets/stylesheets/mailer.scss +61 -0
- data/lib/generators/rolemodel/mailers/templates/app/mailers/example_mailer.rb +8 -0
- data/lib/generators/rolemodel/mailers/templates/app/mailers/staging_mailer_interceptor.rb +9 -0
- data/lib/generators/rolemodel/mailers/templates/app/views/example_mailer/example_email.html.slim +16 -0
- data/lib/generators/rolemodel/mailers/templates/app/views/layouts/mailer.html.slim +16 -0
- data/lib/generators/rolemodel/mailers/templates/config/initializers/premailer_rails.rb +15 -0
- data/lib/generators/rolemodel/mailers/templates/public/logo.png +0 -0
- data/lib/generators/rolemodel/mailers/templates/spec/mailers/previews/example_mailer_preview.rb +6 -0
- data/lib/generators/rolemodel/optics/README.md +8 -0
- data/lib/generators/rolemodel/optics/USAGE +5 -0
- data/lib/generators/rolemodel/optics/all_generator.rb +12 -0
- data/lib/generators/rolemodel/optics/base/README.md +9 -0
- data/lib/generators/rolemodel/optics/base/USAGE +5 -0
- data/lib/generators/rolemodel/optics/base/base_generator.rb +21 -0
- data/lib/generators/rolemodel/optics/icons/README.md +7 -0
- data/lib/generators/rolemodel/optics/icons/USAGE +8 -0
- data/lib/generators/rolemodel/optics/icons/icons_generator.rb +48 -0
- data/lib/generators/rolemodel/optics/icons/templates/app/helpers/icon_helper.rb.tt +24 -0
- data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/custom_icon_builder.rb +53 -0
- data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/feather_icon_builder.rb +22 -0
- data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/icon_builder.rb +73 -0
- data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/lucide_icon_builder.rb +22 -0
- data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/material_icon_builder.rb +31 -0
- data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/phosphor_icon_builder.rb +27 -0
- data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/tabler_icon_builder.rb +22 -0
- data/lib/generators/rolemodel/react/README.md +12 -0
- data/lib/generators/rolemodel/react/USAGE +5 -0
- data/lib/generators/rolemodel/react/react_generator.rb +36 -0
- data/lib/generators/rolemodel/react/templates/app/helpers/react_helper.rb +11 -0
- data/lib/generators/rolemodel/react/templates/app/javascript/components/HelloReact.jsx +14 -0
- data/lib/generators/rolemodel/react/templates/app/javascript/controllers/react_controller.js +24 -0
- data/lib/generators/rolemodel/readme/README.md +9 -0
- data/lib/generators/rolemodel/readme/USAGE +8 -0
- data/lib/generators/rolemodel/readme/readme_generator.rb +11 -0
- data/lib/generators/rolemodel/readme/templates/README.md.erb +116 -0
- data/lib/generators/rolemodel/replace_content_helper.rb +29 -0
- data/lib/generators/rolemodel/saas/README.md +7 -0
- data/lib/generators/rolemodel/saas/USAGE +5 -0
- data/lib/generators/rolemodel/saas/all_generator.rb +15 -0
- data/lib/generators/rolemodel/saas/devise/README.md +24 -0
- data/lib/generators/rolemodel/saas/devise/USAGE +25 -0
- data/lib/generators/rolemodel/saas/devise/devise_generator.rb +172 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/assets/stylesheets/login.css +30 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/controllers/admin/users_controller.rb +34 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/controllers/application_controller.rb +11 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/controllers/users/invitations_controller.rb +77 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/controllers/users/omniauth_callbacks_controller.rb +30 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/controllers/users/registrations_controller.rb +80 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/admin/users/edit.html.slim +10 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/admin/users/index.html.slim +27 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/confirmations/new.html.slim +11 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/invitations/edit.html.slim +13 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/invitations/new.html.slim +14 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/confirmation_instructions.html.slim +3 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/email_changed.html.slim +5 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/invitation_instructions.html.slim +11 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/invitation_instructions.text.slim +6 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/password_change.html.slim +2 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/reset_password_instructions.html.slim +5 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/unlock_instructions.html.slim +4 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/passwords/edit.html.slim +13 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/passwords/new.html.slim +11 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/registrations/edit.html.slim +34 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/registrations/new.html.slim +17 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/sessions/new.html.slim +14 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/shared/_error_messages.html.slim +9 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/shared/_links.html.slim +14 -0
- data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/unlocks/new.html.slim +11 -0
- data/lib/generators/rolemodel/saas/devise/templates/config/locales/devise.en.yml +151 -0
- data/lib/generators/rolemodel/saas/devise/templates/config/locales/devise_invitable.en.yml +31 -0
- data/lib/generators/rolemodel/saas/devise/templates/spec/factories/organizations.rb +9 -0
- data/lib/generators/rolemodel/saas/devise/templates/spec/factories/users.rb +33 -0
- data/lib/generators/rolemodel/saas/devise/templates/spec/mailers/previews/devise_mailer_preview.rb +36 -0
- data/lib/generators/rolemodel/saas/devise/templates/spec/models/user_spec.rb +29 -0
- data/lib/generators/rolemodel/saas/devise/templates/spec/support/devise.rb +8 -0
- data/lib/generators/rolemodel/saas/devise/templates/spec/system/users_spec.rb +128 -0
- data/lib/generators/rolemodel/semaphore/README.md +15 -0
- data/lib/generators/rolemodel/semaphore/USAGE +11 -0
- data/lib/generators/rolemodel/semaphore/semaphore_generator.rb +25 -0
- data/lib/generators/rolemodel/semaphore/templates/heroku-deployment-commands.sh +3 -0
- data/lib/generators/rolemodel/semaphore/templates/production-deploy.yml.erb +17 -0
- data/lib/generators/rolemodel/semaphore/templates/semaphore.yml.erb +145 -0
- data/lib/generators/rolemodel/semaphore/templates/staging-deploy.yml.erb +17 -0
- data/lib/generators/rolemodel/simple_form/README.md +10 -0
- data/lib/generators/rolemodel/simple_form/USAGE +11 -0
- data/lib/generators/rolemodel/simple_form/simple_form_generator.rb +20 -0
- data/lib/generators/rolemodel/simple_form/templates/app/inputs/collection_check_boxes_input.rb +7 -0
- data/lib/generators/rolemodel/simple_form/templates/app/inputs/collection_select_input.rb +7 -0
- data/lib/generators/rolemodel/simple_form/templates/app/inputs/grouped_collection_select_input.rb +7 -0
- data/lib/generators/rolemodel/simple_form/templates/app/inputs/segmented_control_input.rb +48 -0
- data/lib/generators/rolemodel/simple_form/templates/app/inputs/switch_checkbox_input.rb +39 -0
- data/lib/generators/rolemodel/simple_form/templates/app/inputs/tailored_select_input.rb +75 -0
- data/lib/generators/rolemodel/simple_form/templates/config/initializers/simple_form.rb +207 -0
- data/lib/generators/rolemodel/simple_form/templates/config/locales/simple_form.en.yml +31 -0
- data/lib/generators/rolemodel/simple_form/templates/lib/templates/slim/scaffold/_form.html.slim.tt +12 -0
- data/lib/generators/rolemodel/slim/README.md +9 -0
- data/lib/generators/rolemodel/slim/USAGE +5 -0
- data/lib/generators/rolemodel/slim/slim_generator.rb +24 -0
- data/lib/generators/rolemodel/slim/templates/app/views/application/_head.html.slim.tt +13 -0
- data/lib/generators/rolemodel/slim/templates/app/views/layouts/application.html.slim.tt +6 -0
- data/lib/generators/rolemodel/slim/templates/lib/templates/slim/scaffold/edit.html.slim.tt +15 -0
- data/lib/generators/rolemodel/slim/templates/lib/templates/slim/scaffold/index.html.slim.tt +13 -0
- data/lib/generators/rolemodel/slim/templates/lib/templates/slim/scaffold/new.html.slim.tt +13 -0
- data/lib/generators/rolemodel/slim/templates/lib/templates/slim/scaffold/partial.html.slim.tt +10 -0
- data/lib/generators/rolemodel/slim/templates/lib/templates/slim/scaffold/show.html.slim.tt +33 -0
- data/lib/generators/rolemodel/soft_destroyable/README.md +8 -0
- data/lib/generators/rolemodel/soft_destroyable/USAGE +9 -0
- data/lib/generators/rolemodel/soft_destroyable/soft_destroyable_generator.rb +13 -0
- data/lib/generators/rolemodel/soft_destroyable/templates/soft_destroyable.rb +82 -0
- data/lib/generators/rolemodel/soft_destroyable/templates/soft_destroyable_behavior.rb +166 -0
- data/lib/generators/rolemodel/source_map/README.md +13 -0
- data/lib/generators/rolemodel/source_map/USAGE +9 -0
- data/lib/generators/rolemodel/source_map/source_map_generator.rb +22 -0
- data/lib/generators/rolemodel/source_map/templates/lib/middleware/rolemodel/source_map.rb +45 -0
- data/lib/generators/rolemodel/source_map/templates/lib/tasks/assets.rake +43 -0
- data/lib/generators/rolemodel/tailored_select/README.md +7 -0
- data/lib/generators/rolemodel/tailored_select/USAGE +5 -0
- data/lib/generators/rolemodel/tailored_select/tailored_select_generator.rb +13 -0
- data/lib/generators/rolemodel/testing/README.md +11 -0
- data/lib/generators/rolemodel/testing/USAGE +5 -0
- data/lib/generators/rolemodel/testing/all_generator.rb +17 -0
- data/lib/generators/rolemodel/testing/factory_bot/README.md +18 -0
- data/lib/generators/rolemodel/testing/factory_bot/USAGE +8 -0
- data/lib/generators/rolemodel/testing/factory_bot/factory_bot_generator.rb +20 -0
- data/lib/generators/rolemodel/testing/factory_bot/templates/support/factory_bot.rb +3 -0
- data/lib/generators/rolemodel/testing/jasmine_playwright/README.md +9 -0
- data/lib/generators/rolemodel/testing/jasmine_playwright/jasmine_playwright_generator.rb +52 -0
- data/lib/generators/rolemodel/testing/jasmine_playwright/templates/jp-runner.config.mjs +5 -0
- data/lib/generators/rolemodel/testing/jasmine_playwright/templates/spec/javascript/browser/example_spec.js +15 -0
- data/lib/generators/rolemodel/testing/jasmine_playwright/templates/spec/javascript/browser/setupTests.js +3 -0
- data/lib/generators/rolemodel/testing/jasmine_playwright/templates/support/react.mjs +26 -0
- data/lib/generators/rolemodel/testing/parallel_tests/README.md +53 -0
- data/lib/generators/rolemodel/testing/parallel_tests/USAGE +12 -0
- data/lib/generators/rolemodel/testing/parallel_tests/parallel_tests_generator.rb +42 -0
- data/lib/generators/rolemodel/testing/rspec/README.md +46 -0
- data/lib/generators/rolemodel/testing/rspec/USAGE +14 -0
- data/lib/generators/rolemodel/testing/rspec/rspec_generator.rb +46 -0
- data/lib/generators/rolemodel/testing/rspec/templates/rails_helper.rb +72 -0
- data/lib/generators/rolemodel/testing/rspec/templates/spec_helper.rb +97 -0
- data/lib/generators/rolemodel/testing/rspec/templates/support/capybara_drivers.rb +51 -0
- data/lib/generators/rolemodel/testing/rspec/templates/support/capybara_testid.rb +5 -0
- data/lib/generators/rolemodel/testing/rspec/templates/support/helpers/action_cable_helper.rb +5 -0
- data/lib/generators/rolemodel/testing/rspec/templates/support/helpers/capybara_helper.rb +72 -0
- data/lib/generators/rolemodel/testing/rspec/templates/support/helpers/playwright_helper.rb +85 -0
- data/lib/generators/rolemodel/testing/rspec/templates/support/helpers/select_helper.rb +33 -0
- data/lib/generators/rolemodel/testing/rspec/templates/support/helpers/test_element_helper.rb +11 -0
- data/lib/generators/rolemodel/testing/rspec/templates/support/helpers.rb +12 -0
- data/lib/generators/rolemodel/testing/test_prof/README.md +5 -0
- data/lib/generators/rolemodel/testing/test_prof/USAGE +5 -0
- data/lib/generators/rolemodel/testing/test_prof/test_prof_generator.rb +14 -0
- data/lib/generators/rolemodel/testing/vitest/README.md +5 -0
- data/lib/generators/rolemodel/testing/vitest/USAGE +5 -0
- data/lib/generators/rolemodel/testing/vitest/templates/spec/javascript/example.spec.js +12 -0
- data/lib/generators/rolemodel/testing/vitest/templates/spec/javascript/test-setup.js +1 -0
- data/lib/generators/rolemodel/testing/vitest/templates/vitest.config.js +23 -0
- data/lib/generators/rolemodel/testing/vitest/vitest_generator.rb +38 -0
- data/lib/generators/rolemodel/ui_components/README.md +9 -0
- data/lib/generators/rolemodel/ui_components/USAGE +5 -0
- data/lib/generators/rolemodel/ui_components/all_generator.rb +15 -0
- data/lib/generators/rolemodel/ui_components/flash/README.md +10 -0
- data/lib/generators/rolemodel/ui_components/flash/USAGE +9 -0
- data/lib/generators/rolemodel/ui_components/flash/flash_generator.rb +22 -0
- data/lib/generators/rolemodel/ui_components/flash/templates/app/views/application/_flash.html.slim +6 -0
- data/lib/generators/rolemodel/ui_components/flash/templates/spec/support/matchers/flash_matchers.rb +19 -0
- data/lib/generators/rolemodel/ui_components/modals/README.md +119 -0
- data/lib/generators/rolemodel/ui_components/modals/USAGE +8 -0
- data/lib/generators/rolemodel/ui_components/modals/modals_generator.rb +74 -0
- data/lib/generators/rolemodel/ui_components/modals/templates/app/helpers/turbo_frame_link_helper.rb +20 -0
- data/lib/generators/rolemodel/ui_components/modals/templates/app/javascript/controllers/morph_controller.js +23 -0
- data/lib/generators/rolemodel/ui_components/modals/templates/app/javascript/controllers/toggle_controller.js +55 -0
- data/lib/generators/rolemodel/ui_components/modals/templates/app/javascript/initializers/before_morph_handler.js +21 -0
- data/lib/generators/rolemodel/ui_components/modals/templates/app/javascript/initializers/frame_missing_handler.js +12 -0
- data/lib/generators/rolemodel/ui_components/modals/templates/app/javascript/initializers/turbo_confirm.js +3 -0
- data/lib/generators/rolemodel/ui_components/modals/templates/app/views/application/_confirm.html.slim +12 -0
- data/lib/generators/rolemodel/ui_components/modals/templates/app/views/layouts/modal.html.slim.tt +26 -0
- data/lib/generators/rolemodel/ui_components/modals/templates/app/views/layouts/panel.html.slim.tt +21 -0
- data/lib/generators/rolemodel/ui_components/navbar/README.md +11 -0
- data/lib/generators/rolemodel/ui_components/navbar/USAGE +10 -0
- data/lib/generators/rolemodel/ui_components/navbar/navbar_generator.rb +54 -0
- data/lib/generators/rolemodel/ui_components/navbar/templates/app/assets/stylesheets/components/shoelace/index.scss +2 -0
- data/lib/generators/rolemodel/ui_components/navbar/templates/app/javascript/lib/shoelace.js +9 -0
- data/lib/generators/rolemodel/ui_components/navbar/templates/app/views/layouts/_navbar.html.slim +29 -0
- data/lib/generators/rolemodel/webpack/README.md +8 -0
- data/lib/generators/rolemodel/webpack/USAGE +5 -0
- data/lib/generators/rolemodel/webpack/templates/app/assets/stylesheets/application.scss +5 -0
- data/lib/generators/rolemodel/webpack/templates/app/javascript/initializers/honeybadger.js +26 -0
- data/lib/generators/rolemodel/webpack/templates/postcss.config.cjs +14 -0
- data/lib/generators/rolemodel/webpack/templates/webpack.config.js +104 -0
- data/lib/generators/rolemodel/webpack/webpack_generator.rb +76 -0
- data/lib/generators/templates/generator/%filename%.rb.tt +11 -0
- data/lib/generators/templates/generator/README.md.tt +11 -0
- data/lib/generators/templates/generator/USAGE.tt +5 -0
- data/lib/generators/templates/generator_spec/%filename%_spec.rb.tt +5 -0
- data/lib/rolemodel/engine.rb +9 -0
- data/lib/rolemodel/version.rb +5 -0
- data/lib/rolemodel-rails.rb +7 -0
- metadata +416 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.shared_examples 'a soft destroyable' do |factory_name, **options|
|
|
4
|
+
let(:factory_traits) { options[:factory_traits] }
|
|
5
|
+
let(:dependent_destroy_relations) { options[:dependent_destroy_relations] }
|
|
6
|
+
|
|
7
|
+
# we want to access the local variables of the block scope above, which
|
|
8
|
+
# you lose when you enter an instance method scope, but retain when you
|
|
9
|
+
# enter a block scope.
|
|
10
|
+
define_method(:create_instance) do
|
|
11
|
+
create factory_name, *factory_traits
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe '.kept' do
|
|
15
|
+
it 'only returns records that haven\'t been deleted' do
|
|
16
|
+
# given
|
|
17
|
+
first_destroyable = create_instance
|
|
18
|
+
second_destroyable = create_instance
|
|
19
|
+
first_destroyable.soft_destroy!
|
|
20
|
+
klass = first_destroyable.class
|
|
21
|
+
# when
|
|
22
|
+
remaining = klass.kept
|
|
23
|
+
# then
|
|
24
|
+
expect(remaining).to include(second_destroyable)
|
|
25
|
+
expect(remaining).not_to include(first_destroyable)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe '.only_deleted' do
|
|
30
|
+
it 'only returns records that have been deleted' do
|
|
31
|
+
# given
|
|
32
|
+
first_destroyable = create_instance
|
|
33
|
+
second_destroyable = create_instance
|
|
34
|
+
first_destroyable.soft_destroy!
|
|
35
|
+
klass = first_destroyable.class
|
|
36
|
+
# when
|
|
37
|
+
deleted = klass.only_deleted
|
|
38
|
+
# then
|
|
39
|
+
expect(deleted).to include(first_destroyable)
|
|
40
|
+
expect(deleted).not_to include(second_destroyable)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe '#assign_attributes' do
|
|
45
|
+
it 'ignores other attributes when _soft_destroy is present' do
|
|
46
|
+
destroyable = create_instance
|
|
47
|
+
destroyable.assign_attributes(updated_at: Time.current, _soft_destroy: '1')
|
|
48
|
+
expect(destroyable.changes).to_not include(:updated_at)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'includes all attributes when _soft_destroy is not present' do
|
|
52
|
+
destroyable = create_instance
|
|
53
|
+
destroyable.assign_attributes(updated_at: Time.current)
|
|
54
|
+
expect(destroyable.changes).to include(:updated_at)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe '#soft_destroy!' do
|
|
59
|
+
it 'sets deleted_at' do
|
|
60
|
+
# given
|
|
61
|
+
destroyable = create_instance
|
|
62
|
+
expect(destroyable.deleted_at).to be_nil
|
|
63
|
+
# when
|
|
64
|
+
destroyable.soft_destroy!
|
|
65
|
+
# then
|
|
66
|
+
expect(destroyable.deleted_at).not_to be_nil
|
|
67
|
+
end
|
|
68
|
+
context 'with dependents', if: options[:dependent_destroy_relations]&.present? do
|
|
69
|
+
it 'soft_destroys dependents' do
|
|
70
|
+
# given
|
|
71
|
+
destroyable = create_instance
|
|
72
|
+
dependent_objects = dependent_destroy_relations.map { |relation_name| destroyable.send(relation_name) }.flatten
|
|
73
|
+
dependent_deleted_timestamps = dependent_objects.map(&:deleted_at)
|
|
74
|
+
expect(dependent_deleted_timestamps.compact).to be_empty
|
|
75
|
+
# when
|
|
76
|
+
destroyable.soft_destroy!
|
|
77
|
+
# then
|
|
78
|
+
dependent_deleted_timestamps = dependent_objects.map { |dependent_object| dependent_object.reload.deleted_at }.compact.uniq
|
|
79
|
+
expect(dependent_deleted_timestamps).not_to be_empty
|
|
80
|
+
end
|
|
81
|
+
it 'uses the parent deleted_at timestamp for children' do
|
|
82
|
+
# given
|
|
83
|
+
destroyable = create_instance
|
|
84
|
+
dependent_objects = dependent_destroy_relations.map { |relation_name| destroyable.send(relation_name) }.flatten
|
|
85
|
+
dependent_deleted_timestamps = dependent_objects.map(&:deleted_at)
|
|
86
|
+
expect(dependent_deleted_timestamps.compact).to be_empty
|
|
87
|
+
# when
|
|
88
|
+
destroyable.soft_destroy!
|
|
89
|
+
# then
|
|
90
|
+
dependent_deleted_timestamps = dependent_objects.map { |dependent_object| dependent_object.reload.deleted_at }.compact.uniq
|
|
91
|
+
expect(dependent_deleted_timestamps.size).to eq(1)
|
|
92
|
+
expect(dependent_deleted_timestamps.first).to eq(destroyable.reload.deleted_at)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'raises errors when they are encountered' do
|
|
97
|
+
destroyable = create_instance
|
|
98
|
+
destroyable.define_singleton_method(:update) do |_arg|
|
|
99
|
+
errors.add(:base, 'This record is invalid')
|
|
100
|
+
false
|
|
101
|
+
end
|
|
102
|
+
expect { destroyable.soft_destroy! }.to raise_error(ActiveModel::ValidationError)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe 'restore!' do
|
|
107
|
+
it 'clears out deleted_at' do
|
|
108
|
+
# given
|
|
109
|
+
destroyable = create_instance
|
|
110
|
+
destroyable.update(deleted_at: 1.day.ago)
|
|
111
|
+
expect(destroyable.deleted_at).not_to be_nil
|
|
112
|
+
# when
|
|
113
|
+
destroyable.restore!
|
|
114
|
+
# then
|
|
115
|
+
expect(destroyable.deleted_at).to be_nil
|
|
116
|
+
end
|
|
117
|
+
context 'with dependents', if: options[:dependent_destroy_relations]&.present? do
|
|
118
|
+
it 'restores dependents (that were soft_destroyed at the same time)' do
|
|
119
|
+
destroyable = create_instance
|
|
120
|
+
timestamp = 1.day.ago
|
|
121
|
+
destroyable.update(deleted_at: timestamp)
|
|
122
|
+
deleted_associated_objects = []
|
|
123
|
+
dependent_destroy_relations.each do |assoc|
|
|
124
|
+
associated_objects = Array.wrap(destroyable.send(assoc))
|
|
125
|
+
associated_objects.each do |obj|
|
|
126
|
+
obj.update(deleted_at: timestamp)
|
|
127
|
+
deleted_associated_objects << obj
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
# when
|
|
131
|
+
destroyable.reload.restore!
|
|
132
|
+
# then
|
|
133
|
+
expect(deleted_associated_objects).not_to be_empty
|
|
134
|
+
deleted_associated_objects.each { |obj| expect(obj.reload).not_to be_soft_destroyed }
|
|
135
|
+
end
|
|
136
|
+
it 'does not restore dependents (when they have different deleted_at timestamps)' do
|
|
137
|
+
destroyable = create_instance
|
|
138
|
+
timestamp = 1.day.ago
|
|
139
|
+
destroyable.update(deleted_at: timestamp)
|
|
140
|
+
associated_objects_that_were_already_deleted = []
|
|
141
|
+
dependent_destroy_relations.each do |assoc|
|
|
142
|
+
associated_objects = Array.wrap(destroyable.send(assoc))
|
|
143
|
+
associated_objects.each do |obj|
|
|
144
|
+
obj.update(deleted_at: 2.days.ago)
|
|
145
|
+
associated_objects_that_were_already_deleted << obj
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
# when
|
|
149
|
+
destroyable.reload.restore!
|
|
150
|
+
# then
|
|
151
|
+
expect(associated_objects_that_were_already_deleted).not_to be_empty
|
|
152
|
+
expect(associated_objects_that_were_already_deleted.map(&:reload)).to all be_soft_destroyed
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it 'raises errors when they are encountered' do
|
|
157
|
+
destroyable = create_instance
|
|
158
|
+
destroyable.update(deleted_at: 1.day.ago)
|
|
159
|
+
destroyable.define_singleton_method(:update) do |_arg|
|
|
160
|
+
errors.add(:base, 'This record is invalid')
|
|
161
|
+
false
|
|
162
|
+
end
|
|
163
|
+
expect { destroyable.restore! }.to raise_error(ActiveModel::ValidationError)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Rack middleware Generator
|
|
2
|
+
|
|
3
|
+
## What you get
|
|
4
|
+
|
|
5
|
+
* Rack middleware for serving source maps
|
|
6
|
+
* Enhanced assets rake tasks to relocate and manage source map files
|
|
7
|
+
|
|
8
|
+
Adds Rack middleware for serving js source maps only to allowed users in a production environment.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
* Ensure that app uses Warden::Manager middleware
|
|
13
|
+
* Set ENV['SOURCE_MAPS_ALLOWED_USERS_EMAILS'] to a comma-separated list of emails or update the middleware to allow all super admins
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rolemodel
|
|
4
|
+
class SourceMapGenerator < BaseGenerator
|
|
5
|
+
source_root File.expand_path('templates', __dir__)
|
|
6
|
+
|
|
7
|
+
def inject_config_for_production
|
|
8
|
+
inject_into_file 'config/environments/production.rb',
|
|
9
|
+
"\nrequire_relative Rails.root.join('lib/middleware/rolemodel/source_map.rb')\n", after: "require \"active_support/core_ext/integer/time\"\n"
|
|
10
|
+
inject_into_file 'config/environments/production.rb',
|
|
11
|
+
"\n config.middleware.insert_after Warden::Manager, Middleware::Rolemodel::SourceMap\n\n", after: "Rails.application.configure do\n"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def copy_middleware_files
|
|
15
|
+
copy_file 'lib/middleware/rolemodel/source_map.rb'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def copy_assets_rake_task
|
|
19
|
+
copy_file 'lib/tasks/assets.rake'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Middleware
|
|
4
|
+
module Rolemodel
|
|
5
|
+
class SourceMap
|
|
6
|
+
def initialize(app, **options)
|
|
7
|
+
root = options.delete(:root) || 'maps'
|
|
8
|
+
default_headers = { 'Set-Cookie' => 'Same-Site=None', 'Cache-Control' => 'max-age=0;no-cache' }
|
|
9
|
+
custom_headers = default_headers.merge(options.delete(:headers) || {})
|
|
10
|
+
@app = app
|
|
11
|
+
@allowed_users_emails = ENV.fetch('SOURCE_MAPS_ALLOWED_USERS_EMAILS', '').split(',')
|
|
12
|
+
@file_server = Rack::Files.new(root, custom_headers)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def call(env)
|
|
16
|
+
if allowed_sourcemap?(env)
|
|
17
|
+
@file_server.call(env.tap { |env| env['PATH_INFO'].sub!(%r{^/[\w-]+[^/]}, '') })
|
|
18
|
+
else
|
|
19
|
+
@app.call(env)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def allowed_sourcemap?(env)
|
|
26
|
+
return false unless env['PATH_INFO'].end_with?('.map')
|
|
27
|
+
|
|
28
|
+
permit_user?(env)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def permit_user?(env)
|
|
32
|
+
# Alternatively, allow sourcemaps for all super admins
|
|
33
|
+
# current_user(env)&.super_admin?
|
|
34
|
+
current_user_email = current_user(env)&.email
|
|
35
|
+
return false if current_user_email.blank?
|
|
36
|
+
|
|
37
|
+
@allowed_users_emails.include?(current_user_email)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def current_user(env)
|
|
41
|
+
env['warden']&.user
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :assets do
|
|
4
|
+
task clean_sourcemaps: :environment do
|
|
5
|
+
maps_root = Rails.root.join('maps')
|
|
6
|
+
next unless maps_root.exist?
|
|
7
|
+
|
|
8
|
+
assets_root = Rails.public_path.join('assets')
|
|
9
|
+
|
|
10
|
+
puts 'Cleaning sourcemaps folder'
|
|
11
|
+
maps_root.glob('*.map').each do |map_file|
|
|
12
|
+
asset_file = map_file.basename('.map')
|
|
13
|
+
map_file.delete unless assets_root.join(asset_file).exist?
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
task relocate_sourcemaps: :environment do
|
|
18
|
+
maps_root = Rails.root.join('maps')
|
|
19
|
+
maps_root.mkpath
|
|
20
|
+
|
|
21
|
+
puts 'Relocating sourcemap files'
|
|
22
|
+
Rails.root.glob('public/assets/*.map').each do |map_file|
|
|
23
|
+
map_file.rename(maps_root.join(map_file.basename))
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
task clear_sourcemaps: :environment do
|
|
28
|
+
maps_root = Rails.root.join('maps')
|
|
29
|
+
maps_root.rmtree if maps_root.exist?
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Rake::Task['assets:clean'].enhance do
|
|
34
|
+
Rake::Task['assets:clean_sourcemaps'].invoke
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
Rake::Task['assets:precompile'].enhance do
|
|
38
|
+
Rake::Task['assets:relocate_sourcemaps'].invoke
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
Rake::Task['assets:clobber'].enhance do
|
|
42
|
+
Rake::Task['assets:clear_sourcemaps'].invoke
|
|
43
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rolemodel
|
|
4
|
+
class TailoredSelectGenerator < BaseGenerator
|
|
5
|
+
source_root File.expand_path('templates', __dir__)
|
|
6
|
+
|
|
7
|
+
def add_tailored_select_package
|
|
8
|
+
say 'Installing Tailored Select package', :green
|
|
9
|
+
|
|
10
|
+
run 'yarn add @rolemodel/tailored-select'
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Rolemodel
|
|
2
|
+
module Testing
|
|
3
|
+
class AllGenerator < BaseGenerator
|
|
4
|
+
source_root File.expand_path('templates', __dir__)
|
|
5
|
+
|
|
6
|
+
def run_all_the_generators
|
|
7
|
+
generate 'rolemodel:testing:factory_bot'
|
|
8
|
+
if yes?('Would you like to add jasmine-playwright-runner for browser testing?')
|
|
9
|
+
generate 'rolemodel:testing:jasmine_playwright'
|
|
10
|
+
end
|
|
11
|
+
generate 'rolemodel:testing:parallel_tests'
|
|
12
|
+
generate 'rolemodel:testing:rspec'
|
|
13
|
+
generate 'rolemodel:testing:test_prof'
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# FactoryBot Generator
|
|
2
|
+
|
|
3
|
+
Depends on [RSpec Generator](../rspec)
|
|
4
|
+
|
|
5
|
+
## What you get
|
|
6
|
+
|
|
7
|
+
Installs [factory_bot_rails](https://github.com/thoughtbot/factory_bot_rails)
|
|
8
|
+
|
|
9
|
+
### Factory Syntax methods
|
|
10
|
+
|
|
11
|
+
Allow you to use the short hand methods for creating or building factories
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
it 'tests something' do
|
|
15
|
+
created_user = create(:user)
|
|
16
|
+
built_user = build(:user)
|
|
17
|
+
end
|
|
18
|
+
```
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rolemodel
|
|
4
|
+
module Testing
|
|
5
|
+
class FactoryBotGenerator < BaseGenerator
|
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
|
7
|
+
|
|
8
|
+
def install_factory_bot_rails
|
|
9
|
+
gem_group :development, :test do
|
|
10
|
+
gem 'factory_bot_rails'
|
|
11
|
+
end
|
|
12
|
+
run_bundle
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def add_spec_files
|
|
16
|
+
template 'support/factory_bot.rb', 'spec/support/factory_bot.rb'
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Jasmine Playwright Generator
|
|
2
|
+
Sets up Jasmine Playwright
|
|
3
|
+
|
|
4
|
+
**Notes**:
|
|
5
|
+
* Configured for testing Web Components and generic DOM. If you need tests for stimulus controllers and/or react components, see the documentation for jasmine-playwright-runner.
|
|
6
|
+
|
|
7
|
+
## What you get
|
|
8
|
+
* A command for running component tests (yarn test:browser)
|
|
9
|
+
* An example test (example_spec.js)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rolemodel
|
|
4
|
+
module Testing
|
|
5
|
+
class JasminePlaywrightGenerator < BaseGenerator
|
|
6
|
+
include ReplaceContentHelper
|
|
7
|
+
source_root File.expand_path('templates', __dir__)
|
|
8
|
+
class_option :github_package_token, type: :string, default: ENV['GITHUB_PACKAGES_TOKEN'], desc: 'GitHub Packages token with access to @rolemodel packages'
|
|
9
|
+
|
|
10
|
+
TEST_COMMAND = 'NODE_ENV=test jp-runner --config jp-runner.config.mjs --webpack-config webpack.config.cjs'
|
|
11
|
+
DEV_DEPENDENCIES = %w[
|
|
12
|
+
@rolemodel/jasmine-playwright-runner
|
|
13
|
+
playwright
|
|
14
|
+
lit-html
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
17
|
+
def fail_without_github_token
|
|
18
|
+
raise 'a --github_package_token option or GITHUB_PACKAGES_TOKEN environment variable is required' if options[:github_package_token].blank?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def yarn_init_unless_package_json_exists
|
|
22
|
+
run 'yarn init' unless File.exist?(File.expand_path('package.json', destination_root))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def add_browser_test_script
|
|
26
|
+
say 'Adding yarn test:browser command', :green
|
|
27
|
+
|
|
28
|
+
add_package_json_script 'test:browser', TEST_COMMAND
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def set_node_version
|
|
32
|
+
say "Setting local Node version to #{set_color(NODE_VERSION, :yellow)}", :green
|
|
33
|
+
|
|
34
|
+
create_file '.node-version', NODE_VERSION, force: true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def add_dev_dependencies
|
|
38
|
+
say 'Adding new dev dependency to package.json', :green
|
|
39
|
+
|
|
40
|
+
run "yarn add --dev #{DEV_DEPENDENCIES.join(' ')}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def add_spec_config_files
|
|
44
|
+
say 'Adding Jasmine Playwright configuration files', :green
|
|
45
|
+
|
|
46
|
+
template 'spec/javascript/browser/example_spec.js'
|
|
47
|
+
template 'jp-runner.config.mjs'
|
|
48
|
+
template 'spec/javascript/browser/setupTests.js'
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { html } from '@rolemodel/jasmine-playwright-runner/dom'
|
|
2
|
+
import { page } from '@rolemodel/jasmine-playwright-runner/page'
|
|
3
|
+
|
|
4
|
+
describe('example', () => {
|
|
5
|
+
it('is there', async () => {
|
|
6
|
+
const content = 'Hello World'
|
|
7
|
+
await html`
|
|
8
|
+
<div>
|
|
9
|
+
${content}
|
|
10
|
+
</div>
|
|
11
|
+
`
|
|
12
|
+
|
|
13
|
+
await expectAsync(page.getByText(content)).toBeInTheDocument()
|
|
14
|
+
})
|
|
15
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import ReactDOM from 'react-dom'
|
|
3
|
+
|
|
4
|
+
let reactDOMRoot
|
|
5
|
+
|
|
6
|
+
export function setup() {
|
|
7
|
+
window.React = React
|
|
8
|
+
window.ReactDOM = ReactDOM
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
if (reactDOMRoot) {
|
|
12
|
+
ReactDOM.unmountComponentAtNode(reactDOMRoot)
|
|
13
|
+
reactDOMRoot.remove()
|
|
14
|
+
reactDOMRoot = undefined
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function render(reactNode) {
|
|
20
|
+
if (!reactDOMRoot) {
|
|
21
|
+
reactDOMRoot = document.createElement('div')
|
|
22
|
+
document.body.append(reactDOMRoot)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
ReactDOM.render(reactNode, reactDOMRoot)
|
|
26
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Parallel Tests Generator
|
|
2
|
+
|
|
3
|
+
## What you get
|
|
4
|
+
|
|
5
|
+
### Parallel Tests Setup
|
|
6
|
+
|
|
7
|
+
This generator configures your Rails application to run RSpec tests in parallel, greatly reducing the time it takes to run your test suite.
|
|
8
|
+
|
|
9
|
+
### Gemfile Addition
|
|
10
|
+
|
|
11
|
+
The generator will add the `parallel_tests`, `turbo_tests`, and `rspec_junit_formatter` gems to your Gemfile and run bundle install.
|
|
12
|
+
|
|
13
|
+
```rb
|
|
14
|
+
group :development, :test do
|
|
15
|
+
gem 'parallel_tests'
|
|
16
|
+
gem 'turbo_tests', require: false
|
|
17
|
+
gem 'rspec_junit_formatter', require: false
|
|
18
|
+
end
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### RSpec Configuration
|
|
22
|
+
The generator will create a `.rspec_parallel` file in your Rails root directory.
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
--format RspecJunitFormatter --out tmp/rspec-<%= ENV['TEST_ENV_NUMBER'] %>.xml
|
|
26
|
+
--format ParallelTests::RSpec::RuntimeLogger --out tmp/turbo_rspec_runtime.log
|
|
27
|
+
--format ParallelTests::RSpec::FailuresLogger
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Database Configuration
|
|
31
|
+
|
|
32
|
+
Your `database.yml` will be updated to support parallel test databases. This allows each test process to use its own isolated database.
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
test:
|
|
36
|
+
# ...existing configuration...
|
|
37
|
+
database: your_app_test<%= ENV['TEST_ENV_NUMBER'] %>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Running Parallel Tests
|
|
41
|
+
|
|
42
|
+
Once configured, you can run your tests in parallel using:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Run entire test suite in parallel
|
|
46
|
+
bundle exec rake parallel:spec
|
|
47
|
+
|
|
48
|
+
# Run specific tests in parallel
|
|
49
|
+
bundle exec rake parallel:spec[spec/models]
|
|
50
|
+
|
|
51
|
+
# Specify number of processes (default is the number of CPUs)
|
|
52
|
+
bundle exec rake parallel:spec[spec,4]
|
|
53
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
generates configuration for running RSpec tests in parallel
|
|
3
|
+
|
|
4
|
+
Example:
|
|
5
|
+
rails generate rolemodel:testing:parallel_rspec
|
|
6
|
+
|
|
7
|
+
This will add:
|
|
8
|
+
parallel_tests to your Gemfile
|
|
9
|
+
turbo_tests to your Gemfile for a nicer testing experience
|
|
10
|
+
rspec_junit_formatter for test reporting
|
|
11
|
+
.rspec_parallel file for RSpec configuration
|
|
12
|
+
database.yml configuration for parallel testing
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rolemodel
|
|
4
|
+
module Testing
|
|
5
|
+
class ParallelTestsGenerator < BaseGenerator # rubocop:disable Style/Documentation
|
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
|
7
|
+
|
|
8
|
+
def install_parallel_tests
|
|
9
|
+
gem_group :development, :test do
|
|
10
|
+
gem 'parallel_tests'
|
|
11
|
+
gem 'turbo_tests', require: false
|
|
12
|
+
gem 'rspec_junit_formatter', require: false
|
|
13
|
+
end
|
|
14
|
+
run_bundle
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def add_rspec_parallel_file
|
|
18
|
+
template '.rspec_parallel', '.rspec_parallel'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def configure_database_for_parallel_testing
|
|
22
|
+
say_status :update, 'Updating database.yml for parallel testing', :blue
|
|
23
|
+
|
|
24
|
+
# If there is, append the TEST_ENV_NUMBER to it
|
|
25
|
+
gsub_file 'config/database.yml', /(test:.*\n\s+database:.*_test)/m, "\\1<%= ENV['TEST_ENV_NUMBER'] %>"
|
|
26
|
+
|
|
27
|
+
say_status :update, 'Updated database configuration successfully', :green
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def setup_parallel_test_databases
|
|
31
|
+
say_status :setup, 'Setting up parallel test databases...', :blue
|
|
32
|
+
bundle_command 'exec rake parallel:setup'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def display_post_install_message
|
|
36
|
+
say_status :info, 'Parallel Tests has been configured!', :green
|
|
37
|
+
say_status :info, 'You can now run your tests in parallel with:', :green
|
|
38
|
+
say_status :info, 'bundle exec rake parallel:spec', :green
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|