Remove dead code and tests that cannot fail #605
Labels
No labels
bug
duplicate
enhancement
help wanted
high priority
invalid
L
low priority
M
medium priority
needs refinement
optional
question
S
security
technical improvement
UX Improvement
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
local-it/mitgliederverwaltung#605
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Motivation
#598 traced two flaky tests to code nobody used and to assertions that could not fail: the member
:searchread action had no production caller, and the HasPermission log tests passed throughlog == ""because the message was never captured. A read-only sweep of the codebase found more ofboth kinds. Dead code costs maintenance and misleads readers. Tests that cannot fail give false
confidence and, like in #598, can turn into flakes.
Sweep method and full tables: see "Evidence" below. Line numbers are from
mainataffbefe6;re-check them when starting the work.
Findings
1. Production code without a caller (high confidence)
CustomFieldValue :by_custom_field_id(lib/mv/membership/custom_field_value.ex:68): no caller in lib, priv or test.CustomField :prepare_deletionand interfaceprepare_custom_field_deletion(lib/mv/membership/custom_field.ex:103,membership.ex:67): used only bycustom_field_deletion_test.exs. Remove them, or wire them into the delete confirmation if that was the intent.overview_members(membership.ex:50): never called; production usesAsh.Query.for_read(:overview). Remove thedefine; the action stays.Mv.Accounts.Userhas noconfirmationadd-on, so these are unreachable:SendNewUserConfirmationEmail(lib/mv/accounts/user/senders/send_new_user_confirmation_email.ex)confirm_route Mv.Accounts.User, :confirm_new_user(lib/mv_web/router.ex:133-137){:confirm_new_user, :confirm}andCannotConfirmUnconfirmedUserbranches inauth_controller.ex(:41,:196)CODE_GUIDELINES.mdanddocs/smtp-configuration-concept.mdMvWeb.MemberLive.Index.FieldSelection:save_to_session/2,get_from_cookie/1andsave_to_cookie/2are used only by tests.get_from_session/1is called inmount, but nothing writes the"member_field_selection"session key, so it always returns%{}. Check the intent, then remove the unused functions, their tests and the dead session read.Mv.Vereinfacht.Client.get_contact/1: no caller, no test.MvWeb.RoleLive.Helpers.permission_set_badge_class/1(marked deprecated): no caller, no test.MvWeb.CoreComponents.translate_errors/2(generator boilerplate): no caller.Mv.Constants.vereinfacht_required_field?/1: no caller, no test.Statistics.open_amount_total/1: used only by tests.CalendarCycles.current_cycle?/2andlast_completed_cycle?/2,3: unused or only called internally (medium; make private or remove).update_member_field_visibility/2andupdate_single_member_field_visibility/2next to code interfaces with the same names: both used only by tests (medium; settle together with decision 1).1b. Front-end and translations (high confidence unless noted)
assets/js/app.js:671-678: listener forphx:set-input-value. The lastpush_eventfor it was removed ineb81d5f7.Layouts.appattr:current_scope: never passed and never read.table :row_value_id,button :active,dropdown_menu :menu_class. Remove them, or keep them and document them as API.priv/gettext/errors.pot(+de/enerrors.po): 4 stale entries.user.ex:499now says "'sub', 'uid', or 'id'"), so the German translation is never applied. This is a user-visible bug: fix the catalog entry.056fd04d,17540c6b,fb59ef99). Remove them.default.po: 23 (de) / 30 (en) obsolete#~entries, becausejust gettextmerges with--on-obsolete=mark_as_obsolete(medium). Purge them once, and decide whether the recipe should keep marking or should delete.2. Tests that cannot fail (high confidence)
Every page that uses
Layouts.apprendersid="flash-group"andid="client-error", sohtml =~ "error"andhas_element?(view, "#flash-group")are always true. Substrings such as"0","2","name","new","create"always occur in rendered HTML.test/mv_web/live/member_live/form_error_handling_test.exs: all 5 tests. Assert the specific flash or field error text.test/mv_web/live/group_live/form_test.exs(7 assertions),group_live/index_test.exs(4),group_live/integration_test.exs:107,member_live/index_test.exs:621: OR chains over such substrings.test/mv_web/live/global_settings_live_test.exs:139: "shows warning when SMTP is not configured" does not test the warning (its own comment says so).match?({:ok, _}) or match?({:error, _})):test/mv/membership/import/member_csv_test.exs:39, 76(stricter siblings exist, delete) andtest/mv/helpers/system_actor_test.exs:236(force the failure path or delete).sort_header_component_test.exs:277,group_live/show_add_member_test.exs:282,group_live/show_authorization_test.exs:135,member_live/index_field_visibility_test.exs:257. Add the missing assertion (e.g.assert_patch) or delete.3. Weak tests (medium confidence)
is_list:group_policies_test.exs(4),membership_fee_type_policies_test.exs(4),membership_fee_cycle_policies_test.exs(3). A policy that filters out every record would still pass. Assert that the setup fixture is in the list.html =~ "badge" or …/html =~ "true" or …inmember_field_live/index_component_test.exs:45andmember_live/index_custom_fields_display_test.exs:228: scope the assertion to an element.role_live_test.exs:102, 235, 440.calendar_cycles_test.exs:82(onlyis_boolean, covered by the /3 tests) andcsv_parser_test.exs:209("module has @moduledoc").4. Unused test helpers (high confidence)
test/support/filter_builder_helpers.ex:apply_fee_type_filter/3,apply_boolean_filter/3,apply_payment_filter/2..6.test/support/conn_case.ex:conn_with_admin_user/1.test/support/fixtures.ex:password_user_with_role_fixture/1.Decisions needed
list_custom_field_values,update_custom_field_value,destroy_custom_field_value,update_custom_field,destroy_custom_field,list_member_groups,list_users,destroy_user,list_membership_fee_cycles. Used only by tests:destroy_member,create_custom_field_value,update_group,create_register_with_oidc, fee type/cycle create/update/destroy,update_role. Keep them as deliberate domain API, or adopt the rule "interfaces only for production callers"?Mv.MembershipFees.CycleGenerationJob: no caller and no tests; its moduledoc calls it a skeleton for future Oban use. Remove it, or turn it into a documented admin/release entry point?Possibly a separate issue
mix join_requests.cleanup_expiredis a Mix task. Mix tasks are not available in an OTP release, andMv.Releasehas no equivalent. Check how production deletes expired join requests. If nothing does, this is a functional gap, not dead code.Handed to other issues
These findings sit in code that a planned issue rewrites anyway. They are fixed there, not here. List them in the PR as "handled by #…".
FieldSelectioncookie/session functions → #549 (saved views), together with #213, #252, #415. Do not delete them before #549 decides how a view is stored.button :active→ #602.dropdown_menu :menu_class→ U8.table :row_value_id→ U9.Layouts.app :current_scope→ U6.phx:set-input-valuelistener → #554.global_settings_live_test.exs→ #540.CustomField :prepare_deletion→ U4/U9: use it for the delete dialog with member count, or delete it.CycleGenerationJob→ keep until the fee-automation milestone (89) is decided.mix join_requests.cleanup_expiredrelease entry point → #267.#~gettext entries and the merge recipe → the roadmap item "reduce gettext merge conflicts".This issue replaces #225 ("Clean tests").
Scope rule during implementation
The two sweeps below are the complete list for this issue;
/analyzeverifies and prioritizes, it does not search again. If more instances of the same class turn up in a file the work already touches, fix them here. Anything else goes to a follow-up note, not into this issue.Out of scope
:searchaction,fuzzy_search/2, and the HasPermission log tests.attr/slot, JS hooks, gettext msgids, migrations: not swept.Mv.Oidc.Discovery.put_cache/2,clear_cache/0andSystemActor.invalidate_cache/0: deliberate test seams, keep them.classify_smtp_error/1,normalize_base_url/1): turning them intodefpis optional cleanup, low value.sortable_table :row_item,input :multiple/:class/:error_class/:checked,:classontheme_swap/spinner).Acceptance criteria
sub/uid/idclaim is translated again. Tests that are rewritten assert something that fails when the behaviour breaks; check each one by breaking the behaviour once locally.just ci-devandjust typecheckgreen.Evidence
Two read-only sweeps, 2026-10-17, on
mainataffbefe6.Ash.Resource.Info; a caller grep per action and interface; a module and function inventory with a grep per name (dynamic callers excluded); an AST walk for tests without assertions; a grep for tautological assertion patterns; a usage grep fortest/supporthelpers.phx-hookusages (15/15 match); function components and theirattr/slotusage; gettext source references indefault.pot/errors.pot; a call graph from the compiled BEAM files plusmix xreffor same-name functions and modules without incoming edges (52 files, 49 referenced from Ash DSL, migrations, config or OTP entry points).Limits: the test suite was not run and nothing was mutation-tested, so "cannot fail" is derived from the rendered layout. The BEAM graph does not see
apply/3or MFA tuples; callers inpriv/configwere grep-checked.