Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


SSL ariaqueryhandler.spec.ts   Sprache: unbekannt

 
/**
 * @license
 * Copyright 2020 Google Inc.
 * SPDX-License-Identifier: Apache-2.0
 */

import assert from 'assert';

import expect from 'expect';
import {TimeoutError} from 'puppeteer';
import type {ElementHandle} from 'puppeteer-core/internal/api/ElementHandle.js';

import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {attachFrame, detachFrame} from './utils.js';

describe('AriaQueryHandler', () => {
  setupTestBrowserHooks();

  describe('parseAriaSelector', () => {
    it('should handle non-breaking spaces', async () => {
      const {page} = await getTestState();
      await page.setContent(
        '<button id="btn" role="button"><span> </span><span> </span>Submit button and some spaces</button>',
      );
      const expectFound = async (button: ElementHandle | null) => {
        assert(button);
        const id = await button.evaluate(button => {
          return button.id;
        });
        expect(id).toBe('btn');
      };
      {
        using button = await page.$(
          'aria/\u00A0\u00A0Submit button and some spaces',
        );
        await expectFound(button);
      }
      {
        using button = await page.$('aria/Submit button and some spaces');
        expect(button).toBe(null);
      }
    });
    it('should handle non-breaking spaces', async () => {
      const {page} = await getTestState();
      await page.setContent(
        '<button id="btn" role="button">  Submit button and some spaces</button>',
      );
      const expectFound = async (button: ElementHandle | null) => {
        assert(button);
        const id = await button.evaluate(button => {
          return button.id;
        });
        expect(id).toBe('btn');
      };
      {
        using button = await page.$('aria/ubmit button and some spaces');
        expect(button).toBe(null);
      }
      {
        using button = await page.$('aria/Submit button and some spaces');
        await expectFound(button);
      }
    });
    it('should handle zero width spaces', async () => {
      const {page} = await getTestState();
      await page.setContent(
        '<button id="btn" role="button"><span>​</span><span>​</span>Submit button and some spaces</button>',
      );
      const expectFound = async (button: ElementHandle | null) => {
        assert(button);
        const id = await button.evaluate(button => {
          return button.id;
        });
        expect(id).toBe('btn');
      };
      {
        using button = await page.$(
          'aria/\u200B\u200BSubmit button and some spaces',
        );
        await expectFound(button);
      }
      {
        using button = await page.$('aria/Submit button and some spaces');
        expect(button).toBe(null);
      }
    });
    it('should find button', async () => {
      const {page} = await getTestState();
      await page.setContent(
        '<button id="btn" role="button"> Submit  button   and some spaces  </button>',
      );
      const expectFound = async (button: ElementHandle | null) => {
        assert(button);
        const id = await button.evaluate(button => {
          return button.id;
        });
        expect(id).toBe('btn');
      };
      {
        using button = await page.$(
          'aria/Submit button and some spaces[role="button"]',
        );
        await expectFound(button);
      }
      {
        using button = await page.$(
          "aria/Submit button and some spaces[role='button']",
        );
        await expectFound(button);
      }
      {
        using button = await page.$(
          'aria/  Submit button and some spaces[role="button"]',
        );
        expect(button).toBe(null);
      }
      {
        using button = await page.$(
          'aria/Submit button and some spaces  [role="button"]',
        );
        expect(button).toBe(null);
      }
      {
        using button = await page.$(
          'aria/Submit  button   and  some  spaces   [  role  =  "button" ] ',
        );
        expect(button).toBe(null);
      }
      {
        using button = await page.$(
          'aria/[role="button"]Submit button and some spaces',
        );
        await expectFound(button);
      }
      {
        using button = await page.$(
          'aria/Submit button [role="button"]and some spaces',
        );
        await expectFound(button);
      }
      {
        using button = await page.$(
          'aria/[name="  Submit  button and some  spaces"][role="button"]',
        );
        expect(button).toBe(null);
      }
      {
        using button = await page.$(
          "aria/[name='  Submit  button and some  spaces'][role='button']",
        );
        expect(button).toBe(null);
      }
      {
        using button = await page.$(
          'aria/ignored[name="Submit button and some spaces"][role="button"]',
        );
        await expectFound(button);
        await expect(page.$('aria/smth[smth="true"]')).rejects.toThrow(
          'Unknown aria attribute "smth" in selector',
        );
      }
    });
  });

  describe('queryOne', () => {
    it('should find button by role', async () => {
      const {page} = await getTestState();
      await page.setContent(
        '<div id="div"><button id="btn" role="button">Submit</button></div>',
      );
      using button = (await page.$(
        'aria/[role="button"]',
      )) as ElementHandle<HTMLButtonElement>;
      const id = await button!.evaluate(button => {
        return button.id;
      });
      expect(id).toBe('btn');
    });

    it('should find button by name and role', async () => {
      const {page} = await getTestState();
      await page.setContent(
        '<div id="div"><button id="btn" role="button">Submit</button></div>',
      );
      using button = (await page.$(
        'aria/Submit[role="button"]',
      )) as ElementHandle<HTMLButtonElement>;
      const id = await button!.evaluate(button => {
        return button.id;
      });
      expect(id).toBe('btn');
    });

    it('should find first matching element', async () => {
      const {page} = await getTestState();
      await page.setContent(
        `
        <div role="menu" id="mnu1" aria-label="menu div"></div>
        <div role="menu" id="mnu2" aria-label="menu div"></div>
        `,
      );
      using div = (await page.$(
        'aria/menu div',
      )) as ElementHandle<HTMLDivElement>;
      const id = await div!.evaluate(div => {
        return div.id;
      });
      expect(id).toBe('mnu1');
    });

    it('should find by name', async () => {
      const {page} = await getTestState();
      await page.setContent(
        `
        <div role="menu" id="mnu1" aria-label="menu-label1">menu div</div>
        <div role="menu" id="mnu2" aria-label="menu-label2">menu div</div>
        `,
      );
      using menu = (await page.$(
        'aria/menu-label1',
      )) as ElementHandle<HTMLDivElement>;
      const id = await menu!.evaluate(div => {
        return div.id;
      });
      expect(id).toBe('mnu1');
    });

    it('should find 2nd element by name', async () => {
      const {page} = await getTestState();
      await page.setContent(
        `
        <div role="menu" id="mnu1" aria-label="menu-label1">menu div</div>
        <div role="menu" id="mnu2" aria-label="menu-label2">menu div</div>
        `,
      );
      using menu = (await page.$(
        'aria/menu-label2',
      )) as ElementHandle<HTMLDivElement>;
      const id = await menu!.evaluate(div => {
        return div.id;
      });
      expect(id).toBe('mnu2');
    });
  });

  describe('queryAll', () => {
    it('should find menu by name', async () => {
      const {page} = await getTestState();
      await page.setContent(
        `
        <div role="menu" id="mnu1" aria-label="menu div"></div>
        <div role="menu" id="mnu2" aria-label="menu div"></div>
        `,
      );
      const divs = (await page.$$('aria/menu div')) as Array<
        ElementHandle<HTMLDivElement>
      >;
      const ids = await Promise.all(
        divs.map(n => {
          return n.evaluate(div => {
            return div.id;
          });
        }),
      );
      expect(ids.join(', ')).toBe('mnu1, mnu2');
    });
  });
  describe('queryAllArray', () => {
    it('$$eval should handle many elements', async function () {
      this.timeout(40_000);

      const {page} = await getTestState();
      await page.setContent('');
      await page.evaluate(
        `
        for (var i = 0; i <= 10000; i++) {
            const button = document.createElement('button');
            button.textContent = i;
            document.body.appendChild(button);
        }
        `,
      );
      const sum = await page.$$eval('aria/[role="button"]', buttons => {
        return buttons.reduce((acc, button) => {
          return acc + Number(button.textContent);
        }, 0);
      });
      expect(sum).toBe(50005000);
    });
  });

  describe('waitForSelector (aria)', function () {
    const addElement = (tag: string) => {
      return document.body.appendChild(document.createElement(tag));
    };

    it('should immediately resolve promise if node exists', async () => {
      const {page, server} = await getTestState();
      await page.goto(server.EMPTY_PAGE);
      await page.evaluate(addElement, 'button');
      await page.waitForSelector('aria/[role="button"]');
    });

    it('should work for ElementHandle.waitForSelector', async () => {
      const {page, server} = await getTestState();
      await page.goto(server.EMPTY_PAGE);
      await page.evaluate(() => {
        return (document.body.innerHTML = `<div><button>test</button></div>`);
      });
      using element = (await page.$('div'))!;
      await element!.waitForSelector('aria/test');
    });

    it('should persist query handler bindings across reloads', async () => {
      const {page, server} = await getTestState();
      await page.goto(server.EMPTY_PAGE);
      await page.evaluate(addElement, 'button');
      await page.waitForSelector('aria/[role="button"]');
      await page.reload();
      await page.evaluate(addElement, 'button');
      await page.waitForSelector('aria/[role="button"]');
    });

    it('should persist query handler bindings across navigations', async () => {
      const {page, server} = await getTestState();

      // Reset page but make sure that execution context ids start with 1.
      await page.goto('data:text/html,');
      await page.goto(server.EMPTY_PAGE);
      await page.evaluate(addElement, 'button');
      await page.waitForSelector('aria/[role="button"]');

      // Reset page but again make sure that execution context ids start with 1.
      await page.goto('data:text/html,');
      await page.goto(server.EMPTY_PAGE);
      await page.evaluate(addElement, 'button');
      await page.waitForSelector('aria/[role="button"]');
    });

    it('should work independently of `exposeFunction`', async () => {
      const {page, server} = await getTestState();
      await page.goto(server.EMPTY_PAGE);
      await page.exposeFunction('ariaQuerySelector', (a: number, b: number) => {
        return a + b;
      });
      await page.evaluate(addElement, 'button');
      await page.waitForSelector('aria/[role="button"]');
      const result = await page.evaluate('globalThis.ariaQuerySelector(2,8)');
      expect(result).toBe(10);
    });

    it('should work with removed MutationObserver', async () => {
      const {page} = await getTestState();

      await page.evaluate(() => {
        // @ts-expect-error This is the point of the test.
        return delete window.MutationObserver;
      });
      const [handle] = await Promise.all([
        page.waitForSelector('aria/anything'),
        page.setContent(`<h1>anything</h1>`),
      ]);
      assert(handle);
      expect(
        await page.evaluate(x => {
          return x.textContent;
        }, handle),
      ).toBe('anything');
    });

    it('should resolve promise when node is added', async () => {
      const {page, server} = await getTestState();

      await page.goto(server.EMPTY_PAGE);
      const frame = page.mainFrame();
      const watchdog = frame.waitForSelector('aria/[role="heading"]');
      await frame.evaluate(addElement, 'br');
      await frame.evaluate(addElement, 'h1');
      using elementHandle = (await watchdog)!;
      const tagName = await (
        await elementHandle.getProperty('tagName')
      ).jsonValue();
      expect(tagName).toBe('H1');
    });

    it('should work when node is added through innerHTML', async () => {
      const {page, server} = await getTestState();

      await page.goto(server.EMPTY_PAGE);
      const watchdog = page.waitForSelector('aria/name');
      await page.evaluate(addElement, 'span');
      await page.evaluate(() => {
        return (document.querySelector('span')!.innerHTML =
          '<h3><div aria-label="name"></div></h3>');
      });
      await watchdog;
    });

    it('Page.waitForSelector is shortcut for main frame', async () => {
      const {page, server} = await getTestState();

      await page.goto(server.EMPTY_PAGE);
      await attachFrame(page, 'frame1', server.EMPTY_PAGE);
      const otherFrame = page.frames()[1];
      const watchdog = page.waitForSelector('aria/[role="button"]');
      await otherFrame!.evaluate(addElement, 'button');
      await page.evaluate(addElement, 'button');
      using elementHandle = await watchdog;
      expect(elementHandle!.frame).toBe(page.mainFrame());
    });

    it('should run in specified frame', async () => {
      const {page, server} = await getTestState();

      await attachFrame(page, 'frame1', server.EMPTY_PAGE);
      await attachFrame(page, 'frame2', server.EMPTY_PAGE);
      const frame1 = page.frames()[1];
      const frame2 = page.frames()[2];
      const waitForSelectorPromise = frame2!.waitForSelector(
        'aria/[role="button"]',
      );
      await frame1!.evaluate(addElement, 'button');
      await frame2!.evaluate(addElement, 'button');
      using elementHandle = await waitForSelectorPromise;
      expect(elementHandle!.frame).toBe(frame2);
    });

    it('should throw when frame is detached', async () => {
      const {page, server} = await getTestState();

      await attachFrame(page, 'frame1', server.EMPTY_PAGE);
      const frame = page.frames()[1];
      let waitError!: Error;
      const waitPromise = frame!
        .waitForSelector('aria/does-not-exist')
        .catch(error => {
          return (waitError = error);
        });
      await detachFrame(page, 'frame1');
      await waitPromise;
      expect(waitError).toBeTruthy();
      expect(waitError.message).atLeastOneToContain([
        'waitForFunction failed: frame got detached.',
        'Browsing context already closed.',
      ]);
    });

    it('should survive cross-process navigation', async () => {
      const {page, server} = await getTestState();

      let imgFound = false;
      const waitForSelector = page
        .waitForSelector('aria/[role="image"]')
        .then(() => {
          return (imgFound = true);
        });
      await page.goto(server.EMPTY_PAGE);
      expect(imgFound).toBe(false);
      await page.reload();
      expect(imgFound).toBe(false);
      await page.goto(server.CROSS_PROCESS_PREFIX + '/grid.html');
      await waitForSelector;
      expect(imgFound).toBe(true);
    });

    it('should wait for visible', async () => {
      const {page} = await getTestState();

      let divFound = false;
      const waitForSelector = page
        .waitForSelector('aria/name', {visible: true})
        .then(() => {
          return (divFound = true);
        });
      await page.setContent(
        `<div aria-label='name' style='display: none; visibility: hidden;'>1</div>`,
      );
      expect(divFound).toBe(false);
      await page.evaluate(() => {
        return document.querySelector('div')!.style.removeProperty('display');
      });
      expect(divFound).toBe(false);
      await page.evaluate(() => {
        return document
          .querySelector('div')!
          .style.removeProperty('visibility');
      });
      expect(await waitForSelector).toBe(true);
      expect(divFound).toBe(true);
    });

    it('should wait for visible recursively', async () => {
      const {page} = await getTestState();

      let divVisible = false;
      const waitForSelector = page
        .waitForSelector('aria/inner', {visible: true})
        .then(() => {
          return (divVisible = true);
        })
        .catch(() => {
          return (divVisible = false);
        });
      await page.setContent(
        `<div style='display: none; visibility: hidden;'><div aria-label="inner">hi</div></div>`,
      );
      expect(divVisible).toBe(false);
      await page.evaluate(() => {
        return document.querySelector('div')!.style.removeProperty('display');
      });
      expect(divVisible).toBe(false);
      await page.evaluate(() => {
        return document
          .querySelector('div')!
          .style.removeProperty('visibility');
      });
      expect(await waitForSelector).toBe(true);
      expect(divVisible).toBe(true);
    });

    it('hidden should wait for visibility: hidden', async () => {
      const {page} = await getTestState();

      let divHidden = false;
      await page.setContent(
        `<div role='button' style='display: block;'>text</div>`,
      );
      const waitForSelector = page
        .waitForSelector('aria/[role="button"]', {hidden: true})
        .then(() => {
          return (divHidden = true);
        })
        .catch(() => {
          return (divHidden = false);
        });
      await page.waitForSelector('aria/[role="button"]'); // do a round trip
      expect(divHidden).toBe(false);
      await page.evaluate(() => {
        return document
          .querySelector('div')!
          .style.setProperty('visibility', 'hidden');
      });
      expect(await waitForSelector).toBe(true);
      expect(divHidden).toBe(true);
    });

    it('hidden should wait for display: none', async () => {
      const {page} = await getTestState();

      let divHidden = false;
      await page.setContent(
        `<div role='main' style='display: block;'>text</div>`,
      );
      const waitForSelector = page
        .waitForSelector('aria/[role="main"]', {hidden: true})
        .then(() => {
          return (divHidden = true);
        })
        .catch(() => {
          return (divHidden = false);
        });
      await page.waitForSelector('aria/[role="main"]'); // do a round trip
      expect(divHidden).toBe(false);
      await page.evaluate(() => {
        return document
          .querySelector('div')!
          .style.setProperty('display', 'none');
      });
      expect(await waitForSelector).toBe(true);
      expect(divHidden).toBe(true);
    });

    it('hidden should wait for removal', async () => {
      const {page} = await getTestState();

      await page.setContent(`<div role='main'>text</div>`);
      let divRemoved = false;
      const waitForSelector = page
        .waitForSelector('aria/[role="main"]', {hidden: true})
        .then(() => {
          return (divRemoved = true);
        })
        .catch(() => {
          return (divRemoved = false);
        });
      await page.waitForSelector('aria/[role="main"]'); // do a round trip
      expect(divRemoved).toBe(false);
      await page.evaluate(() => {
        return document.querySelector('div')!.remove();
      });
      expect(await waitForSelector).toBe(true);
      expect(divRemoved).toBe(true);
    });

    it('should return null if waiting to hide non-existing element', async () => {
      const {page} = await getTestState();

      using handle = await page.waitForSelector('aria/non-existing', {
        hidden: true,
      });
      expect(handle).toBe(null);
    });

    it('should respect timeout', async () => {
      const {page} = await getTestState();

      const error = await page
        .waitForSelector('aria/[role="button"]', {
          timeout: 10,
        })
        .catch(error => {
          return error;
        });
      expect(error.message).toContain(
        'Waiting for selector `[role="button"]` failed: Waiting failed: 10ms exceeded',
      );
      expect(error).toBeInstanceOf(TimeoutError);
    });

    it('should have an error message specifically for awaiting an element to be hidden', async () => {
      const {page} = await getTestState();

      await page.setContent(`<div role='main'>text</div>`);
      const promise = page.waitForSelector('aria/[role="main"]', {
        hidden: true,
        timeout: 10,
      });
      await expect(promise).rejects.toMatchObject({
        message:
          'Waiting for selector `[role="main"]` failed: Waiting failed: 10ms exceeded',
      });
    });

    it('should respond to node attribute mutation', async () => {
      const {page} = await getTestState();

      let divFound = false;
      const waitForSelector = page
        .waitForSelector('aria/zombo')
        .then(() => {
          return (divFound = true);
        })
        .catch(() => {
          return (divFound = false);
        });
      await page.setContent(`<div aria-label='notZombo'></div>`);
      expect(divFound).toBe(false);
      await page.evaluate(() => {
        return document
          .querySelector('div')!
          .setAttribute('aria-label', 'zombo');
      });
      expect(await waitForSelector).toBe(true);
    });

    it('should return the element handle', async () => {
      const {page} = await getTestState();

      const waitForSelector = page.waitForSelector('aria/zombo').catch(err => {
        return err;
      });
      await page.setContent(`<div aria-label='zombo'>anything</div>`);
      expect(
        await page.evaluate(
          x => {
            return x?.textContent;
          },
          await waitForSelector,
        ),
      ).toBe('anything');
    });

    it('should have correct stack trace for timeout', async () => {
      const {page} = await getTestState();

      let error!: Error;
      await page.waitForSelector('aria/zombo', {timeout: 10}).catch(error_ => {
        return (error = error_);
      });
      expect(error!.stack).toContain(
        'Waiting for selector `zombo` failed: Waiting failed: 10ms exceeded',
      );
    });
  });

  describe('queryOne (Chromium web test)', () => {
    async function setupPage(): ReturnType<typeof getTestState> {
      const state = await getTestState();
      await state.page.setContent(
        `
          <h2 id="shown">title</h2>
          <h2 id="hidden" aria-hidden="true">title</h2>
          <div id="node1" aria-labelledby="node2"></div>
          <div id="node2" aria-label="bar"></div>
          <div id="node3" aria-label="foo"></div>
          <div id="node4" class="container">
          <div id="node5" role="button" aria-label="foo"></div>
          <div id="node6" role="button" aria-label="foo"></div>
          <!-- Accessible name not available when element is hidden -->
          <div id="node7" hidden role="button" aria-label="foo"></div>
          <div id="node8" role="button" aria-label="bar"></div>
          </div>
          <button id="node10">text content</button>
          <h1 id="node11">text content</h1>
          <!-- Accessible name not available when role is "presentation" -->
          <h1 id="node12" role="presentation">text content</h1>
          <!-- Elements inside shadow dom should be found -->
          <script>
          const div = document.createElement('div');
          const shadowRoot = div.attachShadow({mode: 'open'});
          const h1 = document.createElement('h1');
          h1.textContent = 'text content';
          h1.id = 'node13';
          shadowRoot.appendChild(h1);
          document.documentElement.appendChild(div);
          </script>
          <img id="node20" src="" alt="Accessible Name">
          <input id="node21" type="submit" value="Accessible Name">
          <label id="node22" for="node23">Accessible Name</label>
          <!-- Accessible name for the <input> is "Accessible Name" -->
          <input id="node23">
          <div id="node24" title="Accessible Name"></div>
          <div role="tree">
          <div role="treeitem" id="node30">
          <div role="treeitem" id="node31">
          <div role="treeitem" id="node32">item1</div>
          <div role="treeitem" id="node33">item2</div>
          </div>
          <div role="treeitem" id="node34">item3</div>
          </div>
          </div>
          <!-- Accessible name for the <div> is "item1 item2 item3" -->
          <div aria-describedby="node30"></div>
          `,
      );
      return state;
    }
    const getIds = async (elements: ElementHandle[]) => {
      return await Promise.all(
        elements.map(element => {
          return element.evaluate(element => {
            return element.id;
          });
        }),
      );
    };
    it('should find by name "foo"', async () => {
      const {page} = await setupPage();
      const found = await page.$$('aria/foo');
      const ids = await getIds(found);
      expect(ids).toEqual(['node3', 'node5', 'node6']);
    });
    it('should find by name "bar"', async () => {
      const {page} = await setupPage();
      const found = await page.$$('aria/bar');
      const ids = await getIds(found);
      expect(ids).toEqual(['node1', 'node2', 'node8']);
    });
    it('should find treeitem by name', async () => {
      const {page} = await setupPage();
      const found = await page.$$('aria/item1 item2 item3');
      const ids = await getIds(found);
      expect(ids).toEqual(['node30']);
    });
    it('should find by role "button"', async () => {
      const {page} = await setupPage();
      const found = (await page.$$('aria/[role="button"]')) as Array<
        ElementHandle<HTMLButtonElement>
      >;
      const ids = await getIds(found);
      expect(ids).toEqual(['node5', 'node6', 'node8', 'node10', 'node21']);
    });
    it('should find by role "heading"', async () => {
      const {page} = await setupPage();
      const found = await page.$$('aria/[role="heading"]');
      const ids = await getIds(found);
      expect(ids).toEqual(['shown', 'node11', 'node13']);
    });
    it('should find both ignored and unignored', async () => {
      const {page} = await setupPage();
      const found = await page.$$('aria/title');
      const ids = await getIds(found);
      expect(ids).toEqual(['shown']);
    });
  });
});

[ Verzeichnis aufwärts0.35unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge