Skip to content

Migrate epub viewer search tests to Vue Testing Library#14321

Merged
rtibbles merged 6 commits intolearningequality:developfrom
sahibsiddiqui:migrate-epub-tests-vtl
Mar 9, 2026
Merged

Migrate epub viewer search tests to Vue Testing Library#14321
rtibbles merged 6 commits intolearningequality:developfrom
sahibsiddiqui:migrate-epub-tests-vtl

Conversation

@sahibsiddiqui
Copy link
Copy Markdown
Contributor

Summary

This PR migrates the epub viewer search unit tests from @vue/test-utils to @testing-library/vue.

The following files were updated:

  • SearchButton.spec.js
  • SearchSideBar.spec.js

Changes include:

  • Removed @vue/test-utils usage
  • Rewrote tests to follow Testing Library principles
  • Updated queries to prioritize user-facing interactions (e.g., getByRole)
  • Removed direct access to component internals (wrapper, vm, etc.)

Manual verification

  • Ran pnpm run test-jest -- --testPathPattern epub_viewer
  • Confirmed all epub_viewer tests pass locally

References

Closes #14187

Reviewer guidance

  • Reviewers can verify by running: pnpm run test-jest -- --testPathPattern epub_viewer
  • Only two files were modified, no other files were changed.

@github-actions github-actions Bot added DEV: renderers HTML5 apps, videos, exercises, etc. DEV: frontend SIZE: small labels Mar 3, 2026
@learning-equality-bot
Copy link
Copy Markdown

👋 Thanks for contributing!

We will assign a reviewer within the next two weeks. In the meantime, please ensure that:

  • You ran pre-commit locally
  • All issue requirements are satisfied
  • The contribution is aligned with our Contributing guidelines. Pay extra attention to Using generative AI. Pull requests that don't follow the guidelines will be closed.

We'll be in touch! 😊

@rtibbles rtibbles requested a review from rtibblesbot March 3, 2026 20:54
@rtibbles
Copy link
Copy Markdown
Member

rtibbles commented Mar 3, 2026

Requesting rtibblesbot review for first pass, we will do a full review when it is satisfied!

Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

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

Clean migration of epub viewer search tests to Vue Testing Library. CI passing (admin checks only — no build/test CI ran).

  • blocking: Focus test in SearchSideBar no longer tests the component's focusOnInput() method (see inline comment)
  • praise: Good use of getByRole queries in both files

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Reviewed the pull request diff checking for:

  • Correctness: bugs, edge cases, undocumented behavior, resource leaks, hardcoded values
  • Design: unnecessary complexity, naming, readability, comment accuracy, redundant state
  • Architecture: duplicated concerns, minimal interfaces, composition over inheritance
  • Testing: behavior-based assertions, mocks only at hard boundaries, accurate coverage
  • Completeness: missing dependencies, unupdated usages, i18n, accessibility, security
  • Principles: DRY (same reason to change), SRP, Rule of Three (no premature abstraction)
  • Checked CI status and linked issue acceptance criteria
  • For UI changes: inspected screenshots for layout, visual completeness, and consistency


const input = screen.getByRole('searchbox');

input.focus();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

blocking: This test no longer verifies the component's focusOnInput() public method — it just calls input.focus() directly on the DOM element, which tests native browser behavior rather than component behavior.

The original test called wrapper.vm.focusOnInput(), which verified that the component's ref wiring (this.$refs.searchInput.focus() at line 181 of SearchSideBar.vue) works correctly. The new test bypasses that entirely.

Vue Testing Library's render returns the component instance on the container property's parent. One option that preserves the behavioral test while staying within VTL patterns:

it('should allow parent to focus on input box', async () => {
  const { container } = renderComponent();
  const vm = container.__vue_app__ ? ... // Vue 3
  // For Vue 2 with VTL, you can access the instance via:
  // const wrapper = renderComponent();
  // wrapper.vm is not exposed by VTL by design.

Since VTL intentionally discourages vm access, consider testing this indirectly — e.g., by simulating what a parent component would do. Alternatively, if the team accepts that focusOnInput is an internal detail not worth testing through VTL, the test description should at minimum be updated to reflect what it actually tests (e.g., "search input should be focusable") rather than implying it tests the parent-facing API.

it('should render', () => {
render(SearchButton);

const button = screen.getByRole('button');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

praise: Good use of getByRole('button') — queries by accessible role rather than CSS selectors, which is exactly what Testing Library encourages.

Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

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

Clean migration overall, but the focus test finding from the prior review remains unaddressed.

CI passing.

  • blocking: Focus test still bypasses the component's focusOnInput() public method (see inline comment)
  • nitpick: Missing newline at end of SearchSideBar.spec.js

1 prior finding(s) resolved (praise on getByRole usage).


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria


const input = screen.getByRole('searchbox');

input.focus();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

blocking (UNADDRESSED): This still calls input.focus() directly on the DOM element rather than testing the component's focusOnInput() method (line 180 of SearchSideBar.vue, marked @public). The test now only proves that a native <input> can receive focus, which is a browser default.

Since VTL discourages vm access, the pragmatic options are:

  1. Rename the test to "search input should be focusable" so it describes what it actually tests, accepting that focusOnInput() is no longer unit-tested.
  2. Use a thin wrapper parent component in the test that calls the child's focusOnInput() via a template ref, verifying the public API as a parent would.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Apologies for the duplicate review here!

I do agree though that we still need to test the component method, not the trivial assertion that an input, once focused, has focus.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

thanks for the review!
i understand the issue that the current test focuses the input directly instead of verifying the component’s 'focusOnInput()' method.
so i’ll update the test acc, and will push a fix shortly.

@sahibsiddiqui
Copy link
Copy Markdown
Contributor Author

@rtibbles i've updated the test to verify the component's focusOnInput() behavior using a parent wrapper component. please let me know if further adjustments are needed.

Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

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

Clean migration to Vue Testing Library. The focus test now properly verifies focusOnInput() through a parent wrapper component.

CI passing.

  • nitpick: Commented-out renderComponent() on line 23 of SearchSideBar.spec.js (see inline)
  • praise: Parent wrapper pattern for testing focusOnInput() (see inline)

2 prior finding(s) resolved.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

const elementThatIsFocused = document.activeElement;
expect(elementThatIsFocused).toHaveClass('search-input');
it('should allow parent to focus on input box', async () => {
// renderComponent();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nitpick: Remove the commented-out // renderComponent(); — it's leftover from development and not needed since the parent wrapper handles rendering.

const sidebarRef = ref(null);

function focusInput() {
sidebarRef.value.focusOnInput();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

praise: Nice use of a parent wrapper to test focusOnInput() through its intended public API — this verifies the real parent-child interaction rather than reaching into component internals.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, this is a very nice way of asserting the overall behaviour!

@sahibsiddiqui
Copy link
Copy Markdown
Contributor Author

yeah, even the cleanup's done

Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

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

Clean migration of epub viewer search tests to Vue Testing Library. All prior findings resolved.

CI passing.

3 prior finding(s) resolved.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

expect(wrapper.emitted().click).toBeTruthy();

it('should emit an event when the button is clicked', async() => {
const { emitted } = render(SearchButton);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

praise: Clean use of emitted() destructuring from the render return — keeps the assertion on line 18 concise and readable.

Copy link
Copy Markdown
Member

@rtibbles rtibbles left a comment

Choose a reason for hiding this comment

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

Looks good, should be good to merge assuming the tests pass.

const sidebarRef = ref(null);

function focusInput() {
sidebarRef.value.focusOnInput();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, this is a very nice way of asserting the overall behaviour!

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 5, 2026

@rtibbles
Copy link
Copy Markdown
Member

rtibbles commented Mar 6, 2026

Linting failures still present:

[ERROR: Kolibri Format] Linting errors for kolibri/plugins/epub_viewer/frontend/views/tests/SearchSideBar.spec.js

/home/runner/work/kolibri/kolibri/kolibri/plugins/epub_viewer/frontend/views/tests/SearchSideBar.spec.js
34:18 error 'sidebarRef' of property returned from setup() found, but never used vue/no-unused-properties
34:30 error 'focusInput' of property returned from setup() found, but never used vue/no-unused-properties

@rtibbles rtibbles merged commit ea134e2 into learningequality:develop Mar 9, 2026
51 checks passed
marcellamaki pushed a commit to marcellamaki/kolibri that referenced this pull request Mar 11, 2026
…lity#14321)

* Migrate epub viewer search tests to Vue Testing Library

* fixed SearchSideBar focus test to verify focusOnInput method

* removed leftover comment renderComponent & added a newline at the end as well

* [pre-commit.ci lite] apply automatic fixes

* fixes lint errors and updated focus assertion

* fixing lint errors in SearchSideBar.spec test wrapper

---------

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DEV: frontend DEV: renderers HTML5 apps, videos, exercises, etc. SIZE: small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Convert epub viewer search unit tests to Vue Testing Library

3 participants