Skip to content

test(widgets): add TextInput dirty state tests#736

Open
srushti-panara wants to merge 1 commit into
Karanjot786:mainfrom
srushti-panara:test/textinput-dirty-state
Open

test(widgets): add TextInput dirty state tests#736
srushti-panara wants to merge 1 commit into
Karanjot786:mainfrom
srushti-panara:test/textinput-dirty-state

Conversation

@srushti-panara
Copy link
Copy Markdown
Contributor

@srushti-panara srushti-panara commented Jun 4, 2026

Description

Adds regression tests for TextInput dirty-state propagation.


The new test suite verifies that all state-mutating methods correctly mark the widget as dirty after updating internal state. This helps prevent future regressions of the TextInput rendering bug fixed in #675.

Related Issue

Closes #686

Which package(s)?

@termuijs/widgets

Type of Change

  • 🐛 Bug fix (type:bug)
  • ✨ Feature (type:feature)
  • 📝 Docs (type:docs)
  • 🧪 Tests (type:testing)
  • ♻️ Refactor (type:refactor)
  • 🎨 Design / UX (type:design)
  • ♿ Accessibility (type:accessibility)
  • ⚡ Performance (type:performance)
  • 🔧 DevOps / CI (type:devops)
  • 🔒 Security (type:security)

Checklist

  • ⭐ You starred the repo. The needs-star check blocks your merge otherwise.
  • Tests pass locally: bun vitest run
  • Build passes: bun run build
  • Typecheck passes: bun run typecheck
  • You read CONTRIBUTING.md.
  • Your PR title follows type: short description.
  • Widget state mutators call markDirty() (if your change affects rendering).
  • No new any types without an inline comment explaining why.
  • No unrelated refactors bundled into this PR.

GSSoC 2026 Participation

  • You are a GSSoC 2026 contributor.
  • Your GSSoC profile: https://gssoc.girlscript.org/profile/a80c7e63-fb5a-4d58-aec9-115f9a2798b7

Screenshots / Recordings (UI changes)

N/A

Notes for the Reviewer

This PR adds regression tests for TextInput dirty-state propagation.

The test suite covers:

  • value setter
  • insertChar()
  • deleteBack()
  • deleteForward()
  • clear()
  • cursor movement methods

These tests provide regression coverage for the TextInput dirty-state behavior introduced in the fix for issue #675 and help prevent similar rendering issues from being reintroduced in future changes.

Validation completed:

  • bun vitest run packages/widgets/src/input/TextInput.test.ts
  • bun run build

Note: repository-wide bun run typecheck currently reports failures in the recently added examples/markdown-editor package that are unrelated to this PR.

Summary by CodeRabbit

  • Tests
    • Added comprehensive test coverage for the TextInput component to verify state management behavior across various user interactions and operations.

@github-actions github-actions Bot added the type:testing +10 pts. Tests. label Jun 4, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 4, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

A new Vitest test suite for TextInput verifies that the isDirty flag is set to true after text mutations (insertChar, deleteBack, deleteForward, clear, value setter) and cursor movement operations (moveCursorLeft, moveCursorRight, moveCursorHome, moveCursorEnd).

Changes

TextInput dirty-state verification

Layer / File(s) Summary
TextInput mutation and cursor tracking tests
packages/widgets/src/input/TextInput.test.ts
Comprehensive test suite with individual test cases verifying that isDirty is set to true after each state-mutating method and cursor movement, with clearDirty() called before each assertion to reset dirty state.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

  • #675: The new tests explicitly target the same TextInput mutation methods (insertChar, deleteBack, deleteForward, clear, cursor moves) to assert the dirty flag changes, providing regression coverage for the missing markDirty() bug.
  • #686: This PR directly implements the acceptance criteria from this issue to add TextInput test coverage for dirty-state propagation across all state-mutating methods.

Possibly related PRs

  • Karanjot786/TermUI#677: The main PR adds markDirty() calls to TextInput state-mutating methods, and this test PR validates those changes by asserting isDirty is true after each mutation.

Suggested labels

gssoc:approved, quality:clean, area:widgets, type:testing, level:beginner

Suggested reviewers

  • Karanjot786

Poem

🐰 A TextInput so spry, now wears tests so dry,
Dirty flags flip high with each keystroke nigh,
insertChar! deleteBack! moveCursor with ease,
Every mutation traced—regressions appease! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'test(widgets): add TextInput dirty state tests' clearly and concisely summarizes the primary change: adding test coverage for TextInput dirty state behavior.
Description check ✅ Passed The PR description follows the template with complete sections including description, related issue (#686), package identification, type of change (tests), completed checklist items, and detailed notes for reviewers.
Linked Issues check ✅ Passed All acceptance criteria from issue #686 are met: insertChar(), deleteBack(), deleteForward(), clear(), cursor movement methods, and value setter are all tested; tests pass locally; regression coverage for #675 is provided.
Out of Scope Changes check ✅ Passed The PR contains only test-only additions for TextInput dirty state verification, with no unrelated changes or refactors outside the defined scope of issue #686.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the area:widgets @termuijs/widgets label Jun 4, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
packages/widgets/src/input/TextInput.test.ts (3)

14-45: ⚡ Quick win

Consider testing that no-op operations don't mark dirty.

The current tests verify that successful mutations mark the widget dirty. For more complete coverage, consider adding tests that verify no-op operations (where guards prevent mutation) don't unnecessarily mark dirty:

  • insertChar() when already at maxLength
  • deleteBack() when cursor is at position 0
  • deleteForward() when cursor is at end of value
📋 Example test for no-op edge cases
it('does not mark dirty when deleteBack is no-op', () => {
    const input = new TextInput();
    input.value = 'abc';
    input.moveCursorHome(); // cursor at position 0
    input.clearDirty();

    input.deleteBack(); // no-op

    expect(input.isDirty).toBe(false);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/widgets/src/input/TextInput.test.ts` around lines 14 - 45, Add tests
that assert no-op operations do not mark the widget dirty: for TextInput, add
cases where insertChar() is called when value length is already at maxLength,
deleteBack() is called when cursor is at position 0 (use moveCursorHome() to
position), and deleteForward() is called when cursor is at end (use
moveCursorEnd()); in each test call clearDirty() before invoking the no-op
action and assert input.isDirty is false afterwards. Use the existing test
patterns around TextInput, clearDirty, isDirty, insertChar, deleteBack,
deleteForward, moveCursorHome, moveCursorEnd, and maxLength to locate where to
add these assertions.

58-78: 💤 Low value

Consider splitting cursor movement tests into separate cases.

All four cursor movement methods are tested in a single test case. Splitting them into individual test cases would improve debuggability and make it clearer which specific method fails if a test breaks.

🔧 Optional refactor to separate test cases
-    it('marks dirty after cursor movement', () => {
+    it('marks dirty after moveCursorLeft()', () => {
         const input = new TextInput();
-
         input.value = 'abc';
 
         input.clearDirty();
         input.moveCursorLeft();
         expect(input.isDirty).toBe(true);
+    });
 
+    it('marks dirty after moveCursorRight()', () => {
+        const input = new TextInput();
+        input.value = 'abc';
+        input.moveCursorHome();
+
         input.clearDirty();
         input.moveCursorRight();
         expect(input.isDirty).toBe(true);
+    });
 
+    it('marks dirty after moveCursorHome()', () => {
+        const input = new TextInput();
+        input.value = 'abc';
+
         input.clearDirty();
         input.moveCursorHome();
         expect(input.isDirty).toBe(true);
+    });
 
+    it('marks dirty after moveCursorEnd()', () => {
+        const input = new TextInput();
+        input.value = 'abc';
+        input.moveCursorHome();
+
         input.clearDirty();
         input.moveCursorEnd();
         expect(input.isDirty).toBe(true);
     });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/widgets/src/input/TextInput.test.ts` around lines 58 - 78, Split the
single "marks dirty after cursor movement" test into four focused tests: one
each for moveCursorLeft, moveCursorRight, moveCursorHome, and moveCursorEnd. For
each new test, instantiate TextInput, set input.value = 'abc', call
input.clearDirty(), invoke the specific cursor method (moveCursorLeft /
moveCursorRight / moveCursorHome / moveCursorEnd), and assert
expect(input.isDirty).toBe(true); keep helper calls (clearDirty, value setup)
consistent across tests to keep them independent and debuggable.

1-79: TextInput.test.ts: No need for Screen when only asserting dirty-state; add Screen rendering tests only for output assertions

  • Current tests validate isDirty/markDirty behavior without new Screen, which matches existing widget unit tests (e.g., packages/widgets/src/data/markDirty.test.ts, packages/widgets/src/input/CommandPalette.test.ts, packages/widgets/src/layout/Stack.test.ts).
  • Add a separate test that constructs a real Screen, calls updateRect(), and render() if you need assertions about rendered characters/cursor positioning.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/widgets/src/input/TextInput.test.ts` around lines 1 - 79, The
current tests in TextInput.test.ts correctly assert isDirty/markDirty behavior
without creating a Screen; keep those unit tests as-is, and add a new test file
(or new test case) that constructs a real Screen, attaches the TextInput, calls
updateRect() and render() on the Screen, then asserts rendered output/cursor
positions—use Screen, Screen.updateRect(), Screen.render(), and TextInput
methods (value, moveCursor*, insertChar, deleteBack, deleteForward) for the
rendering-specific assertions so dirty-state tests remain isolated from
rendering concerns.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/widgets/src/input/TextInput.test.ts`:
- Around line 14-45: Add tests that assert no-op operations do not mark the
widget dirty: for TextInput, add cases where insertChar() is called when value
length is already at maxLength, deleteBack() is called when cursor is at
position 0 (use moveCursorHome() to position), and deleteForward() is called
when cursor is at end (use moveCursorEnd()); in each test call clearDirty()
before invoking the no-op action and assert input.isDirty is false afterwards.
Use the existing test patterns around TextInput, clearDirty, isDirty,
insertChar, deleteBack, deleteForward, moveCursorHome, moveCursorEnd, and
maxLength to locate where to add these assertions.
- Around line 58-78: Split the single "marks dirty after cursor movement" test
into four focused tests: one each for moveCursorLeft, moveCursorRight,
moveCursorHome, and moveCursorEnd. For each new test, instantiate TextInput, set
input.value = 'abc', call input.clearDirty(), invoke the specific cursor method
(moveCursorLeft / moveCursorRight / moveCursorHome / moveCursorEnd), and assert
expect(input.isDirty).toBe(true); keep helper calls (clearDirty, value setup)
consistent across tests to keep them independent and debuggable.
- Around line 1-79: The current tests in TextInput.test.ts correctly assert
isDirty/markDirty behavior without creating a Screen; keep those unit tests
as-is, and add a new test file (or new test case) that constructs a real Screen,
attaches the TextInput, calls updateRect() and render() on the Screen, then
asserts rendered output/cursor positions—use Screen, Screen.updateRect(),
Screen.render(), and TextInput methods (value, moveCursor*, insertChar,
deleteBack, deleteForward) for the rendering-specific assertions so dirty-state
tests remain isolated from rendering concerns.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: dfefbe6d-6384-4103-a841-33bc9f06fe89

📥 Commits

Reviewing files that changed from the base of the PR and between f90f75c and 36a7fc4.

📒 Files selected for processing (1)
  • packages/widgets/src/input/TextInput.test.ts

@srushti-panara
Copy link
Copy Markdown
Contributor Author

Thanks for the review.

I checked the failing CI job and the failure originates from packages/widgets/src/data/Meter.test.ts, which is unrelated to the changes in this PR. The only file modified here is packages/widgets/src/input/TextInput.test.ts.

Locally, the added TextInput tests pass successfully, and the failure appears to be caused by the current Meter implementation/test setup on the base branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:widgets @termuijs/widgets type:testing +10 pts. Tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test(widgets): add TextInput tests

1 participant