diff --git a/README.md b/README.md index 58191b1..1290a88 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ cy.realPress(key, options); | Name | Type | Default value | Description | | --------- | -------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `key` | `string \| string[]` | - | key or keys to press. Should be the same as cypress's [type command argument](https://docs.cypress.io/api/commands/type.html#Arguments). All the keys available [here](https://github.com/dmtrKovalenko/cypress-real-events/blob/main/src/keyCodeDefinitions.ts) | +| `key` | `string \| string[]` | - | key or keys to press. Should be the same as cypress's [type command argument](https://docs.cypress.io/api/commands/type.html#Arguments). | | `options` | Options | {} | | Options: @@ -217,7 +217,7 @@ cy.realType(text, options); | Name | Type | Default value | Description | | --------- | ------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| `text` | string | - | text to type. Should be around the same as cypress's type command argument (https://docs.cypress.io/api/commands/type.html#Arguments. All the keys available [here](https://github.com/dmtrKovalenko/cypress-real-events/blob/main/src/keyCodeDefinitions.ts) | +| `text` | string | - | text to type. Should be around the same as cypress's type command argument | | `options` | Options | {} | | Options: diff --git a/cypress/e2e/press.cy.ts b/cypress/e2e/press.cy.ts index 4fdb40e..5ac98ce 100644 --- a/cypress/e2e/press.cy.ts +++ b/cypress/e2e/press.cy.ts @@ -14,6 +14,19 @@ describe("cy.realPress", { retries: 10 }, () => { cy.get("input").should("have.value", "cypress"); }); + it("Can type non alpha-num into an input", () => { + cy.intercept("http://presstest.com/", (req) => { + const html = document.implementation.createHTMLDocument(); + html.body.innerHTML = ``; + req.reply(html.documentElement.innerHTML); + }); + cy.visit("http://presstest.com/"); + cy.get("input").focus(); + + cy.realPress("😊"); + cy.get("input").should("have.value", "😊"); + }); + it("Can fire native Tab focus switch", () => { cy.visit("./cypress/fixtures/focus-order.html"); cy.window().focus(); diff --git a/cypress/e2e/type.cy.ts b/cypress/e2e/type.cy.ts index c71393a..346c1bf 100644 --- a/cypress/e2e/type.cy.ts +++ b/cypress/e2e/type.cy.ts @@ -38,4 +38,11 @@ describe("cy.realType", () => { cy.realType("{{}test}"); cy.get("input[name=q]").should("have.value", "{test}"); }); + + it("can type text with emoji and cyrillic characters", () => { + const msg = "cypress-real-events is awesome! ❤️❤️❤️❤️❤️❤️ В"; + cy.realType(msg); + + cy.get("input[name=q]").should("have.value", msg); + }); }); diff --git a/src/commands/realPress.ts b/src/commands/realPress.ts index f4e10d9..21f6d3e 100644 --- a/src/commands/realPress.ts +++ b/src/commands/realPress.ts @@ -16,10 +16,29 @@ export interface RealPressOptions { log?: boolean; } -function getKeyDefinition(key: keyof typeof keyCodeDefinitions) { - const keyDefinition = keyCodeDefinitions[key]; +// Emoji Unicode range +const EMOJI_RE = + /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F700}-\u{1F77F}\u{1F780}-\u{1F7FF}\u{1F800}-\u{1F8FF}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u; + +function isEmoji(char: string) { + return EMOJI_RE.test(char); +} + +function getKeyDefinition(key: string) { + const keyDefinition = + keyCodeDefinitions[key as keyof typeof keyCodeDefinitions]; if (!keyDefinition) { + if (key.length === 1 || isEmoji(key)) { + return { + keyCode: key.charCodeAt(0), + key, + text: key, + code: `Key${key.toUpperCase()}`, + location: 0, + windowsVirtualKeyCode: key.charCodeAt(0), + }; + } throw new Error(`Unsupported key '${key}'.`); } @@ -38,11 +57,11 @@ function getKeyDefinition(key: keyof typeof keyCodeDefinitions) { type Key = keyof typeof keyCodeDefinitions; // unfortunately passing a string like Shift+P is not possible cause typescript template literals can not handle such giant union -type KeyOrShortcut = Key | Array; +export type KeyOrShortcut = Key | Array; /** @ignore this, update documentation for this function at index.d.ts */ export async function realPress( - keyOrShortcut: KeyOrShortcut, + keyOrShortcut: string | string[], options: RealPressOptions = {}, ) { let log; diff --git a/src/commands/realType.ts b/src/commands/realType.ts index 5461c24..f67a053 100644 --- a/src/commands/realType.ts +++ b/src/commands/realType.ts @@ -1,7 +1,8 @@ +import { realPress, type KeyOrShortcut } from "./"; import { keyCodeDefinitions } from "../keyCodeDefinitions"; -import { realPress } from "./realPress"; import { wait } from "../utils"; + export interface RealTypeOptions { /** * Delay after each keypress (ms) @@ -20,15 +21,6 @@ export interface RealTypeOptions { log?: boolean; } -const availableChars = Object.keys(keyCodeDefinitions); -function assertChar( - char: string, -): asserts char is keyof typeof keyCodeDefinitions { - if (!availableChars.includes(char)) { - throw new Error(`Unrecognized character "${char}".`); - } -} - /** @ignore this, update documentation for this function at index.d.ts */ export async function realType(text: string, options: RealTypeOptions = {}) { let log; @@ -53,8 +45,7 @@ export async function realType(text: string, options: RealTypeOptions = {}) { }, [] as string[]); for (const char of chars) { - assertChar(char); - await realPress(char, { + await realPress(char as KeyOrShortcut, { pressDelay: options.pressDelay ?? 15, log: false, });