Skip to content

Fix missing task groups and duplicate click listener in All Tasks view#959

Open
Ridanshi wants to merge 1 commit into
Charushi06:mainfrom
Ridanshi:fix/task-group-rendering
Open

Fix missing task groups and duplicate click listener in All Tasks view#959
Ridanshi wants to merge 1 commit into
Charushi06:mainfrom
Ridanshi:fix/task-group-rendering

Conversation

@Ridanshi
Copy link
Copy Markdown

Closes #353

Root cause analysis

Three independent bugs in js/app.js combined to break the All Tasks view:

Bug 1 — ASI trap in renderTasks (missing task groups)

The innerHTML assignment for the all-tasks / archived branch ended line 725 with a bare ) and placed the + operator at the start of line 726:

// Before — ASI-unsafe:
tasksSection.innerHTML = actionBar +
    renderGroup('⚠ Due soon', dueSoon, ...)
    + renderGroup('This week', thisWeek, ...) +
    renderGroup('Completed', completed, ...) +
    emptyState;

Because the statement up to and including the first renderGroup(...) call is a syntactically complete ExpressionStatement, JavaScript's Automatic Semicolon Insertion can insert a semicolon after that line. The This week and Completed groups are then evaluated as a separate, discarded expression — they are never appended to innerHTML.

Fix: move every + to the end of its line so the continuation is always unambiguous:

// After — explicit continuation:
tasksSection.innerHTML =
    actionBar +
    renderGroup('⚠ Due soon', dueSoon, ...) +
    renderGroup('This week',   thisWeek, ...) +
    renderGroup('Completed',   completed, ...) +
    emptyState;

Bug 2 — Duplicate const calendarDownloadBtn declaration (SyntaxError)

calendarDownloadBtn was declared with const at module scope on both line 89 and line 1384. Duplicate const bindings in the same scope are a SyntaxError in ES modules (which are always strict mode). This prevents the entire module from parsing, making the app completely non-functional in modern environments.

Fix: remove the redundant declaration at line 1384. The if (calendarDownloadBtn) guard on line 1386 continues to use the binding from line 89.

Bug 3 — Duplicate addItemsBtn click listener risk

The addItemsBtn click handler was registered inside the DOMContentLoaded callback while all similar paste-workflow handlers (extractBtn, clearBtn, pasteInput) are registered at module scope. This inconsistency created the risk that the handler could be registered from both execution contexts.

Fix: move the handler outside DOMContentLoaded (consistent with the other paste-workflow listeners) and switch from addEventListener to an onclick property assignment. An onclick assignment guarantees only one handler fires per click regardless of how many times the registration code is reached.

Files modified

  • js/app.js — three targeted changes as described above
  • tests/taskRendering.test.js (new) — 19 tests

Tests added (tests/taskRendering.test.js)

Tests use Node's built-in node:test runner (same runner as the existing ICS / CSV test suites). Pure functions are tested without DOM dependencies.

Coverage:

  • Task classification: due-soon (≤ 3 days), this-week (> 3 days), completed (status Done), empty list, mixed buckets
  • renderGroup: empty array → '', non-empty → correct HTML structure, per-task card count
  • Full rendering: all three groups present when each bucket is non-empty; only populated groups appear; empty-state when all buckets empty
  • Archived view: same classification applies, prefixed group headings rendered
  • Event handler: single insertion per invocation; double invocation skipped after clearExtracted; regression documenting double-insertion when guard is absent
  • onclick semantics: second assignment overwrites first, single handler fires per click
  • Regression: explicit + pattern vs. ASI-truncated pattern; task counts per bucket

Test results

node --test tests/taskRendering.test.js
# tests 19  pass 19  fail 0

node --test tests/exportIcs.test.js
# tests 5   pass 5   fail 0

Three independent bugs were causing the All Tasks view to be broken:

1. Automatic Semicolon Insertion trap in renderTasks: the innerHTML
   assignment for the all-tasks / archived view ended line 725 with
   a bare `)` and placed the `+` operator at the start of line 726.
   JavaScript's ASI rules can insert a semicolon after the first
   renderGroup call, discarding the concatenation of the This week
   and Completed groups. Fixed by moving every `+` to the end of its
   line so the statement continuation is unambiguous.

2. Duplicate `const calendarDownloadBtn` declaration: the variable
   was declared at module scope on both line 89 and line 1384.
   Duplicate `const` at the same scope is a SyntaxError in ES modules
   (which are always strict), preventing the entire module from
   parsing. The redundant declaration at line 1384 is removed; the
   `if (calendarDownloadBtn)` guard at line 1386 continues to use
   the binding from line 89.

3. addItemsBtn duplicate listener risk: the click handler was
   registered inside the DOMContentLoaded callback while all similar
   paste-workflow handlers (extractBtn, clearBtn, etc.) live at
   module scope. Moving it outside DOMContentLoaded and switching to
   an `onclick` property assignment (rather than addEventListener)
   guarantees only one handler can fire per click even if the
   registration path is accidentally executed more than once.

Adds tests/taskRendering.test.js with 19 tests covering task
classification, renderGroup HTML output, all-three-groups rendering,
archived view, event-handler insertion counts, onclick single-handler
semantics, and regression cases for both the ASI and duplicate-
insertion bugs. All 19 new tests and 5 existing ICS tests pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: "This week" and "Completed" task groups do not render in All Tasks view

1 participant