inline_forms_installer 8.1.5 → 8.1.6
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 +4 -4
- data/lib/inline_forms_installer/installer_core.rb +196 -0
- data/lib/inline_forms_installer/version.rb +1 -1
- data/lib/installer_templates/example_app_assets/1stars.png +0 -0
- data/lib/installer_templates/example_app_assets/2stars.png +0 -0
- data/lib/installer_templates/example_app_assets/3stars.png +0 -0
- data/lib/installer_templates/example_app_assets/4stars.png +0 -0
- data/lib/installer_templates/example_app_assets/5stars.png +0 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_showcase_choice_scale_fields_test.rb +126 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_showcase_date_time_fields_test.rb +84 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_showcase_numeric_fields_test.rb +79 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_showcase_page_render_test.rb +116 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_showcase_text_fields_test.rb +47 -0
- data/lib/installer_templates/example_app_tests/test/models/example_app_form_element_showcase_test.rb +81 -0
- metadata +12 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8780337213fbfb45e061f0f5309c9cb73826461aacca4dd4cc1662214b8654f4
|
|
4
|
+
data.tar.gz: c355bf659cc460fa83ca210a712c91b466dc4d7e30c0c8477906b2d867770674
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1e663a9f2bfdf0ad9e8bab1a93cb397a12374d7918a7f08d069c10b84ca3e635c95cd702c87e1164fb78173f6992cd99191930c1814ffdddc7d996273303c5c5
|
|
7
|
+
data.tar.gz: 210aef3002d3c58c01f226c5f29e6f0a7e548c8b273cb3eca3f08e524beb407f16b75d4cd3ec46abcac4e4a65b21d05c3d2132e79d347cac5a528b54119ac5a4
|
|
@@ -1039,6 +1039,202 @@ if ENV['install_example'] == 'true'
|
|
|
1039
1039
|
say "- Running migrations for owner + seed (owners + apartments.owner_id + 3 apts/3 owners)..."
|
|
1040
1040
|
run "bundle exec rake db:migrate"
|
|
1041
1041
|
|
|
1042
|
+
# ---------------------------------------------------------------------
|
|
1043
|
+
# FormElementShowcase: a fourth example resource that exercises every
|
|
1044
|
+
# kept Tier 1 form_element helper on a single object. The kept set
|
|
1045
|
+
# (and the rationale for what was dropped) is documented in
|
|
1046
|
+
# stuff/form-element-showcase-plan.md. The runtime helpers handle
|
|
1047
|
+
# every element generically; this block wires up the model, value
|
|
1048
|
+
# rows, uploaders, join table, and seed data.
|
|
1049
|
+
# ---------------------------------------------------------------------
|
|
1050
|
+
say "- Generating FormElementShowcase (one resource per kept Tier 1 form_element)..."
|
|
1051
|
+
sleep 1
|
|
1052
|
+
run %q{bundle exec rails g inline_forms FormElementShowcase title:string body_plain_area:plain_text_area count:integer_field price:decimal_field meeting_date:date_select meeting_time:time_select birth_month:month_select start_month:month_year_picker is_active:check_box gender:radio_button rating_int:dropdown_with_integers priority:dropdown_with_values priority2:dropdown_with_values stars:dropdown_with_values_with_stars attachment:file_field jingle:audio_field cover:image_field description:rich_text roles:has_and_belongs_to_many _enabled:yes _list_order:title _list_search:title _presentation:'#{title}'}
|
|
1053
|
+
|
|
1054
|
+
say "- Generating Attachment + Jingle uploaders (Cover reuses ImageUploader)..."
|
|
1055
|
+
run "bundle exec rails generate uploader Attachment"
|
|
1056
|
+
run "bundle exec rails generate uploader Jingle"
|
|
1057
|
+
|
|
1058
|
+
# Cover reuses ImageUploader (already generated for Photo). CarrierWave
|
|
1059
|
+
# is happy to mount one uploader class on multiple models; the global
|
|
1060
|
+
# `remove_previously_stored_files_after_update = false` keeps PaperTrail
|
|
1061
|
+
# revertable for both.
|
|
1062
|
+
gsub_file "app/models/form_element_showcase.rb",
|
|
1063
|
+
"mount_uploader :cover, CoverUploader",
|
|
1064
|
+
"mount_uploader :cover, ImageUploader"
|
|
1065
|
+
|
|
1066
|
+
# First field-level validation in the example app. `allow_blank: true`
|
|
1067
|
+
# keeps PaperTrail revert paths (and the seeded second row, which leaves
|
|
1068
|
+
# count nil) valid. The integration test covers the explicit error
|
|
1069
|
+
# path by POSTing `count: "abc"` to /form_element_showcases.
|
|
1070
|
+
inject_into_file "app/models/form_element_showcase.rb",
|
|
1071
|
+
"\n validates :count, numericality: { only_integer: true }, allow_blank: true\n mount_uploader :attachment, AttachmentUploader\n",
|
|
1072
|
+
after: "class FormElementShowcase < ApplicationRecord\n"
|
|
1073
|
+
|
|
1074
|
+
# Value-bearing rows for every form_element that needs a values hash
|
|
1075
|
+
# (or hash + options_disabled). 8.1.5 row shape: [:attr, :form_element]
|
|
1076
|
+
# for bare rows, [:attr, :form_element, values, options_disabled] for
|
|
1077
|
+
# choice rows.
|
|
1078
|
+
showcase_value_rows = {
|
|
1079
|
+
"[ :is_active, :check_box ]" => "[ :is_active, :check_box, { 0 => 'no', 1 => 'yes' } ]",
|
|
1080
|
+
"[ :gender, :radio_button ]" => "[ :gender, :radio_button, { 1 => 'male', 2 => 'female' } ]",
|
|
1081
|
+
"[ :rating_int, :dropdown_with_integers ]" => "[ :rating_int, :dropdown_with_integers, { 1 => 'one', 2 => 'two', 3 => 'three' } ]",
|
|
1082
|
+
"[ :priority, :dropdown_with_values ]" => "[ :priority, :dropdown_with_values, { 1 => 'low', 2 => 'mid', 3 => 'high' } ]",
|
|
1083
|
+
"[ :priority2, :dropdown_with_values ]" => "[ :priority2, :dropdown_with_values, { 1 => 'low', 2 => 'mid', 3 => 'high' }, [ 2 ] ]",
|
|
1084
|
+
"[ :stars, :dropdown_with_values_with_stars ]" => "[ :stars, :dropdown_with_values_with_stars, { 1 => '1stars', 2 => '2stars', 3 => '3stars', 4 => '4stars', 5 => '5stars' } ]",
|
|
1085
|
+
}
|
|
1086
|
+
showcase_value_rows.each do |from, to|
|
|
1087
|
+
gsub_file "app/models/form_element_showcase.rb", from, to
|
|
1088
|
+
end
|
|
1089
|
+
|
|
1090
|
+
# Section headers + the trailing info/info_list block. `roles` is a
|
|
1091
|
+
# has_and_belongs_to_many relation so the generator skips its
|
|
1092
|
+
# attribute_list row; we hand-insert it as `:info_list` (read-only
|
|
1093
|
+
# checklist of role _presentation strings).
|
|
1094
|
+
showcase_header_inserts = {
|
|
1095
|
+
"[ :title, :text_field ]," => "[ :header_basics, :header ], \n [ :title, :text_field ],",
|
|
1096
|
+
"[ :count, :integer_field ]," => "[ :header_numbers, :header ], \n [ :count, :integer_field ],",
|
|
1097
|
+
"[ :meeting_date, :date_select ]," => "[ :header_dates, :header ], \n [ :meeting_date, :date_select ],",
|
|
1098
|
+
"[ :is_active, :check_box, { 0 => 'no'" => "[ :header_choices, :header ], \n [ :is_active, :check_box, { 0 => 'no'",
|
|
1099
|
+
"[ :attachment, :file_field ]," => "[ :header_files, :header ], \n [ :attachment, :file_field ],",
|
|
1100
|
+
"[ :description, :rich_text ]," => "[ :header_rich, :header ], \n [ :description, :rich_text ],",
|
|
1101
|
+
}
|
|
1102
|
+
showcase_header_inserts.each do |from, to|
|
|
1103
|
+
gsub_file "app/models/form_element_showcase.rb", from, to
|
|
1104
|
+
end
|
|
1105
|
+
|
|
1106
|
+
# Insert :roles (info_list), :header_meta, and the timestamps after
|
|
1107
|
+
# the rich_text row. The generator does not emit a row for
|
|
1108
|
+
# `roles:has_and_belongs_to_many` (relation? is true), so we add it
|
|
1109
|
+
# manually here.
|
|
1110
|
+
gsub_file "app/models/form_element_showcase.rb",
|
|
1111
|
+
"[ :description, :rich_text ], \n",
|
|
1112
|
+
"[ :description, :rich_text ], \n [ :roles, :info_list ], \n [ :header_meta, :header ], \n [ :created_at, :info ], \n [ :updated_at, :info ], \n"
|
|
1113
|
+
|
|
1114
|
+
# Locale keys for the showcase attributes. Headers + the timestamps
|
|
1115
|
+
# need explicit labels so `human_attribute_name` does not fall back to
|
|
1116
|
+
# "Header basics" / "Created at". The leading two-space indent puts
|
|
1117
|
+
# the `activerecord:` key under the existing `en:` root.
|
|
1118
|
+
showcase_locale = <<~END_SHOWCASE_LOCALE
|
|
1119
|
+
activerecord:
|
|
1120
|
+
attributes:
|
|
1121
|
+
form_element_showcase:
|
|
1122
|
+
header_basics: Basics
|
|
1123
|
+
header_numbers: Numbers
|
|
1124
|
+
header_dates: Dates and times
|
|
1125
|
+
header_choices: Choices and scales
|
|
1126
|
+
header_files: Files
|
|
1127
|
+
header_rich: Rich text
|
|
1128
|
+
header_meta: Metadata
|
|
1129
|
+
title: Title
|
|
1130
|
+
body_plain_area: Plain text area
|
|
1131
|
+
count: Count
|
|
1132
|
+
price: Price
|
|
1133
|
+
meeting_date: Meeting date
|
|
1134
|
+
meeting_time: Meeting time
|
|
1135
|
+
birth_month: Birth month
|
|
1136
|
+
start_month: Start month
|
|
1137
|
+
is_active: Is active
|
|
1138
|
+
gender: Gender
|
|
1139
|
+
rating_int: Rating
|
|
1140
|
+
priority: Priority
|
|
1141
|
+
priority2: Priority (with disabled option)
|
|
1142
|
+
stars: Stars
|
|
1143
|
+
attachment: Attachment
|
|
1144
|
+
jingle: Jingle
|
|
1145
|
+
cover: Cover
|
|
1146
|
+
description: Description
|
|
1147
|
+
roles: Roles
|
|
1148
|
+
created_at: Created at
|
|
1149
|
+
updated_at: Updated at
|
|
1150
|
+
END_SHOWCASE_LOCALE
|
|
1151
|
+
append_to_file "config/locales/inline_forms_local.en.yml", showcase_locale.lines.map { |l| " #{l}" }.join
|
|
1152
|
+
|
|
1153
|
+
# Star images for dropdown_with_values_with_stars. The runtime helper
|
|
1154
|
+
# calls `image_tag("\#{n}stars.png")`, so we ship 5 tiny PNGs in
|
|
1155
|
+
# lib/installer_templates/example_app_assets and copy them into
|
|
1156
|
+
# app/assets/images at install time.
|
|
1157
|
+
showcase_assets_root = File.join(INSTALLER_ROOT, "lib/installer_templates/example_app_assets")
|
|
1158
|
+
(1..5).each do |n|
|
|
1159
|
+
src = File.join(showcase_assets_root, "#{n}stars.png")
|
|
1160
|
+
copy_file src, File.join("app/assets/images", "#{n}stars.png") if File.exist?(src)
|
|
1161
|
+
end
|
|
1162
|
+
|
|
1163
|
+
# Join table for has_and_belongs_to_many :roles. Mirrors the
|
|
1164
|
+
# roles_users join migration created for the user model above.
|
|
1165
|
+
say "- Creating form_element_showcases_roles join migration..."
|
|
1166
|
+
sleep 1
|
|
1167
|
+
habtm_ts = Time.now.utc.strftime("%Y%m%d%H%M%S")
|
|
1168
|
+
create_file "db/migrate/#{habtm_ts}_create_join_table_form_element_showcases_roles.rb", <<-HABTM_MIGRATION.strip_heredoc
|
|
1169
|
+
class CreateJoinTableFormElementShowcasesRoles < ActiveRecord::Migration[8.1]
|
|
1170
|
+
def self.up
|
|
1171
|
+
create_table :form_element_showcases_roles, id: false, force: true do |t|
|
|
1172
|
+
t.integer :form_element_showcase_id
|
|
1173
|
+
t.integer :role_id
|
|
1174
|
+
end
|
|
1175
|
+
end
|
|
1176
|
+
|
|
1177
|
+
def self.down
|
|
1178
|
+
drop_table :form_element_showcases_roles
|
|
1179
|
+
end
|
|
1180
|
+
end
|
|
1181
|
+
HABTM_MIGRATION
|
|
1182
|
+
|
|
1183
|
+
# Seed two showcase rows: one fully populated (so every show branch
|
|
1184
|
+
# has data), and one with no roles + no uploads (so info_list's empty
|
|
1185
|
+
# branch and the uploader empty branches render). Idempotent.
|
|
1186
|
+
say "- Creating FormElementShowcase seed migration..."
|
|
1187
|
+
sleep 1
|
|
1188
|
+
showcase_seed_ts = Time.now.utc.strftime("%Y%m%d%H%M%S")
|
|
1189
|
+
create_file "db/migrate/#{showcase_seed_ts}_seed_form_element_showcases.rb", <<-SHOWCASE_SEED.strip_heredoc
|
|
1190
|
+
class SeedFormElementShowcases < ActiveRecord::Migration[8.1]
|
|
1191
|
+
def up
|
|
1192
|
+
return unless defined?(FormElementShowcase)
|
|
1193
|
+
|
|
1194
|
+
full = FormElementShowcase.find_or_create_by!(title: "Full demo") do |s|
|
|
1195
|
+
s.body_plain_area = "A short plain-text paragraph."
|
|
1196
|
+
s.count = 7
|
|
1197
|
+
s.price = "12.34"
|
|
1198
|
+
s.meeting_date = Date.new(2026, 6, 1)
|
|
1199
|
+
s.meeting_time = Time.utc(2000, 1, 1, 14, 30)
|
|
1200
|
+
s.birth_month = 7
|
|
1201
|
+
s.start_month = Date.new(2026, 9, 1)
|
|
1202
|
+
s.is_active = true
|
|
1203
|
+
s.gender = 1
|
|
1204
|
+
s.rating_int = 2
|
|
1205
|
+
s.priority = 2
|
|
1206
|
+
s.priority2 = 3
|
|
1207
|
+
s.stars = 4
|
|
1208
|
+
s.description = "<p>A rich-text paragraph for the showcase.</p>"
|
|
1209
|
+
end
|
|
1210
|
+
if defined?(Role) && Role.exists?(1) && full.roles.empty?
|
|
1211
|
+
full.roles << Role.find(1)
|
|
1212
|
+
end
|
|
1213
|
+
|
|
1214
|
+
# "Empty" refers to the role and uploader fields (their empty
|
|
1215
|
+
# branches need to render). The other fields keep valid values
|
|
1216
|
+
# because several show helpers (e.g. dropdown_with_integers) raise
|
|
1217
|
+
# on nil/out-of-range integers.
|
|
1218
|
+
FormElementShowcase.find_or_create_by!(title: "Empty demo") do |s|
|
|
1219
|
+
s.is_active = false
|
|
1220
|
+
s.gender = 1
|
|
1221
|
+
s.rating_int = 1
|
|
1222
|
+
s.priority = 1
|
|
1223
|
+
s.priority2 = 1
|
|
1224
|
+
s.stars = 1
|
|
1225
|
+
end
|
|
1226
|
+
end
|
|
1227
|
+
|
|
1228
|
+
def down
|
|
1229
|
+
return unless defined?(FormElementShowcase)
|
|
1230
|
+
FormElementShowcase.where(title: ["Full demo", "Empty demo"]).destroy_all
|
|
1231
|
+
end
|
|
1232
|
+
end
|
|
1233
|
+
SHOWCASE_SEED
|
|
1234
|
+
|
|
1235
|
+
say "- Running showcase migrations (create table + join + seed)..."
|
|
1236
|
+
run "bundle exec rake db:migrate"
|
|
1237
|
+
|
|
1042
1238
|
example_views_root = File.join(INSTALLER_ROOT, "lib/installer_templates/example_app_views")
|
|
1043
1239
|
Dir.glob(File.join(example_views_root, "**", "*")).sort.each do |abs|
|
|
1044
1240
|
next unless File.file?(abs)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../example_app/example_integration_test_case"
|
|
4
|
+
|
|
5
|
+
# Choice helpers on FormElementShowcase:
|
|
6
|
+
# check_box (is_active, 0|1)
|
|
7
|
+
# radio_button (gender, hash)
|
|
8
|
+
# dropdown_with_integers (rating_int)
|
|
9
|
+
# dropdown_with_values (priority normal + priority2 options_disabled)
|
|
10
|
+
# dropdown_with_values_with_stars (stars)
|
|
11
|
+
# (scale_with_integers / scale_with_values are dropped from the showcase
|
|
12
|
+
# until their runtime show helpers are repaired; see CHANGELOG 8.1.6.)
|
|
13
|
+
class ExampleAppShowcaseChoiceScaleFieldsTest < ExampleAppIntegrationTestCase
|
|
14
|
+
setup do
|
|
15
|
+
@showcase = FormElementShowcase.find_or_create_by!(title: "Choice/scale demo")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def field_frame(attr)
|
|
19
|
+
"form_element_showcase_#{@showcase.id}_#{attr}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def field_headers(attr)
|
|
23
|
+
{ "Turbo-Frame" => field_frame(attr), "Accept" => "text/html" }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def underscored_param_root
|
|
27
|
+
"_form_element_showcase"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
test "check_box toggles is_active from 0 to 1" do
|
|
31
|
+
@showcase.update!(is_active: false)
|
|
32
|
+
frame = field_frame(:is_active)
|
|
33
|
+
put form_element_showcase_path(
|
|
34
|
+
@showcase,
|
|
35
|
+
attribute: "is_active",
|
|
36
|
+
form_element: "check_box",
|
|
37
|
+
update: frame
|
|
38
|
+
), params: { is_active: 1 }, headers: field_headers(:is_active)
|
|
39
|
+
|
|
40
|
+
assert_response :success
|
|
41
|
+
assert_equal 1, @showcase.reload.is_active ? 1 : 0
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
test "check_box toggles is_active back to 0 when param missing" do
|
|
45
|
+
@showcase.update!(is_active: true)
|
|
46
|
+
frame = field_frame(:is_active)
|
|
47
|
+
put form_element_showcase_path(
|
|
48
|
+
@showcase,
|
|
49
|
+
attribute: "is_active",
|
|
50
|
+
form_element: "check_box",
|
|
51
|
+
update: frame
|
|
52
|
+
), params: {}, headers: field_headers(:is_active)
|
|
53
|
+
|
|
54
|
+
assert_response :success
|
|
55
|
+
assert_equal false, !!@showcase.reload.is_active
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
test "radio_button sets gender via attribute param" do
|
|
59
|
+
frame = field_frame(:gender)
|
|
60
|
+
put form_element_showcase_path(
|
|
61
|
+
@showcase,
|
|
62
|
+
attribute: "gender",
|
|
63
|
+
form_element: "radio_button",
|
|
64
|
+
update: frame
|
|
65
|
+
), params: { gender: 2 }, headers: field_headers(:gender)
|
|
66
|
+
|
|
67
|
+
assert_response :success
|
|
68
|
+
assert_equal 2, @showcase.reload.gender
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
test "dropdown_with_integers sets rating_int" do
|
|
72
|
+
frame = field_frame(:rating_int)
|
|
73
|
+
put form_element_showcase_path(
|
|
74
|
+
@showcase,
|
|
75
|
+
attribute: "rating_int",
|
|
76
|
+
form_element: "dropdown_with_integers",
|
|
77
|
+
update: frame
|
|
78
|
+
), params: { underscored_param_root => { rating_int: 2 } }, headers: field_headers(:rating_int)
|
|
79
|
+
|
|
80
|
+
assert_response :success
|
|
81
|
+
assert_equal 2, @showcase.reload.rating_int
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
test "dropdown_with_values priority round-trips" do
|
|
85
|
+
frame = field_frame(:priority)
|
|
86
|
+
put form_element_showcase_path(
|
|
87
|
+
@showcase,
|
|
88
|
+
attribute: "priority",
|
|
89
|
+
form_element: "dropdown_with_values",
|
|
90
|
+
update: frame
|
|
91
|
+
), params: { underscored_param_root => { priority: 3 } }, headers: field_headers(:priority)
|
|
92
|
+
|
|
93
|
+
assert_response :success
|
|
94
|
+
assert_equal 3, @showcase.reload.priority
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
test "dropdown_with_values priority2 disables the third option in the edit form" do
|
|
98
|
+
@showcase.update!(priority2: 1)
|
|
99
|
+
frame = field_frame(:priority2)
|
|
100
|
+
get edit_form_element_showcase_path(
|
|
101
|
+
@showcase,
|
|
102
|
+
attribute: "priority2",
|
|
103
|
+
form_element: "dropdown_with_values",
|
|
104
|
+
update: frame
|
|
105
|
+
), headers: field_headers(:priority2)
|
|
106
|
+
|
|
107
|
+
assert_response :success
|
|
108
|
+
assert_includes @response.body, %(<turbo-frame id="#{frame}">)
|
|
109
|
+
# options_disabled is [2] for priority2; that option should render with `disabled`.
|
|
110
|
+
assert_match(%r{<option [^>]*disabled[^>]*value="2"|<option [^>]*value="2"[^>]*disabled}, @response.body)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
test "dropdown_with_values_with_stars sets stars" do
|
|
114
|
+
frame = field_frame(:stars)
|
|
115
|
+
put form_element_showcase_path(
|
|
116
|
+
@showcase,
|
|
117
|
+
attribute: "stars",
|
|
118
|
+
form_element: "dropdown_with_values_with_stars",
|
|
119
|
+
update: frame
|
|
120
|
+
), params: { underscored_param_root => { stars: 5 } }, headers: field_headers(:stars)
|
|
121
|
+
|
|
122
|
+
assert_response :success
|
|
123
|
+
assert_equal 5, @showcase.reload.stars
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../example_app/example_integration_test_case"
|
|
4
|
+
|
|
5
|
+
# Date/time-shaped Tier 1 helpers on FormElementShowcase:
|
|
6
|
+
# date_select (meeting_date)
|
|
7
|
+
# time_select (meeting_time)
|
|
8
|
+
# month_select (birth_month, 1..12 integer)
|
|
9
|
+
# month_year_picker (start_month, date)
|
|
10
|
+
class ExampleAppShowcaseDateTimeFieldsTest < ExampleAppIntegrationTestCase
|
|
11
|
+
setup do
|
|
12
|
+
@showcase = FormElementShowcase.find_or_create_by!(title: "Date/time demo")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
test "date_select meeting_date renders datepicker on edit" do
|
|
16
|
+
frame = "form_element_showcase_#{@showcase.id}_meeting_date"
|
|
17
|
+
headers = { "Turbo-Frame" => frame, "Accept" => "text/html" }
|
|
18
|
+
|
|
19
|
+
get edit_form_element_showcase_path(
|
|
20
|
+
@showcase,
|
|
21
|
+
attribute: "meeting_date",
|
|
22
|
+
form_element: "date_select",
|
|
23
|
+
update: frame
|
|
24
|
+
), headers: headers
|
|
25
|
+
|
|
26
|
+
assert_response :success
|
|
27
|
+
assert_includes @response.body, %(<turbo-frame id="#{frame}">)
|
|
28
|
+
assert_includes @response.body, %(class="datepicker")
|
|
29
|
+
assert_includes @response.body, %(name="meeting_date")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
test "time_select meeting_time renders timepicker on edit" do
|
|
33
|
+
@showcase.update!(meeting_time: Time.utc(2000, 1, 1, 9, 15))
|
|
34
|
+
frame = "form_element_showcase_#{@showcase.id}_meeting_time"
|
|
35
|
+
headers = { "Turbo-Frame" => frame, "Accept" => "text/html" }
|
|
36
|
+
|
|
37
|
+
get edit_form_element_showcase_path(
|
|
38
|
+
@showcase,
|
|
39
|
+
attribute: "meeting_time",
|
|
40
|
+
form_element: "time_select",
|
|
41
|
+
update: frame
|
|
42
|
+
), headers: headers
|
|
43
|
+
|
|
44
|
+
assert_response :success
|
|
45
|
+
assert_includes @response.body, %(<turbo-frame id="#{frame}">)
|
|
46
|
+
assert_includes @response.body, %(class="timepicker")
|
|
47
|
+
assert_includes @response.body, %(name="meeting_time")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
test "month_select birth_month renders 12 options on edit" do
|
|
51
|
+
@showcase.update!(birth_month: 6)
|
|
52
|
+
frame = "form_element_showcase_#{@showcase.id}_birth_month"
|
|
53
|
+
headers = { "Turbo-Frame" => frame, "Accept" => "text/html" }
|
|
54
|
+
|
|
55
|
+
get edit_form_element_showcase_path(
|
|
56
|
+
@showcase,
|
|
57
|
+
attribute: "birth_month",
|
|
58
|
+
form_element: "month_select",
|
|
59
|
+
update: frame
|
|
60
|
+
), headers: headers
|
|
61
|
+
|
|
62
|
+
assert_response :success
|
|
63
|
+
assert_includes @response.body, %(<turbo-frame id="#{frame}">)
|
|
64
|
+
assert_match(/<select[^>]+name="date\[birth_month\]"/, @response.body)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
test "month_year_picker start_month renders datepicker class hook" do
|
|
68
|
+
@showcase.update!(start_month: Date.new(2026, 5, 1))
|
|
69
|
+
frame = "form_element_showcase_#{@showcase.id}_start_month"
|
|
70
|
+
headers = { "Turbo-Frame" => frame, "Accept" => "text/html" }
|
|
71
|
+
|
|
72
|
+
get edit_form_element_showcase_path(
|
|
73
|
+
@showcase,
|
|
74
|
+
attribute: "start_month",
|
|
75
|
+
form_element: "month_year_picker",
|
|
76
|
+
update: frame
|
|
77
|
+
), headers: headers
|
|
78
|
+
|
|
79
|
+
assert_response :success
|
|
80
|
+
assert_includes @response.body, %(<turbo-frame id="#{frame}">)
|
|
81
|
+
assert_includes @response.body, %(datepicker-month-year)
|
|
82
|
+
assert_includes @response.body, %(name="start_month")
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../example_app/example_integration_test_case"
|
|
4
|
+
|
|
5
|
+
# Numeric Tier 1 helpers on FormElementShowcase:
|
|
6
|
+
# integer_field (count) + numericality validation regression
|
|
7
|
+
# decimal_field (price)
|
|
8
|
+
# (money_field is dropped from the showcase; the runtime helper depends on
|
|
9
|
+
# money-rails' `humanized_money_with_symbol`, which is not in the installer
|
|
10
|
+
# Gemfile. See CHANGELOG 8.1.6 "Dropped" section.)
|
|
11
|
+
class ExampleAppShowcaseNumericFieldsTest < ExampleAppIntegrationTestCase
|
|
12
|
+
setup do
|
|
13
|
+
@showcase = FormElementShowcase.find_or_create_by!(title: "Numeric demo")
|
|
14
|
+
@list_frame = "form_element_showcases_list"
|
|
15
|
+
@list_headers = { "Turbo-Frame" => @list_frame, "Accept" => "text/html" }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
test "integer_field count round-trips" do
|
|
19
|
+
frame = "form_element_showcase_#{@showcase.id}_count"
|
|
20
|
+
headers = { "Turbo-Frame" => frame, "Accept" => "text/html" }
|
|
21
|
+
|
|
22
|
+
put form_element_showcase_path(
|
|
23
|
+
@showcase,
|
|
24
|
+
attribute: "count",
|
|
25
|
+
form_element: "integer_field",
|
|
26
|
+
update: frame
|
|
27
|
+
), params: { count: "42" }, headers: headers
|
|
28
|
+
|
|
29
|
+
assert_response :success
|
|
30
|
+
assert_includes @response.body, %(<turbo-frame id="#{frame}">)
|
|
31
|
+
assert_includes @response.body, "42"
|
|
32
|
+
assert_equal 42, @showcase.reload.count
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
test "decimal_field price round-trips" do
|
|
36
|
+
frame = "form_element_showcase_#{@showcase.id}_price"
|
|
37
|
+
headers = { "Turbo-Frame" => frame, "Accept" => "text/html" }
|
|
38
|
+
|
|
39
|
+
put form_element_showcase_path(
|
|
40
|
+
@showcase,
|
|
41
|
+
attribute: "price",
|
|
42
|
+
form_element: "decimal_field",
|
|
43
|
+
update: frame
|
|
44
|
+
), params: { price: "99.95" }, headers: headers
|
|
45
|
+
|
|
46
|
+
assert_response :success
|
|
47
|
+
assert_includes @response.body, %(<turbo-frame id="#{frame}">)
|
|
48
|
+
assert_includes @response.body, "99.95"
|
|
49
|
+
assert_equal "99.95", @showcase.reload.price
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
test "integer_field count rejects non-integer via top-level create" do
|
|
53
|
+
# The controller's create iterates every attribute and calls each
|
|
54
|
+
# form_element's update method. Several helpers crash on nil params:
|
|
55
|
+
# - month_year_picker_update -> Date.parse("") raises
|
|
56
|
+
# - dropdown_with_integers_update / dropdown_with_values{_with_stars}_update
|
|
57
|
+
# -> params[:_form_element_showcase][:attr] dereferences nil
|
|
58
|
+
# We supply just enough to let the create walk reach the validation step.
|
|
59
|
+
assert_no_difference "FormElementShowcase.count" do
|
|
60
|
+
post form_element_showcases_path(update: @list_frame),
|
|
61
|
+
params: {
|
|
62
|
+
title: "Bad Count",
|
|
63
|
+
count: "abc",
|
|
64
|
+
start_month: "September 2026",
|
|
65
|
+
_form_element_showcase: {
|
|
66
|
+
rating_int: 1,
|
|
67
|
+
priority: 1,
|
|
68
|
+
priority2: 1,
|
|
69
|
+
stars: 1,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
headers: @list_headers
|
|
73
|
+
end
|
|
74
|
+
assert_response :success
|
|
75
|
+
body = @response.body
|
|
76
|
+
assert_match(/is not a number|count[^<]*is not a number/i, body,
|
|
77
|
+
"expected numericality error to render after invalid count")
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../example_app/example_integration_test_case"
|
|
4
|
+
|
|
5
|
+
# Smoke test for the full FormElementShowcase show page. Covers the
|
|
6
|
+
# display-only helpers (`header`, `info`, `info_list`) and the show
|
|
7
|
+
# branches of every uploader helper + rich_text.
|
|
8
|
+
class ExampleAppShowcasePageRenderTest < ExampleAppIntegrationTestCase
|
|
9
|
+
# All non-header attributes on FormElementShowcase that should each
|
|
10
|
+
# be wrapped in a `<turbo-frame id="form_element_showcase_<id>_<attr>">`.
|
|
11
|
+
SHOWCASE_FIELD_ATTRIBUTES = %i[
|
|
12
|
+
title
|
|
13
|
+
body_plain_area
|
|
14
|
+
count
|
|
15
|
+
price
|
|
16
|
+
meeting_date
|
|
17
|
+
meeting_time
|
|
18
|
+
birth_month
|
|
19
|
+
start_month
|
|
20
|
+
is_active
|
|
21
|
+
gender
|
|
22
|
+
rating_int
|
|
23
|
+
priority
|
|
24
|
+
priority2
|
|
25
|
+
stars
|
|
26
|
+
attachment
|
|
27
|
+
jingle
|
|
28
|
+
cover
|
|
29
|
+
description
|
|
30
|
+
roles
|
|
31
|
+
created_at
|
|
32
|
+
updated_at
|
|
33
|
+
].freeze
|
|
34
|
+
|
|
35
|
+
SHOWCASE_HEADER_ATTRIBUTES = %i[
|
|
36
|
+
header_basics
|
|
37
|
+
header_numbers
|
|
38
|
+
header_dates
|
|
39
|
+
header_choices
|
|
40
|
+
header_files
|
|
41
|
+
header_rich
|
|
42
|
+
header_meta
|
|
43
|
+
].freeze
|
|
44
|
+
|
|
45
|
+
setup do
|
|
46
|
+
locale = Locale.find_or_create_by!(name: "en") { |l| l.title = "English" }
|
|
47
|
+
@role = Role.find_or_create_by!(name: "superadmin") { |r| r.description = "Super Admin" }
|
|
48
|
+
|
|
49
|
+
@full = FormElementShowcase.find_or_create_by!(title: "Full demo") do |s|
|
|
50
|
+
s.body_plain_area = "Plain text body"
|
|
51
|
+
s.count = 7
|
|
52
|
+
s.price = "12.34"
|
|
53
|
+
s.meeting_date = Date.new(2026, 6, 1)
|
|
54
|
+
s.meeting_time = Time.utc(2000, 1, 1, 14, 30)
|
|
55
|
+
s.birth_month = 7
|
|
56
|
+
s.start_month = Date.new(2026, 9, 1)
|
|
57
|
+
s.is_active = true
|
|
58
|
+
s.gender = 1
|
|
59
|
+
s.rating_int = 2
|
|
60
|
+
s.priority = 2
|
|
61
|
+
s.priority2 = 3
|
|
62
|
+
s.stars = 4
|
|
63
|
+
s.description = "<p>A rich-text body.</p>"
|
|
64
|
+
end
|
|
65
|
+
@full.roles << @role unless @full.roles.where(id: @role.id).exists?
|
|
66
|
+
|
|
67
|
+
@empty = FormElementShowcase.find_or_create_by!(title: "Empty demo") do |s|
|
|
68
|
+
# Keep dropdown/scale integers at valid indices so the show helpers
|
|
69
|
+
# do not crash on nil. The point of "empty demo" is that roles and
|
|
70
|
+
# uploads are blank, not every integer attribute.
|
|
71
|
+
s.gender = 1
|
|
72
|
+
s.rating_int = 1
|
|
73
|
+
s.priority = 1
|
|
74
|
+
s.priority2 = 1
|
|
75
|
+
s.stars = 1
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
test "full showcase show page renders every per-attribute turbo-frame" do
|
|
80
|
+
row_frame = "form_element_showcase_#{@full.id}"
|
|
81
|
+
get form_element_showcase_path(@full, update: row_frame),
|
|
82
|
+
headers: { "Turbo-Frame" => row_frame, "Accept" => "text/html" }
|
|
83
|
+
|
|
84
|
+
assert_response :success
|
|
85
|
+
|
|
86
|
+
SHOWCASE_FIELD_ATTRIBUTES.each do |attr|
|
|
87
|
+
frame = "form_element_showcase_#{@full.id}_#{attr}"
|
|
88
|
+
assert_includes @response.body, %(<turbo-frame id="#{frame}">),
|
|
89
|
+
"expected per-attribute frame for #{attr}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
SHOWCASE_HEADER_ATTRIBUTES.each do |attr|
|
|
93
|
+
label = FormElementShowcase.human_attribute_name(attr)
|
|
94
|
+
assert_includes @response.body, label,
|
|
95
|
+
"expected header label for #{attr} (#{label.inspect})"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
assert_includes @response.body, @role.name,
|
|
99
|
+
"expected info_list to render the role's _presentation"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
test "empty showcase info_list renders the no-roles placeholder" do
|
|
103
|
+
row_frame = "form_element_showcase_#{@empty.id}"
|
|
104
|
+
get form_element_showcase_path(@empty, update: row_frame),
|
|
105
|
+
headers: { "Turbo-Frame" => row_frame, "Accept" => "text/html" }
|
|
106
|
+
|
|
107
|
+
assert_response :success
|
|
108
|
+
frame = "form_element_showcase_#{@empty.id}_roles"
|
|
109
|
+
body = @response.body
|
|
110
|
+
assert_includes body, %(<turbo-frame id="#{frame}">)
|
|
111
|
+
frame_block = body[body.index(%(<turbo-frame id="#{frame}">"))..-1] rescue nil
|
|
112
|
+
# info_list_show emits a `--` placeholder for empty associations.
|
|
113
|
+
assert_match(/<turbo-frame id="#{frame}">[^<]*<div class='row [^']+'>--<\/div>/m, body,
|
|
114
|
+
"expected info_list empty placeholder `--` inside roles frame")
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../example_app/example_integration_test_case"
|
|
4
|
+
|
|
5
|
+
# Round-trip the text-shaped Tier 1 helpers on FormElementShowcase:
|
|
6
|
+
# text_field (title)
|
|
7
|
+
# plain_text_area (body_plain_area)
|
|
8
|
+
class ExampleAppShowcaseTextFieldsTest < ExampleAppIntegrationTestCase
|
|
9
|
+
setup do
|
|
10
|
+
@showcase = FormElementShowcase.find_or_create_by!(title: "TextFields demo")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
test "text_field title round-trips through the field turbo-frame" do
|
|
14
|
+
frame = "form_element_showcase_#{@showcase.id}_title"
|
|
15
|
+
headers = { "Turbo-Frame" => frame, "Accept" => "text/html" }
|
|
16
|
+
|
|
17
|
+
put form_element_showcase_path(
|
|
18
|
+
@showcase,
|
|
19
|
+
attribute: "title",
|
|
20
|
+
form_element: "text_field",
|
|
21
|
+
update: frame
|
|
22
|
+
), params: { title: "TextFields updated" }, headers: headers
|
|
23
|
+
|
|
24
|
+
assert_response :success
|
|
25
|
+
assert_includes @response.body, %(<turbo-frame id="#{frame}">)
|
|
26
|
+
assert_includes @response.body, "TextFields updated"
|
|
27
|
+
assert_equal "TextFields updated", @showcase.reload.title
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
test "plain_text_area body round-trips through the field turbo-frame" do
|
|
31
|
+
frame = "form_element_showcase_#{@showcase.id}_body_plain_area"
|
|
32
|
+
headers = { "Turbo-Frame" => frame, "Accept" => "text/html" }
|
|
33
|
+
|
|
34
|
+
body = "Hello plain text\nMulti-line content"
|
|
35
|
+
put form_element_showcase_path(
|
|
36
|
+
@showcase,
|
|
37
|
+
attribute: "body_plain_area",
|
|
38
|
+
form_element: "plain_text_area",
|
|
39
|
+
update: frame
|
|
40
|
+
), params: { body_plain_area: body }, headers: headers
|
|
41
|
+
|
|
42
|
+
assert_response :success
|
|
43
|
+
assert_includes @response.body, %(<turbo-frame id="#{frame}">)
|
|
44
|
+
assert_includes @response.body, "Hello plain text"
|
|
45
|
+
assert_equal body, @showcase.reload.body_plain_area
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/installer_templates/example_app_tests/test/models/example_app_form_element_showcase_test.rb
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
# Pins the FormElementShowcase model wiring:
|
|
6
|
+
# - plain_text columns are present (no rich_text drift)
|
|
7
|
+
# - every kept Tier 1 attribute is in the attribute list
|
|
8
|
+
# - priority2 keeps its options_disabled tuple slot (8.1.5 row shape)
|
|
9
|
+
# - integer numericality is enforced on :count
|
|
10
|
+
class ExampleAppFormElementShowcaseTest < ActiveSupport::TestCase
|
|
11
|
+
EXPECTED_ATTRIBUTES = %i[
|
|
12
|
+
header_basics
|
|
13
|
+
title
|
|
14
|
+
body_plain_area
|
|
15
|
+
header_numbers
|
|
16
|
+
count
|
|
17
|
+
price
|
|
18
|
+
header_dates
|
|
19
|
+
meeting_date
|
|
20
|
+
meeting_time
|
|
21
|
+
birth_month
|
|
22
|
+
start_month
|
|
23
|
+
header_choices
|
|
24
|
+
is_active
|
|
25
|
+
gender
|
|
26
|
+
rating_int
|
|
27
|
+
priority
|
|
28
|
+
priority2
|
|
29
|
+
stars
|
|
30
|
+
header_files
|
|
31
|
+
attachment
|
|
32
|
+
jingle
|
|
33
|
+
cover
|
|
34
|
+
header_rich
|
|
35
|
+
description
|
|
36
|
+
roles
|
|
37
|
+
header_meta
|
|
38
|
+
created_at
|
|
39
|
+
updated_at
|
|
40
|
+
].freeze
|
|
41
|
+
|
|
42
|
+
test "plain_text helper configuration validates without drift" do
|
|
43
|
+
assert_nothing_raised do
|
|
44
|
+
InlineForms.validate_plain_text_configuration_for!(FormElementShowcase)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
test "inline_forms_attribute_list contains every expected attribute" do
|
|
49
|
+
keys = FormElementShowcase.new.inline_forms_attribute_list.map { |row| row.first }
|
|
50
|
+
EXPECTED_ATTRIBUTES.each do |attr|
|
|
51
|
+
assert_includes keys, attr, "expected #{attr} in inline_forms_attribute_list"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
test "priority2 keeps options_disabled at tuple slot 3 (8.1.5 row shape)" do
|
|
56
|
+
row = FormElementShowcase.new.inline_forms_attribute_list.assoc(:priority2)
|
|
57
|
+
assert_not_nil row, "expected a :priority2 row"
|
|
58
|
+
assert_equal :dropdown_with_values, row[1]
|
|
59
|
+
assert_kind_of Hash, row[2]
|
|
60
|
+
assert_equal [2], row[3],
|
|
61
|
+
"expected options_disabled at index 3 (was the 8.1.5 row-shape shift)"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
test "count rejects non-integer input with a numericality error" do
|
|
65
|
+
showcase = FormElementShowcase.new(title: "X", count: "abc")
|
|
66
|
+
assert_not showcase.valid?
|
|
67
|
+
assert_includes showcase.errors.attribute_names, :count
|
|
68
|
+
assert showcase.errors[:count].any? { |m| m.match?(/not a number/i) },
|
|
69
|
+
"expected `not a number` error on :count, got #{showcase.errors[:count].inspect}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
test "count accepts a valid integer" do
|
|
73
|
+
showcase = FormElementShowcase.new(title: "X", count: 5)
|
|
74
|
+
assert showcase.valid?, "expected showcase to be valid with count=5, got #{showcase.errors.full_messages.inspect}"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
test "count allows blank" do
|
|
78
|
+
showcase = FormElementShowcase.new(title: "X", count: nil)
|
|
79
|
+
assert showcase.valid?, "expected showcase to be valid with count=nil (allow_blank), got #{showcase.errors.full_messages.inspect}"
|
|
80
|
+
end
|
|
81
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: inline_forms_installer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.1.
|
|
4
|
+
version: 8.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ace Suares
|
|
@@ -89,6 +89,11 @@ files:
|
|
|
89
89
|
- lib/installer_templates/dartsass/devise_main.scss
|
|
90
90
|
- lib/installer_templates/dartsass/inline_forms_dartsass_builds.rb
|
|
91
91
|
- lib/installer_templates/dartsass/inline_forms_main.scss
|
|
92
|
+
- lib/installer_templates/example_app_assets/1stars.png
|
|
93
|
+
- lib/installer_templates/example_app_assets/2stars.png
|
|
94
|
+
- lib/installer_templates/example_app_assets/3stars.png
|
|
95
|
+
- lib/installer_templates/example_app_assets/4stars.png
|
|
96
|
+
- lib/installer_templates/example_app_assets/5stars.png
|
|
92
97
|
- lib/installer_templates/example_app_tests/test/example_app/example_integration_test_case.rb
|
|
93
98
|
- lib/installer_templates/example_app_tests/test/integration/example_app_apartment_field_turbo_test.rb
|
|
94
99
|
- lib/installer_templates/example_app_tests/test/integration/example_app_apartment_name_list_test.rb
|
|
@@ -104,10 +109,16 @@ files:
|
|
|
104
109
|
- lib/installer_templates/example_app_tests/test/integration/example_app_photo_revert_test.rb
|
|
105
110
|
- lib/installer_templates/example_app_tests/test/integration/example_app_photos_test.rb
|
|
106
111
|
- lib/installer_templates/example_app_tests/test/integration/example_app_routing_test.rb
|
|
112
|
+
- lib/installer_templates/example_app_tests/test/integration/example_app_showcase_choice_scale_fields_test.rb
|
|
113
|
+
- lib/installer_templates/example_app_tests/test/integration/example_app_showcase_date_time_fields_test.rb
|
|
114
|
+
- lib/installer_templates/example_app_tests/test/integration/example_app_showcase_numeric_fields_test.rb
|
|
115
|
+
- lib/installer_templates/example_app_tests/test/integration/example_app_showcase_page_render_test.rb
|
|
116
|
+
- lib/installer_templates/example_app_tests/test/integration/example_app_showcase_text_fields_test.rb
|
|
107
117
|
- lib/installer_templates/example_app_tests/test/integration/example_app_turbo_layout_test.rb
|
|
108
118
|
- lib/installer_templates/example_app_tests/test/integration/example_app_validation_hints_test.rb
|
|
109
119
|
- lib/installer_templates/example_app_tests/test/models/example_app_apartment_name_validation_test.rb
|
|
110
120
|
- lib/installer_templates/example_app_tests/test/models/example_app_apartment_photo_test.rb
|
|
121
|
+
- lib/installer_templates/example_app_tests/test/models/example_app_form_element_showcase_test.rb
|
|
111
122
|
- lib/installer_templates/example_app_tests/test/models/example_app_paper_trail_changeset_test.rb
|
|
112
123
|
- lib/installer_templates/example_app_tests/test/models/example_app_plain_text_rich_text_edge_cases_test.rb
|
|
113
124
|
- lib/installer_templates/example_app_views/apartments/name_list.html.erb
|