diff --git a/install.js b/install.js index 38c5815ac1..0f49b4a11b 100644 --- a/install.js +++ b/install.js @@ -18,6 +18,7 @@ if (require('./package.json').name === 'playwright-core') return; +const browserSkips = {Chromium: false, Firefox: false, WebKit: false}; for (const browser of ['Chromium', 'Firefox', 'WebKit']) { const templates = [ `PLAYWRIGHT_SKIP_${browser}_DOWNLOAD`, @@ -28,7 +29,8 @@ for (const browser of ['Chromium', 'Firefox', 'WebKit']) { for (const varName of varNames) { if (process.env[varName.toUpperCase()]) { logPolitely(`**INFO** Skipping ${browser} download. "${varName}" environment variable was found.`); - return; + browserSkips[browser] = true; + break; } } } @@ -47,14 +49,18 @@ if (require('fs').existsSync(require('path').join(__dirname, 'src'))) { (async function() { const {generateWebKitProtocol, generateChromeProtocol} = require('./utils/protocol-types-generator/') ; + if (!browserSkips.Chromium) { + const chromeRevision = await downloadBrowser('chromium', require('./chromium').createBrowserFetcher({host: downloadHost})); + await generateChromeProtocol(chromeRevision); + } - const chromeRevision = await downloadBrowser('chromium', require('./chromium').createBrowserFetcher({host: downloadHost})); - await generateChromeProtocol(chromeRevision); + if (!browserSkips.Firefox) + await downloadBrowser('firefox', require('./firefox').createBrowserFetcher({host: downloadHost})); - await downloadBrowser('firefox', require('./firefox').createBrowserFetcher({host: downloadHost})); - - const webkitRevision = await downloadBrowser('webkit', require('./webkit').createBrowserFetcher({host: downloadHost})); - await generateWebKitProtocol(webkitRevision); + if (!browserSkips.WebKit) { + const webkitRevision = await downloadBrowser('webkit', require('./webkit').createBrowserFetcher({host: downloadHost})); + await generateWebKitProtocol(webkitRevision); + } })(); function getRevision(browser) { if (browser === 'chromium') diff --git a/package.json b/package.json index df10ab45b7..ce0dfdad43 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "playwright": { "chromium_revision": "706915", "firefox_revision": "1", - "webkit_revision": "1" + "webkit_revision": "2" }, "scripts": { "unit": "node test/test.js", diff --git a/src/USKeyboardLayout.ts b/src/USKeyboardLayout.ts index fc046d5c3c..67be3d9d60 100644 --- a/src/USKeyboardLayout.ts +++ b/src/USKeyboardLayout.ts @@ -23,7 +23,8 @@ type KeyDefinition = { code?: string text?: string shiftText?: string - location ?: number + location ?: number, + windowsVirtualKeyCode?: number; } export const keyDefinitions: { [s: string]: KeyDefinition; } = { @@ -48,12 +49,12 @@ export const keyDefinitions: { [s: string]: KeyDefinition; } = { 'Enter': {'keyCode': 13, 'code': 'Enter', 'key': 'Enter', 'text': '\r'}, '\r': {'keyCode': 13, 'code': 'Enter', 'key': 'Enter', 'text': '\r'}, '\n': {'keyCode': 13, 'code': 'Enter', 'key': 'Enter', 'text': '\r'}, - 'ShiftLeft': {'keyCode': 16, 'code': 'ShiftLeft', 'key': 'Shift', 'location': 1}, - 'ShiftRight': {'keyCode': 16, 'code': 'ShiftRight', 'key': 'Shift', 'location': 2}, - 'ControlLeft': {'keyCode': 17, 'code': 'ControlLeft', 'key': 'Control', 'location': 1}, - 'ControlRight': {'keyCode': 17, 'code': 'ControlRight', 'key': 'Control', 'location': 2}, - 'AltLeft': {'keyCode': 18, 'code': 'AltLeft', 'key': 'Alt', 'location': 1}, - 'AltRight': {'keyCode': 18, 'code': 'AltRight', 'key': 'Alt', 'location': 2}, + 'ShiftLeft': {'keyCode': 16, 'code': 'ShiftLeft', 'key': 'Shift', 'location': 1, 'windowsVirtualKeyCode': 160}, + 'ShiftRight': {'keyCode': 16, 'code': 'ShiftRight', 'key': 'Shift', 'location': 2, 'windowsVirtualKeyCode': 161}, + 'ControlLeft': {'keyCode': 17, 'code': 'ControlLeft', 'key': 'Control', 'location': 1, 'windowsVirtualKeyCode': 162}, + 'ControlRight': {'keyCode': 17, 'code': 'ControlRight', 'key': 'Control', 'location': 2, 'windowsVirtualKeyCode': 163}, + 'AltLeft': {'keyCode': 18, 'code': 'AltLeft', 'key': 'Alt', 'location': 1, 'windowsVirtualKeyCode': 164}, + 'AltRight': {'keyCode': 18, 'code': 'AltRight', 'key': 'Alt', 'location': 2, 'windowsVirtualKeyCode': 165}, 'Pause': {'keyCode': 19, 'code': 'Pause', 'key': 'Pause'}, 'CapsLock': {'keyCode': 20, 'code': 'CapsLock', 'key': 'CapsLock'}, 'Escape': {'keyCode': 27, 'code': 'Escape', 'key': 'Escape'}, @@ -175,9 +176,9 @@ export const keyDefinitions: { [s: string]: KeyDefinition; } = { 'Props': {'keyCode': 247, 'code': 'Props', 'key': 'CrSel'}, 'Cancel': {'keyCode': 3, 'key': 'Cancel', 'code': 'Abort'}, 'Clear': {'keyCode': 12, 'key': 'Clear', 'code': 'Numpad5', 'location': 3}, - 'Shift': {'keyCode': 16, 'key': 'Shift', 'code': 'ShiftLeft', 'location': 1}, - 'Control': {'keyCode': 17, 'key': 'Control', 'code': 'ControlLeft', 'location': 1}, - 'Alt': {'keyCode': 18, 'key': 'Alt', 'code': 'AltLeft', 'location': 1}, + 'Shift': {'keyCode': 16, 'key': 'Shift', 'code': 'ShiftLeft', 'location': 1, 'windowsVirtualKeyCode': 160}, + 'Control': {'keyCode': 17, 'key': 'Control', 'code': 'ControlLeft', 'location': 1, 'windowsVirtualKeyCode': 162}, + 'Alt': {'keyCode': 18, 'key': 'Alt', 'code': 'AltLeft', 'location': 1, 'windowsVirtualKeyCode': 164}, 'Accept': {'keyCode': 30, 'key': 'Accept'}, 'ModeChange': {'keyCode': 31, 'key': 'ModeChange'}, ' ': {'keyCode': 32, 'key': ' ', 'code': 'Space'}, diff --git a/src/webkit/Input.ts b/src/webkit/Input.ts index 19535bd8a9..c6277c408e 100644 --- a/src/webkit/Input.ts +++ b/src/webkit/Input.ts @@ -24,7 +24,7 @@ type KeyDescription = { key: string, text: string, code: string, - location: number, + isKeypad: boolean }; export type Modifier = 'Alt' | 'Control' | 'Meta' | 'Shift'; @@ -58,7 +58,7 @@ export class Keyboard { text: text, unmodifiedText: text, autoRepeat, - isKeypad: description.location === 3, + isKeypad: description.isKeypad, }); } @@ -86,7 +86,7 @@ export class Keyboard { keyCode: 0, code: '', text: '', - location: 0 + isKeypad: false }; const definition = keyDefinitions[keyString]; @@ -98,15 +98,13 @@ export class Keyboard { description.key = definition.shiftKey; if (definition.keyCode) - description.keyCode = definition.keyCode; + description.keyCode = definition.windowsVirtualKeyCode || definition.keyCode; if (shift && definition.shiftKeyCode) description.keyCode = definition.shiftKeyCode; if (definition.code) description.code = definition.code; - if (definition.location) - description.location = definition.location; if (description.key.length === 1) description.text = description.key; @@ -117,9 +115,11 @@ export class Keyboard { description.text = definition.shiftText; // if any modifiers besides shift are pressed, no text should be sent - if (this._modifiers & ~8) + if (this._modifiers & ~1) description.text = ''; + description.isKeypad = definition.location === 3; + return description; } @@ -146,7 +146,7 @@ export class Keyboard { } else { if (delay) await new Promise(f => setTimeout(f, delay)); - // unsupported character + await this.sendCharacter(char); } } } @@ -179,6 +179,12 @@ export class Keyboard { await Promise.all(promises); return restore; } + + async sendCharacter(text: string) { + await this._session.send('Page.insertText', { + text + }); + } } export class Mouse { diff --git a/test/keyboard.spec.js b/test/keyboard.spec.js index e9597f610a..a7d0f92bf9 100644 --- a/test/keyboard.spec.js +++ b/test/keyboard.spec.js @@ -67,13 +67,13 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) { await textarea.press('b'); expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('a'); }); - it.skip(FFOX || WEBKIT)('ElementHandle.press should support |text| option', async({page, server}) => { + it.skip(FFOX)('ElementHandle.press should support |text| option', async({page, server}) => { await page.goto(server.PREFIX + '/input/textarea.html'); const textarea = await page.$('textarea'); await textarea.press('a', {text: 'ё'}); expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('ё'); }); - it.skip(WEBKIT)('should send a character with sendCharacter', async({page, server}) => { + it('should send a character with sendCharacter', async({page, server}) => { await page.goto(server.PREFIX + '/input/textarea.html'); await page.focus('textarea'); await page.keyboard.sendCharacter('嗨'); @@ -82,7 +82,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) { await page.keyboard.sendCharacter('a'); expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('嗨a'); }); - it.skip(WEBKIT)('should report shiftKey', async({page, server}) => { + it('should report shiftKey', async({page, server}) => { await page.goto(server.PREFIX + '/input/keyboard.html'); const keyboard = page.keyboard; const codeForKey = {'Shift': 16, 'Alt': 18, 'Control': 17}; @@ -102,7 +102,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) { expect(await page.evaluate(() => getResult())).toBe('Keyup: ' + modifierKey + ' ' + modifierKey + 'Left ' + codeForKey[modifierKey] + ' []'); } }); - it.skip(WEBKIT)('should report multiple modifiers', async({page, server}) => { + it('should report multiple modifiers', async({page, server}) => { await page.goto(server.PREFIX + '/input/keyboard.html'); const keyboard = page.keyboard; await keyboard.down('Control'); @@ -118,7 +118,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) { await keyboard.up('Alt'); expect(await page.evaluate(() => getResult())).toBe('Keyup: Alt AltLeft 18 []'); }); - it.skip(WEBKIT)('should send proper codes while typing', async({page, server}) => { + it('should send proper codes while typing', async({page, server}) => { await page.goto(server.PREFIX + '/input/keyboard.html'); await page.keyboard.type('!'); expect(await page.evaluate(() => getResult())).toBe( @@ -131,7 +131,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) { 'Keypress: ^ Digit6 94 94 []', 'Keyup: ^ Digit6 54 []'].join('\n')); }); - it.skip(WEBKIT)('should send proper codes while typing with shift', async({page, server}) => { + it('should send proper codes while typing with shift', async({page, server}) => { await page.goto(server.PREFIX + '/input/keyboard.html'); const keyboard = page.keyboard; await keyboard.down('Shift'); @@ -143,7 +143,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) { 'Keyup: ~ Backquote 192 [Shift]'].join('\n')); await keyboard.up('Shift'); }); - it.skip(WEBKIT)('should not type canceled events', async({page, server}) => { + it('should not type canceled events', async({page, server}) => { await page.goto(server.PREFIX + '/input/textarea.html'); await page.focus('textarea'); await page.evaluate(() => { @@ -159,7 +159,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) { await page.keyboard.type('Hello World!'); expect(await page.evaluate(() => textarea.value)).toBe('He Wrd!'); }); - it.skip(WEBKIT)('should specify repeat property', async({page, server}) => { + it('should specify repeat property', async({page, server}) => { await page.goto(server.PREFIX + '/input/textarea.html'); await page.focus('textarea'); await page.evaluate(() => document.querySelector('textarea').addEventListener('keydown', e => window.lastEvent = e, true)); @@ -177,14 +177,14 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) { await page.keyboard.down('a'); expect(await page.evaluate(() => window.lastEvent.repeat)).toBe(false); }); - it.skip(WEBKIT)('should type all kinds of characters', async({page, server}) => { + it('should type all kinds of characters', async({page, server}) => { await page.goto(server.PREFIX + '/input/textarea.html'); await page.focus('textarea'); const text = 'This text goes onto two lines.\nThis character is 嗨.'; await page.keyboard.type(text); expect(await page.evaluate('result')).toBe(text); }); - it.skip(WEBKIT)('should specify location', async({page, server}) => { + it('should specify location', async({page, server}) => { await page.goto(server.PREFIX + '/input/textarea.html'); await page.evaluate(() => { window.addEventListener('keydown', event => window.keyLocation = event.location, true); @@ -203,7 +203,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) { await textarea.press('NumpadSubtract'); expect(await page.evaluate('keyLocation')).toBe(3); }); - it.skip(WEBKIT)('should throw on unknown keys', async({page, server}) => { + it('should throw on unknown keys', async({page, server}) => { let error = await page.keyboard.press('NotARealKey').catch(e => e); expect(error.message).toBe('Unknown key: "NotARealKey"'); @@ -213,12 +213,12 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) { error = await page.keyboard.press('😊').catch(e => e); expect(error && error.message).toBe('Unknown key: "😊"'); }); - it.skip(WEBKIT)('should type emoji', async({page, server}) => { + it('should type emoji', async({page, server}) => { await page.goto(server.PREFIX + '/input/textarea.html'); await page.type('textarea', '👹 Tokyo street Japan 🇯🇵'); expect(await page.$eval('textarea', textarea => textarea.value)).toBe('👹 Tokyo street Japan 🇯🇵'); }); - it.skip(WEBKIT)('should type emoji into an iframe', async({page, server}) => { + it('should type emoji into an iframe', async({page, server}) => { await page.goto(server.EMPTY_PAGE); await utils.attachFrame(page, 'emoji-test', server.PREFIX + '/input/textarea.html'); const frame = page.frames()[1]; @@ -226,7 +226,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) { await textarea.type('👹 Tokyo street Japan 🇯🇵'); expect(await frame.$eval('textarea', textarea => textarea.value)).toBe('👹 Tokyo street Japan 🇯🇵'); }); - it.skip(WEBKIT)('should press the meta key', async({page}) => { + it('should press the meta key', async({page}) => { await page.evaluate(() => { window.result = null; document.addEventListener('keydown', event => {