Repository: ionic-team/ionic-framework
File: core/src/components/select/test/a11y/select.e2e.ts (TypeScript)

Code before:
              html {
                font-size: 310%;
              }
            </style>
            <ion-select label="Fruit" value="apple" placeholder="Placeholder">
              <ion-select-option value="apple">Apple</ion-select-option>
              <ion-select-option value="banana">Banana</ion-select-option>
              <ion-select-option value="orange">Orange</ion-select-option>
            </ion-select>
          `,
          config
        );

        const select = page.locator('ion-select');
        await expect(select).toHaveScreenshot(screenshot('select-scale'));
      });
    });
  });
});

/**
 * This behavior does not vary across modes/directions.
 */
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
  test.describe(title('select: aria attributes'), () => {
    test('should have a aria-description on the selected option when action sheet interface is open', async ({
      page,
    }) => {
      await page.setContent(
        `
          <ion-select label="Fruit" value="apple" interface="action-sheet">
            <ion-select-option value="apple">Apple</ion-select-option>
            <ion-select-option value="banana">Banana</ion-select-option>
            <ion-select-option value="orange">Orange</ion-select-option>
          </ion-select>
        `,
        config
      );

      const ionActionSheetDidPresent = await page.spyOnEvent('ionActionSheetDidPresent');

      const select = page.locator('ion-select');

      await select.click();
      await ionActionSheetDidPresent.next();

      const selectedOption = page.locator('.action-sheet-selected');
      await expect(selectedOption).toHaveAttribute('aria-description', 'selected');

      // Check that the attribut is not added to non-selected option
      const nonSelectedOption = page.locator('.select-interface-option:not(.action-sheet-selected)').first();

Review comment (suggestion):
```suggestion
    test('should have an aria-description on the selected option when action sheet interface is open', async ({
```

Code after:
import AxeBuilder from '@axe-core/playwright';
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';

configs({ directions: ['ltr'], palettes: ['light', 'dark'] }).forEach(({ title, config }) => {
  test.describe(title('select: a11y'), () => {
    test('default layout should not have accessibility violations', async ({ page }) => {
      await page.setContent(
        `
        <main>
          <ion-select label="Label" placeholder="Placeholder"></ion-select>
          <ion-select placeholder="Placeholder">
            <div slot="label">Label</div>
          </ion-select>
          <ion-select label="Label" value="a">
            <ion-select-option value="a">Apple</ion-select-option>
          </ion-select>
          <ion-select aria-label="Label"></ion-select>
          <ion-item>
            <ion-select label="My Label" value="apples">
              <ion-select-option value="apples">Apples</ion-select-option>
              <ion-select-option value="bananas">Bananas</ion-select-option>
              <ion-select-option value="oranges">Oranges</ion-select-option>
            </ion-select>
          </ion-item>
          <ion-select id="multiple" multiple="true" label="My Label">
            <ion-select-option value="apples">Apples</ion-select-option>
            <ion-select-option value="bananas">Bananas</ion-select-option>
            <ion-select-option value="oranges">Oranges</ion-select-option>
          </ion-select>
          <ion-select label="My Label" label-placement="floating">
            <ion-icon slot="start" name="pizza" aria-hidden="true"></ion-icon>
            <ion-select-option value="apples">Apples</ion-select-option>
            <ion-select-option value="bananas">Bananas</ion-select-option>
            <ion-select-option value="oranges">Oranges</ion-select-option>
            <ion-button slot="end" aria-label="button">
              <ion-icon slot="icon-only" name="lock-closed" aria-hidden="true"></ion-icon>
            </ion-button>
          </ion-select>

          <script>
            const multiple = document.querySelector('#multiple');
            multiple.value = ['apples', 'bananas'];
          </script>
        </main>
      `,
        config
      );

      const results = await new AxeBuilder({ page }).analyze();
      expect(results.violations).toEqual([]);
    });

    test('focused state should not have accessibility violations', async ({ page }) => {
      /**
       * The primary color against the focus background
       * when using fill="solid" does not meet AA
       * contrast guidelines so it excluded from the test.
       * The contrast here is a significant improvement
       * over what Ionic has had in the past, so the team
       * has decided that this tradeoff is acceptable since
       * the scope of the problem is limited to the focus
       * state with the primary color when fill="solid".
       */
      await page.setContent(
        `
        <main>
          <ion-select class="has-focus" label="Label" value="a">
            <ion-select-option value="a">Apple</ion-select-option>
          </ion-select>
          <ion-select class="has-focus" label-placement="floating" label="Label" value="a">
            <ion-select-option value="a">Apple</ion-select-option>
          </ion-select>
          <ion-select class="has-focus" fill="outline" label-placement="floating" label="Label" value="a">
            <ion-select-option value="a">Apple</ion-select-option>
          </ion-select>
        </main>
      `,
        config
      );

      const results = await new AxeBuilder({ page }).analyze();
      expect(results.violations).toEqual([]);
    });
  });
});

configs({ directions: ['ltr'] }).forEach(({ title, config, screenshot }) => {
  test.describe(title('select: a11y'), () => {
    test.describe(title('select: font scaling'), () => {
      test('should scale text on larger font sizes', async ({ page }) => {
        await page.setContent(
          `
            <style>
              html {
                font-size: 310%;
              }
            </style>
            <ion-select label="Fruit" value="apple" placeholder="Placeholder">
              <ion-select-option value="apple">Apple</ion-select-option>
              <ion-select-option value="banana">Banana</ion-select-option>
              <ion-select-option value="orange">Orange</ion-select-option>
            </ion-select>
          `,
          config
        );

        const select = page.locator('ion-select');
        await expect(select).toHaveScreenshot(screenshot('select-scale'));
      });
    });
  });
});