uchi 0.1.0 → 0.1.2

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 (93) 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/package.json +31 -0
  6. data/test/components/uchi/field/belongs_to_test.rb +134 -0
  7. data/test/components/uchi/field/blank_test.rb +119 -0
  8. data/test/components/uchi/field/boolean_test.rb +163 -0
  9. data/test/components/uchi/field/date_test.rb +163 -0
  10. data/test/components/uchi/field/date_time_test.rb +152 -0
  11. data/test/components/uchi/field/has_many_test.rb +138 -0
  12. data/test/components/uchi/field/id_test.rb +113 -0
  13. data/test/components/uchi/field/number_test.rb +163 -0
  14. data/test/components/uchi/field/string_test.rb +159 -0
  15. data/test/controllers/uchi/authors_controller_test.rb +119 -0
  16. data/test/controllers/uchi/repository_controller_test.rb +93 -0
  17. data/test/controllers/uchi/scoped_repository_controller_test.rb +73 -0
  18. data/test/dummy/Rakefile +6 -0
  19. data/test/dummy/app/assets/images/.keep +0 -0
  20. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  21. data/test/dummy/app/controllers/application_controller.rb +4 -0
  22. data/test/dummy/app/controllers/concerns/.keep +0 -0
  23. data/test/dummy/app/controllers/uchi/authors_controller.rb +7 -0
  24. data/test/dummy/app/controllers/uchi/books_controller.rb +7 -0
  25. data/test/dummy/app/controllers/uchi/titles_controller.rb +7 -0
  26. data/test/dummy/app/helpers/application_helper.rb +2 -0
  27. data/test/dummy/app/jobs/application_job.rb +7 -0
  28. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  29. data/test/dummy/app/models/application_record.rb +3 -0
  30. data/test/dummy/app/models/author.rb +3 -0
  31. data/test/dummy/app/models/book.rb +3 -0
  32. data/test/dummy/app/models/concerns/.keep +0 -0
  33. data/test/dummy/app/models/title.rb +3 -0
  34. data/test/dummy/app/uchi/repositories/author.rb +20 -0
  35. data/test/dummy/app/uchi/repositories/book.rb +16 -0
  36. data/test/dummy/app/uchi/repositories/title.rb +17 -0
  37. data/test/dummy/app/views/layouts/application.html.erb +27 -0
  38. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  39. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  40. data/test/dummy/app/views/pwa/manifest.json.erb +22 -0
  41. data/test/dummy/app/views/pwa/service-worker.js +26 -0
  42. data/test/dummy/bin/dev +2 -0
  43. data/test/dummy/bin/rails +4 -0
  44. data/test/dummy/bin/rake +4 -0
  45. data/test/dummy/bin/setup +34 -0
  46. data/test/dummy/config/application.rb +29 -0
  47. data/test/dummy/config/boot.rb +5 -0
  48. data/test/dummy/config/cable.yml +10 -0
  49. data/test/dummy/config/database.yml +32 -0
  50. data/test/dummy/config/environment.rb +5 -0
  51. data/test/dummy/config/environments/development.rb +69 -0
  52. data/test/dummy/config/environments/production.rb +89 -0
  53. data/test/dummy/config/environments/test.rb +53 -0
  54. data/test/dummy/config/initializers/content_security_policy.rb +25 -0
  55. data/test/dummy/config/initializers/filter_parameter_logging.rb +8 -0
  56. data/test/dummy/config/initializers/inflections.rb +16 -0
  57. data/test/dummy/config/locales/da.yml +51 -0
  58. data/test/dummy/config/locales/en.yml +31 -0
  59. data/test/dummy/config/puma.rb +38 -0
  60. data/test/dummy/config/routes.rb +9 -0
  61. data/test/dummy/config/storage.yml +34 -0
  62. data/test/dummy/config.ru +6 -0
  63. data/test/dummy/db/migrate/20251002183635_create_authors.rb +11 -0
  64. data/test/dummy/db/migrate/20251005131726_create_books.rb +9 -0
  65. data/test/dummy/db/migrate/20251005131811_create_titles.rb +11 -0
  66. data/test/dummy/db/schema.rb +38 -0
  67. data/test/dummy/log/.keep +0 -0
  68. data/test/dummy/public/400.html +114 -0
  69. data/test/dummy/public/404.html +114 -0
  70. data/test/dummy/public/406-unsupported-browser.html +114 -0
  71. data/test/dummy/public/422.html +114 -0
  72. data/test/dummy/public/500.html +114 -0
  73. data/test/dummy/public/icon.png +0 -0
  74. data/test/dummy/public/icon.svg +3 -0
  75. data/test/dummy/storage/.keep +0 -0
  76. data/test/dummy/test/fixtures/authors.yml +11 -0
  77. data/test/dummy/test/models/author_test.rb +7 -0
  78. data/test/dummy/tmp/.keep +0 -0
  79. data/test/dummy/tmp/pids/.keep +0 -0
  80. data/test/dummy/tmp/storage/.keep +0 -0
  81. data/test/test_helper.rb +15 -0
  82. data/test/uchi/field_test.rb +63 -0
  83. data/test/uchi/i18n_test.rb +18 -0
  84. data/test/uchi/repository/routes_test.rb +49 -0
  85. data/test/uchi/repository/translate_test.rb +263 -0
  86. data/test/uchi/repository_test.rb +137 -0
  87. data/test/uchi/sort_order_test.rb +47 -0
  88. data/test/uchi_test.rb +7 -0
  89. metadata +146 -7
  90. data/README.md +0 -35
  91. data/Rakefile +0 -6
  92. data/lib/uchi/version.rb +0 -5
  93. data/lib/uchi.rb +0 -8
@@ -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,138 @@
1
+ require "test_helper"
2
+ require "ostruct"
3
+
4
+ module Uchi
5
+ class Field
6
+ class HasManyTest < ActiveSupport::TestCase
7
+ def setup
8
+ @field = Uchi::Field::HasMany.new(:titles)
9
+ @form = OpenStruct.new(object: Book.new)
10
+ @repository = Uchi::Repositories::Book.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 specific to HasMany field" do
18
+ assert_equal [:show], @field.on # Different from other fields - only on show
19
+ assert_not @field.searchable?
20
+ assert @field.sortable?
21
+ end
22
+
23
+ test "has custom collection_query" do
24
+ custom_query = ->(query) { query.where(published: true) }
25
+ field = Uchi::Field::HasMany.new(:titles, collection_query: custom_query)
26
+ assert_equal custom_query, field.collection_query
27
+ end
28
+
29
+ test "uses default collection_query" do
30
+ assert_equal Uchi::Field::HasMany::DEFAULT_COLLECTION_QUERY, @field.collection_query
31
+ end
32
+
33
+ test "#param_key returns foreign key name" do
34
+ assert_equal :titles_id, @field.param_key
35
+ end
36
+
37
+ test "#group_as returns :associations" do
38
+ assert_equal :associations, @field.group_as(:show)
39
+ assert_equal :associations, @field.group_as(:edit)
40
+ end
41
+
42
+ test "#edit_component returns an instance of Edit component" do
43
+ component = @field.edit_component(form: @form, hint: "Custom hint", label: "Custom label", repository: @repository)
44
+ assert_equal "Custom hint", component.hint
45
+ assert_equal "Custom label", component.label
46
+ assert_equal @field, component.field
47
+ assert_equal @form, component.form
48
+ assert_equal @repository, component.repository
49
+ assert_kind_of Uchi::Field::HasMany::Edit, component
50
+ end
51
+
52
+ test "#index_component returns an instance of Index component" do
53
+ component = @field.index_component(record: @form.object, repository: @repository)
54
+ assert_equal @field, component.field
55
+ assert_equal @form.object, component.record
56
+ assert_equal @repository, component.repository
57
+ assert_kind_of Uchi::Field::HasMany::Index, component
58
+ end
59
+
60
+ test "#show_component returns an instance of Show component" do
61
+ component = @field.show_component(record: @form.object, repository: @repository)
62
+ assert_equal @field, component.field
63
+ assert_equal @form.object, component.record
64
+ assert_equal @repository, component.repository
65
+ assert_kind_of Uchi::Field::HasMany::Show, component
66
+ end
67
+
68
+ test "#searchable? returns false when explicitly set" do
69
+ field = Uchi::Field::HasMany.new(:titles, searchable: false)
70
+ assert_not field.searchable?
71
+ end
72
+
73
+ test "#sortable? returns false when explicitly set" do
74
+ field = Uchi::Field::HasMany.new(:titles, sortable: false)
75
+ assert_not field.sortable?
76
+ end
77
+ end
78
+
79
+ class HasManyEditTest < ViewComponent::TestCase
80
+ def setup
81
+ @field = Uchi::Field::HasMany.new(:titles)
82
+ @book = Book.new(original_title: "The Hobbit")
83
+ @repository = Uchi::Repositories::Book.new
84
+ @view_context = ActionController::Base.new.view_context
85
+
86
+ @form = ActionView::Helpers::FormBuilder.new(:book, @book, @view_context, {})
87
+
88
+ @component = Uchi::Field::HasMany::Edit.new(
89
+ field: @field,
90
+ form: @form,
91
+ hint: "Custom hint",
92
+ label: "Custom label",
93
+ repository: @repository
94
+ )
95
+ end
96
+
97
+ test "inherits from Base component" do
98
+ assert_kind_of Uchi::Field::Base::Edit, @component
99
+ end
100
+ end
101
+
102
+ class HasManyIndexTest < ViewComponent::TestCase
103
+ def setup
104
+ @field = Uchi::Field::HasMany.new(:titles)
105
+ @book = Book.new(original_title: "The Hobbit")
106
+ @repository = Uchi::Repositories::Book.new
107
+
108
+ @component = Uchi::Field::HasMany::Index.new(
109
+ field: @field,
110
+ record: @book,
111
+ repository: @repository
112
+ )
113
+ end
114
+
115
+ test "inherits from Base component" do
116
+ assert_kind_of Uchi::Field::Base::Index, @component
117
+ end
118
+ end
119
+
120
+ class HasManyShowTest < ViewComponent::TestCase
121
+ def setup
122
+ @field = Uchi::Field::HasMany.new(:titles)
123
+ @book = Book.new(original_title: "The Hobbit")
124
+ @repository = Uchi::Repositories::Book.new
125
+
126
+ @component = Uchi::Field::HasMany::Show.new(
127
+ field: @field,
128
+ record: @book,
129
+ repository: @repository
130
+ )
131
+ end
132
+
133
+ test "inherits from Base component" do
134
+ assert_kind_of Uchi::Field::Base::Show, @component
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,113 @@
1
+ require "test_helper"
2
+ require "ostruct"
3
+
4
+ module Uchi
5
+ class Field
6
+ class IdTest < ActiveSupport::TestCase
7
+ def setup
8
+ @field = Uchi::Field::Id.new(:id)
9
+ @form = OpenStruct.new(object: OpenStruct.new(id: 123))
10
+ @repository = Uchi::Repositories::Author.new
11
+ end
12
+
13
+ test "inherits from Uchi::Field::Number" do
14
+ assert_kind_of Uchi::Field::Number, @field
15
+ assert_kind_of Uchi::Field, @field
16
+ end
17
+
18
+ test "has default options specific to Id field" do
19
+ assert_equal [:index, :show], @field.on # Different from other fields
20
+ assert @field.searchable? # Different from other fields
21
+ assert @field.sortable?
22
+ end
23
+
24
+ test "does not have edit_component because not in :edit on list" do
25
+ # Since Id field defaults to [:index, :show], it doesn't include :edit
26
+ # But we can still create the component if needed
27
+ assert_nothing_raised do
28
+ @field.edit_component(form: @form, hint: "Custom hint", label: "Custom label", repository: @repository)
29
+ end
30
+ end
31
+
32
+ test "#index_component returns an instance of Index component" do
33
+ component = @field.index_component(record: @form.object, repository: @repository)
34
+ assert_equal @field, component.field
35
+ assert_equal @form.object, component.record
36
+ assert_equal @repository, component.repository
37
+ assert_kind_of Uchi::Field::Id::Index, component
38
+ end
39
+
40
+ test "#searchable? returns true by default for Id field" do
41
+ assert @field.searchable?
42
+ end
43
+
44
+ test "#searchable? returns false when explicitly set" do
45
+ field = Uchi::Field::Id.new(:id, searchable: false)
46
+ assert_not field.searchable?
47
+ end
48
+
49
+ test "#show_component returns an instance of Show component" do
50
+ component = @field.show_component(record: @form.object, repository: @repository)
51
+ assert_equal @field, component.field
52
+ assert_equal @form.object, component.record
53
+ assert_equal @repository, component.repository
54
+ assert_kind_of Uchi::Field::Id::Show, component
55
+ end
56
+
57
+ test "#sortable? returns false when explicitly set" do
58
+ field = Uchi::Field::Id.new(:id, sortable: false)
59
+ assert_not field.sortable?
60
+ end
61
+ end
62
+
63
+ class IdIndexTest < ViewComponent::TestCase
64
+ def setup
65
+ @field = Uchi::Field::Id.new(:id)
66
+ @record = Author.new(name: "Test Author")
67
+ @record.define_singleton_method(:id) { 123 }
68
+ @repository = Uchi::Repositories::Author.new
69
+
70
+ @component = Uchi::Field::Id::Index.new(
71
+ field: @field,
72
+ record: @record,
73
+ repository: @repository
74
+ )
75
+ end
76
+
77
+ test "inherits from Base component" do
78
+ assert_kind_of Uchi::Field::Base::Index, @component
79
+ end
80
+
81
+ test "renders the field content" do
82
+ result = render_inline(@component)
83
+
84
+ assert_includes result.to_html, "123"
85
+ end
86
+ end
87
+
88
+ class IdShowTest < ViewComponent::TestCase
89
+ def setup
90
+ @field = Uchi::Field::Id.new(:id)
91
+ @record = Author.new(name: "Test Author")
92
+ @record.define_singleton_method(:id) { 123 }
93
+ @repository = Uchi::Repositories::Author.new
94
+
95
+ @component = Uchi::Field::Id::Show.new(
96
+ field: @field,
97
+ record: @record,
98
+ repository: @repository
99
+ )
100
+ end
101
+
102
+ test "inherits from Base component" do
103
+ assert_kind_of Uchi::Field::Base::Show, @component
104
+ end
105
+
106
+ test "renders the field content" do
107
+ result = render_inline(@component)
108
+
109
+ assert_includes result.to_html, "123"
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,163 @@
1
+ require "test_helper"
2
+ require "ostruct"
3
+
4
+ module Uchi
5
+ class Field
6
+ class NumberTest < ActiveSupport::TestCase
7
+ def setup
8
+ @field = Uchi::Field::Number.new(:age)
9
+ @form = OpenStruct.new(object: OpenStruct.new(age: 25))
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::Number::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::Number::Index, component
39
+ end
40
+
41
+ test "#searchable? returns false when explicitly set" do
42
+ field = Uchi::Field::Number.new(:age, 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::Number::Show, component
52
+ end
53
+
54
+ test "#sortable? returns false when explicitly set" do
55
+ field = Uchi::Field::Number.new(:age, sortable: false)
56
+ assert_not field.sortable?
57
+ end
58
+ end
59
+
60
+ class NumberEditTest < ViewComponent::TestCase
61
+ def setup
62
+ @field = Uchi::Field::Number.new(:age)
63
+ @record = Author.new(name: "Test Author")
64
+ @record.define_singleton_method(:age) { 25 }
65
+ @record.define_singleton_method(:age=) { |val| @age = 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::Number::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 number input field with the field content" do
85
+ render_inline(@component)
86
+
87
+ assert_selector("input[name='author[age]']")
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: :age,
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 NumberIndexTest < ViewComponent::TestCase
114
+ def setup
115
+ @field = Uchi::Field::Number.new(:age)
116
+ @record = Author.new(name: "Test Author")
117
+ @record.define_singleton_method(:age) { 25 }
118
+ @repository = Uchi::Repositories::Author.new
119
+
120
+ @component = Uchi::Field::Number::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, "25"
135
+ end
136
+ end
137
+
138
+ class NumberShowTest < ViewComponent::TestCase
139
+ def setup
140
+ @field = Uchi::Field::Number.new(:age)
141
+ @record = Author.new(name: "Test Author")
142
+ @record.define_singleton_method(:age) { 25 }
143
+ @repository = Uchi::Repositories::Author.new
144
+
145
+ @component = Uchi::Field::Number::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, "25"
160
+ end
161
+ end
162
+ end
163
+ end