8000 [#272]: Assert no JS errors. by skipper-vp · Pull Request #405 · drevops/behat-steps · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

[#272]: Assert no JS errors. #405

New issue
8000

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

skipper-vp
Copy link
Contributor
@skipper-vp skipper-vp commented May 19, 2025

#272

Summary by CodeRabbit

  • New Features
    • Introduced enhanced JavaScript error tracking and verification in Behat tests, allowing detection and assertion of JavaScript errors on web pages.
  • Tests
    • Added new automated test scenarios to validate JavaScript error detection and assertions during test execution.
    • Included a test fixture with a button that triggers a JavaScript error to verify error detection.

Copy link
coderabbitai bot commented May 19, 2025

Walkthrough

A new PHP trait, JavascriptTrait, is introduced to provide Behat step definitions for tracking and asserting JavaScript errors in browser-based tests. The trait is incorporated into the Behat FeatureContext, and a new Behat feature file is added to test scenarios involving JavaScript error detection and assertions. Additionally, an HTML fixture with a JavaScript error trigger is added for testing purposes.

Changes

File(s) Change Summary
src/JavascriptTrait.php Added JavascriptTrait with methods for injecting JS error collectors, executing JS, and asserting JS errors.
tests/behat/bootstrap/FeatureContext.php Imported and applied JavascriptTrait to the FeatureContext class.
tests/behat/features/javascript.feature Added Behat feature file with scenarios to test JavaScript error detection and assertion steps.
tests/behat/fixtures/relative.html Added a button that triggers a JavaScript error when clicked to support error detection testing.

Sequence Diagram(s)

sequenceDiagram
    participant Tester as Behat Tester
    participant FeatureContext
    participant JavascriptTrait
    participant Browser

    Tester->>FeatureContext: Start scenario (@javascript)
    FeatureContext->>JavascriptTrait: jsCollectorBeforeScenario()
    JavascriptTrait->>Browser: Inject JS error collector (window.onerror, console.error, etc.)

    Tester->>FeatureContext: Execute monitored step
    FeatureContext->>JavascriptTrait: jsCollectorBeforeStep()
    JavascriptTrait->>Browser: Inject JS error collector (if needed)

    FeatureContext->>Browser: Perform step actions (e.g., click button)
    Browser-->>JavascriptTrait: Collect JS errors after step
    FeatureContext->>JavascriptTrait: jsCollectorAfterStep()

    Tester->>FeatureContext: End scenario (@javascript @no-js-errors)
    FeatureContext->>JavascriptTrait: jsCollectorAssertScenarioClean()
    JavascriptTrait->>Browser: Retrieve and assert no JS errors

    Tester->>FeatureContext: Assert no JS errors on current page (optional)
    FeatureContext->>JavascriptTrait: assertNoJsErrorsOnCurrentPage()
    JavascriptTrait->>Browser: Retrieve and assert no JS errors
Loading

Suggested reviewers

  • AlexSkrypnyk

Poem

In the warren of code where the JavaScripts play,
A trait hops in to clear errors away.
With Behat it checks, with Selenium it peers,
Catching those bugs that bring testers to tears.
Now every scenario, with a hop and a cheer,
Finds JavaScript troubles before they appear!
🐇✨

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.


Note

⚡️ Faster reviews with caching

CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boost—your workflow just got faster.


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
@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: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6d27528 and 1aa0fce.

📒 Files selected for processing (3)
  • src/JavascriptTrait.php (1 hunks)
  • tests/behat/bootstrap/FeatureContext.php (2 hunks)
  • tests/behat/features/javascript.feature (1 hunks)
🔇 Additional comments (12)
tests/behat/bootstrap/FeatureContext.php (1)

33-33: Well-integrated trait usage

The JavascriptTrait has been properly imported and included in the FeatureContext class, following the established pattern of trait usage in this file.

Also applies to: 74-74

tests/behat/features/javascript.feature (4)

1-5: Good feature description

The feature description clearly explains the purpose of the JavascriptTrait functionality, focusing on tracking and verifying JavaScript errors.


6-10: Well-structured first scenario

This scenario correctly tests for the absence of JavaScript errors, which is a common use case. The @javascript tag ensures the trait's BeforeScenario hook runs properly.


11-16: Good error detection test

This scenario properly tests the error detection capability using a thrown JavaScript error, which is a common source of JavaScript errors.


17-21: Comprehensive error detection

This scenario nicely tests the console.error detection capability, ensuring that errors logged via console.error are also captured by the trait.

src/JavascriptTrait.php (7)

1-14: Well-structured trait declaration

The namespace, imports, and documentation are appropriate. The trait clearly states its purpose of tracking and verifying JavaScript errors in web pages.


15-26: Good initialization with BeforeScenario hook

The @BeforeScenario hook correctly targets @javascript scenarios and resets the error buffer at the beginning of each scenario, which prevents errors from previous scenarios affecting current ones.


28-48: Consider improving error reporting in javascriptExecuteCode

The method correctly executes JavaScript code on the page, but it silently ignores JavaScript errors. This might be confusing if a developer expects the step to fail when JavaScript errors occur.

Consider if it would be better to log a warning message when JavaScript errors are caught but ignored, to help with debugging. For example:

  try {
    $this->getSession()->getDriver()->executeScript($code);
  } catch (\Throwable $e) {
    // Ignore JavaScript errors
    if (stripos($e->getMessage(), 'javascript error') === false) {
      throw $e;
+   } else {
+     // Log that a JavaScript error was caught and ignored
+     error_log('JavaScript error was caught and ignored: ' . $e->getMessage());
    }
  }

50-67: Effective error assertion method

The javascriptAssertError method correctly checks for JavaScript capability, injects the collector, and asserts that at least one JavaScript error was detected.


69-86: Clear error message for assertions

The javascriptAssertNoErrors method provides a helpful error message that includes the specific JavaScript errors found, which aids in debugging.


88-129: Efficient error collector injection

The injectCollector method efficiently checks if the collector is already installed before installing it, avoiding redundant script execution. The JavaScript collector properly captures both window.onerror events and console.error calls.


131-146: Robust error retrieval

The getJavaScriptErrors method properly handles type checking and exceptions when retrieving errors from the page.

@javascript
Scenario: Assert JavaScript error is detected when one exists
When I go to "/"
And I execute the JavaScript code "throw new Error('Test JS error');"
Copy link
Member

Choose a reason for hiding this comment

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

this should be added to the test suite of the behat-steps itself, not the consumer trait.

Copy link
Member

Choose a reason for hiding this comment

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

also, you could creae a fixture html page that has errors or that could throw an error if you click a button and use that for tests

Copy link
@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: 3

♻️ Duplicate comments (1)
src/JavascriptTrait.php (1)

179-183: 👍 Flexible JS-capable driver check

Thanks for switching to supportsJavascript() – this removes the hard dependency on Selenium2Driver and makes the trait work with any Mink driver that advertises JS support.
No further action needed.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Lite

📥 Commits

Reviewing files that changed from the base of the PR and between 1aa0fce and 5696e81.

📒 Files selected for processing (3)
  • src/JavascriptTrait.php (1 hunks)
  • tests/behat/features/javascript.feature (1 hunks)
  • tests/behat/fixtures/relative.html (1 hunks)
🔇 Additional comments (1)
tests/behat/fixtures/relative.html (1)

444-446: Fixture looks good

Adding an explicit error trigger makes the test deterministic and self-contained.
No issues spotted here.

Comment on lines +79 to +86
if (!$this->driverIsJsCapable()) {
return;
}

$this->harvestErrorsIntoRegistry();
$path = $this->currentPath();
$errors = $this->jsErrorRegistry[$path] ?? [];

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Inject the collector before harvesting to avoid undefined global

harvestErrorsIntoRegistry() assumes that window.__behatJsErrors has already been declared.
If assertNoJsErrorsOnCurrentPage() is called on a page that has never gone through a monitored step, this variable will be undefined, triggering a JavaScript reference error in some drivers and masking real problems.

   public function assertNoJsErrorsOnCurrentPage(): void
   {
     if (!$this->driverIsJsCapable()) {
       return;
     }

+    // Ensure the collector exists even if no monitored step ran on this page.
+    $this->injectJsCollector();
     $this->harvestErrorsIntoRegistry();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!$this->driverIsJsCapable()) {
return;
}
$this->harvestErrorsIntoRegistry();
$path = $this->currentPath();
$errors = $this->jsErrorRegistry[$path] ?? [];
public function assertNoJsErrorsOnCurrentPage(): void
{
if (!$this->driverIsJsCapable()) {
return;
}
// Ensure the collector exists even if no monitored step ran on this page.
$this->injectJsCollector();
$this->harvestErrorsIntoRegistry();
$path = $this->currentPath();
$errors = $this->jsErrorRegistry[$path] ?? [];
🤖 Prompt for AI Agents
In src/JavascriptTrait.php around lines 79 to 86, the method
harvestErrorsIntoRegistry() is called before ensuring the JavaScript error
collector is injected, which can cause a JavaScript reference error if
window.__behatJsErrors is undefined. To fix this, inject the collector script
before calling harvestErrorsIntoRegistry() so that window.__behatJsErrors is
always defined when accessed.

Comment on lines +185 to +190
private function safeExecute(string $script): void
{
try {
$this->getSession()->executeScript($script);
} catch (DriverException $e) {
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Swallowing driver exceptions hides valuable diagnostics

safeExecute() silently drops every DriverException. When troubleshooting flaky tests it is extremely helpful to know why a script could not be executed (e.g., cross-origin restriction, browser crashed, etc.).

Consider at least logging the message at NOTICE/DEBUG level:

   } catch (DriverException $e) {
-  }
+      // Do not break the test flow, but surface the problem for debugging.
+      error_log(sprintf('[Behat JS-collector] DriverException: %s', $e->getMessage()));
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private function safeExecute(string $script): void
{
try {
$this->getSession()->executeScript($script);
} catch (DriverException $e) {
}
private function safeExecute(string $script): void
{
try {
$this->getSession()->executeScript($script);
} catch (DriverException $e) {
// Do not break the test flow, but surface the problem for debugging.
error_log(sprintf('[Behat JS-collector] DriverException: %s', $e->getMessage()));
}
}
🤖 Prompt for AI Agents
In src/JavascriptTrait.php around lines 185 to 190, the safeExecute method
currently catches DriverException but silently ignores it, which hides important
diagnostic information. Modify the catch block to log the exception message at
NOTICE or DEBUG level using the appropriate logger, so that failures in script
execution are recorded for troubleshooting without interrupting the flow.

Comment on lines +11 to +16
@javascript @no-js-errors
Scenario: Assert JavaScript error is detected when one exists
When I visit "/sites/default/files/relative.html"
And the element "#js-error-trigger" should be displayed
And I click on the element "#js-error-trigger"

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

@no-js-errors tag makes the “error expected” scenario fail

The second scenario intentionally triggers a JavaScript error, but the @no-js-errors tag instructs JavascriptTrait to assert zero errors after the scenario, resulting in an unavoidable failure.

Remove the tag (or replace it with an explicit step that asserts the presence of errors):

-  @javascript @no-js-errors
+  @javascript
   Scenario: Assert JavaScript error is detected when one exists
🤖 Prompt for AI Agents
In tests/behat/features/javascript.feature around lines 11 to 16, the scenario
that intentionally triggers a JavaScript error is incorrectly tagged with
@no-js-errors, which causes the test to fail by asserting zero errors. Remove
the @no-js-errors tag from this scenario or replace it with a step that
explicitly asserts the presence of JavaScript errors to correctly reflect the
test's intent.

@AlexSkrypnyk AlexSkrypnyk added the PR: Requires more work Pull request was reviewed and reviver(s) asked to work further on the pull request label May 21, 2025
@AlexSkrypnyk AlexSkrypnyk self-assigned this May 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PR: Requires more work Pull request was reviewed and reviver(s) asked to work further on the pull request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0