Skip to content

Fix frontend highlighter crash when issue ID is missing#1415

Open
SteveJonesDev wants to merge 1 commit intodevelopfrom
codex/fix-showissue-missing-id-crash
Open

Fix frontend highlighter crash when issue ID is missing#1415
SteveJonesDev wants to merge 1 commit intodevelopfrom
codex/fix-showissue-missing-id-crash

Conversation

@SteveJonesDev
Copy link
Copy Markdown
Member

@SteveJonesDev SteveJonesDev commented Feb 14, 2026

Summary

  • guard showIssue so it exits gracefully when this.issues is uninitialized
  • guard showIssue when an issue id is not found instead of dereferencing undefined
  • add Jest coverage for both missing-data paths in showIssue

Root cause

showIssue assumed the issue list was always initialized and that every requested id existed. In those edge cases it attempted to read issue.tooltip and issue.element from undefined, causing a runtime crash.

Evidence type

  • test: added regression coverage in tests/jest/frontendHighlighterApp/showIssue.test.js and confirmed full Jest + PHP test suites pass

Risk assessment

  • low risk: change is localized to showIssue fallback handling and does not alter the happy path for valid issues

Environment limitations

  • npm ci --ignore-scripts still reports an npm internal error (Exit handler never called) in this runner, but lint and test commands executed successfully with the current dependency state

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced error handling for accessibility issue detection to gracefully manage cases where issues are not found or unavailable on the page.
  • Tests

    • Added comprehensive test coverage for edge cases in issue detection and handling.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @SteveJonesDev, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the stability of the frontend highlighter by addressing potential runtime crashes. It introduces defensive programming within the showIssue method to ensure graceful handling when the issue list is not initialized or when a specific issue ID cannot be located, thereby improving the user experience by preventing unexpected application failures.

Highlights

  • Error Handling: Implemented robust error handling in showIssue to prevent crashes when the issues array is uninitialized.
  • Missing Issue ID: Added a check in showIssue to gracefully handle cases where a requested issue ID is not found, preventing dereferencing undefined.
  • Test Coverage: Introduced new Jest tests to ensure comprehensive coverage for the showIssue method's new error handling paths.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/frontendHighlighterApp/index.js
    • Added checks to showIssue to handle cases where this.issues is not an array, setting currentButtonIndex to -1 and currentIssueStatus to a 'not found' message.
    • Implemented a check within showIssue to verify if a specific issue id exists in this.issues before attempting to access its properties, preventing undefined dereferencing.
    • Refactored showIssue from an arrow function property to a standard class method.
    • Exported the AccessibilityCheckerHighlight class for better modularity and testability.
  • tests/jest/frontendHighlighterApp/showIssue.test.js
    • Created a new Jest test file specifically for AccessibilityCheckerHighlight.showIssue.
    • Added a test case to confirm showIssue does not throw an error when this.issues is null or uninitialized, and correctly updates status.
    • Included a test case to verify showIssue handles scenarios where the requested issue id is not found in an empty issues array, updating status appropriately.
Activity
  • Regression coverage was added in tests/jest/frontendHighlighterApp/showIssue.test.js.
  • Full Jest and PHP test suites were confirmed to pass.
  • Noted an npm internal error during npm ci --ignore-scripts in the runner, but lint and test commands executed successfully.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 14, 2026

Walkthrough

The showIssue method was refactored from an arrow function to a standard class method with added defensive guard clauses. When issues are not initialized or an issue cannot be found, the method now explicitly sets error state and returns early. A corresponding test suite was added to verify this error-handling behavior.

Changes

Cohort / File(s) Summary
Method refactoring with error handling
src/frontendHighlighterApp/index.js
Converted showIssue from an arrow function to a standard class method, added guard clauses to handle missing issues array or unfound issue IDs with early returns and explicit status messaging, and added explicit module export for AccessibilityCheckerHighlight.
Test suite for error handling
tests/jest/frontendHighlighterApp/showIssue.test.js
New Jest test file with mocked dependencies covering two scenarios: uninitialized issues (null) and empty issues array, verifying correct state assignments and descriptionOpen calls in both cases.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • pattonwebz

Poem

🐰 A method once swift as an arrow now stands tall,
With guards that catch errors before they fall.
When issues hide or vanish away,
Our fuzzy friend handles it with grace each day! ✨

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix frontend highlighter crash when issue ID is missing' directly and clearly summarizes the main change: adding guards in showIssue to handle missing issue IDs and prevent crashes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into develop

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-showissue-missing-id-crash

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

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively addresses the reported crash in showIssue by adding guards for uninitialized issues and for missing issue IDs. The accompanying tests are a good addition. However, the fix introduces a new critical bug: descriptionOpen is now called in code paths where it will crash because it doesn't expect this.issues to be uninitialized. The new tests unfortunately hide this problem by mocking descriptionOpen. I've provided details in a comment. Additionally, I've suggested a small performance improvement for showIssue.

if ( ! Array.isArray( this.issues ) ) {
this.currentButtonIndex = -1;
this.currentIssueStatus = __( 'The element was not found on the page.', 'accessibility-checker' );
this.descriptionOpen( id );
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.

critical

This call to this.descriptionOpen(id) will cause a crash. Inside descriptionOpen (line 762), this.issues.find(...) is called without checking if this.issues is an array. Since in this code block this.issues is not an array, it will lead to a TypeError. The test for this case in showIssue.test.js mocks descriptionOpen, which is why this crash is not caught by tests.

Furthermore, even if this.issues is an array but the id is not found (the case on line 552), descriptionOpen currently does nothing, so the currentIssueStatus message you set is never displayed to the user.

descriptionOpen needs to be refactored to handle these cases: it should not crash if this.issues is not an array, and it should display a message (like currentIssueStatus) when an issue is not found.

Comment on lines 548 to +554
const issue = this.issues.find( ( i ) => i.id === id );
this.currentButtonIndex = this.issues.findIndex( ( i ) => i.id === id );
if ( ! issue ) {
this.currentIssueStatus = __( 'The element was not found on the page.', 'accessibility-checker' );
this.descriptionOpen( id );
return;
}
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.

medium

This block can be made more efficient by using only findIndex and avoiding iterating over the issues array twice (once with find and once with findIndex).

Suggested change
const issue = this.issues.find( ( i ) => i.id === id );
this.currentButtonIndex = this.issues.findIndex( ( i ) => i.id === id );
if ( ! issue ) {
this.currentIssueStatus = __( 'The element was not found on the page.', 'accessibility-checker' );
this.descriptionOpen( id );
return;
}
this.currentButtonIndex = this.issues.findIndex( ( i ) => i.id === id );
if ( -1 === this.currentButtonIndex ) {
this.currentIssueStatus = __( 'The element was not found on the page.', 'accessibility-checker' );
this.descriptionOpen( id );
return;
}
const issue = this.issues[ this.currentButtonIndex ];

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2e065e94bb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if ( ! Array.isArray( this.issues ) ) {
this.currentButtonIndex = -1;
this.currentIssueStatus = __( 'The element was not found on the page.', 'accessibility-checker' );
this.descriptionOpen( id );
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Skip descriptionOpen when issues array is missing

In the new !Array.isArray(this.issues) guard, showIssue still calls descriptionOpen(id) before returning, but descriptionOpen immediately does this.issues.find(...) (same file), so this path still throws a TypeError when issues is null/undefined and the highlighter crashes in the exact scenario this patch is meant to fix. The added Jest test masks this by mocking descriptionOpen, so the runtime crash is not covered.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@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.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/frontendHighlighterApp/index.js`:
- Around line 541-546: The guard detects uninitialized this.issues but still
calls descriptionOpen(id), which will call this.issues.find() and throw; either
stop calling descriptionOpen when this.issues is not an array (i.e., remove the
descriptionOpen(id) call in the if block that sets
currentButtonIndex/currentIssueStatus) or add an early-return guard inside
descriptionOpen(dataId) that checks if Array.isArray(this.issues) and returns
immediately if not; update the code around currentButtonIndex/currentIssueStatus
and descriptionOpen to use one of these fixes to avoid the TypeError.

In `@tests/jest/frontendHighlighterApp/showIssue.test.js`:
- Around line 48-64: The test reveals a latent crash because descriptionOpen
assumes this.issues is an array; add a null/array guard inside descriptionOpen
(the method named descriptionOpen should check if Array.isArray(this.issues)
before calling this.issues.find()) and return or handle the "not found" case
safely when issues is null/undefined; alternatively, remove the call to
descriptionOpen from the null-issues branch inside showIssue, but the preferred
fix is to harden descriptionOpen by validating this.issues before using .find().
🧹 Nitpick comments (1)
src/frontendHighlighterApp/index.js (1)

550-554: Guard prevents crash, but error message won't display.

This guard correctly prevents accessing issue.tooltip and issue.element when the issue isn't found. However, descriptionOpen only renders content when matchingObj is truthy (line 764), so the currentIssueStatus message won't actually be shown to users.

This is a minor UX gap—the crash is prevented, but users won't see feedback. Consider logging to console or showing the panel with just the status message.

Comment on lines +541 to +546
if ( ! Array.isArray( this.issues ) ) {
this.currentButtonIndex = -1;
this.currentIssueStatus = __( 'The element was not found on the page.', 'accessibility-checker' );
this.descriptionOpen( id );
return;
}
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.

⚠️ Potential issue | 🔴 Critical

Calling descriptionOpen when this.issues is null will crash.

The guard correctly detects uninitialized issues, but then calls descriptionOpen(id) which attempts to call this.issues.find() at line 762. This will throw TypeError: Cannot read property 'find' of null, defeating the graceful error handling intent.

🐛 Proposed fix: Skip descriptionOpen when issues aren't initialized
 if ( ! Array.isArray( this.issues ) ) {
   this.currentButtonIndex = -1;
   this.currentIssueStatus = __( 'The element was not found on the page.', 'accessibility-checker' );
-  this.descriptionOpen( id );
   return;
 }

Alternatively, add a guard at the start of descriptionOpen:

descriptionOpen( dataId ) {
  if ( ! Array.isArray( this.issues ) ) {
    return;
  }
  // ... rest of method
}

Based on learnings: "Gracefully handle JavaScript errors to avoid breaking accessibility features"

🤖 Prompt for AI Agents
In `@src/frontendHighlighterApp/index.js` around lines 541 - 546, The guard
detects uninitialized this.issues but still calls descriptionOpen(id), which
will call this.issues.find() and throw; either stop calling descriptionOpen when
this.issues is not an array (i.e., remove the descriptionOpen(id) call in the if
block that sets currentButtonIndex/currentIssueStatus) or add an early-return
guard inside descriptionOpen(dataId) that checks if Array.isArray(this.issues)
and returns immediately if not; update the code around
currentButtonIndex/currentIssueStatus and descriptionOpen to use one of these
fixes to avoid the TypeError.

Comment on lines +48 to +64
it( 'does not throw when issues are not initialized', () => {
const subject = {
removeSelectedClasses: jest.fn(),
descriptionOpen: jest.fn(),
issues: null,
currentButtonIndex: null,
currentIssueStatus: null,
};

expect( () => {
AccessibilityCheckerHighlight.prototype.showIssue.call( subject, 'missing' );
} ).not.toThrow();

expect( subject.currentButtonIndex ).toBe( -1 );
expect( subject.currentIssueStatus ).toBe( 'The element was not found on the page.' );
expect( subject.descriptionOpen ).toHaveBeenCalledWith( 'missing' );
} );
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find the main implementation file that contains descriptionOpen and showIssue
fd -type f -name "*.js" | grep -E "(index|showIssue)" | head -20

Repository: equalizedigital/accessibility-checker

Length of output: 251


🏁 Script executed:

# Search for the descriptionOpen method definition
rg -A 10 "descriptionOpen\s*[:=]|descriptionOpen\s*\(" --type js | head -50

Repository: equalizedigital/accessibility-checker

Length of output: 3378


🏁 Script executed:

# Search for the showIssue method implementation
rg -A 20 "showIssue\s*[:=]|showIssue\s*\(" --type js | head -80

Repository: equalizedigital/accessibility-checker

Length of output: 5320


🏁 Script executed:

# Check for null/undefined guards in descriptionOpen
rg -B 5 -A 15 "descriptionOpen.*\{" --type js | grep -A 15 "this.issues"

Repository: equalizedigital/accessibility-checker

Length of output: 1112


Test masks a latent crash in descriptionOpen when this.issues is null.

The showIssue method correctly guards against null issues with if ( ! Array.isArray( this.issues ) ) before calling descriptionOpen. However, the real descriptionOpen implementation calls this.issues.find() without checking if this.issues is null first. Because the test mocks descriptionOpen, it never executes the crashing code, making the test pass while masking a real production bug.

Fix by either:

  1. Adding a null guard in descriptionOpen before accessing this.issues.find(), or
  2. Not calling descriptionOpen in the null-issues path within showIssue
🤖 Prompt for AI Agents
In `@tests/jest/frontendHighlighterApp/showIssue.test.js` around lines 48 - 64,
The test reveals a latent crash because descriptionOpen assumes this.issues is
an array; add a null/array guard inside descriptionOpen (the method named
descriptionOpen should check if Array.isArray(this.issues) before calling
this.issues.find()) and return or handle the "not found" case safely when issues
is null/undefined; alternatively, remove the call to descriptionOpen from the
null-issues branch inside showIssue, but the preferred fix is to harden
descriptionOpen by validating this.issues before using .find().

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant