mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-19 06:07:40 +00:00
test(web): add e2e tests for examples from guide
Build-bot: skip build:web Test-bot: skip
This commit is contained in:
parent
58a565be21
commit
bda4b50e2a
8 changed files with 353 additions and 15 deletions
15
web/build.sh
15
web/build.sh
|
|
@ -114,6 +114,21 @@ build_tests_action() {
|
|||
|
||||
cp "${KEYMAN_ROOT}/web/src/test/auto/dom/cases/attachment/textStoreForElement.tests.html" \
|
||||
"${KEYMAN_ROOT}/web/build/test/dom/cases/attachment/"
|
||||
|
||||
# Copy and update guide examples - for local, PR, and test builds we
|
||||
# replace the CDN URL with the local build path, so that we can test
|
||||
# against the current build
|
||||
mkdir -p "${KEYMAN_ROOT}/web/build/docs/engine/guide"
|
||||
cp -r "${KEYMAN_ROOT}/web/docs/engine/guide/examples" \
|
||||
"${KEYMAN_ROOT}/web/build/docs/engine/guide/"
|
||||
|
||||
# shellcheck disable=SC2310
|
||||
if ! builder_is_ci_release_build; then
|
||||
for f in "${KEYMAN_ROOT}/web/build/docs/engine/guide/examples"/*.html; do
|
||||
sed "s|https://s\.keyman\.com/kmw/engine/[0-9]*\.[0-9]*\.[0-9]*/|/build/publish/${config}/|g" \
|
||||
"${f}" > "${f}.tmp" && mv "${f}.tmp" "${f}"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
coverage_action() {
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
<body>
|
||||
<h1>Automatic Mode Example</h1>
|
||||
<form action='.' method='post'>
|
||||
<p><input type='text' id='multilingual' name='multilingual' size="40" /></p>
|
||||
<p><textarea cols='40' rows='5'></textarea></p>
|
||||
<p><input type='text' id='multilingual' name='multilingual' size="40" data-testid='multilingual'/></p>
|
||||
<p><textarea cols='40' rows='5' data-testid='textarea'></textarea></p>
|
||||
</form>
|
||||
|
||||
<a href="automatic-control">Back to Document</a>
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ keyman.init().then(async function() {
|
|||
}
|
||||
document.f.multilingual.focus();
|
||||
|
||||
keyman.setActiveKeyboard('', '');
|
||||
await keyman.setActiveKeyboard('', '');
|
||||
});
|
||||
|
||||
function KWControlChange() {
|
||||
async function KWControlChange() {
|
||||
var name = KWControl.value.substr(0, KWControl.value.indexOf("$$"));
|
||||
var languageCode = KWControl.value.substr(KWControl.value.indexOf("$$") + 2);
|
||||
keyman.setActiveKeyboard(name, languageCode);
|
||||
await keyman.setActiveKeyboard(name, languageCode);
|
||||
document.f.multilingual.focus();
|
||||
}
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ function KWControlChange() {
|
|||
<h1>Manual Control - Custom Interface</h1>
|
||||
<form name='f' action='.' method='post'>
|
||||
|
||||
<p>Keyboard: <select id='KWControl' onchange='KWControlChange()'><option value=''>English</option></select></p>
|
||||
<p><label for='KWControl'>Keyboard:</label> <select id='KWControl' onchange='KWControlChange()'><option value=''>English</option></select></p>
|
||||
|
||||
<p><input type='text' id='multilingual' name='multilingual' size="40" placeholder="id='multilingual'"/></p>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
languages: { id: 'lo', name: 'Lao' },
|
||||
filename: "./js/laokeys.js"
|
||||
});
|
||||
keyman.setActiveKeyboard('laokeys');
|
||||
await keyman.setActiveKeyboard('laokeys');
|
||||
keyman.osk.hide();
|
||||
});
|
||||
|
||||
|
|
@ -30,8 +30,8 @@
|
|||
|
||||
<p><img style="border: solid 1px black; padding: 2px 2px 3px 2px" src='js/kmicon.png' alt='KeymanWeb' onclick='KWControlClick()' id='KWControl' /></p>
|
||||
|
||||
<p><input type='text' id='multilingual' name='multilingual' size="40" /></p>
|
||||
<p><textarea cols='40' rows='5'></textarea></p>
|
||||
<p><input type='text' id='multilingual' name='multilingual' size="40" data-testid='multilingual'/></p>
|
||||
<p><textarea cols='40' rows='5' data-testid='textarea'></textarea></p>
|
||||
|
||||
<a href="manual-control">Back to Document</a>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -28,15 +28,15 @@ Include the following script in the HEAD of your page:
|
|||
}
|
||||
document.f.multilingual.focus();
|
||||
|
||||
keyman.setActiveKeyboard('', '');
|
||||
await keyman.setActiveKeyboard('', '');
|
||||
});
|
||||
|
||||
/* KWControlChange: Called when user selects an item in the KWControl SELECT */
|
||||
function KWControlChange() {
|
||||
async function KWControlChange() {
|
||||
/* Select the keyboard in KeymanWeb */
|
||||
var name = KWControl.value.substr(0, KWControl.value.indexOf("$$"));
|
||||
var languageCode = KWControl.value.substr(KWControl.value.indexOf("$$"+2));
|
||||
keyman.setActiveKeyboard(name, languageCode);
|
||||
var languageCode = KWControl.value.substr(KWControl.value.indexOf("$$") + 2);
|
||||
await keyman.setActiveKeyboard(name, languageCode);
|
||||
/* Focus onto the multilingual field in the form */
|
||||
document.f.multilingual.focus();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@
|
|||
title: Manual Mode Example
|
||||
---
|
||||
|
||||
In this example, the web page designer specifies when KeymanWeb's on-screen keyboard may be displayed on non-mobile devices. They have also specified that the LaoKeys keyboard should be activated by default. This example continues to use the KeymanWeb default interface. Please click [this link](__manual-control.html) to open the test page.
|
||||
In this example, the web page designer specifies when KeymanWeb's on-screen keyboard may be
|
||||
displayed on non-mobile devices. They have also specified that the LaoKeys keyboard should be
|
||||
activated by default. This example continues to use the KeymanWeb default interface. Please click
|
||||
[this link](__manual-control.html) to open the test page.
|
||||
|
||||
## Code Walkthrough
|
||||
|
||||
|
|
@ -17,7 +20,7 @@ Include the following script in the HEAD of your page:
|
|||
languages:{id:'lo',name:'Lao'},
|
||||
filename: "./js/laokeys.js"
|
||||
});
|
||||
keyman.setActiveKeyboard('laokeys');
|
||||
await keyman.setActiveKeyboard('laokeys');
|
||||
keyman.osk.hide();
|
||||
});
|
||||
|
||||
|
|
|
|||
64
web/src/test/auto/e2e/e2eUtils.ts
Normal file
64
web/src/test/auto/e2e/e2eUtils.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
|
||||
import { type Locator, type Page } from "@playwright/test";
|
||||
|
||||
/**
|
||||
* Expands the keyboard selection menu and returns the text content of the
|
||||
* currently selected keyboard.
|
||||
*/
|
||||
export async function getSelectedKeyboardMenuText(page: Page): Promise<string | undefined> {
|
||||
const watchDog = page.waitForFunction(() => !!document.getElementById('KeymanWeb_KbdList'));
|
||||
await page.getByRole('img', { name: 'Use Web Keyboard' }).click();
|
||||
await watchDog;
|
||||
return page.evaluate(() => {
|
||||
const selectedKbd = document.querySelector('#kmwico .selected');
|
||||
return selectedKbd?.textContent;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Expands the keyboard selection menu and returns the menu items as an array
|
||||
*/
|
||||
export async function getAllKeyboardMenuText(page: Page): Promise<(string|undefined)[]> {
|
||||
const watchDog = page.waitForFunction(() => !!document.getElementById('KeymanWeb_KbdList'));
|
||||
await page.getByRole('img', { name: 'Use Web Keyboard' }).hover();
|
||||
await watchDog;
|
||||
return page.evaluate(() => {
|
||||
const menuItems = [];
|
||||
const menuDiv = document.querySelector('#kmwico');
|
||||
const kbdList = menuDiv?.lastElementChild;
|
||||
for (let i = 0; i < (kbdList ? kbdList.children.length : 0); i++) {
|
||||
const item = kbdList?.children[i];
|
||||
menuItems.push(item?.textContent);
|
||||
}
|
||||
return menuItems;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the specified URL and waits for the page load event.
|
||||
*/
|
||||
export async function loadPage(page: Page, url: string): Promise<Page> {
|
||||
const loadPromise = page.waitForEvent('load');
|
||||
await page.goto(url);
|
||||
return loadPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks the specified field and waits for the OSK to be shown, returning a
|
||||
* locator for the OSK title bar.
|
||||
*/
|
||||
export async function clickFieldAndWaitForOSK(page: Page, fieldLocator: Locator): Promise<Locator> {
|
||||
const keyboardchangePromise = page.evaluate(async () => {
|
||||
return new Promise((resolve) => {
|
||||
keyman.addEventListener('keyboardchange', function (kbd) {
|
||||
resolve(kbd);
|
||||
});
|
||||
});
|
||||
});
|
||||
await fieldLocator.click();
|
||||
await keyboardchangePromise;
|
||||
return page.locator('#keymanweb_title_bar');
|
||||
}
|
||||
256
web/src/test/auto/e2e/guide-examples.tests.ts
Normal file
256
web/src/test/auto/e2e/guide-examples.tests.ts
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
import { test, expect, type Page } from '@playwright/test';
|
||||
import { clickFieldAndWaitForOSK, getAllKeyboardMenuText, getSelectedKeyboardMenuText, loadPage } from './e2eUtils';
|
||||
|
||||
async function setTimeoutAndLoadPage(page: Page, url: string): Promise<void> {
|
||||
test.setTimeout(5000);
|
||||
await loadPage(page, url);
|
||||
}
|
||||
|
||||
test.describe('First example from the guide', function () {
|
||||
const beforeEach = async (page: Page) => {
|
||||
await setTimeoutAndLoadPage(page, 'http://localhost:3000/build/docs/engine/guide/examples/__first-example.html');
|
||||
}
|
||||
|
||||
test('Input field shows US keyboard', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
const oskTitleBar = await clickFieldAndWaitForOSK(page, page.getByPlaceholder('Hello World'));
|
||||
|
||||
// Verify OSK shows US keyboard
|
||||
await expect(page.getByRole('img', { name: 'Use Web Keyboard' })).toBeVisible();
|
||||
await expect(page.getByRole('img', { name: 'Show On Screen Keyboard' })).toBeVisible();
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).toBeTruthy();
|
||||
await expect(oskTitleBar).toContainText('US');
|
||||
|
||||
await expect(await getSelectedKeyboardMenuText(page)).toBe('English - US');
|
||||
});
|
||||
|
||||
test('Keyman menu has expected keyboards', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
await clickFieldAndWaitForOSK(page, page.getByPlaceholder('Hello World'));
|
||||
|
||||
// Verify OSK menu has expected entries
|
||||
await expect(page.getByRole('img', { name: 'Use Web Keyboard' })).toBeVisible();
|
||||
await expect(page.getByRole('img', { name: 'Show On Screen Keyboard' })).toBeVisible();
|
||||
await expect(await getAllKeyboardMenuText(page)).toEqual(['(System keyboard)', 'English - US', 'Thai - Thai Kedmanee Basic'])
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Auto-control example from the guide', function () {
|
||||
const beforeEach = async (page: Page) => {
|
||||
await setTimeoutAndLoadPage(page, 'http://localhost:3000/build/docs/engine/guide/examples/__auto-control.html');
|
||||
}
|
||||
|
||||
test('Input field shows Lao keyboard', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
await page.getByTestId('multilingual' ).click();
|
||||
|
||||
// Verify OSK is shown
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).toBeTruthy();
|
||||
await expect(page.locator('#keymanweb_title_bar')).toContainText('Lao (Phonetic)');
|
||||
});
|
||||
|
||||
test('Textarea shows Lao keyboard', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
await page.getByTestId('textarea').click();
|
||||
|
||||
// Verify OSK is shown
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).toBeTruthy();
|
||||
await expect(page.locator('#keymanweb_title_bar')).toContainText('Lao (Phonetic)');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Control-by-control example from the guide', function () {
|
||||
const beforeEach = async (page: Page) => {
|
||||
await setTimeoutAndLoadPage(page, 'http://localhost:3000/build/docs/engine/guide/examples/__control-by-control.html');
|
||||
}
|
||||
|
||||
test('address field does not have KeymanWeb enabled', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
await page.getByPlaceholder('id = address').click();
|
||||
|
||||
// Verify OSK is not shown
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).toBeFalsy();
|
||||
await expect(page.getByRole('img', { name: 'Use Web Keyboard' })).not.toBeVisible();
|
||||
await expect(page.getByRole('img', { name: 'Show On Screen Keyboard' })).not.toBeVisible();
|
||||
});
|
||||
|
||||
// TODO: #16080
|
||||
test.skip('subject field does not show keyboard and defaults to system keyboard', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
await page.getByPlaceholder('id = subject').click();
|
||||
|
||||
// Verify OSK is shown
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).toBeTruthy();
|
||||
await expect(page.getByRole('img', { name: 'Use Web Keyboard' })).toBeVisible();
|
||||
await expect(page.getByRole('img', { name: 'Show On Screen Keyboard' })).not.toBeVisible();
|
||||
|
||||
await expect(await getSelectedKeyboardMenuText(page)).toBe('(System keyboard)');
|
||||
});
|
||||
|
||||
test('message body field shows Lao keyboard', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
await page.getByPlaceholder('id = text').click();
|
||||
|
||||
// Verify OSK is shown
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).toBeTruthy();
|
||||
await expect(page.getByRole('img', { name: 'Use Web Keyboard' })).toBeVisible();
|
||||
await expect(page.getByRole('img', { name: 'Show On Screen Keyboard' })).toBeVisible();
|
||||
|
||||
// Verify Lao (Phonetic) keyboard is active
|
||||
await expect(page.locator('#keymanweb_title_bar')).toContainText('Lao (Phonetic)');
|
||||
// Verify "Lao - Lao (Phonetic)" is selected (bold) in the menu
|
||||
await expect(await getSelectedKeyboardMenuText(page)).toBe('Lao - Lao (Phonetic)');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Full manual control example from the guide', function () {
|
||||
const beforeEach = async (page: Page) => {
|
||||
await setTimeoutAndLoadPage(page, 'http://localhost:3000/build/docs/engine/guide/examples/__full-manual-control.html');
|
||||
}
|
||||
|
||||
test('Shows English and no OSK after loading page', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
|
||||
// Verify 'English' selected (which has the value '') and no OSK showing
|
||||
await expect(page.getByLabel('Keyboard')).toHaveValue('');
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).not.toBeTruthy();
|
||||
});
|
||||
|
||||
test('Selecting English keyboard shows no OSK', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
// first switch to Hebrew
|
||||
let keyboardchangePromise = page.evaluate(async () => {
|
||||
return new Promise((resolve) => {
|
||||
keyman.addEventListener('keyboardchange', function (kbd) {
|
||||
resolve(kbd);
|
||||
});
|
||||
});
|
||||
});
|
||||
await page.getByLabel('Keyboard').selectOption('Hebrew');
|
||||
await keyboardchangePromise;
|
||||
|
||||
// then back to English
|
||||
keyboardchangePromise = page.evaluate(async () => {
|
||||
return new Promise((resolve) => {
|
||||
keyman.addEventListener('keyboardchange', function (kbd) {
|
||||
resolve(kbd);
|
||||
});
|
||||
});
|
||||
});
|
||||
await page.getByLabel('Keyboard').selectOption('English');
|
||||
await keyboardchangePromise;
|
||||
|
||||
// Verify no OSK showing
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).not.toBeTruthy();
|
||||
});
|
||||
|
||||
test('Selecting Devanagari keyboard shows Devanagari OSK', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
const keyboardchangePromise = page.evaluate(async () => {
|
||||
return new Promise((resolve) => {
|
||||
keyman.addEventListener('keyboardchange', function (kbd) {
|
||||
resolve(kbd);
|
||||
});
|
||||
});
|
||||
});
|
||||
await page.getByLabel('Keyboard').selectOption('Devanagari (INSCRIPT)');
|
||||
await keyboardchangePromise;
|
||||
|
||||
// Verify Devanagari OSK showing
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).toBeTruthy();
|
||||
await expect(page.locator('#keymanweb_title_bar')).toContainText('Devanagari (INSCRIPT)');
|
||||
});
|
||||
|
||||
test('Selecting Hebrew shows Hebrew OSK', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
const keyboardchangePromise = page.evaluate(async () => {
|
||||
return new Promise((resolve) => {
|
||||
keyman.addEventListener('keyboardchange', function (kbd) {
|
||||
resolve(kbd);
|
||||
});
|
||||
});
|
||||
});
|
||||
await page.getByLabel('Keyboard').selectOption('Hebrew');
|
||||
await keyboardchangePromise;
|
||||
|
||||
// Verify Hebrew OSK showing
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).toBeTruthy();
|
||||
await expect(page.locator('#keymanweb_title_bar')).toContainText('Hebrew');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Manual control example from the guide', function () {
|
||||
const beforeEach = async (page: Page) => {
|
||||
await setTimeoutAndLoadPage(page, 'http://localhost:3000/build/docs/engine/guide/examples/__manual-control.html');
|
||||
}
|
||||
|
||||
test('Does not show OSK after loading', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
await page.getByTestId('multilingual').click();
|
||||
|
||||
// Verify no OSK showing
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).not.toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).not.toBeTruthy();
|
||||
});
|
||||
|
||||
test('Shows Lao OSK after clicking button', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
await page.getByAltText('KeymanWeb').click();
|
||||
await page.getByTestId('multilingual').click();
|
||||
|
||||
// Verify Lao OSK showing
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).toBeTruthy();
|
||||
await expect(page.locator('#keymanweb_title_bar')).toContainText('Lao');
|
||||
});
|
||||
|
||||
test('Hides Lao OSK after clicking button', async ({ page }) => {
|
||||
// Setup
|
||||
await beforeEach(page);
|
||||
|
||||
// click button
|
||||
await page.getByAltText('KeymanWeb').click();
|
||||
|
||||
// Verify Lao OSK showing
|
||||
await page.getByTestId('multilingual').click();
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).toBeTruthy();
|
||||
await expect(page.locator('#keymanweb_title_bar')).toContainText('Lao');
|
||||
|
||||
// Click button again to hide OSK
|
||||
await page.getByAltText('KeymanWeb').click();
|
||||
|
||||
// Verify Lao OSK not showing
|
||||
await page.getByTestId('multilingual').click();
|
||||
await expect(await page.evaluate(() => keyman.osk.isEnabled())).not.toBeTruthy();
|
||||
await expect(await page.evaluate(() => keyman.osk.isVisible())).not.toBeTruthy();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Add table
Reference in a new issue