katapult 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +5 -5
  2. data/.rspec +1 -0
  3. data/.ruby-version +1 -1
  4. data/Gemfile +9 -0
  5. data/README.md +122 -94
  6. data/Rakefile +13 -0
  7. data/bin/katapult +59 -25
  8. data/features/application_model.feature +55 -0
  9. data/features/authenticate.feature +88 -62
  10. data/features/basics.feature +64 -402
  11. data/features/binary.feature +56 -42
  12. data/features/configuration.feature +4 -4
  13. data/features/model.feature +21 -30
  14. data/features/navigation.feature +35 -48
  15. data/features/step_definitions/aruba_steps.rb +3 -0
  16. data/features/step_definitions/katapult_steps.rb +307 -8
  17. data/features/step_definitions/rails_steps.rb +74 -14
  18. data/features/step_definitions/test_steps.rb +5 -5
  19. data/features/step_definitions/version_steps.rb +22 -0
  20. data/features/support/env.rb +11 -3
  21. data/features/{wui.feature → web_ui.feature} +175 -148
  22. data/katapult.gemspec +8 -13
  23. data/lib/generators/katapult/app_model/app_model_generator.rb +12 -0
  24. data/lib/generators/katapult/app_model/templates/lib/katapult/application_model.rb +40 -0
  25. data/lib/generators/katapult/basics/basics_generator.rb +186 -51
  26. data/lib/generators/katapult/basics/templates/.browserslistrc +1 -0
  27. data/lib/generators/katapult/basics/templates/.gitignore +20 -21
  28. data/lib/generators/katapult/basics/templates/.rspec_parallel +3 -0
  29. data/lib/generators/katapult/basics/templates/Capfile +5 -1
  30. data/lib/generators/katapult/basics/templates/Gemfile +23 -34
  31. data/lib/generators/katapult/basics/templates/Guardfile +0 -12
  32. data/lib/generators/katapult/basics/templates/app/controllers/errors_controller.rb +9 -0
  33. data/lib/generators/katapult/basics/templates/app/helpers/unpoly_helper.rb +13 -0
  34. data/lib/generators/katapult/{haml → basics}/templates/app/views/layouts/_flashes.html.haml +1 -1
  35. data/lib/generators/katapult/basics/templates/app/views/layouts/_menu_bar.html.haml.tt +12 -0
  36. data/lib/generators/katapult/basics/templates/app/views/layouts/application.html.haml.tt +25 -0
  37. data/lib/generators/katapult/basics/templates/app/webpack/assets/images/.keep +0 -0
  38. data/lib/generators/katapult/basics/templates/app/webpack/assets/index.js +16 -0
  39. data/lib/generators/katapult/basics/templates/app/webpack/assets/javascripts/application.js +0 -0
  40. data/lib/generators/katapult/basics/templates/app/webpack/assets/javascripts/bootstrap.js +12 -0
  41. data/lib/generators/katapult/basics/templates/app/webpack/assets/javascripts/compilers/.keep +0 -0
  42. data/lib/generators/katapult/basics/templates/app/webpack/assets/javascripts/macros/content_link.js +17 -0
  43. data/lib/generators/katapult/basics/templates/app/webpack/assets/javascripts/macros/modal_link.js +17 -0
  44. data/lib/generators/katapult/basics/templates/app/webpack/assets/javascripts/unpoly.js +9 -0
  45. data/lib/generators/katapult/basics/templates/app/webpack/assets/stylesheets/_definitions.sass +25 -0
  46. data/lib/generators/katapult/basics/templates/app/webpack/assets/stylesheets/_environment.sass +2 -0
  47. data/lib/generators/katapult/basics/templates/app/webpack/assets/stylesheets/_mixins.sass +3 -0
  48. data/lib/generators/katapult/basics/templates/app/webpack/assets/stylesheets/blocks/.keep +0 -0
  49. data/lib/generators/katapult/basics/templates/app/webpack/assets/stylesheets/custom_bootstrap.sass +50 -0
  50. data/lib/generators/katapult/basics/templates/app/webpack/assets/stylesheets/ext/.keep +0 -0
  51. data/lib/generators/katapult/basics/templates/app/webpack/assets/stylesheets/ext/bootstrap/navbar.sass +83 -0
  52. data/lib/generators/katapult/basics/templates/app/webpack/assets/stylesheets/theme.sass +11 -0
  53. data/lib/generators/katapult/basics/templates/app/webpack/assets/stylesheets/unpoly.sass +2 -0
  54. data/lib/generators/katapult/basics/templates/app/webpack/packs/application.js +13 -0
  55. data/lib/generators/katapult/basics/templates/config/database.sample.yml +1 -1
  56. data/lib/generators/katapult/basics/templates/config/deploy.rb +3 -4
  57. data/lib/generators/katapult/basics/templates/config/environments/staging.rb +5 -0
  58. data/lib/generators/katapult/basics/templates/config/initializers/better_errors.rb +23 -0
  59. data/lib/generators/katapult/basics/templates/config/initializers/exception_notification.rb.tt +1 -1
  60. data/lib/generators/katapult/basics/templates/config/initializers/ext.rb +1 -1
  61. data/lib/generators/katapult/basics/templates/config/webpack/loaders/unpoly.js +4 -0
  62. data/lib/generators/katapult/basics/templates/features/support/capybara_screenshot.rb +7 -0
  63. data/lib/generators/katapult/basics/templates/features/support/factory_bot.rb +1 -0
  64. data/lib/generators/katapult/basics/templates/features/support/paths.rb +7 -2
  65. data/lib/generators/katapult/basics/templates/features/support/rspec_doubles.rb +1 -0
  66. data/lib/generators/katapult/basics/templates/features/support/selectors.rb +3 -3
  67. data/lib/generators/katapult/basics/templates/features/support/selenium.rb +13 -0
  68. data/lib/generators/katapult/basics/templates/features/support/{env-custom.rb → spreewald.rb} +0 -0
  69. data/lib/generators/katapult/basics/templates/features/support/webpacker.rb +35 -0
  70. data/lib/generators/katapult/basics/templates/lib/ext/action_view/form_for_with_development_errors.rb +31 -31
  71. data/lib/generators/katapult/basics/templates/lib/ext/active_record/find_by_anything.rb +4 -3
  72. data/lib/generators/katapult/basics/templates/public/robots.txt +5 -0
  73. data/lib/generators/katapult/basics/templates/spec/assets/sample.pdf +0 -0
  74. data/lib/generators/katapult/basics/templates/spec/factories/factories.rb +1 -1
  75. data/lib/generators/katapult/basics/templates/spec/support/database_cleaner.rb +20 -0
  76. data/lib/generators/katapult/basics/templates/spec/support/factory_bot.rb +3 -0
  77. data/lib/generators/katapult/basics/templates/spec/support/fixture_file.rb +6 -0
  78. data/lib/generators/katapult/basics/templates/spec/support/postgresql_sequences.rb +15 -0
  79. data/lib/generators/katapult/basics/templates/spec/support/timecop.rb +3 -0
  80. data/lib/generators/katapult/clearance/clearance_generator.rb +14 -2
  81. data/lib/generators/katapult/clearance/templates/app/views/layouts/_current_user.html.haml +11 -0
  82. data/lib/generators/katapult/clearance/templates/app/views/passwords/create.html.haml +10 -4
  83. data/lib/generators/katapult/clearance/templates/app/views/passwords/edit.html.haml +12 -12
  84. data/lib/generators/katapult/clearance/templates/app/views/passwords/new.html.haml +14 -11
  85. data/lib/generators/katapult/clearance/templates/app/views/sessions/new.html.haml +16 -15
  86. data/lib/generators/katapult/clearance/templates/features/authentication.feature +3 -3
  87. data/lib/generators/katapult/cucumber_features/templates/feature.feature +1 -1
  88. data/lib/generators/katapult/model_specs/templates/model_spec.rb +3 -5
  89. data/lib/generators/katapult/navigation/navigation_generator.rb +7 -1
  90. data/lib/generators/katapult/navigation/templates/app/views/layouts/_navigation.html.haml +15 -0
  91. data/lib/generators/katapult/transform/transform_generator.rb +12 -17
  92. data/lib/generators/katapult/views/templates/_form.html.haml +48 -0
  93. data/lib/generators/katapult/views/templates/app/helpers/table_helper.rb +14 -0
  94. data/lib/generators/katapult/views/templates/app/webpack/assets/stylesheets/blocks/action_bar.sass +22 -0
  95. data/lib/generators/katapult/views/templates/app/webpack/assets/stylesheets/blocks/title.sass +11 -0
  96. data/lib/generators/katapult/views/templates/custom_action.html.haml +5 -0
  97. data/lib/generators/katapult/views/templates/edit.html.haml +4 -0
  98. data/lib/generators/katapult/views/templates/index.html.haml +26 -0
  99. data/lib/generators/katapult/{haml → views}/templates/new.html.haml +1 -1
  100. data/lib/generators/katapult/views/templates/show.html.haml +39 -0
  101. data/lib/generators/katapult/{haml/haml_generator.rb → views/views_generator.rb} +19 -25
  102. data/lib/generators/katapult/{w_u_i → web_ui}/templates/_route.rb +3 -3
  103. data/lib/generators/katapult/{w_u_i → web_ui}/templates/controller.rb +21 -23
  104. data/lib/generators/katapult/{w_u_i/w_u_i_generator.rb → web_ui/web_ui_generator.rb} +7 -12
  105. data/lib/katapult/action.rb +1 -1
  106. data/lib/katapult/application_model.rb +8 -8
  107. data/lib/katapult/binary_util.rb +48 -10
  108. data/lib/katapult/generator.rb +2 -10
  109. data/lib/katapult/generator_goodies.rb +23 -0
  110. data/lib/katapult/navigation.rb +10 -5
  111. data/lib/katapult/parser.rb +15 -8
  112. data/lib/katapult/version.rb +5 -1
  113. data/lib/katapult/{wui.rb → web_ui.rb} +19 -4
  114. data/lib/katapult.rb +0 -5
  115. data/script/console +5 -2
  116. data/script/kta +8 -0
  117. data/script/update +80 -0
  118. data/spec/action_spec.rb +0 -1
  119. data/spec/attribute_spec.rb +0 -1
  120. data/spec/element_spec.rb +0 -1
  121. data/spec/model_spec.rb +0 -1
  122. data/spec/parser_spec.rb +26 -0
  123. data/spec/util_spec.rb +0 -1
  124. data/spec/{wui_spec.rb → web_ui_spec.rb} +24 -12
  125. metadata +86 -124
  126. data/lib/generators/katapult/basics/templates/app/assets/stylesheets/application/blocks/_all.sass +0 -4
  127. data/lib/generators/katapult/basics/templates/app/assets/stylesheets/application/blocks/_items.sass +0 -11
  128. data/lib/generators/katapult/basics/templates/app/assets/stylesheets/application/blocks/_layout.sass +0 -26
  129. data/lib/generators/katapult/basics/templates/app/assets/stylesheets/application/blocks/_navigation.sass +0 -11
  130. data/lib/generators/katapult/basics/templates/app/assets/stylesheets/application/blocks/_tools.sass +0 -12
  131. data/lib/generators/katapult/basics/templates/app/assets/stylesheets/application.sass +0 -6
  132. data/lib/generators/katapult/basics/templates/config/spring.rb +0 -3
  133. data/lib/generators/katapult/basics/templates/features/support/factory_girl.rb +0 -1
  134. data/lib/generators/katapult/basics/templates/spec/support/factory_girl.rb +0 -3
  135. data/lib/generators/katapult/haml/templates/_form.html.haml +0 -38
  136. data/lib/generators/katapult/haml/templates/app/views/layouts/application.html.haml +0 -33
  137. data/lib/generators/katapult/haml/templates/custom_action.html.haml +0 -5
  138. data/lib/generators/katapult/haml/templates/edit.html.haml +0 -4
  139. data/lib/generators/katapult/haml/templates/index.html.haml +0 -29
  140. data/lib/generators/katapult/haml/templates/show.html.haml +0 -39
  141. data/lib/generators/katapult/install/install_generator.rb +0 -14
  142. data/lib/generators/katapult/install/templates/lib/katapult/application_model.rb +0 -20
  143. data/lib/generators/katapult/navigation/templates/app/models/navigation.rb +0 -12
@@ -0,0 +1,17 @@
1
+ const DEFAULT_TARGET = '.content'
2
+
3
+ up.macro('[content-link]', ($link) => {
4
+ let target = $link.attr('content-link') || DEFAULT_TARGET
5
+ let attrs = {
6
+ 'up-target': target,
7
+ 'up-preload': '',
8
+ 'up-instant': '',
9
+ }
10
+
11
+ // It feels wrong for a button
12
+ if ($link.is('.btn:not(.btn-link)')) {
13
+ delete attrs['up-instant']
14
+ }
15
+
16
+ $link.attr(attrs)
17
+ })
@@ -0,0 +1,17 @@
1
+ const DEFAULT_TARGET = '.content'
2
+
3
+ up.macro('[modal-link]', function($link) {
4
+ let target = $link.attr('modal-link') || DEFAULT_TARGET
5
+ let attrs = {
6
+ 'up-modal': target,
7
+ 'up-preload': '',
8
+ 'up-instant': '',
9
+ }
10
+
11
+ // It feels wrong for a button
12
+ if ($link.is('.btn:not(.btn-link)')) {
13
+ delete attrs['up-instant']
14
+ }
15
+
16
+ $link.attr(attrs)
17
+ })
@@ -0,0 +1,9 @@
1
+ $(() => {
2
+ if ($(document.body).data('environment') === 'test') {
3
+ // Disable animations in tests
4
+ up.motion.config.enabled = false
5
+
6
+ // When revealing elements, don't animate the scrolling
7
+ up.layout.config.duration = 0
8
+ }
9
+ })
@@ -0,0 +1,25 @@
1
+ // Colors
2
+ $theme-blue: #4682B4
3
+
4
+ $white: #fff
5
+
6
+ // Transitions
7
+ $transition-distinct: .21s
8
+ $transition-quick: .14s
9
+ $transition-subtle: .07s
10
+
11
+ // Spacing
12
+ $space-xs: 10px
13
+ $space-sm: 20px
14
+ $space-md: 30px
15
+ $space-lg: 40px
16
+
17
+ // Bootstrap configuration /////////////////////////////////////////////////////
18
+ $brand-primary: $theme-blue
19
+
20
+ $font-family-sans-serif: 'Open Sans', 'Segoe UI', sans-serif
21
+
22
+ $input-border-focus: $brand-primary
23
+ $border-radius-base: 3px
24
+
25
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/variables
@@ -0,0 +1,2 @@
1
+ @import definitions
2
+ @import mixins
@@ -0,0 +1,3 @@
1
+ =within-modal
2
+ .modal-content &
3
+ @content
@@ -0,0 +1,50 @@
1
+ @import environment
2
+
3
+ // Core variables and mixins
4
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/variables
5
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/mixins
6
+
7
+ // Reset and dependencies
8
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/normalize
9
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/print
10
+
11
+ // Core CSS
12
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/scaffolding
13
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/type
14
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/code
15
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/grid
16
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/tables
17
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/forms
18
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/buttons
19
+
20
+ // Components
21
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/component-animations
22
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/dropdowns
23
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/button-groups
24
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/input-groups
25
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/navs
26
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/navbar
27
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/breadcrumbs
28
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/pagination
29
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/pager
30
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/labels
31
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/badges
32
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/jumbotron
33
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/thumbnails
34
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/alerts
35
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/progress-bars
36
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/media
37
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/list-group
38
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/responsive-embed
39
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/wells
40
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/close
41
+
42
+ // Components w/ JavaScript
43
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/modal
44
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/tooltip
45
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/popover
46
+ //@import ~bootstrap-sass/assets/stylesheets/bootstrap/carousel
47
+
48
+ // Utility classes
49
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/utilities
50
+ @import ~bootstrap-sass/assets/stylesheets/bootstrap/responsive-utilities
@@ -0,0 +1,83 @@
1
+ @import ../../environment
2
+
3
+ .navbar-default .navbar-nav
4
+ & > li > a
5
+ transition: background-color $transition-subtle
6
+ &:hover
7
+ background-color: lighten($brand-primary, 5%)
8
+
9
+ .navbar-logout
10
+ &:hover
11
+ background-color: $btn-danger-bg
12
+ color: white
13
+
14
+ // Generated navbar ////////////////////////////////////////////////////////////
15
+ // Source: http://work.smarchal.com/twbscolor/sass/0066b3035ea3ffffffffffff0
16
+ $bgDefault: $brand-primary
17
+ $bgHighlight: darken($brand-primary, 5%)
18
+ $colDefault: $white
19
+ $colHighlight: $white
20
+ $dropDown: false
21
+
22
+ .navbar-default
23
+ background-color: $bgDefault
24
+ border-color: $bgHighlight
25
+ .navbar-brand
26
+ color: $colDefault
27
+ &:hover, &:focus
28
+ color: $colHighlight
29
+ .navbar-text
30
+ color: $colDefault
31
+ .navbar-nav
32
+ > li
33
+ > a
34
+ color: $colDefault
35
+ &:hover, &:focus
36
+ color: $colHighlight
37
+ @if $dropDown
38
+ > .dropdown-menu
39
+ background-color: $bgDefault
40
+ > li
41
+ > a
42
+ color: $colDefault
43
+ &:hover, &:focus
44
+ color: $colHighlight
45
+ background-color: $bgHighlight
46
+ > .divider
47
+ background-color: $bgHighlight
48
+ @if $dropDown
49
+ .open .dropdown-menu > .active
50
+ > a, > a:hover, > a:focus
51
+ color: $colHighlight
52
+ background-color: $bgHighlight
53
+ > .active
54
+ > a, > a:hover, > a:focus
55
+ color: $colHighlight
56
+ background-color: $bgHighlight
57
+ > .open
58
+ > a, > a:hover, > a:focus
59
+ color: $colHighlight
60
+ background-color: $bgHighlight
61
+ .navbar-toggle
62
+ border-color: $bgHighlight
63
+ &:hover, &:focus
64
+ background-color: $bgHighlight
65
+ .icon-bar
66
+ background-color: $colDefault
67
+ .navbar-collapse,
68
+ .navbar-form
69
+ border-color: $colDefault
70
+ .navbar-link
71
+ color: $colDefault
72
+ &:hover
73
+ color: $colHighlight
74
+ @media (max-width: 767px)
75
+ .navbar-default .navbar-nav .open .dropdown-menu
76
+ > li > a
77
+ color: $colDefault
78
+ &:hover, &:focus
79
+ color: $colHighlight
80
+ > .active
81
+ > a, > a:hover, > a:focus
82
+ color: $colHighlight
83
+ background-color: $bgHighlight
@@ -0,0 +1,11 @@
1
+ @import environment
2
+ @import url('https://fonts.googleapis.com/css?family=Open+Sans:400,700&subset=latin-ext')
3
+
4
+ html
5
+ -webkit-text-size-adjust: 100% // Prevent iOS font scaling in landscape
6
+
7
+ body
8
+ -webkit-font-smoothing: antialiased
9
+ -moz-osx-font-smoothing: grayscale
10
+
11
+ padding: $space-sm 0
@@ -0,0 +1,2 @@
1
+ @import ~unpoly/dist/unpoly
2
+ @import ~unpoly/dist/unpoly-bootstrap3
@@ -0,0 +1,13 @@
1
+ /* eslint no-console:0 */
2
+ import 'babel-polyfill' // ES6 for browsers like IE
3
+
4
+ import 'unpoly/dist/unpoly'
5
+ import 'unpoly/dist/unpoly-bootstrap3'
6
+ import 'jquery-ujs' // Rails goodies
7
+
8
+ import 'assets'
9
+
10
+ // Expose jQuery to developers
11
+ import jQuery from 'jquery'
12
+ window.$ = jQuery
13
+ window.jQuery = jQuery
@@ -2,7 +2,7 @@ common: &common
2
2
  adapter: postgresql
3
3
  encoding: unicode
4
4
  host: localhost
5
- username: root
5
+ username:
6
6
  password:
7
7
 
8
8
  development:
@@ -1,7 +1,7 @@
1
1
  abort 'You must run this using "bundle exec ..."' unless ENV['BUNDLE_BIN_PATH'] || ENV['BUNDLE_GEMFILE']
2
2
 
3
3
  # config valid only for current version of Capistrano
4
- lock '3.4.0'
4
+ lock '<%= @version %>'
5
5
 
6
6
  # Default value for :format is :pretty
7
7
  # set :format, :pretty
@@ -13,11 +13,11 @@ set :log_level, :info # %i(debug info error), default: :debug
13
13
 
14
14
  # Default value for :linked_files is []
15
15
  # set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')
16
- set :linked_files, %w(config/database.yml)
16
+ set :linked_files, %w(config/database.yml config/secrets.yml)
17
17
 
18
18
  # Default value for linked_dirs is []
19
19
  # set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
20
- set :linked_dirs, %w(log public/system)
20
+ set :linked_dirs, %w(log public/system tmp/pids)
21
21
 
22
22
  # Default value for default_env is {}
23
23
  # set :default_env, { path: "/opt/ruby/bin:$PATH" }
@@ -27,7 +27,6 @@ set :keep_releases, 10
27
27
  set :ssh_options, {
28
28
  forward_agent: true
29
29
  }
30
- set :scm, :git
31
30
  set :repo_url, 'git@code.makandra.de:makandra/<%= app_name %>.git'
32
31
 
33
32
  # set :whenever_roles, :cron
@@ -0,0 +1,5 @@
1
+ require_relative 'production'
2
+
3
+ Rails.application.configure do
4
+
5
+ end
@@ -0,0 +1,23 @@
1
+ # Avoid better_errors taking forever to render by ignoring variables larger than
2
+ # 10 Kilobytes. Based on https://github.com/charliesome/better_errors/issues/334
3
+
4
+ if defined?(BetterErrors) && Rails.env.development?
5
+ module BetterErrorsHugeInspectWarning
6
+
7
+ def inspect_value(obj)
8
+ inspected = obj.inspect
9
+ if inspected.size > 20_000
10
+ inspected = "Object was too large to inspect (#{inspected.size} bytes)."
11
+ end
12
+ CGI.escapeHTML(inspected)
13
+ rescue NoMethodError
14
+ "<span class='unsupported'>(object doesn't support inspect)</span>"
15
+ rescue Exception
16
+ "<span class='unsupported'>(exception was raised in inspect)</span>"
17
+ end
18
+
19
+ end
20
+
21
+ BetterErrors.ignored_instance_variables += [:@_request, :@_assigns, :@_controller, :@view_renderer]
22
+ BetterErrors::ErrorPage.prepend(BetterErrorsHugeInspectWarning)
23
+ end
@@ -5,7 +5,7 @@ ExceptionNotification.configure do |config|
5
5
  config.add_notifier :email, {
6
6
  email_prefix: '[<%= app_name %>] ',
7
7
  exception_recipients: %w[fail@makandra.de],
8
- sender_address: 'fail@makandra.de',
8
+ sender_address: Rails.configuration.system_email,
9
9
  sections: %w[request backtrace],
10
10
  background_sections: %w[backtrace],
11
11
  }
@@ -1,3 +1,3 @@
1
- Dir.glob(Rails.root.join('lib/ext/**/*.rb')).each do |filename|
1
+ Dir.glob(Rails.root.join('lib/ext/**/*.rb')).sort.each do |filename|
2
2
  require filename
3
3
  end
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ test: require.resolve('unpoly'),
3
+ use: 'imports-loader?this=>window'
4
+ }
@@ -2,3 +2,10 @@ require 'capybara-screenshot/cucumber'
2
2
 
3
3
  # Keep up to the number of screenshots specified in the hash
4
4
  Capybara::Screenshot.prune_strategy = { keep: 10 }
5
+
6
+ # This asset host will become a `<base>` tag in the HTML's `<head>` and allow
7
+ # resolving test assets via the development Rails server. This makes HTML
8
+ # screenshots prettier.
9
+ # Note that *you won't be using development assets* but the compiled files from
10
+ # `RAILS_ROOT/public/packs-test/`.
11
+ Capybara.asset_host = 'http://localhost:3000/'
@@ -0,0 +1 @@
1
+ World(FactoryBot::Syntax::Methods)
@@ -14,7 +14,7 @@ module NavigationHelpers
14
14
  when /^the (page|form) for the (.*?) above$/
15
15
  action_prose, model_prose = $1, $2
16
16
  route = "#{action_prose == 'form' ? 'edit_' : ''}#{model_prose_to_route_segment(model_prose)}_path"
17
- model = model_prose.classify.constantize
17
+ model = model_prose_to_class(model_prose)
18
18
  send(route, model.last)
19
19
 
20
20
  when /^the (page|form) for the (.*?) "(.*?)"$/
@@ -39,12 +39,17 @@ module NavigationHelpers
39
39
  private
40
40
 
41
41
  def path_to_show_or_edit(action_prose, model_prose, identifier)
42
- model = model_prose.classify.constantize
42
+ model = model_prose_to_class(model_prose)
43
43
  route = "#{action_prose == 'form' ? 'edit_' : ''}#{model_prose_to_route_segment(model_prose)}_path"
44
44
  send(route, model.find_by_anything!(identifier))
45
45
  end
46
46
 
47
+ def model_prose_to_class(model_prose)
48
+ model_prose.gsub(' ', '_').classify.constantize
49
+ end
50
+
47
51
  def model_prose_to_route_segment(model_prose)
52
+ model_prose = model_prose.downcase
48
53
  model_prose.gsub(/[\ \/]/, '_')
49
54
  end
50
55
 
@@ -0,0 +1 @@
1
+ require 'cucumber/rspec/doubles'
@@ -13,12 +13,12 @@ module HtmlSelectorsHelpers
13
13
  # Usage examples:
14
14
  # the main menu -> '.main-menu'
15
15
  # the item box's header -> '.item-box--header'
16
- # the slider's item that is current -> '.slider--item.is-current'
17
- when /^the (.+?)(?:'s (.+?))?(?: that (.+))?$/
16
+ # the slider's item (current) -> '.slider--item.-current'
17
+ when /^the (.+?)(?:'s (.+?))?(?: \((.+)\))?$/
18
18
  selector = '.'
19
19
  selector << selectorify($1)
20
20
  selector << '--' << selectorify($2) if $2
21
- selector << '.' << selectorify($3) if $3
21
+ selector << '.-' << selectorify($3) if $3
22
22
  selector
23
23
 
24
24
  # Add more mappings here.
@@ -0,0 +1,13 @@
1
+ chrome_args = %w[--mute-audio --disable-infobars]
2
+ no_password_bubble = {
3
+ 'credentials_enable_service' => false,
4
+ 'profile.password_manager_enabled' => false
5
+ }
6
+
7
+ Capybara.register_driver :selenium do |app|
8
+ Capybara::Selenium::Driver.new(app,
9
+ browser: :chrome,
10
+ args: chrome_args,
11
+ prefs: no_password_bubble
12
+ )
13
+ end
@@ -0,0 +1,35 @@
1
+ module WebpackerHelper
2
+
3
+ module_function def compile_once
4
+ digest_file = Rails.root.join("tmp/webpacker_#{Rails.env}_digest")
5
+
6
+ packable_contents = Dir[Webpacker.config.source_path.join('**/*')]
7
+ .sort
8
+ .map { |filename| File.read(filename) if File.file?(filename) }
9
+ .join
10
+ digest = Digest::SHA256.hexdigest(packable_contents)
11
+
12
+ return if digest_file.exist? && digest_file.read == digest
13
+
14
+ # Base process compiles
15
+ if ENV['TEST_ENV_NUMBER'].to_i < 1
16
+ output_path = Webpacker.config.public_output_path
17
+ FileUtils.rm_r(output_path) if File.exist?(output_path)
18
+ puts "Removed Webpack output directory #{output_path}"
19
+
20
+ Webpacker.compile or raise 'Compilation failed'
21
+
22
+ digest_file.write(digest)
23
+
24
+ # Parallel processes wait for compilation
25
+ else
26
+ loop do
27
+ break if digest_file.exist? && digest_file.read == digest
28
+ sleep 0.1
29
+ end
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ WebpackerHelper.compile_once
@@ -1,43 +1,43 @@
1
- if Rails.env == 'development'
2
-
3
- ActionView::Helpers::FormHelper.class_eval do
1
+ if Rails.env.development?
4
2
 
3
+ ActionView::Helpers::FormHelper.module_eval do
5
4
  def form_for_with_development_errors(*args, &block)
6
5
  form_for_without_development_errors(*args) do |form|
7
6
  html = ''.html_safe
8
- if form.object && form.object.respond_to?(:errors) && form.object.errors.any?
9
- html << content_tag(:div, form.object.errors.full_messages.collect { |m| h m }.join('<br />').html_safe, :class => 'development_errors', :onclick => 'this.parentNode.removeChild(this);')
10
- html << '<style type="text/css"><!--'.html_safe
11
- css = <<-EOF
12
- .development_errors {
13
- position: fixed;
14
- bottom: 0;
15
- right: 0;
16
- z-index: 999999;
17
- font-size: 11px;
18
- line-height: 15px;
19
- background-color: #fed;
20
- border-top: 1px solid #cba;
21
- border-left: 1px solid #cba;
22
- color: #821;
23
- padding: 10px;
24
- cursor: pointer;
25
- filter:alpha(opacity=80);
26
- -moz-opacity:0.8;
27
- -khtml-opacity: 0.8;
28
- opacity: 0.8;
29
-
30
- }
31
- EOF
32
- html << css.html_safe
33
- html << '</style>'.html_safe
34
- end
7
+ html << form_development_errors(form.object)
35
8
  html << capture(form, &block)
36
9
  end
37
10
  end
38
11
 
39
- alias_method_chain :form_for, :development_errors
12
+ alias_method :form_for_without_development_errors, :form_for
13
+ alias_method :form_for, :form_for_with_development_errors
14
+
15
+ private
16
+
17
+ def form_development_errors(object)
18
+ return unless object
19
+ return unless object.respond_to?(:errors)
20
+ return unless object.errors.any?
40
21
 
22
+ safe_messages = object.errors.full_messages.map { |message| h(message) }.join('<br />').html_safe
23
+
24
+ styles = <<~CSS
25
+ position: fixed;
26
+ bottom: 0;
27
+ right: 0;
28
+ z-index: 999999;
29
+ font-size: 0.8rem;
30
+ background-color: #fed;
31
+ border-top: 1px solid #cba;
32
+ border-left: 1px solid #cba;
33
+ color: #821;
34
+ padding: 0.5em 1em;
35
+ cursor: pointer;
36
+ opacity: 0.8;
37
+ CSS
38
+
39
+ content_tag(:div, safe_messages, style: styles.squish, onclick: 'this.parentNode.removeChild(this)')
40
+ end
41
41
  end
42
42
 
43
43
  end
@@ -4,16 +4,17 @@ ActiveRecord::Base.class_eval do
4
4
  matchable_columns = columns.reject { |column| [:binary, :boolean].include?(column.type) }
5
5
  query_clauses = matchable_columns.collect do |column|
6
6
  qualified_column_name = "#{table_name}.#{column.name}"
7
- column_as_string = "CAST(#{qualified_column_name} AS CHAR)"
7
+ is_mysql = connection.class.name =~ /mysql/i
8
+ target_type = is_mysql ? 'CHAR' : 'TEXT' # CHAR is only 1 character in PostgreSQL
9
+ column_as_string = "CAST(#{qualified_column_name} AS #{target_type})"
8
10
  "#{column_as_string} = ?"
9
11
  end
10
12
  bindings = [identifier] * query_clauses.size
11
13
  where([query_clauses.join(' OR '), *bindings]).first
12
14
  end
13
-
15
+
14
16
  def self.find_by_anything!(identifier)
15
17
  find_by_anything(identifier) or raise ActiveRecord::RecordNotFound, "No column equals \"#{identifier}\""
16
18
  end
17
19
 
18
20
  end
19
-
@@ -0,0 +1,5 @@
1
+ # This empty file allows all robots, see http://www.robotstxt.org/robotstxt.html
2
+ #
3
+ # To exclude all robots from the entire domain, uncomment this:
4
+ # User-agent: *
5
+ # Disallow: /
@@ -1,4 +1,4 @@
1
- FactoryGirl.define do
1
+ FactoryBot.define do
2
2
 
3
3
  factory :EXAMPLE do
4
4
  status 'pending'
@@ -0,0 +1,20 @@
1
+ RSpec.configure do |config|
2
+ config.before(:suite) do
3
+ DatabaseCleaner.clean_with(:deletion)
4
+ end
5
+
6
+ config.around do |example|
7
+ DatabaseCleaner.strategy = case
8
+ when example.metadata[:transaction] == false
9
+ :deletion
10
+ when example.metadata[:js] == true
11
+ :deletion
12
+ else
13
+ :transaction
14
+ end
15
+
16
+ DatabaseCleaner.start
17
+ example.run
18
+ DatabaseCleaner.clean
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ RSpec.configure do |config|
2
+ config.include FactoryBot::Syntax::Methods
3
+ end
@@ -0,0 +1,6 @@
1
+ include ActionDispatch::TestProcess
2
+
3
+ def fixture_file(file_name)
4
+ file_path = Rails.root.join('spec/assets', file_name)
5
+ File.open(file_path)
6
+ end
@@ -0,0 +1,15 @@
1
+ # We initialize all Postgres sequences with high values so that tests setting
2
+ # specific ids will not accidentally reuse the same ids
3
+
4
+ RSpec.configure do |config|
5
+ config.before(:suite) do
6
+
7
+ connection = ActiveRecord::Base.connection
8
+ sequences = connection.select_values("SELECT relname FROM pg_class WHERE pg_class.relkind = 'S'")
9
+
10
+ sequences.each do |sequence|
11
+ connection.execute("SELECT setval('#{sequence}', 1000000)")
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ RSpec.configure do |config|
2
+ config.after { Timecop.return }
3
+ end