Skip to content
New issue

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

test(dropdown): Add UI test cases for dropdown components #55

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from

Conversation

MomoPoppy
Copy link
Collaborator

@MomoPoppy MomoPoppy commented Sep 24, 2024

PR

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • New Features

    • Introduced comprehensive automated UI tests for the dropdown component, ensuring compliance with design specifications across various scenarios, including hover, click, and tooltip functionalities.
    • Validated visual representation and behavior of dropdowns in different states, such as disabled, multi-level, and size variations.
  • Bug Fixes

    • Enhanced error handling in tests to ensure robustness during execution.
  • Tests

    • Added multiple new test files covering various aspects of the dropdown component, including its appearance, interactions, and compliance with design guidelines.

Copy link

coderabbitai bot commented Sep 24, 2024

Walkthrough

The pull request introduces a comprehensive suite of Playwright end-to-end tests for a dropdown component, ensuring its compliance with xdesign specifications. Multiple test files are created, each focusing on different aspects of the dropdown functionality, such as visual appearance, interaction behaviors, and specific features like tooltips and split buttons. The tests include various scenarios, capturing screenshots for visual regression testing and validating the component's behavior under different conditions.

Changes

File(s) Change Summary
tests/dropdown/basic.spec.ts Introduces tests for default display and hover states of the dropdown, capturing relevant screenshots.
tests/dropdown/border.spec.ts Tests the visual appearance of the dropdown with rounded borders, comparing against a reference image.
tests/dropdown/check-status.spec.ts Verifies the UI of the dropdown's selected state and captures a screenshot for validation.
tests/dropdown/disabled.spec.ts Tests various scenarios for the dropdown's disabled state, ensuring correct visual representation.
tests/dropdown/events.spec.ts Validates dropdown interactions through hover and click events, capturing screenshots for verification.
tests/dropdown/hide-on-click.spec.ts Checks visibility of the dropdown arrow after interactions, capturing screenshots for validation.
tests/dropdown/inherit-width.spec.ts Tests width inheritance and content fitting of the dropdown, capturing screenshots for validation.
tests/dropdown/lazy-show-popper.spec.ts Validates lazy loading behavior of the dropdown through visual tests and screenshot comparisons.
tests/dropdown/multi-level.spec.ts Tests multi-level dropdown menus through various interactions and captures screenshots for validation.
tests/dropdown/options.spec.ts Validates dropdown options under different configurations, capturing screenshots for visual regression.
tests/dropdown/show-icon.spec.ts Tests dropdown behavior with icons, ensuring correct visual output through screenshots.
tests/dropdown/size.spec.ts Checks visual representation of the dropdown at different sizes, capturing screenshots for comparison.
tests/dropdown/slot.spec.ts Tests default behavior of the dropdown regarding content expansion, capturing relevant screenshots.
tests/dropdown/split-button.spec.ts Validates the split button functionality of the dropdown through visual tests and screenshot captures.
tests/dropdown/tip.spec.ts Tests tooltip functionality in dropdowns, capturing screenshots for both configuration and attribute tooltips.
tests/dropdown/title.spec.ts Validates the custom trigger source text for the dropdown through visual tests and screenshot captures.
tests/dropdown/trigger.spec.ts Tests hover and click-triggered dropdowns, capturing screenshots for validation.
tests/dropdown/visible-arrow.spec.ts Tests visibility of the dropdown arrow under different conditions, capturing screenshots for validation.

Suggested labels

e2e

Suggested reviewers

  • zzcr

Poem

In the meadow where bunnies play,
New dropdown tests come out to stay.
With clicks and hovers, they leap and bound,
Ensuring the UI is safe and sound.
So hop along, let's cheer and sing,
For the joy that these tests will bring! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
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.
    -- Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    -- @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 generate unit testing code.
    -- @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.

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

@github-actions github-actions bot added the e2e playwright label Sep 24, 2024
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: 43

Outside diff range and nitpick comments (34)
tests/dropdown/title.spec.ts (1)

3-3: Consider using English for test descriptions and provide more context.

While the use of test.describe is correct, consider the following improvements:

  1. Use English for test descriptions to enhance international collaboration.
  2. Provide more context about the xdesign specifications being tested.

Example:

test.describe('Dropdown component alignment with xdesign specifications', () => {

Also, consider adding a comment explaining what xdesign specifications are being tested.

tests/dropdown/size.spec.ts (2)

3-3: Consider using English for test descriptions.

While the current description is clear, using non-English descriptions in code might affect readability for non-Chinese speaking developers. Consider using English or adding English translations alongside the Chinese description.

Here's a suggested change:

-test.describe('dropdown 组件对齐xdesign规范', () => {
+test.describe('Dropdown component alignment with xdesign specifications (dropdown 组件对齐xdesign规范)', () => {

4-9: LGTM: Test setup and navigation are correct. Consider using English for the test title.

The test setup, error handling, and navigation are implemented correctly. However, consider using English for the test title to improve readability for non-Chinese speaking developers.

Here's a suggested change for the test title:

-  test('dropdown 不同尺寸显示-- UI截图', async ({ page }) => {
+  test('Dropdown different sizes display -- UI screenshot (dropdown 不同尺寸显示-- UI截图)', async ({ page }) => {
tests/dropdown/border.spec.ts (2)

3-3: Consider using English or bilingual descriptions for better international collaboration.

The test suite description is currently in Chinese. To improve readability for non-Chinese speaking developers, consider translating it to English or using both languages.

Here's a suggested bilingual description:

test.describe('Dropdown component alignment with xdesign specifications (dropdown 组件对齐xdesign规范)', () => {
  // ... test cases ...
});

4-4: Consider using English or bilingual test descriptions.

Similar to the test suite description, consider translating the test case description to English or using both languages for better international collaboration.

Here's a suggested bilingual description:

test('Dropdown displays rounded borders -- UI screenshot (dropdown 显示边框圆角-- UI截图)', async ({ page }) => {
  // ... test implementation ...
});
tests/dropdown/slot.spec.ts (1)

1-17: Summary: Good start, but room for improvement

This test file provides a good foundation for testing the dropdown component. However, there are several areas where it can be enhanced:

  1. Use English for test descriptions and comments for better international collaboration.
  2. Add more test cases to cover different aspects of the dropdown component.
  3. Implement more specific assertions to verify the dropdown's behavior.
  4. Improve error handling to provide more context when errors occur.
  5. Use more robust selectors and waiting mechanisms.
  6. Enhance the screenshot naming for clearer visual regression testing.

Consider creating a shared configuration file for common settings like base URL and timeout values. This will make it easier to maintain consistency across multiple test files.

Next steps:

  1. Implement the suggested improvements in this file.
  2. Create additional test files to cover other aspects of the dropdown component (e.g., different sizes, custom content, keyboard navigation).
  3. Set up a visual regression testing workflow to automatically compare screenshots across changes.

These enhancements will significantly improve the test coverage and reliability of the dropdown component.

tests/dropdown/hide-on-click.spec.ts (1)

1-3: Consider using English for test descriptions or add bilingual descriptions.

The test suite description is currently in Chinese. To improve readability for a wider audience, consider using English or providing bilingual descriptions. This will make the tests more accessible to non-Chinese speaking developers.

Example of a bilingual description:

test.describe('Dropdown component alignment with xdesign specifications (dropdown 组件对齐xdesign规范)', () => {
  // ... test cases ...
})
tests/dropdown/check-status.spec.ts (3)

1-3: Consider using English for test descriptions.

While the current description is clear, using English for test descriptions can improve collaboration with non-Chinese speaking developers and maintain consistency across the codebase.

Consider changing the test description to English:

-test.describe('dropdown 组件对齐xdesign规范', () => {
+test.describe('Dropdown component alignment with xdesign specifications', () => {

4-11: Approve setup and navigation, suggest improving test title.

The test setup, including the error handler and navigation, looks good. However, consider improving the test title for clarity.

Consider changing the test title to be more descriptive and in English:

-  test('dropdown 选中状态 -- UI截图', async ({ page }) => {
+  test('Dropdown selected state - UI screenshot comparison', async ({ page }) => {

1-23: Overall assessment and suggestions for improved test coverage.

The introduction of this UI test for the dropdown component is a positive step towards ensuring the component's functionality and appearance. However, there are opportunities to enhance the test's reliability and expand its coverage.

Consider adding the following test cases to improve coverage:

  1. Test different dropdown options and verify the selected value.
  2. Check the dropdown's behavior with keyboard navigation (Tab, Enter, Arrow keys).
  3. Verify the dropdown's accessibility attributes (aria-labels, roles).
  4. Test the dropdown's behavior when disabled.
  5. Check for proper event emission when selections are made.

Example additional test case:

test('Dropdown keyboard navigation', async ({ page }) => {
  await page.goto('dropdown#check-status');
  const trigger = page.locator('.tiny-dropdown__trigger');
  
  // Open dropdown with Enter key
  await trigger.focus();
  await page.keyboard.press('Enter');
  await expect(page.locator('.tiny-dropdown-menu')).toBeVisible();
  
  // Navigate with arrow keys and select with Enter
  await page.keyboard.press('ArrowDown');
  await page.keyboard.press('ArrowDown');
  await page.keyboard.press('Enter');
  
  // Verify selected value
  await expect(trigger).toHaveText('Option 2');
});

Adding these test cases will significantly improve the robustness and coverage of your dropdown component testing.

tests/dropdown/split-button.spec.ts (1)

1-3: Consider translating test descriptions to English.

While the import statement is correct, the test description is in Chinese. For better maintainability and to ensure all team members can understand the tests, consider translating the test descriptions to English.

Here's a suggested translation:

test.describe('Dropdown component alignment with xdesign specification', () => {
  // ... rest of the code
})
tests/dropdown/inherit-width.spec.ts (1)

3-3: Consider translating the test suite description to English.

For better international collaboration, it's recommended to use English for test descriptions. Consider changing:

test.describe('dropdown 组件对齐xdesign规范', () => {

to:

test.describe('Dropdown component alignment with xdesign specifications', () => {

This will make the test suite more accessible to non-Chinese speaking developers.

tests/dropdown/visible-arrow.spec.ts (2)

1-3: Consider using English for test descriptions.

While the imports are correct, the test suite description is in Chinese. For better international collaboration and maintainability, consider using English for all test descriptions and comments.

-test.describe('dropdown 组件对齐xdesign规范', () => {
+test.describe('Dropdown component alignment with xdesign specifications', () => {

1-33: Overall feedback: Good coverage, room for improvement

The test file provides good coverage for the dropdown component, testing both visible and hidden arrow scenarios. The use of visual comparison with screenshots is appropriate for UI testing. However, there are some areas for improvement:

  1. Code organization: Consider extracting common setup code into a separate function or fixture to reduce duplication.
  2. Reliability: Replace hardcoded wait times with more reliable waiting mechanisms.
  3. Error handling: Enhance error handling to provide more specific and informative error messages.
  4. Internationalization: Use English for test descriptions and comments to improve readability for a wider audience.
  5. Naming: Consider using more descriptive names for the screenshot files, e.g., 'dropdown-visible-arrow.png' instead of 'visible-arrow.png'.

To further improve the test suite, consider:

  1. Adding more edge cases, such as testing with different screen sizes or device emulations.
  2. Implementing accessibility tests using Playwright's built-in accessibility testing features.
  3. Adding performance tests to ensure the dropdown opens and closes within acceptable time frames.
  4. Implementing data-driven tests to cover various dropdown configurations if applicable.

These improvements will enhance the robustness and coverage of your dropdown component tests.

tests/dropdown/lazy-show-popper.spec.ts (2)

1-3: Consider translating the test description to English.

The test suite description is currently in Chinese. For better international collaboration and maintainability, it's recommended to use English for test descriptions and comments.

Consider changing the description to something like:

test.describe('Dropdown component alignment with xdesign specifications', () => {

4-18: Approve test structure with a suggestion for screenshot naming.

The test case for the default behavior of the dropdown is well-structured and follows Playwright best practices. Good job on including error catching, appropriate waits, and assertions.

Consider using a more descriptive name for the screenshot, such as:

await expect(wrap).toHaveScreenshot('dropdown_default_not_lazy_loaded.png')

This naming convention provides more context about what the screenshot represents.

tests/dropdown/show-icon.spec.ts (3)

4-12: LGTM! Consider adding a more specific assertion.

The test case is well-structured and follows Playwright best practices. It correctly handles page errors, ensures the element is in the viewport, and captures a screenshot for visual regression testing.

Consider adding a more specific assertion to verify the presence of text and a custom icon before taking the screenshot. For example:

await expect(demo.locator('.tiny-dropdown__title')).toBeVisible();
await expect(demo.locator('.tiny-dropdown__icon')).toBeVisible();

This will make the test more robust and easier to debug if it fails.


15-27: LGTM! Consider improvements for stability and maintainability.

The test case effectively simulates user interaction and captures the dropdown's state after opening. However, there are a few areas where it could be improved:

  1. Replace the hard-coded wait time with a more reliable method:
await page.waitForSelector('.tiny-dropdown__menu', { state: 'visible' });
  1. Add an assertion to verify the dropdown menu is visible before taking the screenshot:
await expect(page.locator('.tiny-dropdown__menu')).toBeVisible();
  1. Consider using a custom command or helper function for opening the dropdown to improve code reusability across tests.

These changes will make the test more stable and easier to maintain.


29-41: LGTM! Consider improvements for stability and consistency.

The test case effectively simulates hovering over the icon and captures the resulting state. However, similar to the previous test, there are areas for improvement:

  1. Replace the hard-coded wait time with a more reliable method:
await page.waitForSelector('.tiny-dropdown__menu', { state: 'visible' });
  1. Add an assertion to verify the dropdown menu is visible before taking the screenshot:
await expect(page.locator('.tiny-dropdown__menu')).toBeVisible();
  1. Consider using a custom command or helper function for hovering over the dropdown trigger to improve code reusability.

  2. For consistency with the previous tests, you might want to use click() instead of hover() if the dropdown is supposed to open on click rather than hover.

These changes will improve the test's reliability and maintain consistency across your test suite.

tests/dropdown/trigger.spec.ts (1)

3-3: Consider using English for test descriptions.

The test suite descriptions are currently in Chinese. For better international collaboration and maintainability, consider using English for all test descriptions and comments.

Example translation:

- test.describe('dropdown 组件对齐xdesign规范', () => {
+ test.describe('Dropdown component alignment with xdesign specifications', () => {

Also applies to: 24-24

tests/dropdown/events.spec.ts (1)

1-47: Good test coverage with room for optimization.

Overall, these tests provide comprehensive coverage of dropdown functionality, including different types and user interactions. The use of screenshot comparisons for visual regression testing is a good approach for UI components.

To further improve these tests:

  1. Implement the suggested refactoring to reduce duplication and improve maintainability.
  2. Replace fixed timeouts with more reliable waiting mechanisms.
  3. Consider adding more specific assertions about the dropdown's state after each interaction.
  4. If possible, add tests for edge cases or error states of the dropdown component.

As you continue to develop these tests, consider creating a shared utilities file for common dropdown testing functions. This will make it easier to maintain consistency across all dropdown-related tests.

Next steps:

  1. Refactor the existing tests as suggested.
  2. Review other dropdown tests in the project and apply similar improvements.
  3. Consider expanding the test suite to cover more scenarios and edge cases.

Great job on improving the test coverage for the dropdown components!

tests/dropdown/disabled.spec.ts (4)

4-12: LGTM! Consider adding an assertion for the disabled state.

The test case effectively captures the UI for the disabled dropdown. Good use of error handling and viewport checking before taking the screenshot.

Consider adding an assertion to verify that the dropdown is actually in a disabled state, for example:

await expect(demo.locator('.tiny-dropdown__trigger')).toHaveAttribute('disabled', '')

14-26: LGTM! Consider using waitForSelector instead of a fixed timeout.

The test case effectively captures the UI for the hover state of a disabled dropdown. Good use of error handling and viewport checking before taking the screenshot.

Instead of using a fixed timeout, consider using waitForSelector to wait for any visual changes that occur on hover. This can make the test more reliable and faster. For example:

await trigger.nth(0).locator('.tiny-dropdown__suffix-inner').hover()
await page.waitForSelector('.some-hover-state-class', { state: 'attached' })

Replace .some-hover-state-class with the actual class or attribute that changes when the dropdown is hovered.


28-40: LGTM! Consider using waitForSelector instead of a fixed timeout.

The test case effectively captures the UI for the hover state of a disabled button-type dropdown. Good use of error handling and viewport checking before taking the screenshot.

Similar to the previous test, consider using waitForSelector instead of a fixed timeout:

await trigger.nth(1).hover()
await page.waitForSelector('.some-hover-state-class', { state: 'attached' })

Replace .some-hover-state-class with the actual class or attribute that changes when the button-type dropdown is hovered.


42-55: LGTM! Consider improvements for consistency and reliability.

The test case effectively captures the UI for the hover state of a disabled menu item. Good use of error handling and viewport checking before taking the screenshot.

  1. Similar to previous suggestions, consider using waitForSelector instead of a fixed timeout:
await trigger.nth(2).locator('.tiny-dropdown__suffix-inner').hover()
await page.waitForSelector('.some-hover-state-class', { state: 'attached' })
  1. For consistency with other tests, consider adding an assertion to verify that the menu item is actually in a disabled state:
await expect(page.locator('.tiny-dropdown__menu-item.is-disabled')).toBeVisible()
  1. The screenshot name 'item-disabled.png' might be more descriptive as 'item-disabled-hover.png' to match the naming convention of other tests.
tests/dropdown/basic.spec.ts (5)

4-12: Add a timeout after navigation to improve test reliability.

The test case has a good structure for UI testing, using appropriate assertions for viewport visibility and screenshot comparison. However, to improve reliability, consider adding a short timeout or waitForLoadState after navigation.

Add a timeout after navigation:

 await page.goto('dropdown#basic-usage')
+await page.waitForLoadState('networkidle')
 const demo = page.locator('#basic-usage .pc-demo')

14-26: Consider using a more reliable waiting mechanism.

The test case has a good structure and appropriately tests the hover state of the dropdown. However, the hardcoded 200ms timeout might lead to flaky tests on slower machines.

Replace the hardcoded timeout with a more reliable waiting mechanism:

 await trigger.hover()
-await page.waitForTimeout(200)
+await page.waitForSelector('.tiny-dropdown-menu', { state: 'visible' })
 await expect(wrap).toBeInViewport()

This change will make the test wait for the dropdown menu to become visible, which is more reliable than a fixed timeout.


28-43: Use first() for clarity and improve waiting mechanism.

The test case effectively checks the hover state of menu items. However, there are two suggestions for improvement:

  1. Use first() instead of nth(0) for better readability.
  2. Replace the hardcoded timeout with a more reliable waiting mechanism, as mentioned in the previous comment.

Apply these changes:

 await trigger.hover()
-await page.waitForTimeout(200)
+await page.waitForSelector('.tiny-dropdown-menu', { state: 'visible' })
-await item.nth(0).hover()
+await item.first().hover()

These changes will improve readability and reliability of the test.


45-60: Add assertion for disabled state and improve waiting mechanism.

The test case checks the hover state of a disabled menu item, which is good. However, there are a few suggestions for improvement:

  1. Add an assertion to verify that the item is actually disabled.
  2. Replace the hardcoded timeout with a more reliable waiting mechanism, as mentioned in previous comments.
  3. Consider using a more explicit selector for the disabled item instead of nth(4).

Apply these changes:

 await trigger.hover()
-await page.waitForTimeout(200)
+await page.waitForSelector('.tiny-dropdown-menu', { state: 'visible' })
-const item = page.locator('.tiny-dropdown-menu .tiny-dropdown-item')
+const disabledItem = page.locator('.tiny-dropdown-menu .tiny-dropdown-item.is-disabled').first()
-await item.nth(4).hover()
+await expect(disabledItem).toHaveClass(/is-disabled/)
+await disabledItem.hover()

These changes will improve the reliability and explicitness of the test.


1-61: Consider refactoring for improved maintainability and internationalization.

The overall structure of the test suite is good, with consistent error handling and test case structure. However, there are a few suggestions for improvement:

  1. Consider extracting common setup code (like navigation and locating elements) into a beforeEach hook to reduce duplication.
  2. If the project is intended for an international audience, consider using English for test descriptions or implementing a localization system for test descriptions.
  3. Implement a custom expect matcher for screenshot comparisons to reduce boilerplate code.

Here's an example of how you might refactor the test suite:

import { expect, test } from '@playwright/test'

test.describe('Dropdown component alignment with xdesign specifications', () => {
  test.beforeEach(async ({ page }) => {
    page.on('pageerror', (exception) => expect(exception).toBeNull())
    await page.goto('dropdown#basic-usage')
  })

  const expectScreenshot = async (page, selector, filename) => {
    const element = page.locator(selector)
    await expect(element).toBeInViewport()
    await expect(element).toHaveScreenshot(filename)
  }

  test('Default display - UI screenshot', async ({ page }) => {
    await expectScreenshot(page, '#basic-usage .pc-demo', 'default.png')
  })

  test('Hover dropdown - UI screenshot', async ({ page }) => {
    const trigger = page.locator('#basic-usage .pc-demo .tiny-dropdown__trigger .tiny-dropdown__suffix-inner')
    await trigger.hover()
    await page.waitForSelector('.tiny-dropdown-menu', { state: 'visible' })
    await expectScreenshot(page, '.docs-tabs-wrap', 'dropdown.png')
  })

  // ... (similar refactoring for other test cases)
})

This refactored version reduces duplication, improves readability, and makes the tests easier to maintain.

tests/dropdown/tip.spec.ts (2)

1-3: Consider using English for test descriptions.

While the current description is clear, using English for test descriptions can improve collaboration in international teams and maintain consistency with code comments.

Consider changing the test suite description to English:

-test.describe('dropdown 组件对齐xdesign规范', () => {
+test.describe('Dropdown component alignment with xdesign specifications', () => {

1-59: Consider adding more test cases for comprehensive coverage.

While the current tests cover the main functionality of dropdown tooltips, there might be room for additional test cases to improve coverage.

Consider adding the following test cases:

  1. Test for keyboard navigation (e.g., using Tab key to navigate through dropdown items).
  2. Test for different screen sizes to ensure responsive behavior.
  3. Test for tooltip content accuracy (if possible to assert text content).
  4. Test for tooltip appearance/disappearance timing.
  5. Test for interaction with other UI elements (e.g., tooltip overlapping).

Example of a keyboard navigation test:

test('dropdown keyboard navigation -- UI screenshot', async ({ page }) => {
  await page.goto('dropdown#tip');
  const demo = page.locator('#tip .pc-demo');
  const trigger = demo.locator('.tiny-dropdown__trigger');

  // Focus on the trigger
  await trigger.nth(0).focus();
  await page.keyboard.press('Enter');
  await page.waitForSelector('.tiny-dropdown-menu', { state: 'visible' });

  // Navigate through items
  for (let i = 0; i < 3; i++) {
    await page.keyboard.press('Tab');
    await page.waitForTimeout(300); // Replace with appropriate wait
    await expect(page.locator('.docs-tabs-wrap')).toHaveScreenshot(`keyboard-nav-item${i}.png`);
  }
});

Adding these test cases will provide more comprehensive coverage of the dropdown component's functionality.

tests/dropdown/options.spec.ts (1)

3-3: Consider translating the test suite description to English.

The current description "dropdown 组件对齐xdesign规范" is in Chinese. For better international collaboration and maintainability, it's recommended to use English for test descriptions.

Suggested translation:

test.describe('Dropdown component alignment with xdesign specifications', () => {
tests/dropdown/multi-level.spec.ts (1)

1-136: Overall assessment and recommendations for the test suite

The test suite for multi-level dropdown menus is comprehensive and covers various scenarios. However, there are several areas for improvement:

  1. Code duplication: Many test cases share similar structures. Refactoring using helper functions and parameterization can significantly reduce duplication and improve maintainability.

  2. Reliability: Replace page.waitForTimeout() calls with more reliable waiting mechanisms like waitForSelector() or locator.waitFor() to reduce the likelihood of flaky tests.

  3. Assertions: Add more specific assertions to verify the visibility and state of dropdown items after each interaction.

  4. Localization: Consider adding English comments or translating variable names to improve code readability for a wider audience.

  5. Parameterization: Further parameterize test cases to handle variations (e.g., number of levels, button types) more efficiently.

Next steps for improving the test suite:

  1. Implement the suggested refactorings to create reusable helper functions.
  2. Review and update all waiting mechanisms to use more reliable methods.
  3. Add specific assertions for each step of the dropdown interactions.
  4. Consider creating a config file to manage test parameters (e.g., URLs, locators) for easier maintenance.
  5. If not already in place, set up visual regression testing tools to automate the comparison of captured screenshots.

These improvements will result in a more maintainable, reliable, and efficient test suite for your dropdown components.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 8c9ee66 and 2370f69.

Files ignored due to path filters (46)
  • tests/dropdown/basic.spec.ts-snapshots/default-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/basic.spec.ts-snapshots/dropdown-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/basic.spec.ts-snapshots/item-disabled-hover-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/basic.spec.ts-snapshots/item-hover-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/border.spec.ts-snapshots/border-default-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/check-status.spec.ts-snapshots/check-status-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/disabled.spec.ts-snapshots/button-disabled-hover-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/disabled.spec.ts-snapshots/disabled-default-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/disabled.spec.ts-snapshots/disabled-hover-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/disabled.spec.ts-snapshots/item-disabled-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/events.spec.ts-snapshots/button-events-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/events.spec.ts-snapshots/default-events-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/hide-on-click.spec.ts-snapshots/click-visible-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/inherit-width.spec.ts-snapshots/default-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/inherit-width.spec.ts-snapshots/inherit-width-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/lazy-show-popper.spec.ts-snapshots/default-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/lazy-show-popper.spec.ts-snapshots/lazy-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/multi-level.spec.ts-snapshots/multi-level-0-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/multi-level.spec.ts-snapshots/multi-level-1-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/multi-level.spec.ts-snapshots/multi-level-2-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/multi-level.spec.ts-snapshots/multi-level-3-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/multi-level.spec.ts-snapshots/multi-level-4-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/options.spec.ts-snapshots/option0-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/options.spec.ts-snapshots/option1-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/options.spec.ts-snapshots/option2-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/options.spec.ts-snapshots/option3-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/options.spec.ts-snapshots/option4-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/show-icon.spec.ts-snapshots/default-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/show-icon.spec.ts-snapshots/icon-hover-dropdown-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/show-icon.spec.ts-snapshots/text-hover-dropdown-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/size.spec.ts-snapshots/size-default-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/slot.spec.ts-snapshots/slot-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/split-button.spec.ts-snapshots/button-hover-dropdown-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/split-button.spec.ts-snapshots/default-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/tip.spec.ts-snapshots/trigger0-item0-tip-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/tip.spec.ts-snapshots/trigger0-item1-tip-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/tip.spec.ts-snapshots/trigger0-item2-tip-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/tip.spec.ts-snapshots/trigger1-item0-tip-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/tip.spec.ts-snapshots/trigger1-item1-tip-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/tip.spec.ts-snapshots/trigger1-item2-tip-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/title.spec.ts-snapshots/default-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/trigger.spec.ts-snapshots/default-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/trigger.spec.ts-snapshots/trigger-click-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/trigger.spec.ts-snapshots/trigger-hover-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/visible-arrow.spec.ts-snapshots/hidden-arrow-chromium-win32.png is excluded by !**/*.png
  • tests/dropdown/visible-arrow.spec.ts-snapshots/visible-arrow-chromium-win32.png is excluded by !**/*.png
Files selected for processing (18)
  • tests/dropdown/basic.spec.ts (1 hunks)
  • tests/dropdown/border.spec.ts (1 hunks)
  • tests/dropdown/check-status.spec.ts (1 hunks)
  • tests/dropdown/disabled.spec.ts (1 hunks)
  • tests/dropdown/events.spec.ts (1 hunks)
  • tests/dropdown/hide-on-click.spec.ts (1 hunks)
  • tests/dropdown/inherit-width.spec.ts (1 hunks)
  • tests/dropdown/lazy-show-popper.spec.ts (1 hunks)
  • tests/dropdown/multi-level.spec.ts (1 hunks)
  • tests/dropdown/options.spec.ts (1 hunks)
  • tests/dropdown/show-icon.spec.ts (1 hunks)
  • tests/dropdown/size.spec.ts (1 hunks)
  • tests/dropdown/slot.spec.ts (1 hunks)
  • tests/dropdown/split-button.spec.ts (1 hunks)
  • tests/dropdown/tip.spec.ts (1 hunks)
  • tests/dropdown/title.spec.ts (1 hunks)
  • tests/dropdown/trigger.spec.ts (1 hunks)
  • tests/dropdown/visible-arrow.spec.ts (1 hunks)
Additional comments not posted (15)
tests/dropdown/title.spec.ts (3)

1-1: LGTM: Imports are correct and concise.

The necessary Playwright test utilities are imported correctly.


4-5: Good practice: Error listener setup.

Setting up an error listener to catch unexpected exceptions is a good practice. It ensures that any unhandled errors during the test execution are caught and cause the test to fail.


11-11: Verify baseline screenshot existence and update process.

The test is comparing against a baseline screenshot named 'default.png'. Ensure that:

  1. This baseline image exists in the appropriate directory.
  2. There's a process in place for updating the baseline when intentional UI changes are made.
  3. Consider using a more descriptive name for the screenshot, e.g., 'dropdown_custom_trigger.png'.

Run the following script to check for the existence of the baseline image:

tests/dropdown/size.spec.ts (1)

1-2: LGTM: Imports and structure are correct.

The imports and overall structure follow Playwright's testing conventions and best practices.

tests/dropdown/border.spec.ts (2)

1-1: LGTM: Imports are correct and concise.

The necessary Playwright test utilities are imported correctly.


1-13: Good start on UI testing, with room for improvements.

This test file provides a solid foundation for UI testing of the dropdown component's border styling. The use of Playwright for screenshot comparison is a good approach. However, there are several areas where the test can be improved:

  1. Internationalization: Consider using English or bilingual descriptions for better collaboration.
  2. Code organization: Move common setups (like error handling) to global configurations.
  3. Maintainability: Use constants for URLs and selectors to make tests less fragile.
  4. Comprehensive testing: Consider testing multiple viewport sizes and themes.

Implementing these suggestions will make the tests more robust, maintainable, and comprehensive.

tests/dropdown/slot.spec.ts (1)

1-1: LGTM: Imports are correct and necessary.

The imports from '@playwright/test' are appropriate for writing Playwright tests.

tests/dropdown/inherit-width.spec.ts (2)

1-1: LGTM: Imports are correct and concise.

The necessary Playwright test utilities are imported correctly.


1-31: Well-structured tests that align with PR objectives.

These tests effectively address the PR objective of adding UI test cases for dropdown components. The use of visual testing with screenshots is particularly suitable for verifying UI behavior. The tests cover two important aspects of the dropdown: default content expansion and width inheritance.

Suggestions for improvement:

  1. Translate test descriptions to English for better international collaboration.
  2. Refactor common setup code to reduce duplication and improve maintainability.
  3. Replace fixed timeouts with more reliable wait conditions.

Overall, these tests provide a solid foundation for ensuring the correct behavior of the dropdown component. Good job on implementing these UI tests!

tests/dropdown/trigger.spec.ts (3)

1-1: LGTM: Imports are correct and necessary.

The import statement is appropriate for Playwright tests, importing only the necessary functions.


3-22: LGTM: Well-structured test for hover-triggered dropdown.

The test case is well-organized and covers both default and hover states of the dropdown. It follows Playwright's best practices and includes error handling for page errors.


24-45: LGTM: Well-structured test for click-triggered dropdown.

The test case is well-organized, consistent with the first suite, and covers both hover and click interactions for the click-triggered dropdown. It follows Playwright's best practices and includes error handling for page errors.

tests/dropdown/events.spec.ts (1)

1-3: LGTM: Proper test setup and structure.

The imports and test structure are correctly set up for Playwright tests. The describe block provides a clear context for the dropdown component tests.

tests/dropdown/basic.spec.ts (1)

1-1: LGTM: Imports are correct and necessary.

The import statement is appropriate for Playwright tests, importing the necessary expect and test functions.

tests/dropdown/options.spec.ts (1)

1-1: LGTM: Imports are correct and concise.

The necessary imports from '@playwright/test' are present, and there are no unused imports.

test('dropdown 自定义触发源文本-- UI截图', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())

await page.goto('dropdown#title')
Copy link

Choose a reason for hiding this comment

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

Consider using a more robust navigation method.

The current navigation uses a fragment identifier ('dropdown#title'), which might be brittle if the URL structure changes. Consider using a full URL or a more stable navigation method.

Example:

await page.goto('/components/dropdown?tab=title')

Also, consider adding a wait for network idle or a specific element to ensure the page is fully loaded before proceeding with the test.

Comment on lines +8 to +11
const demo = page.locator('#title .pc-demo')

await expect(demo).toBeInViewport()
await expect(demo).toHaveScreenshot('default.png')
Copy link

Choose a reason for hiding this comment

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

Enhance test reliability with explicit waits and assertions.

While checking for viewport visibility is good, consider adding more explicit waits and assertions to ensure the dropdown is fully rendered and interactive before taking the screenshot. This can help prevent flaky tests.

Example:

const demo = page.locator('#title .pc-demo')
await demo.waitFor({ state: 'visible' })
await expect(demo).toBeInViewport()
await expect(demo.locator('.dropdown-trigger')).toBeEnabled()
await expect(demo).toHaveScreenshot('default.png')

Comment on lines +1 to +13
import { expect, test } from '@playwright/test'

test.describe('dropdown 组件对齐xdesign规范', () => {
test('dropdown 自定义触发源文本-- UI截图', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())

await page.goto('dropdown#title')
const demo = page.locator('#title .pc-demo')

await expect(demo).toBeInViewport()
await expect(demo).toHaveScreenshot('default.png')
})
})
Copy link

Choose a reason for hiding this comment

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

Consider adding more comprehensive test cases.

While this screenshot test is a good start, consider adding more test cases to cover various aspects of the dropdown functionality:

  1. Test opening and closing the dropdown.
  2. Verify correct rendering of dropdown items.
  3. Test keyboard navigation within the dropdown.
  4. Check for correct handling of different screen sizes (responsive behavior).
  5. Test any custom styling or themes applied to the dropdown.

These additional tests will provide more comprehensive coverage of the dropdown component's functionality and appearance.

Comment on lines +10 to +12
await expect(demo).toBeInViewport()
await expect(demo).toHaveScreenshot('size-default.png')
})
Copy link

Choose a reason for hiding this comment

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

Enhance test robustness and coverage.

While the current assertions are a good start for a visual regression test, consider the following improvements:

  1. The test doesn't actually check different sizes as implied by the test title. Consider adding checks for multiple sizes.
  2. Add explicit waits for the page to load and for any animations to complete to prevent flaky tests.
  3. Consider adding a tolerance setting to the screenshot comparison to account for minor rendering differences.

Here's a suggested refactor to address these points:

test('Dropdown different sizes display -- UI screenshot', async ({ page }) => {
  page.on('pageerror', (exception) => expect(exception).toBeNull());

  await page.goto('dropdown#size');
  await page.waitForLoadState('networkidle');

  const demo = page.locator('#size .pc-demo');
  await expect(demo).toBeInViewport();

  // Wait for any animations to complete
  await page.waitForTimeout(500);

  const sizes = ['small', 'medium', 'large'];
  for (const size of sizes) {
    await page.click(`[data-size="${size}"]`);
    await expect(demo).toHaveScreenshot(`size-${size}.png`, {
      maxDiffPixelRatio: 0.01
    });
  }
});

This refactored version:

  • Waits for the page to fully load
  • Checks multiple sizes
  • Adds a wait for animations
  • Includes a tolerance setting for screenshot comparisons

Note: Adjust the selectors and wait times as needed for your specific implementation.


test.describe('dropdown 组件对齐xdesign规范', () => {
test('dropdown 显示边框圆角-- UI截图', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
Copy link

Choose a reason for hiding this comment

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

Consider moving the error handler to a global setup.

The page error handler is a good practice, but it might be more efficient to set it up once for all tests in a global setup file.

You could create a global setup file (e.g., global-setup.ts) with:

import { expect, test as base } from '@playwright/test';

const test = base.extend({
  page: async ({ page }, use) => {
    page.on('pageerror', (exception) => expect(exception).toBeNull());
    await use(page);
  },
});

export { test, expect };

Then, import test and expect from this file instead of directly from '@playwright/test'.

Comment on lines +4 to +31
test('dropdown menu-options三级菜单 -- UI截图', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())

await page.goto('dropdown#multi-level')
const wrap = page.locator('.docs-tabs-wrap')
const demo = page.locator('#multi-level .pc-demo')
const dropdown = demo.locator('.tiny-dropdown')
const trigger = dropdown.nth(0).locator('.tiny-dropdown__trigger')
const item = page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item')
const menu = page.locator('.tiny-dropdown-menu')

await trigger.locator('.tiny-dropdown__suffix-inner').hover()
await page.waitForTimeout(300)

await item.nth(0).locator('.tiny-dropdown-item__content').nth(0).hover()
await page.waitForTimeout(300)

const menu1 = item.nth(0).locator('.tiny-dropdown-menu')
await menu1.nth(0).locator('.tiny-dropdown-item__content').nth(0).hover()
await page.waitForTimeout(300)

const menu2 = menu1.nth(0).locator('.tiny-dropdown-menu')
await menu2.nth(0).locator('.tiny-dropdown-item__content').nth(0).hover()
await page.waitForTimeout(500)

await expect(wrap).toBeInViewport()
await expect(wrap).toHaveScreenshot('multi-level-0.png')
})
Copy link

Choose a reason for hiding this comment

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

Improve test reliability and add assertions

The test case for the three-level dropdown menu is well-structured, but there are a few areas for improvement:

  1. Replace page.waitForTimeout() with more reliable waiting mechanisms to avoid flaky tests. Consider using page.waitForSelector() or locator.waitFor() instead.

  2. Add assertions to verify the visibility of dropdown items after each interaction. This will make the test more robust and catch potential issues with menu item visibility.

  3. Consider adding English comments or translating variable names to improve code readability for a wider audience.

Here's an example of how you could improve the test:

test('dropdown menu-options three-level menu -- UI screenshot', async ({ page }) => {
  // ... (existing setup code)

  await trigger.locator('.tiny-dropdown__suffix-inner').hover();
  await menu.waitFor({ state: 'visible' });

  const firstLevelItem = item.nth(0).locator('.tiny-dropdown-item__content').nth(0);
  await firstLevelItem.hover();
  await menu1.waitFor({ state: 'visible' });
  await expect(firstLevelItem).toBeVisible();

  const secondLevelItem = menu1.nth(0).locator('.tiny-dropdown-item__content').nth(0);
  await secondLevelItem.hover();
  await menu2.waitFor({ state: 'visible' });
  await expect(secondLevelItem).toBeVisible();

  const thirdLevelItem = menu2.nth(0).locator('.tiny-dropdown-item__content').nth(0);
  await thirdLevelItem.hover();
  await expect(thirdLevelItem).toBeVisible();

  // ... (existing screenshot and assertion code)
}

This refactored version improves reliability and adds visibility assertions for each level of the dropdown menu.

Comment on lines +33 to +60
test('dropdown options三级菜单 -- UI截图', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())

await page.goto('dropdown#multi-level')
const wrap = page.locator('.docs-tabs-wrap')
const demo = page.locator('#multi-level .pc-demo')
const dropdown = demo.locator('.tiny-dropdown')
const trigger = dropdown.nth(1).locator('.tiny-dropdown__trigger')
const item = page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item')
const menu = page.locator('.tiny-dropdown-menu')

await trigger.locator('.tiny-dropdown__suffix-inner').hover()
await page.waitForTimeout(300)

await item.nth(0).locator('.tiny-dropdown-item__content').nth(0).hover()
await page.waitForTimeout(300)

const menu1 = item.nth(0).locator('.tiny-dropdown-menu')
await menu1.nth(0).locator('.tiny-dropdown-item__content').nth(0).hover()
await page.waitForTimeout(300)

const menu2 = menu1.nth(0).locator('.tiny-dropdown-menu')
await menu2.nth(0).locator('.tiny-dropdown-item__content').nth(0).hover()
await page.waitForTimeout(500)

await expect(wrap).toBeInViewport()
await expect(wrap).toHaveScreenshot('multi-level-1.png')
})
Copy link

Choose a reason for hiding this comment

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

Refactor similar test cases for better code reuse

This test case is very similar to the previous one, with only minor differences in locators. To improve maintainability and reduce code duplication, consider refactoring these similar test cases.

  1. Create a helper function that encapsulates the common logic for testing multi-level dropdown menus.
  2. Pass the specific locators and any unique behavior as parameters to this helper function.

Here's an example of how you could refactor:

async function testMultiLevelDropdown(page, triggerLocator, itemLocators, screenshotName) {
  const trigger = triggerLocator.locator('.tiny-dropdown__suffix-inner');
  await trigger.hover();
  await page.locator('.tiny-dropdown-menu').waitFor({ state: 'visible' });

  for (let i = 0; i < itemLocators.length; i++) {
    const item = itemLocators[i];
    await item.hover();
    await page.locator(`.tiny-dropdown-menu >> nth=${i + 1}`).waitFor({ state: 'visible' });
    await expect(item).toBeVisible();
  }

  await expect(page.locator('.docs-tabs-wrap')).toBeInViewport();
  await expect(page.locator('.docs-tabs-wrap')).toHaveScreenshot(screenshotName);
}

test('dropdown menu-options three-level menu -- UI screenshot', async ({ page }) => {
  await page.goto('dropdown#multi-level');
  const demo = page.locator('#multi-level .pc-demo');
  const dropdown = demo.locator('.tiny-dropdown');
  const trigger = dropdown.nth(0);
  const itemLocators = [
    page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item').nth(0).locator('.tiny-dropdown-item__content').nth(0),
    page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item').nth(0).locator('.tiny-dropdown-menu').nth(0).locator('.tiny-dropdown-item__content').nth(0),
    page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item').nth(0).locator('.tiny-dropdown-menu').nth(0).locator('.tiny-dropdown-menu').nth(0).locator('.tiny-dropdown-item__content').nth(0)
  ];

  await testMultiLevelDropdown(page, trigger, itemLocators, 'multi-level-0.png');
});

// Similar refactoring for the second test case

This refactoring will make your tests more maintainable and easier to update in the future.

Comment on lines +62 to +85
test('dropdown options二级菜单 -- UI截图', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())

await page.goto('dropdown#multi-level')
const wrap = page.locator('.docs-tabs-wrap')
const demo = page.locator('#multi-level .pc-demo')
const dropdown = demo.locator('.tiny-dropdown')
const trigger = dropdown.nth(2).locator('.tiny-dropdown__trigger')
const item = page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item')
const menu = page.locator('.tiny-dropdown-menu')

await trigger.locator('.tiny-dropdown__suffix-inner').hover()
await page.waitForTimeout(300)

await item.nth(1).locator('.tiny-dropdown-item__content').nth(0).hover()
await page.waitForTimeout(300)

const menu1 = item.nth(1).locator('.tiny-dropdown-menu')
await menu1.nth(0).locator('.tiny-dropdown-item__content').nth(1).hover()
await page.waitForTimeout(300)

await expect(wrap).toBeInViewport()
await expect(wrap).toHaveScreenshot('multi-level-2.png')
})
Copy link

Choose a reason for hiding this comment

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

Maintain consistency and apply previous improvements

This test case for the two-level dropdown menu follows a similar structure to the previous cases. To maintain consistency and improve the overall quality of the test suite:

  1. Apply the same refactoring suggested for the previous test cases, using the helper function approach.
  2. Replace page.waitForTimeout() with more reliable waiting mechanisms.
  3. Add assertions to verify the visibility of dropdown items after each interaction.

Here's how you could refactor this test case using the previously suggested helper function:

test('dropdown options two-level menu -- UI screenshot', async ({ page }) => {
  await page.goto('dropdown#multi-level');
  const demo = page.locator('#multi-level .pc-demo');
  const dropdown = demo.locator('.tiny-dropdown');
  const trigger = dropdown.nth(2);
  const itemLocators = [
    page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item').nth(1).locator('.tiny-dropdown-item__content').nth(0),
    page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item').nth(1).locator('.tiny-dropdown-menu').nth(0).locator('.tiny-dropdown-item__content').nth(1)
  ];

  await testMultiLevelDropdown(page, trigger, itemLocators, 'multi-level-2.png');
});

This refactoring will ensure consistency across your test cases and make them more reliable and maintainable.

Comment on lines +87 to +110
test('dropdown 按钮二级菜单 -- UI截图', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())

await page.goto('dropdown#multi-level')
const wrap = page.locator('.docs-tabs-wrap')
const demo = page.locator('#multi-level .pc-demo')
const dropdown = demo.locator('.tiny-dropdown')
const trigger = dropdown.nth(3).locator('.tiny-dropdown__suffix-inner')
const item = page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item')
const menu = page.locator('.tiny-dropdown-menu')

await trigger.hover()
await page.waitForTimeout(300)

await item.nth(1).locator('.tiny-dropdown-item__content').nth(0).hover()
await page.waitForTimeout(300)

const menu1 = item.nth(1).locator('.tiny-dropdown-menu')
await menu1.nth(0).locator('.tiny-dropdown-item__content').nth(1).hover()
await page.waitForTimeout(300)

await expect(wrap).toBeInViewport()
await expect(wrap).toHaveScreenshot('multi-level-3.png')
})
Copy link

Choose a reason for hiding this comment

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

Adapt refactoring for button trigger and maintain consistency

This test case for the two-level dropdown menu with a button trigger follows a similar structure to the previous cases, with a slight variation in the trigger element. To maintain consistency and improve the test:

  1. Adapt the helper function to accommodate the button trigger variation.
  2. Apply the same improvements suggested for the previous test cases (replacing timeouts, adding assertions).
  3. Ensure the refactored approach can handle this slight variation without duplicating code.

Here's how you could adapt the helper function and refactor this test case:

async function testMultiLevelDropdown(page, triggerLocator, itemLocators, screenshotName, isButtonTrigger = false) {
  const trigger = isButtonTrigger ? triggerLocator : triggerLocator.locator('.tiny-dropdown__suffix-inner');
  await trigger.hover();
  await page.locator('.tiny-dropdown-menu').waitFor({ state: 'visible' });

  for (let i = 0; i < itemLocators.length; i++) {
    const item = itemLocators[i];
    await item.hover();
    await page.locator(`.tiny-dropdown-menu >> nth=${i + 1}`).waitFor({ state: 'visible' });
    await expect(item).toBeVisible();
  }

  await expect(page.locator('.docs-tabs-wrap')).toBeInViewport();
  await expect(page.locator('.docs-tabs-wrap')).toHaveScreenshot(screenshotName);
}

test('dropdown button two-level menu -- UI screenshot', async ({ page }) => {
  await page.goto('dropdown#multi-level');
  const demo = page.locator('#multi-level .pc-demo');
  const dropdown = demo.locator('.tiny-dropdown');
  const trigger = dropdown.nth(3).locator('.tiny-dropdown__suffix-inner');
  const itemLocators = [
    page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item').nth(1).locator('.tiny-dropdown-item__content').nth(0),
    page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item').nth(1).locator('.tiny-dropdown-menu').nth(0).locator('.tiny-dropdown-item__content').nth(1)
  ];

  await testMultiLevelDropdown(page, trigger, itemLocators, 'multi-level-3.png', true);
});

This refactoring maintains consistency with the previous test cases while accommodating the button trigger variation.

Comment on lines +112 to +135
test('dropdown 主要按钮二级菜单 -- UI截图', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())

await page.goto('dropdown#multi-level')
const wrap = page.locator('.docs-tabs-wrap')
const demo = page.locator('#multi-level .pc-demo')
const dropdown = demo.locator('.tiny-dropdown')
const trigger = dropdown.nth(4).locator('.tiny-dropdown__suffix-inner')
const item = page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item')
const menu = page.locator('.tiny-dropdown-menu')

await trigger.hover()
await page.waitForTimeout(300)

await item.nth(1).locator('.tiny-dropdown-item__content').nth(0).hover()
await page.waitForTimeout(300)

const menu1 = item.nth(1).locator('.tiny-dropdown-menu')
await menu1.nth(0).locator('.tiny-dropdown-item__content').nth(1).hover()
await page.waitForTimeout(300)

await expect(wrap).toBeInViewport()
await expect(wrap).toHaveScreenshot('multi-level-4.png')
})
Copy link

Choose a reason for hiding this comment

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

Parameterize similar test cases to reduce duplication

This test case for the two-level dropdown menu with a primary button trigger is almost identical to the previous test case. To further reduce code duplication and improve maintainability:

  1. Parameterize the differences between this test case and the previous one.
  2. Use a single test function that can handle both regular and primary button triggers.

Here's how you could refactor these similar test cases:

function testButtonDropdown(buttonType: 'regular' | 'primary') {
  return async ({ page }) => {
    await page.goto('dropdown#multi-level');
    const demo = page.locator('#multi-level .pc-demo');
    const dropdown = demo.locator('.tiny-dropdown');
    const triggerIndex = buttonType === 'regular' ? 3 : 4;
    const trigger = dropdown.nth(triggerIndex).locator('.tiny-dropdown__suffix-inner');
    const itemLocators = [
      page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item').nth(1).locator('.tiny-dropdown-item__content').nth(0),
      page.locator('body > .tiny-dropdown-menu .tiny-dropdown-item').nth(1).locator('.tiny-dropdown-menu').nth(0).locator('.tiny-dropdown-item__content').nth(1)
    ];

    await testMultiLevelDropdown(page, trigger, itemLocators, `multi-level-${triggerIndex}.png`, true);
  };
}

test('dropdown button two-level menu -- UI screenshot', testButtonDropdown('regular'));
test('dropdown primary button two-level menu -- UI screenshot', testButtonDropdown('primary'));

This refactoring eliminates the duplication between the two button-triggered dropdown test cases while still maintaining the ability to test both regular and primary button triggers separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
e2e playwright
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant