Skip to content

Commit

Permalink
Merge pull request #10250 from keymanapp/chore/web/attachmentTests
Browse files Browse the repository at this point in the history
chore(web): Add unit tests for `pageContextAttachment`
  • Loading branch information
ermshiperete authored Dec 15, 2023
2 parents 69993f6 + f3d2448 commit 3cde93d
Show file tree
Hide file tree
Showing 10 changed files with 677 additions and 38 deletions.
443 changes: 436 additions & 7 deletions package-lock.json

Large diffs are not rendered by default.

48 changes: 28 additions & 20 deletions web/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,28 @@ builder_run_child_actions configure

## Build actions

build_action() {
tsc --project "${KEYMAN_ROOT}/web/src/test/auto/tsconfig.json"
}

test_action() {
TEST_OPTS=
if builder_has_option --ci; then
TEST_OPTS=--ci
fi
./test.sh "${TEST_OPTS}"
}

coverage_action() {
builder_echo "Creating coverage report..."
cd "$KEYMAN_ROOT"
mkdir -p web/build/coverage/tmp
find . -type f -name coverage-\*.json -print0 | xargs -0 cp -t web/build/coverage/tmp
c8 report --config web/.c8rc.json ---reporter html --clean=false --reports-dir=web/build/coverage
rm -rf web/build/coverage/tmp
cd web
}

builder_run_child_actions build:engine/device-detect
builder_run_child_actions build:engine/dom-utils
builder_run_child_actions build:engine/element-wrappers
Expand Down Expand Up @@ -104,26 +126,12 @@ builder_run_child_actions build:tools
# Some test pages refer to KMW tools.
builder_run_child_actions build:test-pages

builder_run_child_actions test
# Build tests
builder_run_action build build_action

if builder_start_action test; then
TEST_OPTS=
if builder_has_option --ci; then
TEST_OPTS=--ci
fi
./test.sh $TEST_OPTS

builder_finish_action success test
fi

coverage_action() {
builder_echo "Creating coverage report..."
cd "$KEYMAN_ROOT"
mkdir -p web/build/coverage/tmp
find . -type f -name coverage-\*.json -print0 | xargs -0 cp -t web/build/coverage/tmp
c8 report --config web/.c8rc.json ---reporter html --clean=false --reports-dir=web/build/coverage
rm -rf web/build/coverage/tmp
cd web
}
# Run tests
builder_run_child_actions test
builder_run_action test test_action

# Create coverage report
builder_run_action coverage coverage_action
33 changes: 28 additions & 5 deletions web/common.inc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,24 +77,47 @@ function prepare() {
#
# * 1: `product` the folder under src/test/auto/headless containing the
# child project's tests
# * 2: `base_dir` the base directory containing the `product` folder.
# Optional. Default: ${KEYMAN_ROOT}/web/src/test/auto/headless/
#
# ### Example
#
# ```bash
# # from engine/osk
# test-headless osk
# test-headless engine/osk
# ```
function test-headless() {
TEST_FOLDER=$1
TEST_BASE=${2:-${KEYMAN_ROOT}/web/src/test/auto/headless/}

TEST_OPTS=
if builder_has_option --ci; then
TEST_OPTS="--reporter mocha-teamcity-reporter"
fi

if [ -e .c8rc.json ]; then
c8 mocha --recursive "${KEYMAN_ROOT}/web/src/test/auto/headless/$TEST_FOLDER" $TEST_OPTS
if [[ -e .c8rc.json ]]; then
c8 mocha --recursive "${TEST_BASE}/${TEST_FOLDER}" $TEST_OPTS
else
mocha --recursive "${KEYMAN_ROOT}/web/src/test/auto/headless/$TEST_FOLDER" $TEST_OPTS
mocha --recursive "${TEST_BASE}/${TEST_FOLDER}" $TEST_OPTS
fi
}
}

# Runs all headless tests (written in typescript) corresponding to the
# specified target.
# This should be called from the working directory of a child project's
# build script.
#
# ### Parameters
#
# * 1: `product` the folder under src/test/auto/headless containing the
# child project's tests
#
# ### Example
#
# ```bash
# # from engine/osk
# test-headless-typescript engine/osk
# ```
function test-headless-typescript() {
test-headless "$1" "${KEYMAN_ROOT}/web/build/test/headless"
}
3 changes: 2 additions & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"@sentry/cli": "2.2.0",
"c8": "^7.12.0",
"chai": "^4.3.4",
"jsdom": "^23.0.1",
"karma": "^6.4.1",
"karma-browserstack-launcher": "^1.6.0",
"karma-chai": "^0.1.0",
Expand Down Expand Up @@ -104,7 +105,7 @@
"@keymanapp/recorder-core": "*",
"@keymanapp/tslib": "*",
"@keymanapp/web-utils": "*",
"@types/node": "^11.9.4",
"@types/node": "^18.19.3",
"eventemitter3": "^4.0.0",
"tslib": "^2.5.2"
},
Expand Down
10 changes: 10 additions & 0 deletions web/src/engine/attachment/.c8rc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"check-coverage": false,
"clean": true,
"exclude-after-remap": true,
"reporter": ["text", "text-summary"],
"reports-dir": "build/coverage",
"src": [
"src/"
]
}
8 changes: 4 additions & 4 deletions web/src/engine/attachment/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ builder_parse "$@"

#### Build action definitions ####

builder_run_action configure verify_npm_setup
builder_run_action clean rm -rf "$KEYMAN_ROOT/web/build/$SUBPROJECT_NAME"
builder_run_action build compile $SUBPROJECT_NAME
builder_run_action test # No headless tests
builder_run_action configure verify_npm_setup
builder_run_action clean rm -rf "${KEYMAN_ROOT}/web/build/${SUBPROJECT_NAME}"
builder_run_action build compile "${SUBPROJECT_NAME}"
builder_run_action test test-headless-typescript "${SUBPROJECT_NAME}"
9 changes: 9 additions & 0 deletions web/src/test/auto/.mocharc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extensions": ["ts"],
"spec": ["**/*.tests.*"],
"node-option": [
"experimental-specifier-resolution=node",
"loader=ts-node/esm"
],
"global": "window"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { assert } from 'chai';
import { JSDOM } from 'jsdom';
import { PageContextAttachment } from 'keyman/engine/attachment';

declare global {
namespace NodeJS {
interface Global {
document: Document;
window: Window;
navigator: Navigator;
}
}
}

describe('PageContextAttachment', () => {
function createDocument(content: string): Document {
const jsdom = new JSDOM(content);
// JSDOM does not support Element.contentEditable
// https://github.com/jsdom/jsdom/issues/1670
Object.defineProperty(jsdom.window.HTMLElement.prototype, 'contentEditable', {
get: function() {
return this.getAttribute('contenteditable')
}
});
const { window } = new JSDOM(content);
global.document = window.document;
global.window = global.document.defaultView;
return global.document;
}

describe('listInputs', () => {
it('empty doc has no elements', () => {
const doc = createDocument('<!doctype html><html><body></body></html>');
const sut = new PageContextAttachment(doc, null);
sut.listInputs();

assert.isEmpty(sut.sortedInputs);
});

it('supported input types', () => {
const doc = createDocument(
`<!doctype html><html><body>
<input type="button">
<input type="checkbox">
<input type="color">
<input type="date">
<input type="datetime-local">
<input type="email">
<input type="file">
<input type="hidden">
<input type="image">
<input type="month">
<input type="number">
<input type="password">
<input type="radio">
<input type="range">
<input type="reset">
<input type="search">
<input type="submit">
<input type="tel">
<input type="text">
<input type="time">
<input type="url">
<input type="week">
<textarea></textarea>
</body></html>`);
const sut = new PageContextAttachment(doc, null);
sut.listInputs();

const expected = ['email', 'search', 'text', 'url', 'textarea'];
const types = sut.sortedInputs.map((e: HTMLInputElement) => (e.type));
assert.equal(types.length, expected.length);
assert.deepEqual(types, expected, `Actual [${types}]`);
});

it('ignores disabled', () => {
const doc = createDocument(
`<!doctype html><html><body>
<input type="text" id="1">
<input type="text" id="2" class="foo kmw-disabled">
<textarea id="3"></textarea>
<textarea id="4" class="kmw-disabled"></textarea>
</body></html>`);
const sut = new PageContextAttachment(doc, null);
sut.listInputs();

const expected = ['1', '3'];
const types = sut.sortedInputs.map((e: HTMLInputElement) => (e.id));
assert.equal(types.length, expected.length);
assert.deepEqual(types, expected, `Actual [${types}]`);
});
});

describe('isKMWInput', () => {
it('supported input types', () => {
['email', 'search', 'text', 'url'].forEach(function (elementType) {
const doc = createDocument(
`<!doctype html><html><body>
<input type="${elementType}" id="1">
</body></html>`);
const sut = new PageContextAttachment(doc, null);
const elem = doc.getElementById('1');

const result = sut.isKMWInput(elem);
assert.isTrue(result, `${elementType} should be treated as input element`);
});
});

it('unsupported input types', () => {
[ 'button', 'date', 'file', 'hidden', 'image', 'month', 'number',
'password', 'radio', 'range', 'reset', 'submit', 'tel', 'time',
'week'].forEach(function (elementType) {
const doc = createDocument(
`<!doctype html><html><body>
<input type="${elementType}" id="1">
</body></html>`);
const sut = new PageContextAttachment(doc, null);
const elem = doc.getElementById('1');

const result = sut.isKMWInput(elem);
assert.isFalse(result, `${elementType} should not be treated as input element`);
});
});

it('text area is input', () => {
const doc = createDocument(
`<!doctype html><html><body>
<textarea id="1"></textarea>
</body></html>`);
const sut = new PageContextAttachment(doc, null);
const elem = doc.getElementById('1');

const result = sut.isKMWInput(elem);
assert.isTrue(result);
});

// Can't test contenteditable because JSDOM doesn't support that attribute.
// See https://github.com/jsdom/jsdom/issues/1670

// missing tests:
// - iframe without content window -> false
// - iframe with touch and designmode -> false
// - iframe with touch and no designmode -> true
// - iframe with _kmwAttachment -> true

});
});
12 changes: 12 additions & 0 deletions web/src/test/auto/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.dom.json",

"compilerOptions": {
"baseUrl": "./",
"outDir": "../../../build/test",
"tsBuildInfoFile": "../../../build/test/tsconfig.tsbuildinfo",
"rootDir": "."
},

"include": [ "**/*.ts" ]
}
2 changes: 1 addition & 1 deletion web/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ fi

# End common configs.

builder_run_action test:dom karma start $KARMA_FLAGS "${KEYMAN_ROOT}/web/src/test/auto/dom/$CONFIG"
builder_run_action test:dom karma start ${KARMA_FLAGS} "${KEYMAN_ROOT}/web/src/test/auto/dom/${CONFIG}"

# The multi-browser test suite, which uses BrowserStack when run by our CI.
if builder_start_action test:integrated; then
Expand Down

0 comments on commit 3cde93d

Please sign in to comment.