uchi 0.1.0 → 0.1.3

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.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +17 -0
  3. data/.github/workflows/build.yml +23 -0
  4. data/.github/workflows/lint.yml +30 -0
  5. data/CHANGELOG.md +29 -0
  6. data/docs/fields.md +82 -0
  7. data/docs/repositories.md +63 -0
  8. data/package.json +31 -0
  9. data/test/components/uchi/field/belongs_to_test.rb +134 -0
  10. data/test/components/uchi/field/blank_test.rb +119 -0
  11. data/test/components/uchi/field/boolean_test.rb +163 -0
  12. data/test/components/uchi/field/date_test.rb +163 -0
  13. data/test/components/uchi/field/date_time_test.rb +152 -0
  14. data/test/components/uchi/field/has_and_belongs_to_many_test.rb +144 -0
  15. data/test/components/uchi/field/has_many_test.rb +138 -0
  16. data/test/components/uchi/field/id_test.rb +113 -0
  17. data/test/components/uchi/field/number_test.rb +163 -0
  18. data/test/components/uchi/field/string_test.rb +159 -0
  19. data/test/components/uchi/field/text_test.rb +160 -0
  20. data/test/components/uchi/ui/form/input/collection_checkboxes_test.rb +171 -0
  21. data/test/controllers/uchi/authors_controller_test.rb +120 -0
  22. data/test/controllers/uchi/repository_controller_test.rb +93 -0
  23. data/test/controllers/uchi/scoped_repository_controller_test.rb +73 -0
  24. data/test/dummy/Rakefile +6 -0
  25. data/test/dummy/app/assets/images/.keep +0 -0
  26. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  27. data/test/dummy/app/controllers/application_controller.rb +4 -0
  28. data/test/dummy/app/controllers/concerns/.keep +0 -0
  29. data/test/dummy/app/controllers/uchi/authors_controller.rb +7 -0
  30. data/test/dummy/app/controllers/uchi/books_controller.rb +7 -0
  31. data/test/dummy/app/controllers/uchi/titles_controller.rb +7 -0
  32. data/test/dummy/app/helpers/application_helper.rb +2 -0
  33. data/test/dummy/app/jobs/application_job.rb +7 -0
  34. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  35. data/test/dummy/app/models/application_record.rb +3 -0
  36. data/test/dummy/app/models/author.rb +5 -0
  37. data/test/dummy/app/models/book.rb +4 -0
  38. data/test/dummy/app/models/concerns/.keep +0 -0
  39. data/test/dummy/app/models/title.rb +3 -0
  40. data/test/dummy/app/uchi/repositories/author.rb +20 -0
  41. data/test/dummy/app/uchi/repositories/book.rb +16 -0
  42. data/test/dummy/app/uchi/repositories/title.rb +17 -0
  43. data/test/dummy/app/views/layouts/application.html.erb +27 -0
  44. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  45. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  46. data/test/dummy/app/views/pwa/manifest.json.erb +22 -0
  47. data/test/dummy/app/views/pwa/service-worker.js +26 -0
  48. data/test/dummy/bin/dev +2 -0
  49. data/test/dummy/bin/rails +4 -0
  50. data/test/dummy/bin/rake +4 -0
  51. data/test/dummy/bin/setup +34 -0
  52. data/test/dummy/config/application.rb +29 -0
  53. data/test/dummy/config/boot.rb +5 -0
  54. data/test/dummy/config/cable.yml +10 -0
  55. data/test/dummy/config/database.yml +32 -0
  56. data/test/dummy/config/environment.rb +5 -0
  57. data/test/dummy/config/environments/development.rb +69 -0
  58. data/test/dummy/config/environments/production.rb +89 -0
  59. data/test/dummy/config/environments/test.rb +53 -0
  60. data/test/dummy/config/initializers/content_security_policy.rb +25 -0
  61. data/test/dummy/config/initializers/filter_parameter_logging.rb +8 -0
  62. data/test/dummy/config/initializers/inflections.rb +16 -0
  63. data/test/dummy/config/locales/da.yml +52 -0
  64. data/test/dummy/config/locales/en.yml +31 -0
  65. data/test/dummy/config/puma.rb +38 -0
  66. data/test/dummy/config/routes.rb +9 -0
  67. data/test/dummy/config/storage.yml +34 -0
  68. data/test/dummy/config.ru +6 -0
  69. data/test/dummy/db/migrate/20251002183635_create_authors.rb +11 -0
  70. data/test/dummy/db/migrate/20251005131726_create_books.rb +9 -0
  71. data/test/dummy/db/migrate/20251005131811_create_titles.rb +11 -0
  72. data/test/dummy/db/migrate/20251031140958_add_author_books_join_table.rb +9 -0
  73. data/test/dummy/db/schema.rb +44 -0
  74. data/test/dummy/log/.keep +0 -0
  75. data/test/dummy/public/400.html +114 -0
  76. data/test/dummy/public/404.html +114 -0
  77. data/test/dummy/public/406-unsupported-browser.html +114 -0
  78. data/test/dummy/public/422.html +114 -0
  79. data/test/dummy/public/500.html +114 -0
  80. data/test/dummy/public/icon.png +0 -0
  81. data/test/dummy/public/icon.svg +3 -0
  82. data/test/dummy/storage/.keep +0 -0
  83. data/test/dummy/test/fixtures/authors.yml +11 -0
  84. data/test/dummy/test/models/author_test.rb +7 -0
  85. data/test/dummy/tmp/.keep +0 -0
  86. data/test/dummy/tmp/pids/.keep +0 -0
  87. data/test/dummy/tmp/storage/.keep +0 -0
  88. data/test/test_helper.rb +15 -0
  89. data/test/uchi/field_test.rb +77 -0
  90. data/test/uchi/i18n_test.rb +18 -0
  91. data/test/uchi/repository/routes_test.rb +49 -0
  92. data/test/uchi/repository/translate_test.rb +272 -0
  93. data/test/uchi/repository_test.rb +137 -0
  94. data/test/uchi/sort_order_test.rb +47 -0
  95. data/test/uchi_test.rb +7 -0
  96. metadata +147 -10
  97. data/README.md +0 -35
  98. data/Rakefile +0 -6
  99. data/lib/uchi/version.rb +0 -5
  100. data/lib/uchi.rb +0 -8
@@ -0,0 +1,163 @@
1
+ require "test_helper"
2
+ require "ostruct"
3
+
4
+ module Uchi
5
+ class Field
6
+ class BooleanTest < ActiveSupport::TestCase
7
+ def setup
8
+ @field = Uchi::Field::Boolean.new(:active)
9
+ @form = OpenStruct.new(object: OpenStruct.new(active: true))
10
+ @repository = Uchi::Repositories::Author.new
11
+ end
12
+
13
+ test "inherits from Uchi::Field" do
14
+ assert_kind_of Uchi::Field, @field
15
+ end
16
+
17
+ test "has default options" do
18
+ assert_equal [:edit, :index, :show], @field.on
19
+ assert_not @field.searchable?
20
+ assert @field.sortable?
21
+ end
22
+
23
+ test "#edit_component returns an instance of Edit component" do
24
+ component = @field.edit_component(form: @form, hint: "Custom hint", label: "Custom label", repository: @repository)
25
+ assert_equal "Custom hint", component.hint
26
+ assert_equal "Custom label", component.label
27
+ assert_equal @field, component.field
28
+ assert_equal @form, component.form
29
+ assert_equal @repository, component.repository
30
+ assert_kind_of Uchi::Field::Boolean::Edit, component
31
+ end
32
+
33
+ test "#index_component returns an instance of Index component" do
34
+ component = @field.index_component(record: @form.object, repository: @repository)
35
+ assert_equal @field, component.field
36
+ assert_equal @form.object, component.record
37
+ assert_equal @repository, component.repository
38
+ assert_kind_of Uchi::Field::Boolean::Index, component
39
+ end
40
+
41
+ test "#searchable? returns false when explicitly set" do
42
+ field = Uchi::Field::Boolean.new(:active).searchable(false)
43
+ assert_not field.searchable?
44
+ end
45
+
46
+ test "#show_component returns an instance of Show component" do
47
+ component = @field.show_component(record: @form.object, repository: @repository)
48
+ assert_equal @field, component.field
49
+ assert_equal @form.object, component.record
50
+ assert_equal @repository, component.repository
51
+ assert_kind_of Uchi::Field::Boolean::Show, component
52
+ end
53
+
54
+ test "#sortable? returns false when explicitly set" do
55
+ field = Uchi::Field::Boolean.new(:active).sortable(false)
56
+ assert_not field.sortable?
57
+ end
58
+ end
59
+
60
+ class BooleanEditTest < ViewComponent::TestCase
61
+ def setup
62
+ @field = Uchi::Field::Boolean.new(:active)
63
+ @record = Author.new(name: "Test Author")
64
+ @record.define_singleton_method(:active) { true }
65
+ @record.define_singleton_method(:active=) { |val| @active = val }
66
+ @repository = Uchi::Repositories::Author.new
67
+ @view_context = ActionController::Base.new.view_context
68
+
69
+ @form = ActionView::Helpers::FormBuilder.new(:author, @record, @view_context, {})
70
+
71
+ @component = Uchi::Field::Boolean::Edit.new(
72
+ field: @field,
73
+ form: @form,
74
+ hint: "Custom hint",
75
+ label: "Custom label",
76
+ repository: @repository
77
+ )
78
+ end
79
+
80
+ test "inherits from Base component" do
81
+ assert_kind_of Uchi::Field::Base::Edit, @component
82
+ end
83
+
84
+ test "renders a checkbox field with the field content" do
85
+ render_inline(@component)
86
+
87
+ assert_selector("input[type='checkbox'][name='author[active]']")
88
+ end
89
+
90
+ test "renders label with specified text" do
91
+ render_inline(@component)
92
+
93
+ assert_selector("label", text: "Custom label")
94
+ end
95
+
96
+ test "renders hint when provided" do
97
+ render_inline(@component)
98
+
99
+ assert_selector("p", text: "Custom hint")
100
+ end
101
+
102
+ test "initializes the input component with the correct options" do
103
+ expected_options = {
104
+ attribute: :active,
105
+ form: @form,
106
+ label: {content: "Custom label"},
107
+ hint: {content: "Custom hint"}
108
+ }
109
+ assert_equal expected_options, @component.send(:options)
110
+ end
111
+ end
112
+
113
+ class BooleanIndexTest < ViewComponent::TestCase
114
+ def setup
115
+ @field = Uchi::Field::Boolean.new(:active)
116
+ @record = Author.new(name: "Test Author")
117
+ @record.define_singleton_method(:active) { true }
118
+ @repository = Uchi::Repositories::Author.new
119
+
120
+ @component = Uchi::Field::Boolean::Index.new(
121
+ field: @field,
122
+ record: @record,
123
+ repository: @repository
124
+ )
125
+ end
126
+
127
+ test "inherits from Base component" do
128
+ assert_kind_of Uchi::Field::Base::Index, @component
129
+ end
130
+
131
+ test "renders the field content" do
132
+ result = render_inline(@component)
133
+
134
+ assert_includes result.to_html, "true"
135
+ end
136
+ end
137
+
138
+ class BooleanShowTest < ViewComponent::TestCase
139
+ def setup
140
+ @field = Uchi::Field::Boolean.new(:active)
141
+ @record = Author.new(name: "Test Author")
142
+ @record.define_singleton_method(:active) { true }
143
+ @repository = Uchi::Repositories::Author.new
144
+
145
+ @component = Uchi::Field::Boolean::Show.new(
146
+ field: @field,
147
+ record: @record,
148
+ repository: @repository
149
+ )
150
+ end
151
+
152
+ test "inherits from Base component" do
153
+ assert_kind_of Uchi::Field::Base::Show, @component
154
+ end
155
+
156
+ test "renders the field content" do
157
+ result = render_inline(@component)
158
+
159
+ assert_includes result.to_html, "true"
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,163 @@
1
+ require "test_helper"
2
+ require "ostruct"
3
+
4
+ module Uchi
5
+ class Field
6
+ class DateTest < ActiveSupport::TestCase
7
+ def setup
8
+ @field = Uchi::Field::Date.new(:born_on)
9
+ @form = OpenStruct.new(object: OpenStruct.new(born_on: ::Date.new(1990, 1, 1)))
10
+ @repository = Uchi::Repositories::Author.new
11
+ end
12
+
13
+ test "inherits from Uchi::Field" do
14
+ assert_kind_of Uchi::Field, @field
15
+ end
16
+
17
+ test "has default options" do
18
+ assert_equal [:edit, :index, :show], @field.on
19
+ assert_not @field.searchable?
20
+ assert @field.sortable?
21
+ end
22
+
23
+ test "#edit_component returns an instance of Edit component" do
24
+ component = @field.edit_component(form: @form, hint: "Custom hint", label: "Custom label", repository: @repository)
25
+ assert_equal "Custom hint", component.hint
26
+ assert_equal "Custom label", component.label
27
+ assert_equal @field, component.field
28
+ assert_equal @form, component.form
29
+ assert_equal @repository, component.repository
30
+ assert_kind_of Uchi::Field::Date::Edit, component
31
+ end
32
+
33
+ test "#index_component returns an instance of Index component" do
34
+ component = @field.index_component(record: @form.object, repository: @repository)
35
+ assert_equal @field, component.field
36
+ assert_equal @form.object, component.record
37
+ assert_equal @repository, component.repository
38
+ assert_kind_of Uchi::Field::Date::Index, component
39
+ end
40
+
41
+ test "#searchable? returns false when explicitly set" do
42
+ field = Uchi::Field::Date.new(:born_on).searchable(false)
43
+ assert_not field.searchable?
44
+ end
45
+
46
+ test "#show_component returns an instance of Show component" do
47
+ component = @field.show_component(record: @form.object, repository: @repository)
48
+ assert_equal @field, component.field
49
+ assert_equal @form.object, component.record
50
+ assert_equal @repository, component.repository
51
+ assert_kind_of Uchi::Field::Date::Show, component
52
+ end
53
+
54
+ test "#sortable? returns false when explicitly set" do
55
+ field = Uchi::Field::Date.new(:born_on).sortable(false)
56
+ assert_not field.sortable?
57
+ end
58
+ end
59
+
60
+ class DateEditTest < ViewComponent::TestCase
61
+ def setup
62
+ @field = Uchi::Field::Date.new(:born_on)
63
+ @record = Author.new(name: "Test Author")
64
+ @record.define_singleton_method(:born_on) { ::Date.new(1990, 1, 1) }
65
+ @record.define_singleton_method(:born_on=) { |val| @born_on = val }
66
+ @repository = Uchi::Repositories::Author.new
67
+ @view_context = ActionController::Base.new.view_context
68
+
69
+ @form = ActionView::Helpers::FormBuilder.new(:author, @record, @view_context, {})
70
+
71
+ @component = Uchi::Field::Date::Edit.new(
72
+ field: @field,
73
+ form: @form,
74
+ hint: "Custom hint",
75
+ label: "Custom label",
76
+ repository: @repository
77
+ )
78
+ end
79
+
80
+ test "inherits from Base component" do
81
+ assert_kind_of Uchi::Field::Base::Edit, @component
82
+ end
83
+
84
+ test "renders a date input field" do
85
+ render_inline(@component)
86
+
87
+ assert_selector("input[name='author[born_on]']")
88
+ end
89
+
90
+ test "renders label with specified text" do
91
+ render_inline(@component)
92
+
93
+ assert_selector("label", text: "Custom label")
94
+ end
95
+
96
+ test "renders hint when provided" do
97
+ render_inline(@component)
98
+
99
+ assert_selector("p", text: "Custom hint")
100
+ end
101
+
102
+ test "initializes the input component with the correct options" do
103
+ expected_options = {
104
+ attribute: :born_on,
105
+ form: @form,
106
+ label: {content: "Custom label"},
107
+ hint: {content: "Custom hint"}
108
+ }
109
+ assert_equal expected_options, @component.send(:options)
110
+ end
111
+ end
112
+
113
+ class DateIndexTest < ViewComponent::TestCase
114
+ def setup
115
+ @field = Uchi::Field::Date.new(:born_on)
116
+ @record = Author.new(name: "Test Author")
117
+ @record.define_singleton_method(:born_on) { ::Date.new(1990, 1, 1) }
118
+ @repository = Uchi::Repositories::Author.new
119
+
120
+ @component = Uchi::Field::Date::Index.new(
121
+ field: @field,
122
+ record: @record,
123
+ repository: @repository
124
+ )
125
+ end
126
+
127
+ test "inherits from Base component" do
128
+ assert_kind_of Uchi::Field::Base::Index, @component
129
+ end
130
+
131
+ test "renders the field content" do
132
+ result = render_inline(@component)
133
+
134
+ assert_includes result.to_html, "1990-01-01"
135
+ end
136
+ end
137
+
138
+ class DateShowTest < ViewComponent::TestCase
139
+ def setup
140
+ @field = Uchi::Field::Date.new(:born_on)
141
+ @record = Author.new(name: "Test Author")
142
+ @record.define_singleton_method(:born_on) { ::Date.new(1990, 1, 1) }
143
+ @repository = Uchi::Repositories::Author.new
144
+
145
+ @component = Uchi::Field::Date::Show.new(
146
+ field: @field,
147
+ record: @record,
148
+ repository: @repository
149
+ )
150
+ end
151
+
152
+ test "inherits from Base component" do
153
+ assert_kind_of Uchi::Field::Base::Show, @component
154
+ end
155
+
156
+ test "renders the field content" do
157
+ result = render_inline(@component)
158
+
159
+ assert_includes result.to_html, "1990-01-01"
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,152 @@
1
+ require "test_helper"
2
+ require "ostruct"
3
+
4
+ module Uchi
5
+ class Field
6
+ class DateTimeTest < ActiveSupport::TestCase
7
+ def setup
8
+ @field = Uchi::Field::DateTime.new(:created_at)
9
+ @form = OpenStruct.new(object: OpenStruct.new(created_at: ::DateTime.new(2024, 1, 1, 12, 0, 0)))
10
+ @repository = Uchi::Repositories::Author.new
11
+ end
12
+
13
+ test "inherits from Uchi::Field" do
14
+ assert_kind_of Uchi::Field, @field
15
+ end
16
+
17
+ test "has default options" do
18
+ assert_equal [:edit, :index, :show], @field.on
19
+ assert_not @field.searchable?
20
+ assert @field.sortable?
21
+ end
22
+
23
+ test "#edit_component returns an instance of Edit component" do
24
+ component = @field.edit_component(form: @form, hint: "Custom hint", label: "Custom label", repository: @repository)
25
+ assert_equal "Custom hint", component.hint
26
+ assert_equal "Custom label", component.label
27
+ assert_equal @field, component.field
28
+ assert_equal @form, component.form
29
+ assert_equal @repository, component.repository
30
+ assert_kind_of Uchi::Field::DateTime::Edit, component
31
+ end
32
+
33
+ test "#index_component returns an instance of Index component" do
34
+ component = @field.index_component(record: @form.object, repository: @repository)
35
+ assert_equal @field, component.field
36
+ assert_equal @form.object, component.record
37
+ assert_equal @repository, component.repository
38
+ assert_kind_of Uchi::Field::DateTime::Index, component
39
+ end
40
+
41
+ test "#searchable? returns false when explicitly set" do
42
+ field = Uchi::Field::DateTime.new(:created_at).searchable(false)
43
+ assert_not field.searchable?
44
+ end
45
+
46
+ test "#show_component returns an instance of Show component" do
47
+ component = @field.show_component(record: @form.object, repository: @repository)
48
+ assert_equal @field, component.field
49
+ assert_equal @form.object, component.record
50
+ assert_equal @repository, component.repository
51
+ assert_kind_of Uchi::Field::DateTime::Show, component
52
+ end
53
+
54
+ test "#sortable? returns false when explicitly set" do
55
+ field = Uchi::Field::DateTime.new(:created_at).sortable(false)
56
+ assert_not field.sortable?
57
+ end
58
+ end
59
+
60
+ class DateTimeEditTest < ViewComponent::TestCase
61
+ def setup
62
+ @field = Uchi::Field::DateTime.new(:created_at)
63
+ @record = Author.new(name: "Test Author")
64
+ @record.define_singleton_method(:created_at) { ::DateTime.new(2024, 1, 1, 12, 0, 0) }
65
+ @record.define_singleton_method(:created_at=) { |val| @created_at = val }
66
+ @repository = Uchi::Repositories::Author.new
67
+ @view_context = ActionController::Base.new.view_context
68
+
69
+ @form = ActionView::Helpers::FormBuilder.new(:author, @record, @view_context, {})
70
+
71
+ @component = Uchi::Field::DateTime::Edit.new(
72
+ field: @field,
73
+ form: @form,
74
+ hint: "Custom hint",
75
+ label: "Custom label",
76
+ repository: @repository
77
+ )
78
+ end
79
+
80
+ test "inherits from Base component" do
81
+ assert_kind_of Uchi::Field::Base::Edit, @component
82
+ end
83
+
84
+ test "can be rendered without errors" do
85
+ # Skip rendering tests due to missing Flowbite::InputField::DateTime dependency
86
+ assert_nothing_raised do
87
+ @component
88
+ end
89
+ end
90
+
91
+ test "initializes the input component with the correct options" do
92
+ expected_options = {
93
+ attribute: :created_at,
94
+ form: @form,
95
+ label: {content: "Custom label"},
96
+ hint: {content: "Custom hint"}
97
+ }
98
+ assert_equal expected_options, @component.send(:options)
99
+ end
100
+ end
101
+
102
+ class DateTimeIndexTest < ViewComponent::TestCase
103
+ def setup
104
+ @field = Uchi::Field::DateTime.new(:created_at)
105
+ @record = Author.new(name: "Test Author")
106
+ @record.define_singleton_method(:created_at) { ::DateTime.new(2024, 1, 1, 12, 0, 0) }
107
+ @repository = Uchi::Repositories::Author.new
108
+
109
+ @component = Uchi::Field::DateTime::Index.new(
110
+ field: @field,
111
+ record: @record,
112
+ repository: @repository
113
+ )
114
+ end
115
+
116
+ test "inherits from Base component" do
117
+ assert_kind_of Uchi::Field::Base::Index, @component
118
+ end
119
+
120
+ test "renders the field content" do
121
+ result = render_inline(@component)
122
+
123
+ assert_includes result.to_html, "2024-01-01T12:00:00+00:00"
124
+ end
125
+ end
126
+
127
+ class DateTimeShowTest < ViewComponent::TestCase
128
+ def setup
129
+ @field = Uchi::Field::DateTime.new(:created_at)
130
+ @record = Author.new(name: "Test Author")
131
+ @record.define_singleton_method(:created_at) { ::DateTime.new(2024, 1, 1, 12, 0, 0) }
132
+ @repository = Uchi::Repositories::Author.new
133
+
134
+ @component = Uchi::Field::DateTime::Show.new(
135
+ field: @field,
136
+ record: @record,
137
+ repository: @repository
138
+ )
139
+ end
140
+
141
+ test "inherits from Base component" do
142
+ assert_kind_of Uchi::Field::Base::Show, @component
143
+ end
144
+
145
+ test "renders the field content" do
146
+ result = render_inline(@component)
147
+
148
+ assert_includes result.to_html, "2024-01-01T12:00:00+00:00"
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,144 @@
1
+ require "test_helper"
2
+ require "ostruct"
3
+
4
+ module Uchi
5
+ class Field
6
+ class HasAndBelongsToManyTest < ActiveSupport::TestCase
7
+ def setup
8
+ @record = Book.new
9
+ @form = OpenStruct.new(object: @record)
10
+
11
+ @repository = Uchi::Repositories::Book.new
12
+ @field = Uchi::Field::HasAndBelongsToMany.new(:authors)
13
+ @field.repository = @repository
14
+ end
15
+
16
+ test "inherits from Uchi::Field" do
17
+ assert_kind_of Uchi::Field, @field
18
+ end
19
+
20
+ test "has default options specific to HasAndBelongsToMany field" do
21
+ assert_not @field.searchable?
22
+ assert @field.sortable?
23
+ end
24
+
25
+ test "has custom collection_query" do
26
+ custom_query = ->(query) { query.where(published: true) }
27
+ field = Uchi::Field::HasAndBelongsToMany.new(:categories).collection_query(custom_query)
28
+ assert_equal custom_query, field.collection_query
29
+ end
30
+
31
+ test "uses default collection_query" do
32
+ assert_equal Uchi::Field::HasAndBelongsToMany::DEFAULT_COLLECTION_QUERY, @field.collection_query
33
+ end
34
+
35
+ test "#param_key returns foreign key name" do
36
+ assert_equal :author_ids, @field.param_key
37
+ end
38
+
39
+ test "#permitted_param returns key for strong parameters" do
40
+ assert_equal({author_ids: []}, @field.permitted_param)
41
+ end
42
+
43
+ test "#group_as returns :associations" do
44
+ assert_equal :associations, @field.group_as(:show)
45
+ assert_equal :associations, @field.group_as(:edit)
46
+ end
47
+
48
+ test "#edit_component returns an instance of Edit component" do
49
+ component = @field.edit_component(form: @form, hint: "Custom hint", label: "Custom label", repository: @repository)
50
+ assert_equal "Custom hint", component.hint
51
+ assert_equal "Custom label", component.label
52
+ assert_equal @field, component.field
53
+ assert_equal @form, component.form
54
+ assert_equal @repository, component.repository
55
+ assert_kind_of Uchi::Field::HasAndBelongsToMany::Edit, component
56
+ end
57
+
58
+ test "#index_component returns an instance of Index component" do
59
+ component = @field.index_component(record: @form.object, repository: @repository)
60
+ assert_equal @field, component.field
61
+ assert_equal @form.object, component.record
62
+ assert_equal @repository, component.repository
63
+ assert_kind_of Uchi::Field::HasAndBelongsToMany::Index, component
64
+ end
65
+
66
+ test "#show_component returns an instance of Show component" do
67
+ component = @field.show_component(record: @form.object, repository: @repository)
68
+ assert_equal @field, component.field
69
+ assert_equal @form.object, component.record
70
+ assert_equal @repository, component.repository
71
+ assert_kind_of Uchi::Field::HasAndBelongsToMany::Show, component
72
+ end
73
+
74
+ test "#searchable? returns false when explicitly set" do
75
+ field = Uchi::Field::HasAndBelongsToMany.new(:categories).searchable(false)
76
+ assert_not field.searchable?
77
+ end
78
+
79
+ test "#sortable? returns false when explicitly set" do
80
+ field = Uchi::Field::HasAndBelongsToMany.new(:categories).sortable(false)
81
+ assert_not field.sortable?
82
+ end
83
+ end
84
+
85
+ class HasAndBelongsToManyEditTest < ViewComponent::TestCase
86
+ def setup
87
+ @field = Uchi::Field::HasAndBelongsToMany.new(:categories)
88
+ @book = Book.new(original_title: "The Hobbit")
89
+ @repository = Uchi::Repositories::Book.new
90
+ @view_context = ActionController::Base.new.view_context
91
+
92
+ @form = ActionView::Helpers::FormBuilder.new(:book, @book, @view_context, {})
93
+
94
+ @component = Uchi::Field::HasAndBelongsToMany::Edit.new(
95
+ field: @field,
96
+ form: @form,
97
+ hint: "Custom hint",
98
+ label: "Custom label",
99
+ repository: @repository
100
+ )
101
+ end
102
+
103
+ test "inherits from Base component" do
104
+ assert_kind_of Uchi::Field::Base::Edit, @component
105
+ end
106
+ end
107
+
108
+ class HasAndBelongsToManyIndexTest < ViewComponent::TestCase
109
+ def setup
110
+ @field = Uchi::Field::HasAndBelongsToMany.new(:categories)
111
+ @book = Book.new(original_title: "The Hobbit")
112
+ @repository = Uchi::Repositories::Book.new
113
+
114
+ @component = Uchi::Field::HasAndBelongsToMany::Index.new(
115
+ field: @field,
116
+ record: @book,
117
+ repository: @repository
118
+ )
119
+ end
120
+
121
+ test "inherits from Base component" do
122
+ assert_kind_of Uchi::Field::Base::Index, @component
123
+ end
124
+ end
125
+
126
+ class HasAndBelongsToManyShowTest < ViewComponent::TestCase
127
+ def setup
128
+ @field = Uchi::Field::HasAndBelongsToMany.new(:categories)
129
+ @book = Book.new(original_title: "The Hobbit")
130
+ @repository = Uchi::Repositories::Book.new
131
+
132
+ @component = Uchi::Field::HasAndBelongsToMany::Show.new(
133
+ field: @field,
134
+ record: @book,
135
+ repository: @repository
136
+ )
137
+ end
138
+
139
+ test "inherits from Base component" do
140
+ assert_kind_of Uchi::Field::Base::Show, @component
141
+ end
142
+ end
143
+ end
144
+ end