Files
sure/test/controllers/pages_controller_test.rb
William Wei Ming bc7e16ff16 Perf/dashboard endpoint optimization (#1897)
* optimize net_category_totals() by using memoized cache

* fix issue - net_category_totals cache is never populated - suggested by coderabbitAI

* fix 422 error for service-worker

* remove warning of [assigned but unused variables] - income_statement.rb

* remove warnings of [assigned but unused] from Prism - income_statement_test.rb

* add some measurements to improve docstring coverage, follow CodeRabbit recommendation

* attach Skylight monitoring for dev env as well - use my own Skylight auth token

* integrate Skylight with my own account auth token for local benchmark

* fix PR review suggestion - Move fallback release-note copy to i18n keys

* follow PR review - Fix changelog GitHub fetch timeout bounding

* FIX - Variable shadowing; Prefer stubbing the specific instance over any_instance.expects

* fix CodeRabbit feedback - Reusing the same stub for both classifications hides a contract mismatch

* fix CodeRabbit FEEDBACK - Reconsider enabling Skylight by default in development

* fix CodeRabbitAI FEEDBACK - reconsider unconditionally enabling Skylight in development

* fix Security scan FEEDBACK before PR merge

* fix jjmata feedback
2026-05-31 00:09:38 +02:00

136 lines
4.4 KiB
Ruby

require "test_helper"
class PagesControllerTest < ActionDispatch::IntegrationTest
include EntriesTestHelper
setup do
sign_in @user = users(:family_admin)
@intro_user = users(:intro_user)
@family = @user.family
end
test "dashboard" do
get root_path
assert_response :ok
end
test "dashboard memoizes income statement period totals while rendering" do
income_statement = IncomeStatement.new(@family)
IncomeStatement.stubs(:new).returns(income_statement)
fake_expense_period_total = IncomeStatement::PeriodTotal.new(
classification: "expense",
total: 0,
currency: @family.currency,
category_totals: []
)
fake_income_period_total = IncomeStatement::PeriodTotal.new(
classification: "income",
total: 0,
currency: @family.currency,
category_totals: []
)
income_statement.expects(:build_period_total)
.with(classification: "expense", period: kind_of(Period))
.once
.returns(fake_expense_period_total)
income_statement.expects(:build_period_total)
.with(classification: "income", period: kind_of(Period))
.once
.returns(fake_income_period_total)
get root_path
assert_response :ok
end
test "intro page requires guest role" do
get intro_path
assert_redirected_to root_path
assert_equal "Intro is only available to guest users.", flash[:alert]
end
test "intro page is accessible for guest users" do
sign_in @intro_user
get intro_path
assert_response :ok
end
test "dashboard renders sankey chart with subcategories" do
# Create parent category with subcategory
parent_category = @family.categories.create!(name: "Shopping", color: "#FF5733")
subcategory = @family.categories.create!(name: "Groceries", parent: parent_category, color: "#33FF57")
# Create transactions using helper
create_transaction(account: @family.accounts.first, name: "General shopping", amount: 100, category: parent_category)
create_transaction(account: @family.accounts.first, name: "Grocery store", amount: 50, category: subcategory)
get root_path
assert_response :ok
assert_select "[data-controller='sankey-chart']"
end
test "dashboard renders sankey chart zoom controls and stable node ids" do
parent_category = @family.categories.create!(name: "Shopping", color: "#FF5733")
subcategory = @family.categories.create!(name: "Groceries", parent: parent_category, color: "#33FF57")
create_transaction(account: @family.accounts.first, name: "General shopping", amount: 100, category: parent_category)
create_transaction(account: @family.accounts.first, name: "Grocery store", amount: 50, category: subcategory)
get root_path
assert_response :ok
assert_select "[data-sankey-chart-target='zoomOutButton'][hidden]", count: 2
chart = css_select("[data-controller='sankey-chart']").first
sankey_data = JSON.parse(chart["data-sankey-chart-data-value"])
assert_includes sankey_data.fetch("nodes").map { |node| node.fetch("id") }, "cash_flow_node"
assert sankey_data.fetch("nodes").any? { |node| node.fetch("id").start_with?("expense_") }
end
test "changelog" do
VCR.use_cassette("git_repository_provider/fetch_latest_release_notes") do
get changelog_path
assert_response :ok
end
end
test "changelog with nil release notes" do
# Mock the GitHub provider to return nil (simulating API failure or no releases)
github_provider = mock
github_provider.expects(:fetch_latest_release_notes).returns(nil)
Provider::Registry.stubs(:get_provider).with(:github).returns(github_provider)
get changelog_path
assert_response :ok
assert_select "h2", text: "Release notes unavailable"
assert_select "a[href='https://github.com/we-promise/sure/releases']"
end
test "changelog with incomplete release notes" do
# Mock the GitHub provider to return incomplete data (missing some fields)
github_provider = mock
incomplete_data = {
avatar: nil,
username: "maybe-finance",
name: "Test Release",
published_at: nil,
body: nil
}
github_provider.expects(:fetch_latest_release_notes).returns(incomplete_data)
Provider::Registry.stubs(:get_provider).with(:github).returns(github_provider)
get changelog_path
assert_response :ok
assert_select "h2", text: "Test Release"
# Should not crash even with nil values
end
end