Skip to content

Commit 92175f8

Browse files
authored
Merge pull request #58 from blocknotes/specs-improvements
Improve specs
2 parents 0e640f9 + 8b0cb28 commit 92175f8

File tree

5 files changed

+276
-0
lines changed

5 files changed

+276
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
require "dummy_rails_app"
4+
require "rails_helper"
5+
6+
RSpec.describe "TinyAdmin.configure" do # rubocop:disable RSpec/DescribeClass
7+
let(:settings) { TinyAdmin::Settings.instance }
8+
9+
around do |example|
10+
saved = settings.instance_variable_get(:@options)&.deep_dup
11+
saved_store = settings.instance_variable_get(:@store)
12+
saved_loaded = settings.instance_variable_get(:@loaded)
13+
example.run
14+
ensure
15+
settings.instance_variable_set(:@options, saved)
16+
settings.instance_variable_set(:@store, saved_store)
17+
settings.instance_variable_set(:@loaded, saved_loaded)
18+
end
19+
20+
it "yields settings to the block" do
21+
yielded = nil
22+
TinyAdmin.configure { |s| yielded = s }
23+
expect(yielded).to eq(settings)
24+
end
25+
26+
it "allows setting options via the block" do
27+
TinyAdmin.configure { |s| s.root_path = "/custom" }
28+
expect(settings.root_path).to eq("/custom")
29+
end
30+
31+
it "returns settings when no block is given" do
32+
result = TinyAdmin.configure
33+
expect(result).to eq(settings)
34+
end
35+
end
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# frozen_string_literal: true
2+
3+
require "dummy_rails_app"
4+
require "rails_helper"
5+
6+
RSpec.describe TinyAdmin::Utils, "#prepare_page" do
7+
let(:utils_instance) { Class.new { include TinyAdmin::Utils }.new }
8+
let(:settings) { TinyAdmin::Settings.instance }
9+
10+
around do |example|
11+
saved = settings.instance_variable_get(:@options)&.deep_dup
12+
saved_store = settings.instance_variable_get(:@store)
13+
saved_loaded = settings.instance_variable_get(:@loaded)
14+
settings.load_settings
15+
example.run
16+
ensure
17+
settings.instance_variable_set(:@options, saved)
18+
settings.instance_variable_set(:@store, saved_store)
19+
settings.instance_variable_set(:@loaded, saved_loaded)
20+
end
21+
22+
it "returns an instance of the given page class" do
23+
page = utils_instance.prepare_page(TinyAdmin::Views::Pages::Root)
24+
expect(page).to be_a(TinyAdmin::Views::Pages::Root)
25+
end
26+
27+
it "assigns head, flash, and navbar components", :aggregate_failures do
28+
page = utils_instance.prepare_page(TinyAdmin::Views::Pages::Root)
29+
expect(page.head_component).to be_a(TinyAdmin::Views::Components::Head)
30+
expect(page.flash_component).to be_a(TinyAdmin::Views::Components::Flash)
31+
expect(page.navbar_component).to be_a(TinyAdmin::Views::Components::Navbar)
32+
end
33+
34+
it "sets the page title from attributes" do
35+
page = utils_instance.prepare_page(TinyAdmin::Views::Pages::Root, attributes: { title: "My Title" })
36+
expect(page.title).to eq("My Title")
37+
end
38+
39+
it "sets params on the page" do
40+
page = utils_instance.prepare_page(TinyAdmin::Views::Pages::Root, params: { "page" => "2" })
41+
expect(page.params).to eq({ "page" => "2" })
42+
end
43+
44+
it "passes no_menu option to hide navbar items" do
45+
page = utils_instance.prepare_page(TinyAdmin::Views::Pages::Root, options: [:no_menu])
46+
expect(page.navbar_component.items).to eq([])
47+
end
48+
49+
it "yields the page to the block when given" do
50+
yielded = nil
51+
utils_instance.prepare_page(TinyAdmin::Views::Pages::Root) { |p| yielded = p }
52+
expect(yielded).to be_a(TinyAdmin::Views::Pages::Root)
53+
end
54+
55+
it "resolves widget class names from strings" do
56+
widget_class = Class.new(Phlex::HTML) do
57+
def view_template
58+
plain "test"
59+
end
60+
end
61+
stub_const("TestWidget", widget_class)
62+
page = utils_instance.prepare_page(TinyAdmin::Views::Pages::Root, attributes: { widgets: ["TestWidget"] })
63+
expect(page.widgets).to eq([TestWidget])
64+
end
65+
end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# frozen_string_literal: true
2+
3+
require "dummy_rails_app"
4+
require "rails_helper"
5+
6+
RSpec.describe TinyAdmin::Views::Components::FieldValue do
7+
let(:settings) { TinyAdmin::Settings.instance }
8+
9+
before { settings.load_settings }
10+
11+
describe "with a basic field" do
12+
let(:field) { TinyAdmin::Field.new(name: "title", type: :string, title: "Title", options: {}) }
13+
let(:record) { double("record", id: 1) } # rubocop:disable RSpec/VerifiedDoubles
14+
15+
it "renders the translated value in a span", :aggregate_failures do
16+
html = described_class.new(field, "Hello", record: record).call
17+
expect(html).to include("Hello")
18+
expect(html).to include("<span")
19+
end
20+
end
21+
22+
describe "with link_to option" do
23+
let(:field) { TinyAdmin::Field.new(name: "author_id", type: :integer, title: "Author", options: { link_to: "authors" }) }
24+
let(:record) { double("record", id: 1) } # rubocop:disable RSpec/VerifiedDoubles
25+
26+
it "wraps the value in a link", :aggregate_failures do
27+
html = described_class.new(field, "42", record: record).call
28+
expect(html).to include("<a")
29+
expect(html).to include("authors")
30+
expect(html).to include("42")
31+
end
32+
end
33+
34+
describe "with value_class option" do
35+
let(:field) { TinyAdmin::Field.new(name: "status", type: :string, title: "Status", options: { options: ["value_class"] }) }
36+
let(:record) { double("record", id: 1) } # rubocop:disable RSpec/VerifiedDoubles
37+
38+
it "adds value-based CSS class to the span" do
39+
html = described_class.new(field, "active", record: record).call
40+
expect(html).to include("value-active")
41+
end
42+
end
43+
end
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# frozen_string_literal: true
2+
3+
require "dummy_rails_app"
4+
require "rails_helper"
5+
6+
RSpec.describe TinyAdmin::Views::Components::FiltersForm do
7+
let(:component) { described_class.new }
8+
9+
before do
10+
TinyAdmin::Settings.instance.load_settings
11+
component.update_attributes(section_path: "/admin/posts", filters: filters)
12+
end
13+
14+
describe "with a boolean filter" do
15+
let(:field) { TinyAdmin::Field.new(name: "published", type: :boolean, title: "Published", options: {}) }
16+
let(:filters) { { field => { filter: { type: :boolean }, value: "1" } } }
17+
18+
it "renders a select with true/false options", :aggregate_failures do
19+
html = component.call
20+
expect(html).to include("form-select")
21+
expect(html).to include("true")
22+
expect(html).to include("false")
23+
end
24+
end
25+
26+
describe "with a date filter" do
27+
let(:field) { TinyAdmin::Field.new(name: "created_at", type: :date, title: "Created At", options: {}) }
28+
let(:filters) { { field => { filter: { type: :date }, value: "2024-01-01" } } }
29+
30+
it "renders a date input", :aggregate_failures do
31+
html = component.call
32+
expect(html).to include('type="date"')
33+
expect(html).to include("2024-01-01")
34+
end
35+
end
36+
37+
describe "with a datetime filter" do
38+
let(:field) { TinyAdmin::Field.new(name: "updated_at", type: :datetime, title: "Updated At", options: {}) }
39+
let(:filters) { { field => { filter: { type: :datetime }, value: "2024-01-01T12:00" } } }
40+
41+
it "renders a datetime-local input" do
42+
html = component.call
43+
expect(html).to include('type="datetime-local"')
44+
end
45+
end
46+
47+
describe "with an integer filter" do
48+
let(:field) { TinyAdmin::Field.new(name: "age", type: :integer, title: "Age", options: {}) }
49+
let(:filters) { { field => { filter: { type: :integer }, value: "25" } } }
50+
51+
it "renders a number input" do
52+
html = component.call
53+
expect(html).to include('type="number"')
54+
end
55+
end
56+
57+
describe "with a select filter" do
58+
let(:field) { TinyAdmin::Field.new(name: "state", type: :select, title: "State", options: {}) }
59+
let(:filters) { { field => { filter: { type: :select, values: %w[available unavailable] }, value: "available" } } }
60+
61+
it "renders a select with the provided values", :aggregate_failures do
62+
html = component.call
63+
expect(html).to include("form-select")
64+
expect(html).to include("available")
65+
expect(html).to include("unavailable")
66+
end
67+
end
68+
69+
describe "with a text filter (default)" do
70+
let(:field) { TinyAdmin::Field.new(name: "title", type: :string, title: "Title", options: {}) }
71+
let(:filters) { { field => { filter: {}, value: "hello" } } }
72+
73+
it "renders a text input", :aggregate_failures do
74+
html = component.call
75+
expect(html).to include('type="text"')
76+
expect(html).to include("hello")
77+
end
78+
end
79+
80+
describe "action buttons" do
81+
let(:field) { TinyAdmin::Field.new(name: "title", type: :string, title: "Title", options: {}) }
82+
let(:filters) { { field => { filter: {}, value: "" } } }
83+
84+
it "renders Clear and Filter buttons", :aggregate_failures do
85+
html = component.call
86+
expect(html).to include("Clear")
87+
expect(html).to include("Filter")
88+
end
89+
end
90+
end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# frozen_string_literal: true
2+
3+
require "dummy_rails_app"
4+
require "rails_helper"
5+
6+
RSpec.describe TinyAdmin::Views::Components::Widgets do
7+
describe "with nil widgets" do
8+
it "renders nothing" do
9+
html = described_class.new(nil).call
10+
expect(html).to eq("")
11+
end
12+
end
13+
14+
describe "with empty widgets" do
15+
it "renders nothing" do
16+
html = described_class.new([]).call
17+
expect(html).to eq("")
18+
end
19+
end
20+
21+
describe "with valid widget classes" do
22+
let(:widget_class) do
23+
Class.new(Phlex::HTML) do
24+
def view_template
25+
plain "Widget content"
26+
end
27+
end
28+
end
29+
30+
it "renders each widget in a card", :aggregate_failures do
31+
html = described_class.new([widget_class]).call
32+
expect(html).to include("Widget content")
33+
expect(html).to include("card-body")
34+
end
35+
end
36+
37+
describe "with non-Phlex widget" do
38+
it "skips non-Phlex classes" do
39+
html = described_class.new([String]).call
40+
expect(html).not_to include("card-body")
41+
end
42+
end
43+
end

0 commit comments

Comments
 (0)