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


Quelle  mouse.spec.ts   Sprache: unbekannt

 
/**
 * @license
 * Copyright 2018 Google Inc.
 * SPDX-License-Identifier: Apache-2.0
 */
import os from 'os';

import expect from 'expect';
import {MouseButton} from 'puppeteer-core/internal/api/Input.js';
import type {Page} from 'puppeteer-core/internal/api/Page.js';
import type {KeyInput} from 'puppeteer-core/internal/common/USKeyboardLayout.js';

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

interface ClickData {
  type: string;
  detail: number;
  clientX: number;
  clientY: number;
  isTrusted: boolean;
  button: number;
  buttons: number;
}

interface Dimensions {
  x: number;
  y: number;
  width: number;
  height: number;
}

function dimensions(): Dimensions {
  const rect = document.querySelector('textarea')!.getBoundingClientRect();
  return {
    x: rect.left,
    y: rect.top,
    width: rect.width,
    height: rect.height,
  };
}

describe('Mouse', function () {
  setupTestBrowserHooks();

  it('should click the document', async () => {
    const {page} = await getTestState();

    await page.evaluate(() => {
      (globalThis as any).clickPromise = new Promise(resolve => {
        document.addEventListener('click', event => {
          resolve({
            type: event.type,
            detail: event.detail,
            clientX: event.clientX,
            clientY: event.clientY,
            isTrusted: event.isTrusted,
            button: event.button,
          });
        });
      });
    });
    await page.mouse.click(50, 60);
    const event = await page.evaluate(() => {
      return (globalThis as any).clickPromise;
    });
    expect(event.type).toBe('click');
    expect(event.detail).toBe(1);
    expect(event.clientX).toBe(50);
    expect(event.clientY).toBe(60);
    expect(event.isTrusted).toBe(true);
    expect(event.button).toBe(0);
  });
  it('should resize the textarea', async () => {
    const {page, server} = await getTestState();

    await page.goto(server.PREFIX + '/input/textarea.html');
    const {x, y, width, height} = await page.evaluate(dimensions);
    const mouse = page.mouse;
    await mouse.move(x + width - 4, y + height - 4);
    await mouse.down();
    await mouse.move(x + width + 100, y + height + 100);
    await mouse.up();
    const newDimensions = await page.evaluate(dimensions);
    expect(newDimensions.width).toBe(Math.round(width + 104));
    expect(newDimensions.height).toBe(Math.round(height + 104));
  });
  it('should select the text with mouse', async () => {
    const {page, server} = await getTestState();

    const text =
      "This is the text that we are going to try to select. Let's see how it goes.";

    await page.goto(`${server.PREFIX}/input/textarea.html`);
    await page.focus('textarea');
    await page.keyboard.type(text);
    using handle = await page
      .locator('textarea')
      .filterHandle(async element => {
        return await element.evaluate((element, text) => {
          return element.value === text;
        }, text);
      })
      .waitHandle();
    const {x, y} = await page.evaluate(dimensions);
    await page.mouse.move(x + 2, y + 2);
    await page.mouse.down();
    await page.mouse.move(100, 100);
    await page.mouse.up();
    expect(
      await handle.evaluate(element => {
        return element.value.substring(
          element.selectionStart,
          element.selectionEnd,
        );
      }),
    ).toBe(text);
  });
  it('should trigger hover state', async () => {
    const {page, server} = await getTestState();

    await page.goto(server.PREFIX + '/input/scrollable.html');
    await page.hover('#button-6');
    expect(
      await page.evaluate(() => {
        return document.querySelector('button:hover')!.id;
      }),
    ).toBe('button-6');
    await page.hover('#button-2');
    expect(
      await page.evaluate(() => {
        return document.querySelector('button:hover')!.id;
      }),
    ).toBe('button-2');
    await page.hover('#button-91');
    expect(
      await page.evaluate(() => {
        return document.querySelector('button:hover')!.id;
      }),
    ).toBe('button-91');
  });
  it('should trigger hover state with removed window.Node', async () => {
    const {page, server} = await getTestState();

    await page.goto(server.PREFIX + '/input/scrollable.html');
    await page.evaluate(() => {
      // @ts-expect-error Expected.
      return delete window.Node;
    });
    await page.hover('#button-6');
    expect(
      await page.evaluate(() => {
        return document.querySelector('button:hover')!.id;
      }),
    ).toBe('button-6');
  });
  it('should set modifier keys on click', async () => {
    const {page, server, isFirefox} = await getTestState();

    await page.goto(server.PREFIX + '/input/scrollable.html');
    await page.evaluate(() => {
      return document.querySelector('#button-3')!.addEventListener(
        'mousedown',
        e => {
          return ((globalThis as any).lastEvent = e);
        },
        true,
      );
    });
    const modifiers = new Map<KeyInput, string>([
      ['Shift', 'shiftKey'],
      ['Control', 'ctrlKey'],
      ['Alt', 'altKey'],
      ['Meta', 'metaKey'],
    ]);
    // In Firefox, the Meta modifier only exists on Mac
    if (isFirefox && os.platform() !== 'darwin') {
      modifiers.delete('Meta');
    }
    for (const [modifier, key] of modifiers) {
      await page.keyboard.down(modifier);
      await page.click('#button-3');
      if (
        !(await page.evaluate(mod => {
          return (globalThis as any).lastEvent[mod];
        }, key))
      ) {
        throw new Error(key + ' should be true');
      }
      await page.keyboard.up(modifier);
    }
    await page.click('#button-3');
    for (const [modifier, key] of modifiers) {
      if (
        await page.evaluate(mod => {
          return (globalThis as any).lastEvent[mod];
        }, key)
      ) {
        throw new Error(modifiers.get(modifier) + ' should be false');
      }
    }
  });
  it('should send mouse wheel events', async () => {
    const {page, server} = await getTestState();

    await page.goto(server.PREFIX + '/input/wheel.html');
    using elem = (await page.$('div'))!;
    const boundingBoxBefore = (await elem.boundingBox())!;
    expect(boundingBoxBefore).toMatchObject({
      width: 115,
      height: 115,
    });

    await page.mouse.move(
      boundingBoxBefore.x + boundingBoxBefore.width / 2,
      boundingBoxBefore.y + boundingBoxBefore.height / 2,
    );

    await page.mouse.wheel({deltaY: -100});
    const boundingBoxAfter = await elem.boundingBox();
    expect(boundingBoxAfter).toMatchObject({
      width: 230,
      height: 230,
    });
  });
  it('should set ctrlKey on the wheel event', async () => {
    const {page, server, isFirefox} = await getTestState();
    await page.goto(server.EMPTY_PAGE);
    const ctrlKey = page.evaluate(() => {
      return new Promise(resolve => {
        window.addEventListener(
          'wheel',
          event => {
            resolve(event.ctrlKey);
          },
          {
            once: true,
          },
        );
      });
    });
    await page.keyboard.down('Control');
    await page.mouse.wheel({deltaY: -100});
    // Scroll back to work around
    // https://bugzilla.mozilla.org/show_bug.cgi?id=1901211.
    if (isFirefox) {
      await page.mouse.wheel({deltaY: 100});
    }
    await page.keyboard.up('Control');
    expect(await ctrlKey).toBeTruthy();
  });
  it('should tween mouse movement', async () => {
    const {page} = await getTestState();

    await page.mouse.move(100, 100);
    await page.evaluate(() => {
      (globalThis as any).result = [];
      document.addEventListener('mousemove', event => {
        (globalThis as any).result.push([event.clientX, event.clientY]);
      });
    });
    await page.mouse.move(200, 300, {steps: 5});
    expect(await page.evaluate('result')).toEqual([
      [120, 140],
      [140, 180],
      [160, 220],
      [180, 260],
      [200, 300],
    ]);
  });
  // @see https://crbug.com/929806
  it('should work with mobile viewports and cross process navigations', async () => {
    const {page, server} = await getTestState();

    await page.goto(server.EMPTY_PAGE);
    await page.setViewport({width: 360, height: 640, isMobile: true});
    await page.goto(server.CROSS_PROCESS_PREFIX + '/mobile.html');
    await page.evaluate(() => {
      document.addEventListener('click', event => {
        (globalThis as any).result = {x: event.clientX, y: event.clientY};
      });
    });

    await page.mouse.click(30, 40);

    expect(await page.evaluate('result')).toEqual({x: 30, y: 40});
  });
  it('should not throw if buttons are pressed twice', async () => {
    const {page, server} = await getTestState();

    await page.goto(server.EMPTY_PAGE);

    await page.mouse.down();
    await page.mouse.down();
  });

  interface AddMouseDataListenersOptions {
    includeMove?: boolean;
  }

  const addMouseDataListeners = (
    page: Page,
    options: AddMouseDataListenersOptions = {},
  ) => {
    return page.evaluate(({includeMove}) => {
      const clicks: ClickData[] = [];
      const mouseEventListener = (event: MouseEvent) => {
        clicks.push({
          type: event.type,
          detail: event.detail,
          clientX: event.clientX,
          clientY: event.clientY,
          isTrusted: event.isTrusted,
          button: event.button,
          buttons: event.buttons,
        });
      };
      document.addEventListener('mousedown', mouseEventListener);
      if (includeMove) {
        document.addEventListener('mousemove', mouseEventListener);
      }
      document.addEventListener('mouseup', mouseEventListener);
      document.addEventListener('click', mouseEventListener);
      document.addEventListener('auxclick', mouseEventListener);
      (window as unknown as {clicks: ClickData[]}).clicks = clicks;
    }, options);
  };

  it('should not throw if clicking in parallel', async () => {
    const {page, server} = await getTestState();

    await page.goto(server.EMPTY_PAGE);
    await addMouseDataListeners(page);

    await Promise.all([page.mouse.click(0, 5), page.mouse.click(6, 10)]);

    const data = await page.evaluate(() => {
      return (window as unknown as {clicks: ClickData[]}).clicks;
    });
    const commonAttrs = {
      isTrusted: true,
      detail: 1,
      clientY: 5,
      clientX: 0,
      button: 0,
    };
    expect(data.splice(0, 3)).toMatchObject({
      0: {
        type: 'mousedown',
        buttons: 1,
        ...commonAttrs,
      },
      1: {
        type: 'mouseup',
        buttons: 0,
        ...commonAttrs,
      },
      2: {
        type: 'click',
        buttons: 0,
        ...commonAttrs,
      },
    });
    Object.assign(commonAttrs, {
      clientX: 6,
      clientY: 10,
    });
    expect(data).toMatchObject({
      0: {
        type: 'mousedown',
        buttons: 1,
        ...commonAttrs,
      },
      1: {
        type: 'mouseup',
        buttons: 0,
        ...commonAttrs,
      },
      2: {
        type: 'click',
        buttons: 0,
        ...commonAttrs,
      },
    });
  });

  it('should reset properly', async () => {
    const {page, server, isChrome} = await getTestState();

    await page.goto(server.EMPTY_PAGE);

    await page.mouse.move(5, 5);
    await Promise.all([
      page.mouse.down({button: MouseButton.Left}),
      page.mouse.down({button: MouseButton.Middle}),
      page.mouse.down({button: MouseButton.Right}),
    ]);

    await addMouseDataListeners(page, {includeMove: true});
    await page.mouse.reset();

    const data = await page.evaluate(() => {
      return (window as unknown as {clicks: ClickData[]}).clicks;
    });
    const commonAttrs = {
      isTrusted: true,
      clientY: 5,
      clientX: 5,
    };

    expect(data.slice(0, 2)).toMatchObject([
      {
        ...commonAttrs,
        button: 2,
        buttons: 5,
        detail: 1,
        type: 'mouseup',
      },
      {
        ...commonAttrs,
        button: 2,
        buttons: 5,
        detail: 1,
        type: 'auxclick',
      },
    ]);
    // TODO(crbug/1485040): This should align with the firefox implementation.
    if (isChrome) {
      expect(data.slice(2)).toMatchObject([
        {
          ...commonAttrs,
          button: 1,
          buttons: 1,
          detail: 0,
          type: 'mouseup',
        },
        {
          ...commonAttrs,
          button: 0,
          buttons: 0,
          detail: 0,
          type: 'mouseup',
        },
      ]);
      return;
    }
    expect(data.slice(2)).toMatchObject([
      {
        ...commonAttrs,
        button: 1,
        buttons: 1,
        detail: 1,
        type: 'mouseup',
      },
      {
        ...commonAttrs,
        button: 1,
        buttons: 1,
        detail: 1,
        type: 'auxclick',
      },
      {
        ...commonAttrs,
        button: 0,
        buttons: 0,
        detail: 1,
        type: 'mouseup',
      },
      {
        ...commonAttrs,
        button: 0,
        buttons: 0,
        detail: 1,
        type: 'click',
      },
    ]);
  });

  it('should evaluate before mouse event', async () => {
    const {page, server} = await getTestState();

    await page.goto(server.EMPTY_PAGE);
    await page.goto(server.CROSS_PROCESS_PREFIX + '/input/button.html');

    using button = await page.waitForSelector('button');

    const point = await button!.clickablePoint();

    const result = page.evaluate(() => {
      return new Promise(resolve => {
        document
          .querySelector('button')
          ?.addEventListener('click', resolve, {once: true});
      });
    });
    await page.mouse.click(point?.x, point?.y);
    await result;
  });
});

[ Dauer der Verarbeitung: 0.35 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


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