microsoft / playwright

Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
https://playwright.dev
Apache License 2.0
65.22k stars 3.55k forks source link

[BUG] CapsLock doesn't work #16214

Open nikolay-yavorovskiy opened 2 years ago

nikolay-yavorovskiy commented 2 years ago

Context:

Code Snippet

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

test('Test CapsLock', async ({ page }) => {
  await page.goto('https://playwright.dev/')
  await page.locator('.DocSearch-Button-Placeholder').click()
  await page.keyboard.press('CapsLock')
  await page.keyboard.press('KeyA')
  await expect(page.locator('.DocSearch-Input')).toHaveValue('A') // actual value is 'a'
})

I was trying to write a test on the password input element which should show the warning message when the CapsLock button is turned on, but run into this issue. It's not a big deal and probably might be a bit painful to fix, but still...

ShaneyWaris commented 1 year ago

Is anyone here who can help me with pressing the "Dot" and "Delete" keys using playwright on mac? What exact string should I pass?

xt0rted commented 1 year ago

Just ran into this issue as well trying to test a capslock warning on password fields.

kumarchandresh commented 1 year ago

Everybody's gonna run into this issue trying to test caps lock warning on password field. 😄

eternalconcert commented 7 months ago

Everybody's gonna run into this issue trying to test caps lock warning on password field. 😄

Yep, same here.. :(

tszynalski commented 5 months ago

I wanted to test CapsLock-related features in a JavaScript text editor -- visual feedback when CapsLock is on, different behavior of buttons for typing special characters. Currently seems impossible to do in Playwright.

kumarchandresh commented 5 months ago

Hacked it using JavaScript! 💀

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

async function pressKey(locator: Locator, key: string, modifiers: { CapsLock?: boolean } = {}) {
  await locator.evaluate((node, { key, modifiers }) => {
    function hacked(event: KeyboardEvent) {
      const _getModifierState = event.getModifierState
      return Object.assign(event, {
        getModifierState: function (key: string) {
          return key == 'CapsLock'
            ? modifiers.CapsLock
            : _getModifierState.call(this, key)
        },
      })
    }
    // Bubbling is needed for jQuery event handlers
    node.dispatchEvent(hacked(new KeyboardEvent('keyup', { key, bubbles: true })))
    node.dispatchEvent(hacked(new KeyboardEvent('keydown', { key, bubbles: true })))
    node.dispatchEvent(hacked(new KeyboardEvent('keypress', { key, bubbles: true })))
  }, { key, modifiers })
}

test('example', async ({ baseURL, page }) => {
  await page.goto(baseURL)
  for (const key of 'secret') {
    await pressKey(page.locator('#password'), key, { CapsLock: true })
  }
  await expect(page.locator('.caps-lock-on')).toBeVisible()
})

Best practice is to manage modifier states using a fixture.

tszynalski commented 4 months ago

@kumarchandresh This works, thanks a lot! Now I can test CapsLock support. BTW, I think you could simply overwrite the .getModifierState method rather than constructing a new object with Object.assign().