potassium 6.3.0 → 6.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +1 -1
- data/.node-version +1 -1
- data/CHANGELOG.md +45 -0
- data/README.md +30 -3
- data/docs/CONTRIBUTING.md +2 -2
- data/lib/potassium/assets/.circleci/config.yml.erb +40 -12
- data/lib/potassium/assets/.eslintrc.json +15 -9
- data/lib/potassium/assets/.pryrc +0 -6
- data/lib/potassium/assets/.rubocop.yml +1 -0
- data/lib/potassium/assets/Aptfile +5 -0
- data/lib/potassium/assets/README.yml +74 -7
- data/lib/potassium/assets/active_admin/admin-component.vue +22 -30
- data/lib/potassium/assets/active_admin/policies/admin_user_policy.rb +2 -0
- data/lib/potassium/assets/active_admin/policies/comment_policy.rb +2 -0
- data/lib/potassium/assets/active_admin/policies/default_policy.rb +49 -0
- data/lib/potassium/assets/active_admin/policies/page_policy.rb +2 -0
- data/lib/potassium/assets/app/javascript/{app.spec.js → components/app.spec.ts} +2 -2
- data/lib/potassium/assets/app/javascript/components/app.vue +9 -0
- data/lib/potassium/assets/app/javascript/types/vue.d.ts +5 -0
- data/lib/potassium/assets/app/jobs/shrine_promote_job.rb +14 -0
- data/lib/potassium/assets/app/mailers/application_mailer.rb +1 -1
- data/lib/potassium/assets/app/mailers/example_mailer.rb +6 -0
- data/lib/potassium/assets/app/serializers/base_serializer.rb +3 -0
- data/lib/potassium/assets/app/serializers/concerns/image_handling_attributes.rb +20 -0
- data/lib/potassium/assets/app/uploaders/cover_image_uploader.rb +52 -0
- data/lib/potassium/assets/app/views/example_mailer/example_mail.html.mjml +7 -0
- data/lib/potassium/assets/app/views/layouts/default_mail.html.mjml +49 -0
- data/lib/potassium/assets/config/initializers/shrine/plugins/image_handling_utilities.rb +143 -0
- data/lib/potassium/assets/config/mailer.rb.erb +0 -2
- data/lib/potassium/assets/config/shrine.rb +15 -0
- data/lib/potassium/assets/config/webpack/rules/css.js +5 -0
- data/lib/potassium/assets/config/webpack/rules/index.js +11 -0
- data/lib/potassium/assets/config/webpack/rules/jquery.js +11 -0
- data/lib/potassium/assets/config/webpack/rules/typescript.js +32 -0
- data/lib/potassium/assets/config/webpack/rules/vue.js +19 -0
- data/lib/potassium/assets/config/webpack/webpack.config.js +4 -0
- data/lib/potassium/assets/public/mails/platanus-logo.png +0 -0
- data/lib/potassium/assets/testing/.rspec +1 -0
- data/lib/potassium/assets/testing/devise_config.rb +6 -0
- data/lib/potassium/assets/testing/factory_bot_config.rb +3 -0
- data/lib/potassium/assets/testing/faker_config.rb +1 -0
- data/lib/potassium/assets/testing/power_types_config.rb +1 -0
- data/lib/potassium/assets/testing/rails_helper.rb +130 -49
- data/lib/potassium/assets/testing/shoulda_matchers_config.rb +8 -0
- data/lib/potassium/assets/testing/simplecov_config.rb +64 -0
- data/lib/potassium/assets/testing/system_tests_config.rb +6 -0
- data/lib/potassium/assets/tsconfig.json +31 -0
- data/lib/potassium/cli/commands/create.rb +3 -1
- data/lib/potassium/cli_options.rb +23 -3
- data/lib/potassium/platanus_config.rb +20 -0
- data/lib/potassium/recipes/admin.rb +37 -16
- data/lib/potassium/recipes/api.rb +8 -85
- data/lib/potassium/recipes/coverage.rb +66 -0
- data/lib/potassium/recipes/file_storage.rb +50 -0
- data/lib/potassium/recipes/front_end.rb +87 -108
- data/lib/potassium/recipes/google_tag_manager.rb +20 -16
- data/lib/potassium/recipes/heroku.rb +1 -2
- data/lib/potassium/recipes/mailer.rb +22 -10
- data/lib/potassium/recipes/mjml.rb +31 -0
- data/lib/potassium/recipes/node.rb +11 -13
- data/lib/potassium/recipes/pundit.rb +29 -10
- data/lib/potassium/recipes/rails.rb +0 -4
- data/lib/potassium/recipes/spring.rb +9 -0
- data/lib/potassium/recipes/style.rb +9 -2
- data/lib/potassium/recipes/testing.rb +75 -18
- data/lib/potassium/recipes/vue_admin.rb +38 -8
- data/lib/potassium/templates/application.rb +5 -2
- data/lib/potassium/version.rb +10 -4
- data/spec/features/api_spec.rb +6 -1
- data/spec/features/ci_spec.rb +1 -1
- data/spec/features/coverage_spec.rb +43 -0
- data/spec/features/file_storage_spec.rb +102 -26
- data/spec/features/front_end_spec.rb +16 -47
- data/spec/features/google_tag_manager_spec.rb +1 -24
- data/spec/features/heroku_spec.rb +0 -4
- data/spec/features/mailer_spec.rb +79 -33
- data/spec/features/mjml_spec.rb +53 -0
- data/spec/features/node_spec.rb +1 -1
- data/spec/features/pundit_spec.rb +34 -0
- data/spec/features/testing_spec.rb +56 -0
- data/spec/features/vue_admin_spec.rb +0 -10
- data/spec/support/potassium_test_helpers.rb +2 -2
- data/spec/support/shared_examples.rb +5 -0
- metadata +50 -27
- data/lib/potassium/assets/active_admin/admin_application.js +0 -14
- data/lib/potassium/assets/active_admin/admin_user_policy.rb +0 -2
- data/lib/potassium/assets/active_admin/comment_policy.rb +0 -2
- data/lib/potassium/assets/active_admin/init_activeadmin_vue.rb +0 -10
- data/lib/potassium/assets/active_admin/pundit_page_policy.rb +0 -5
- data/lib/potassium/assets/app/graphql/graphql_controller.rb +0 -55
- data/lib/potassium/assets/app/graphql/mutations/login_mutation.rb +0 -23
- data/lib/potassium/assets/app/graphql/queries/base_query.rb +0 -4
- data/lib/potassium/assets/app/graphql/types/base/base_argument.rb +0 -4
- data/lib/potassium/assets/app/graphql/types/base/base_enum.rb +0 -4
- data/lib/potassium/assets/app/graphql/types/base/base_field.rb +0 -5
- data/lib/potassium/assets/app/graphql/types/base/base_input_object.rb +0 -5
- data/lib/potassium/assets/app/graphql/types/base/base_interface.rb +0 -7
- data/lib/potassium/assets/app/graphql/types/base/base_object.rb +0 -5
- data/lib/potassium/assets/app/graphql/types/base/base_scalar.rb +0 -4
- data/lib/potassium/assets/app/graphql/types/base/base_union.rb +0 -4
- data/lib/potassium/assets/app/graphql/types/mutation_type.rb +0 -10
- data/lib/potassium/assets/app/graphql/types/query_type.rb +0 -13
- data/lib/potassium/assets/config/graphql_playground.rb +0 -20
- data/spec/features/graphql_spec.rb +0 -71
@@ -0,0 +1,20 @@
|
|
1
|
+
module ImageHandlingAttributes
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
class_methods do
|
5
|
+
def add_image_handling_attributes(attachment_name:, derivatives:, include_original_image: false)
|
6
|
+
attributes attachment_name, "#{attachment_name}_blurhash".to_sym
|
7
|
+
|
8
|
+
define_method(attachment_name) do
|
9
|
+
attachment_hash = derivatives.reduce({}) do |hash, derivative|
|
10
|
+
hash[derivative] = { url: object.send("#{attachment_name}_url", derivative) }
|
11
|
+
hash
|
12
|
+
end
|
13
|
+
if include_original_image
|
14
|
+
attachment_hash[:original] = { url: object.send("#{attachment_name}_url") }
|
15
|
+
end
|
16
|
+
attachment_hash
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "image_processing/vips"
|
2
|
+
|
3
|
+
class CoverImageUploader < ImageUploader
|
4
|
+
plugin :derivation_endpoint, prefix: "derivations/cover_image"
|
5
|
+
plugin :add_metadata
|
6
|
+
plugin :image_handling_utilities
|
7
|
+
|
8
|
+
DERIVATIVES = {
|
9
|
+
sm: { size: [426, 240], type: 'jpg' },
|
10
|
+
md: { size: [960, 540], type: 'jpg' },
|
11
|
+
lg: { size: [1280, 720], type: 'jpg' },
|
12
|
+
webp_sm: { size: [426, 240], type: 'webp' },
|
13
|
+
webp_md: { size: [960, 540], type: 'webp' },
|
14
|
+
webp_lg: { size: [1280, 720], type: 'webp' }
|
15
|
+
}
|
16
|
+
|
17
|
+
Attacher.derivatives do |original|
|
18
|
+
vips = ImageProcessing::Vips.source(original)
|
19
|
+
|
20
|
+
DERIVATIVES.reduce({}) do |derivatives_hash, (name, derivative_info)|
|
21
|
+
derivatives_hash[name] = vips.convert(derivative_info[:type]).resize_to_limit!(
|
22
|
+
*derivative_info[:size]
|
23
|
+
)
|
24
|
+
derivatives_hash
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
derivation :thumbnail do |file, width, height|
|
29
|
+
ImageProcessing::Vips
|
30
|
+
.source(file)
|
31
|
+
.resize_to_limit!(width.to_i, height.to_i)
|
32
|
+
end
|
33
|
+
|
34
|
+
Attacher.default_url do |derivative: nil, **|
|
35
|
+
file&.derivation_url(:thumbnail, *DERIVATIVES.dig(derivative, :size)) if derivative.present?
|
36
|
+
end
|
37
|
+
|
38
|
+
add_metadata :blurhash do |io, derivative: nil, **|
|
39
|
+
if derivative.nil?
|
40
|
+
Shrine.with_file(io) do |file|
|
41
|
+
image = Vips::Image.new_from_file(file.path, access: :sequential)
|
42
|
+
image = image.resize(100.0 / image.width)
|
43
|
+
flat_rgb_pixels = []
|
44
|
+
image.to_a.each do |row|
|
45
|
+
row.each { |pixel| flat_rgb_pixels.concat(pixel[0..2]) }
|
46
|
+
end
|
47
|
+
|
48
|
+
Blurhash.encode(image.width, image.height, flat_rgb_pixels)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<mjml>
|
2
|
+
<mj-head>
|
3
|
+
<mj-attributes>
|
4
|
+
<mj-all font-family="'Helvetica Neue', Helvetica, Arial, sans-serif"></mj-all>
|
5
|
+
<mj-text font-weight="400" font-size="16px" color="#000000" line-height="24px" font-family="'Helvetica Neue', Helvetica, Arial, sans-serif"></mj-text>
|
6
|
+
</mj-attributes>
|
7
|
+
<mj-style inline="inline">
|
8
|
+
.body-section {
|
9
|
+
-webkit-box-shadow: 1px 4px 11px 0px rgba(0, 0, 0, 0.15);
|
10
|
+
-moz-box-shadow: 1px 4px 11px 0px rgba(0, 0, 0, 0.15);
|
11
|
+
box-shadow: 1px 4px 11px 0px rgba(0, 0, 0, 0.15);
|
12
|
+
}
|
13
|
+
</mj-style>
|
14
|
+
<mj-style inline="inline">
|
15
|
+
.text-link {
|
16
|
+
color: #5e6ebf
|
17
|
+
}
|
18
|
+
</mj-style>
|
19
|
+
<mj-style inline="inline">
|
20
|
+
.footer-link {
|
21
|
+
color: #888888
|
22
|
+
}
|
23
|
+
</mj-style>
|
24
|
+
|
25
|
+
</mj-head>
|
26
|
+
<mj-body width="600px">
|
27
|
+
<mj-section full-width="full-width" background-color="#71717A" padding-bottom="0">
|
28
|
+
<mj-column width="100%" background-color="#A1A1AA">
|
29
|
+
<mj-spacer height="25px" />
|
30
|
+
</mj-column>
|
31
|
+
</mj-section>
|
32
|
+
<mj-section background-color="#A1A1AA" padding-bottom="0" padding-top="0">
|
33
|
+
<mj-column>
|
34
|
+
<mj-image width="100px" src="<%= image_url('/mails/platanus-logo.png') %>" align="center">
|
35
|
+
</mj-column>
|
36
|
+
<mj-column width="100%">
|
37
|
+
<mj-spacer height="25px" />
|
38
|
+
</mj-column>
|
39
|
+
</mj-section>
|
40
|
+
<mj-wrapper padding-top="0" padding-bottom="0" css-class="body-section" background-color="#ffffff" padding-left="15px" padding-right="15px">
|
41
|
+
<%= yield %>
|
42
|
+
</mj-wrapper>
|
43
|
+
<mj-section background-color="#A1A1AA" padding-bottom="0" padding-top="0">
|
44
|
+
<mj-column width="100%">
|
45
|
+
<mj-spacer height="25px" />
|
46
|
+
</mj-column>
|
47
|
+
</mj-section>
|
48
|
+
</mj-body>
|
49
|
+
</mjml>
|
@@ -0,0 +1,143 @@
|
|
1
|
+
class Shrine
|
2
|
+
module Plugins
|
3
|
+
module ImageHandlingUtilities
|
4
|
+
# rubocop:disable Metrics/ModuleLength
|
5
|
+
module AttachmentMethods
|
6
|
+
def included(klass)
|
7
|
+
super
|
8
|
+
|
9
|
+
define_instance_methods
|
10
|
+
define_class_methods(klass)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def define_instance_methods
|
16
|
+
define_with_stored_attacher_method
|
17
|
+
define_blurhash_instance_method
|
18
|
+
define_generate_derivatives_instance_method
|
19
|
+
define_generate_metadata_instance_method
|
20
|
+
define_generate_derivatives_and_metadata_instance_method
|
21
|
+
end
|
22
|
+
|
23
|
+
def define_blurhash_instance_method
|
24
|
+
name = @name
|
25
|
+
define_method(:"#{@name}_blurhash") do
|
26
|
+
send(name)&.metadata&.[]('blurhash')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def define_generate_derivatives_instance_method
|
31
|
+
name = @name
|
32
|
+
define_method(:"generate_#{name}_derivatives") do
|
33
|
+
send("with_stored_#{name}_attacher") do |attacher|
|
34
|
+
old_derivatives = attacher.derivatives
|
35
|
+
|
36
|
+
attacher.set_derivatives({})
|
37
|
+
attacher.create_derivatives
|
38
|
+
|
39
|
+
begin
|
40
|
+
attacher.atomic_persist
|
41
|
+
attacher.delete_derivatives(old_derivatives) if old_derivatives.present?
|
42
|
+
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
|
43
|
+
attacher.delete_derivatives
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def define_generate_metadata_instance_method
|
50
|
+
name = @name
|
51
|
+
define_method(:"generate_#{name}_metadata") do
|
52
|
+
send("with_stored_#{name}_attacher") do |attacher|
|
53
|
+
attacher.refresh_metadata!
|
54
|
+
attacher.atomic_persist
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# rubocop:disable Metrics/MethodLength
|
60
|
+
def define_generate_derivatives_and_metadata_instance_method
|
61
|
+
name = @name
|
62
|
+
define_method(:"generate_#{name}_derivatives_and_metadata") do
|
63
|
+
send("with_stored_#{name}_attacher") do |attacher|
|
64
|
+
old_derivatives = attacher.derivatives
|
65
|
+
|
66
|
+
attacher.set_derivatives({})
|
67
|
+
attacher.file.open do
|
68
|
+
attacher.create_derivatives
|
69
|
+
attacher.refresh_metadata!
|
70
|
+
end
|
71
|
+
|
72
|
+
begin
|
73
|
+
attacher.atomic_persist
|
74
|
+
attacher.delete_derivatives(old_derivatives) if old_derivatives.present?
|
75
|
+
rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
|
76
|
+
attacher.delete_derivatives
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
# rubocop:enable Metrics/MethodLength
|
82
|
+
|
83
|
+
def define_class_methods(klass)
|
84
|
+
define_generate_all_derivatives_class_method(klass)
|
85
|
+
define_generate_all_metadata_class_method(klass)
|
86
|
+
define_generate_all_derivatives_and_metadata_class_method(klass)
|
87
|
+
end
|
88
|
+
|
89
|
+
def define_generate_all_derivatives_class_method(klass)
|
90
|
+
name = @name
|
91
|
+
klass.send(
|
92
|
+
:define_singleton_method, :"generate_all_#{name}_derivatives"
|
93
|
+
) do |&error_block|
|
94
|
+
all.find_each do |record|
|
95
|
+
record.send(:"generate_#{name}_derivatives")
|
96
|
+
rescue StandardError => e
|
97
|
+
error_block.call(record, e) if error_block.present?
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def define_generate_all_metadata_class_method(klass)
|
103
|
+
name = @name
|
104
|
+
klass.send(:define_singleton_method, :"generate_all_#{name}_metadata") do |&error_block|
|
105
|
+
all.find_each do |record|
|
106
|
+
record.send(:"generate_#{name}_metadata")
|
107
|
+
rescue StandardError => e
|
108
|
+
error_block.call(record, e) if error_block.present?
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def define_generate_all_derivatives_and_metadata_class_method(klass)
|
114
|
+
name = @name
|
115
|
+
klass.send(
|
116
|
+
:define_singleton_method, :"generate_all_#{name}_derivatives_and_metadata"
|
117
|
+
) do |&error_block|
|
118
|
+
all.find_each do |record|
|
119
|
+
record.send(:"generate_#{name}_derivatives_and_metadata")
|
120
|
+
rescue StandardError => e
|
121
|
+
error_block.call(record, e) if error_block.present?
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def define_with_stored_attacher_method
|
127
|
+
name = @name
|
128
|
+
define_method(:"with_stored_#{name}_attacher") do |&block|
|
129
|
+
return if send(name).blank?
|
130
|
+
|
131
|
+
attacher = send(:"#{name}_attacher")
|
132
|
+
|
133
|
+
block.call(attacher) if attacher.stored?
|
134
|
+
end
|
135
|
+
private :"with_stored_#{name}_attacher"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
# rubocop:enable Metrics/ModuleLength
|
139
|
+
end
|
140
|
+
|
141
|
+
register_plugin(:image_handling_utilities, ImageHandlingUtilities)
|
142
|
+
end
|
143
|
+
end
|
@@ -7,8 +7,6 @@ Rails.application.config.action_mailer.default_url_options = {
|
|
7
7
|
}
|
8
8
|
|
9
9
|
Rails.application.config.action_mailer.default_options = { from: ENV['DEFAULT_EMAIL_ADDRESS'] }
|
10
|
-
ASSET_HOST = ENV.fetch("ASSET_HOST", ENV.fetch("APPLICATION_HOST"))
|
11
|
-
Rails.application.config.action_mailer.asset_host = ASSET_HOST
|
12
10
|
|
13
11
|
if ENV["EMAIL_RECIPIENTS"].present?
|
14
12
|
Mail.register_interceptor RecipientInterceptor.new(
|
@@ -34,3 +34,18 @@ Shrine.plugin :activerecord
|
|
34
34
|
Shrine.plugin :cached_attachment_data
|
35
35
|
Shrine.plugin :restore_cached_data
|
36
36
|
Shrine.plugin :determine_mime_type, analyzer: :marcel
|
37
|
+
Shrine.plugin :derivatives
|
38
|
+
Shrine.plugin :default_url
|
39
|
+
Shrine.plugin :derivation_endpoint, secret_key: ENV.fetch('SHRINE_SECRET_KEY')
|
40
|
+
Shrine.plugin :refresh_metadata
|
41
|
+
Shrine.plugin :backgrounding
|
42
|
+
|
43
|
+
Shrine::Attacher.promote_block do |attacher|
|
44
|
+
ShrinePromoteJob.perform_later(
|
45
|
+
attacher.class.name,
|
46
|
+
attacher.record.class.name,
|
47
|
+
attacher.record.id,
|
48
|
+
attacher.name,
|
49
|
+
attacher.file_data
|
50
|
+
)
|
51
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
const vueConfig = require('./vue');
|
2
|
+
const cssConfig = require('./css');
|
3
|
+
const jQueryConfig = require('./jquery');
|
4
|
+
const typescriptConfig = require('./typescript');
|
5
|
+
|
6
|
+
module.exports = {
|
7
|
+
vueConfig,
|
8
|
+
cssConfig,
|
9
|
+
jQueryConfig,
|
10
|
+
typescriptConfig,
|
11
|
+
};
|
@@ -0,0 +1,32 @@
|
|
1
|
+
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
2
|
+
|
3
|
+
module.exports = {
|
4
|
+
module: {
|
5
|
+
rules: [
|
6
|
+
{
|
7
|
+
test: /\.ts$/,
|
8
|
+
loader: 'ts-loader',
|
9
|
+
exclude: /node_modules/,
|
10
|
+
options: {
|
11
|
+
appendTsSuffixTo: [/\.vue$/],
|
12
|
+
transpileOnly: true,
|
13
|
+
},
|
14
|
+
},
|
15
|
+
],
|
16
|
+
},
|
17
|
+
resolve: {
|
18
|
+
extensions: ['.ts'],
|
19
|
+
},
|
20
|
+
plugins: [
|
21
|
+
new ForkTsCheckerWebpackPlugin({
|
22
|
+
typescript: {
|
23
|
+
extensions: {
|
24
|
+
vue: {
|
25
|
+
enabled: true,
|
26
|
+
compiler: '@vue/compiler-sfc',
|
27
|
+
},
|
28
|
+
},
|
29
|
+
},
|
30
|
+
}),
|
31
|
+
],
|
32
|
+
};
|
@@ -0,0 +1,19 @@
|
|
1
|
+
const { VueLoaderPlugin } = require('vue-loader')
|
2
|
+
|
3
|
+
module.exports = {
|
4
|
+
module: {
|
5
|
+
rules: [
|
6
|
+
{
|
7
|
+
test: /\.vue$/,
|
8
|
+
loader: 'vue-loader'
|
9
|
+
}
|
10
|
+
]
|
11
|
+
},
|
12
|
+
plugins: [new VueLoaderPlugin()],
|
13
|
+
resolve: {
|
14
|
+
extensions: ['.vue'],
|
15
|
+
alias: {
|
16
|
+
'vue$': 'vue/dist/vue.esm-bundler.js',
|
17
|
+
}
|
18
|
+
},
|
19
|
+
}
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'faker'
|
@@ -0,0 +1 @@
|
|
1
|
+
PowerTypes::Observable.observable_disabled = true
|
@@ -1,60 +1,141 @@
|
|
1
|
-
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
2
1
|
ENV['RACK_ENV'] ||= 'test'
|
3
2
|
require File.expand_path('../config/environment', __dir__)
|
4
3
|
require 'rspec/rails'
|
5
4
|
require 'spec_helper'
|
6
|
-
require 'shoulda/matchers'
|
7
|
-
require 'faker'
|
8
|
-
# Add additional requires below this line. Rails is not loaded until this point!
|
9
|
-
|
10
|
-
# Requires supporting ruby files with custom matchers and macros, etc, in
|
11
|
-
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
|
12
|
-
# run as spec files by default. This means that files in spec/support that end
|
13
|
-
# in _spec.rb will both be required and run as specs, causing the specs to be
|
14
|
-
# run twice. It is recommended that you do not name files matching this glob to
|
15
|
-
# end with _spec.rb. You can configure this pattern with the --pattern
|
16
|
-
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
|
17
|
-
#
|
18
|
-
# The following line is provided for convenience purposes. It has the downside
|
19
|
-
# of increasing the boot-up time by auto-requiring all files in the support
|
20
|
-
# directory. Alternatively, in the individual `*_spec.rb` files, manually
|
21
|
-
# require only the support files necessary.
|
22
|
-
#
|
23
|
-
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
|
24
|
-
|
25
|
-
# Checks for pending migrations before tests are run.
|
26
|
-
# If you are not using ActiveRecord, you can remove this line.
|
27
|
-
ActiveRecord::Migration.maintain_test_schema!
|
28
5
|
|
29
|
-
|
6
|
+
=begin
|
30
7
|
|
31
|
-
|
32
|
-
|
33
|
-
# examples within a transaction, remove the following line or assign false
|
34
|
-
# instead of true.
|
35
|
-
config.use_transactional_fixtures = true
|
8
|
+
General
|
9
|
+
=======
|
36
10
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# You can disable this behaviour by removing the line below, and instead
|
42
|
-
# explicitly tag your specs with their type, e.g.:
|
43
|
-
#
|
44
|
-
# RSpec.describe UsersController, :type => :controller do
|
45
|
-
# # ...
|
46
|
-
# end
|
47
|
-
#
|
48
|
-
# The different available types are documented in the features, such as in
|
49
|
-
# https://relishapp.com/rspec/rspec-rails/docs
|
50
|
-
config.infer_spec_type_from_file_location!
|
11
|
+
1) Place your unit tests inside the "spec" directory.
|
12
|
+
2) Run unit tests executing `bin/guard`.
|
13
|
+
3) Use support directories to add helpers and settings.
|
14
|
+
You can only put RSpec configuration on this file.
|
51
15
|
|
52
|
-
|
53
|
-
|
16
|
+
Support
|
17
|
+
-------
|
18
|
+
|
19
|
+
* spec/support/configurations: put testing related gem settings here.
|
20
|
+
|
21
|
+
For example: spec/support/configurations/shoulda_matchers_config.rb
|
22
|
+
|
23
|
+
----------------------------------------
|
24
|
+
require 'shoulda/matchers'
|
25
|
+
|
26
|
+
Shoulda::Matchers.configure do |config|
|
27
|
+
config.integrate do |with|
|
28
|
+
with.test_framework :rspec
|
29
|
+
with.library :rails
|
30
|
+
end
|
31
|
+
end
|
32
|
+
----------------------------------------
|
33
|
+
|
34
|
+
* spec/support/helpers: place here helpers created by you to use in your unit tests.
|
35
|
+
|
36
|
+
For example: spec/support/helpers/attachments_helpers.rb
|
37
|
+
|
38
|
+
----------------------------------------------------------------------------------
|
39
|
+
module AttachmentsHelpers
|
40
|
+
extend ActiveSupport::Concern
|
41
|
+
|
42
|
+
included do
|
43
|
+
def create_attachment_file(filename: "pikachu.png", content_type: "image/png")
|
44
|
+
Rack::Test::UploadedFile.new(file_fixture(filename), content_type)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
RSpec.configure do |config|
|
50
|
+
config.fixture_path = "#{::Rails.root}/spec/assets"
|
51
|
+
config.file_fixture_path = "#{::Rails.root}/spec/assets"
|
52
|
+
|
53
|
+
config.include AttachmentsHelpers
|
54
|
+
end
|
55
|
+
----------------------------------------------------------------------------------
|
56
|
+
|
57
|
+
* spec/support/custom_matchers: place here your custom matchers
|
58
|
+
(https://relishapp.com/rspec/rspec-expectations/v/3-10/docs/custom-matchers)
|
59
|
+
|
60
|
+
* spec/support/shared_examples: place here your shared examples
|
61
|
+
(https://relishapp.com/rspec/rspec-core/v/3-10/docs/example-groups/shared-examples)
|
62
|
+
|
63
|
+
System Tests
|
64
|
+
============
|
65
|
+
|
66
|
+
1) Place your system tests inside the "spec/system" directory.
|
67
|
+
2) Run system tests executing `bin/rspec --tag type:system`.
|
68
|
+
|
69
|
+
Support
|
70
|
+
-------
|
71
|
+
|
72
|
+
* spec/support/configurations/system_tests_config.rb: on this file you will find the
|
73
|
+
general configuration of the system tests. Keep in mind that this type of test will
|
74
|
+
run with the `selenium_chrome_headless` driver unless you put the `no_js` tag.
|
54
75
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
76
|
+
For example: spec/system/login_spec.rb
|
77
|
+
|
78
|
+
----------------------------------------------------------------------------
|
79
|
+
require "rails_helper"
|
80
|
+
|
81
|
+
RSpec.describe "Login" do
|
82
|
+
let!(:user) { create(:user, email: "lean@platan.us") }
|
83
|
+
|
84
|
+
context "without logged user", :no_js do # will use :rack_test driver
|
85
|
+
before { visit("/") }
|
86
|
+
|
87
|
+
it { expect(page).to have_text("Ingresa") }
|
88
|
+
end
|
89
|
+
|
90
|
+
context "with logged user" do # will use :selenium_chrome_headless driver
|
91
|
+
before { sign_in(user) }
|
92
|
+
|
93
|
+
it { expect(page).to have_text("Hola!") }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
----------------------------------------------------------------------------
|
97
|
+
|
98
|
+
* spec/support/helpers/system: place here helpers created by you
|
99
|
+
to use in your system tests.
|
100
|
+
|
101
|
+
For example: spec/support/helpers/login_helpers.rb
|
102
|
+
|
103
|
+
------------------------------------------------
|
104
|
+
module LoginHelpers
|
105
|
+
extend ActiveSupport::Concern
|
106
|
+
|
107
|
+
included do
|
108
|
+
def sign_in(email, password)
|
109
|
+
visit('/users/sign_in')
|
110
|
+
|
111
|
+
within(:xpath, '//*[@id="new_user"]') do
|
112
|
+
fill_in('Email', with: email)
|
113
|
+
fill_in('Contraseña', with: password)
|
114
|
+
end
|
115
|
+
|
116
|
+
click_button('Ingresar')
|
117
|
+
end
|
118
|
+
|
119
|
+
def logout
|
120
|
+
visit('/users/sign_out')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
RSpec.configure do |config|
|
126
|
+
config.include LoginHelpers, type: :system
|
59
127
|
end
|
128
|
+
------------------------------------------------
|
129
|
+
|
130
|
+
Remember to include the system helpers with the tag `type: :system`
|
131
|
+
=end
|
132
|
+
|
133
|
+
Dir[Rails.root.join("spec/support/**/*.rb")].sort.each { |f| require f }
|
134
|
+
|
135
|
+
ActiveRecord::Migration.maintain_test_schema!
|
136
|
+
|
137
|
+
RSpec.configure do |config|
|
138
|
+
config.use_transactional_fixtures = true
|
139
|
+
config.infer_spec_type_from_file_location!
|
140
|
+
config.filter_run_when_matching :focus unless Rails.env.production?
|
60
141
|
end
|