Introduction
Toast messages are commonly used in modern web applications to provide users with quick feedback. These messages are ephemeral and often contain dynamic content, making them challenging to validate in automated end-to-end tests. Although a strict text assertion, such as verifying the exact string displayed in a toast message, might seem like a good practice, it can result in brittle tests that break easily due to minor text changes or localization updates.
In this blog, we will explore why strict text validation for toast messages is problematic and provide practical examples of how to replace such validations with more robust alternatives.
Why Avoid Strict Text Assertions for Toast Messages?
Strict text assertions, such as cy.contains('Exact message here')
, require the message text to match exactly. This approach can fail in several scenarios:
-
Text Changes: A minor update to the toast message, for instance, changing “Creating Jira issue for risk” to “Sending risk to Jira…”, will unnecessarily cause your test to fail.
-
Localization: Applications that support multiple languages often dynamically update toast message text, making exact matches unreliable.
-
Dynamic Content: Toast messages may include placeholders for dynamic data (e.g., “Task created successfully for Task #123”). Hardcoding the text leads to unnecessary test failures.
-
UI/UX Iterations: Improvements or changes in the phrasing of messages can break tests if strict assertions are used.
Flexible Approaches to Validate Toast Messages
-
Partial Text Matching: Instead of matching the full message, focus on key parts of the text that are less likely to change. For example:
cy.contains('Sending risk').should('be.visible');
This approach verifies the intent of the message without being overly strict about exact phrasing.
-
CSS Selector Validation: If the toast message consistently appears in a specific location with a reliable CSS class, validate its visibility without relying on the text content:
cy.get('.toast-message').should('be.visible');
Combine this with partial text matching for added reliability:
cy.get('.toast-message').contains('risk').should('be.visible');
-
Use Data Attributes: Leverage unique data attributes for better targeting and reliability:
cy.get('[data-testid="toast-message"]').contains('success').should('be.visible');
This method circumvents dependence on dynamic text by using stable identifiers.
-
Custom Command for Toast Verification: Abstract the logic into a reusable Cypress command to simplify your tests and make updates easier:
Cypress.Commands.add('verifyToast', (expectedText) => { cy.get('.toast-message').contains(expectedText).should('be.visible'); });
Usage in tests:
cy.verifyToast('risk');
This abstraction simplifies your test suite and allows for centralized changes if your toast implementation evolves.
Real-World Example
Consider the following scenario related to a Jira ticket integration:
Problematic Test:
cy.contains('Creating Jira issue for risk').should('be.visible');
If the text changes to “Sending risk to Jira…”, the test will fail, even though the functionality remains intact.
Improved Test:
cy.contains('risk').should('be.visible');
Alternatively, using a custom command:
cy.verifyToast('risk');
This ensures that the intent of the message is verified without relying on strict, brittle text assertions.
Conclusion
Strict text validations for toast messages can make your tests fragile and challenging to maintain. By adopting flexible matching strategies, such as partial text matching, CSS selector validation, or custom commands, you can ensure your tests remain reliable and resilient to UI changes. These techniques help maintain confidence in your application without the frustration of frequent test failures.