Merge pull request #3122 from keymanapp/feat/web/sentry-start

feat(web): starts proper KMW Sentry integration
This commit is contained in:
Joshua Horton 2020-05-20 15:21:12 +07:00 • committed by GitHub
commit 7742bfdb37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 663 additions and 11 deletions

View file

@ -0,0 +1,17 @@
# Build products
src/environment.inc.ts
# Legacy build folders.
output/
build/
embedded/
# Current build output folder (matches standard node publish location).
dist/
# Other local files.
node_modules/
unit_tests/modernizr.js
**/.idea/**/*.xml
**/*.iml
**/*.kpj.user

View file

@ -0,0 +1,76 @@
{
"name": "@keymanapp/web-sentry-manager",
"version": "14.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@sentry/browser": {
"version": "5.15.5",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.15.5.tgz",
"integrity": "sha512-rqDvjk/EvogfdbZ4TiEpxM/lwpPKmq23z9YKEO4q81+1SwJNua53H60dOk9HpRU8nOJ1g84TMKT2Ov8H7sqDWA==",
"requires": {
"@sentry/core": "5.15.5",
"@sentry/types": "5.15.5",
"@sentry/utils": "5.15.5",
"tslib": "^1.9.3"
}
},
"@sentry/core": {
"version": "5.15.5",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.15.5.tgz",
"integrity": "sha512-enxBLv5eibBMqcWyr+vApqeix8uqkfn0iGsD3piKvoMXCgKsrfMwlb/qo9Ox0lKr71qIlZVt+9/A2vZohdgnlg==",
"requires": {
"@sentry/hub": "5.15.5",
"@sentry/minimal": "5.15.5",
"@sentry/types": "5.15.5",
"@sentry/utils": "5.15.5",
"tslib": "^1.9.3"
}
},
"@sentry/hub": {
"version": "5.15.5",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.15.5.tgz",
"integrity": "sha512-zX9o49PcNIVMA4BZHe//GkbQ4Jx+nVofqU/Il32/IbwKhcpPlhGX3c1sOVQo4uag3cqd/JuQsk+DML9TKkN0Lw==",
"requires": {
"@sentry/types": "5.15.5",
"@sentry/utils": "5.15.5",
"tslib": "^1.9.3"
}
},
"@sentry/minimal": {
"version": "5.15.5",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.15.5.tgz",
"integrity": "sha512-zQkkJ1l9AjmU/Us5IrOTzu7bic4sTPKCatptXvLSTfyKW7N6K9MPIIFeSpZf9o1yM2sRYdK7GV08wS2eCT3JYw==",
"requires": {
"@sentry/hub": "5.15.5",
"@sentry/types": "5.15.5",
"tslib": "^1.9.3"
}
},
"@sentry/types": {
"version": "5.15.5",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.15.5.tgz",
"integrity": "sha512-F9A5W7ucgQLJUG4LXw1ZIy4iLevrYZzbeZ7GJ09aMlmXH9PqGThm1t5LSZlVpZvUfQ2rYA8NU6BdKJSt7B5LPw=="
},
"@sentry/utils": {
"version": "5.15.5",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.15.5.tgz",
"integrity": "sha512-Nl9gl/MGnzSkuKeo3QaefoD/OJrFLB8HmwQ7HUbTXb6E7yyEzNKAQMHXGkwNAjbdYyYbd42iABP6Y5F/h39NtA==",
"requires": {
"@sentry/types": "5.15.5",
"tslib": "^1.9.3"
}
},
"tslib": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz",
"integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA=="
},
"typescript": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
"dev": true
}
}
}

View file

@ -0,0 +1,25 @@
{
"name": "@keymanapp/web-sentry-manager",
"version": "14.0.0",
"description": "Common setup for KeymanWeb's Sentry-based error reporting",
"main": "dist/index.js",
"scripts": {
"tsc": "tsc"
},
"repository": {
"type": "git",
"url": "git+https://github.com/keymanapp/keyman.git"
},
"author": "SIL International",
"license": "MIT",
"bugs": {
"url": "https://github.com/keymanapp/keyman/issues"
},
"homepage": "https://github.com/keymanapp/keyman#readme",
"devDependencies": {
"typescript": "^3.8.3"
},
"dependencies": {
"@sentry/browser": "^5.15.5"
}
}

View file

@ -0,0 +1,66 @@
#! /bin/bash
#
# Compiles development-related KeymanWeb resources for use with developing/running tests.
# - the Recorder module (for engine tests)
# - the DOM module (for touch-alias and element-interface tests)
## START STANDARD BUILD SCRIPT INCLUDE
# adjust relative paths as necessary
THIS_SCRIPT="$(greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null || readlink -f "${BASH_SOURCE[0]}")"
. "$(dirname "$THIS_SCRIPT")/../../../../../../resources/build/build-utils.sh"
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
## END STANDARD BUILD SCRIPT INCLUDE
SCRIPT_DIR="$(dirname "$THIS_SCRIPT")"
display_usage ( ) {
echo "build.sh [-skip-dependency-install]"
echo
echo " -skip-dependency-install skips the `lerna bootstrap` dependency check."
echo " (or -S) Intended for use when this script is called by another build script."
echo ""
echo " If more than one target is specified, the last one will take precedence."
exit 1
}
# Establish default build parameters
set_default_vars ( ) {
FETCH_DEPS=true
}
set_default_vars
# Parse args
while [[ $# -gt 0 ]] ; do
key="$1"
case $key in
-skip-package-install|-S)
set_default_vars
FETCH_DEPS=false
;;
esac
shift # past argument
done
if [ $FETCH_DEPS = true ]; then
verify_npm_setup
fi
# Definition of global compile constants
OUTPUT_DIR="dist"
OUTPUT="index.js"
# Ensures that we rely first upon the local npm-based install of Typescript.
# (Facilitates automated setup for build agents.)
PATH="../node_modules/.bin:$PATH"
# Ensure the environment definition variables are available.
exportEnvironmentDefinitionTS
compiler="npm run tsc --"
compilecmd="$compiler"
$compilecmd -p "$SCRIPT_DIR/tsconfig.json"
if [ $? -ne 0 ]; then
fail "Compilation of package for Sentry integration with KeymanWeb failed."
fi

View file

@ -0,0 +1,147 @@
///<reference path="../node_modules/@sentry/browser/build/bundle.min.js" />
namespace com.keyman {
/**
* Controls whether or not the generated Sentry event is logged to the console (true)
* or sent to our Sentry server (false).
*/
let DEBUG = false;
type Options = typeof KeymanSentryManager.DEFAULT_OPTIONS;
export class KeymanSentryManager {
keymanPlatform: string;
static STANDARD_ALIASABLE_FILES = {
'keymanweb.js': 'keymanweb.js',
'kmwuibutton.js': 'kmwuibutton.js',
'kmwuifloat.js': 'kmwuifloat.js',
'kmwuitoggle.js': 'kmwuitoggle.js',
'kmwuitoolbar.js': 'kmwuitoolbar.js'
// Also add entries for the naming system used by Android and iOS - and map them to the EMBEDDED upload, not the std 'native' one.
}
static DEFAULT_OPTIONS = {
hostPlatform: "native-web"
}
constructor(options: Options = KeymanSentryManager.DEFAULT_OPTIONS) {
this.keymanPlatform = options.hostPlatform;
}
// If we've recognized one of our source files,
aliasFilename(filename: string): string|null {
if(!this.mayAlias(filename)) {
return null;
}
filename = KeymanSentryManager.STANDARD_ALIASABLE_FILES[filename];
switch(location.protocol) {
case 'http:':
return 'http://' + location.host + '/' + filename;
case 'file:':
return 'file:///' + filename;
default:
return null;
}
}
mayAlias(filename: string): boolean {
return !!KeymanSentryManager.STANDARD_ALIASABLE_FILES[filename];
}
// Filters all expected but unnecessary path prefixes, affixes, and suffixes reported by Sentry from our products.
// This allows us to mask all different sorts of installations with a single uploaded path.
// Modifies original object.
pathFilter(event: any) {
// Get the underlying JS error.
let exception = event.exception;
// Iterate through all wrapped exceptions.
for(let e of exception.values) {
for(let frame of e.stacktrace.frames) {
let URL = frame.filename as string;
let filename: string = '';
try {
filename = URL.substr(URL.lastIndexOf('/')+1);
if(this.mayAlias(filename)) {
// Make the file look like it's at the host's root so that the Sentry server will recognize it
// regardless of actual filepath position.
frame.filename = this.aliasFilename(filename) || frame.filename;
}
} catch {
// not sure what to do yet, but... don't make more errors in the error handler. That's a bad idea.
}
}
}
}
// Attaches some useful debugging information to the specified object, pass-by-reference style.
attachEventMetadata(event: any) {
// Ensure that the 'extra' object exists. (May not exist for synthetic/custom Errors.)
event.extra = event.extra || {};
event.extra.keymanState = window['keyman']['getDebugInfo']();
event.extra.keymanHostPlatform = this.keymanPlatform;
}
/**
* Pre-processes a Sentry event object (in-place) to provide more metadata and enhance
* the Sentry server's ability to match the error against release artifacts.
* @param event A Sentry-generated event
*/
prepareEvent(event: any): boolean {
this.pathFilter(event);
this.attachEventMetadata(event);
if(DEBUG) {
console.log("DEBUG: event object for Sentry")
console.log(event);
return false; //event
} else {
return true;
}
}
/**
* Allows debugging our custom event preparation code without bombarding Sentry with errors
* during development.
*
* Note that Sentry expects us either to return the event object to be sent or to return `null`
* if we want to prevent the event from being sent to the server.
* @param event
*/
prepareEventDebugWrapper(event: any) {
if(DEBUG) {
try {
if(this.prepareEvent(event)) {
return event;
} else {
return null;
}
} catch(err) {
console.log(err);
}
} else {
// If not in DEBUG mode, simply forward to the actual preparer; we should be notified
// of any event-prep errors that may occur.
if(this.prepareEvent(event)) {
return event;
} else {
return null;
}
}
}
init() {
// Do the actual Sentry initialization.
//@ts-ignore
Sentry.init({
beforeSend: this.prepareEventDebugWrapper.bind(this),
debug: DEBUG,
dsn: 'https://cf96f32d107c4286ab2fd82af49c4d3b@sentry.keyman.com/11', // keyman-web DSN
release: com.keyman.environment.SENTRY_RELEASE
});
}
}
}

View file

@ -0,0 +1,16 @@
{
"compilerOptions": {
"allowJs": true,
"module": "none",
"outDir": "../dist/",
"inlineSources": true,
"sourceMap": true,
"target": "es5",
"lib": ["es6", "dom"],
"outFile": "../dist/index.js"
},
"files": [
"environment.inc.ts",
"index.ts"
]
}

View file

@ -3,6 +3,7 @@
"common/core/web/input-processor",
"common/core/web/keyboard-processor",
"common/core/web/tools/recorder",
"common/core/web/tools/sentry-manager",
"common/core/web/utils",
"common/lexical-model-types",
"common/predictive-text",

View file

@ -195,6 +195,7 @@ exportEnvironmentDefinitionTS ( ) {
namespace com.keyman.environment {
export var VERSION = \"$VERSION_RELEASE\";
export var BUILD = $VERSION_PATCH;
export var SENTRY_RELEASE = \"release-$VERSION_WITH_TAG\";
}
" >> $ENVIRONMENT_TS
}

88
web/package-lock.json generated
View file

@ -4,6 +4,70 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@sentry/cli": {
"version": "1.52.3",
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.52.3.tgz",
"integrity": "sha512-QOSIg5hxAEa6v6H7oEeF6A/Rpa0wloMhbu0Qed6zHv3lyoqf0Z34Kq2jCXdqGsOE3IzkO+3CNy81F6361j5TKg==",
"dev": true,
"requires": {
"https-proxy-agent": "^5.0.0",
"mkdirp": "^0.5.5",
"node-fetch": "^2.6.0",
"progress": "^2.0.3",
"proxy-from-env": "^1.1.0"
},
"dependencies": {
"agent-base": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz",
"integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==",
"dev": true,
"requires": {
"debug": "4"
}
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"https-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
"integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
"dev": true,
"requires": {
"agent-base": "6",
"debug": "4"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
},
"mkdirp": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"dev": true,
"requires": {
"minimist": "^1.2.5"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
}
}
},
"@types/node": {
"version": "11.9.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.4.tgz",
@ -1552,12 +1616,6 @@
}
}
},
"mocha-teamcity-reporter": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/mocha-teamcity-reporter/-/mocha-teamcity-reporter-3.0.0.tgz",
"integrity": "sha512-FyGgmtFfW2nDwEZU3mrjQShAAK/zhGivwY4HCsqoDoyeS8vV8HGdq1Dn2P+SFaIoCeXTQ0Z+5xVRyikYaKrW5w==",
"dev": true
},
"modernizr": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/modernizr/-/modernizr-3.7.1.tgz",
@ -1585,6 +1643,12 @@
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
"dev": true
},
"node-fetch": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==",
"dev": true
},
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@ -1736,6 +1800,18 @@
"integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==",
"dev": true
},
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true
},
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"dev": true
},
"ps-tree": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.1.tgz",

View file

@ -18,6 +18,8 @@
},
"homepage": "https://github.com/keymanapp/keyman#readme",
"devDependencies": {
"@keymanapp/web-sentry-manager": "^14.0.0",
"@sentry/cli": "^1.52.3",
"chai": "^4.2.0",
"google-closure-compiler-java": "^20200224.0.0",
"html2canvas": "^1.0.0-alpha.12",
@ -45,7 +47,8 @@
"karma": "karma",
"lerna": "cd ../ && npm run lerna --",
"mocha": "mocha",
"modernizr": "modernizr"
"modernizr": "modernizr",
"sentry-cli": "sentry-cli"
},
"dependencies": {
"@keymanapp/input-processor": "^14.0.78",

View file

@ -206,6 +206,13 @@ INTERMEDIATE="../intermediate"
SOURCE="."
NODE_SOURCE="source"
SENTRY_RELEASE_VERSION="release-$VERSION_WITH_TAG"
export SENTRY_URL="https://sentry.keyman.com"
export SENTRY_ORG=keyman
export SENTRY_PROJECT=keyman-web
export SENTRY_LOG_LEVEL=info
readonly WEB_OUTPUT
readonly EMBED_OUTPUT
readonly SOURCE
@ -227,6 +234,7 @@ set_default_vars ( ) {
BUILD_DEBUG_EMBED=false
BUILD_COREWEB=true
DO_MINIFY=true
DO_NATIVE_SENTRY=true
FETCH_DEPS=true
}
@ -264,6 +272,7 @@ while [[ $# -gt 0 ]] ; do
BUILD_FULLWEB=false
BUILD_UI=false
BUILD_COREWEB=false
DO_NATIVE_SENTRY=false
;;
-web)
set_default_vars
@ -276,12 +285,14 @@ while [[ $# -gt 0 ]] ; do
BUILD_COREWEB=false
BUILD_FULLWEB=false
BUILD_DEBUG_EMBED=true
DO_NATIVE_SENTRY=false
;;
-h|-?)
display_usage
;;
-no_minify)
DO_MINIFY=false
DO_NATIVE_SENTRY=false
;;
-clean)
clean
@ -314,6 +325,7 @@ if [ $DO_MINIFY = true ]; then
exit 1
fi
# Only run if BOTH cases are true b/c it's a minification-focused 'dependency'.
if [ $FETCH_DEPS = true ]; then
# Also, build our sourcemap-root tool for cleaning up the minified version's sourcemaps.
echo "Compiling build tools for minified build products"
@ -324,6 +336,14 @@ fi
if [ $BUILD_CORE = true ]; then
CORE_FLAGS="-skip-package-install"
# Build the sentry-manager module - it's used in embedded contexts and on one testing page.
echo "${TERM_HEADING}Compiling KeymanWeb's sentry-manager module...${NORMAL}"
pushd ../../common/core/web/tools/sentry-manager/src
./build.sh $CORE_FLAGS || fail "Failed to compile the sentry-manager module"
popd
echo "${TERM_HEADING}sentry-manager module compiled successfully.${NORMAL}"
if [ $BUILD_LMLAYER = false ]; then
CORE_FLAGS="$CORE_FLAGS -test"
fi
@ -381,6 +401,13 @@ if [ $BUILD_EMBED = true ]; then
echo
echo KMEA/KMEI version $VERSION compiled and saved under $EMBED_OUTPUT
echo
# We always publish "embedded" mode to Sentry when minifying.
pushd $EMBED_OUTPUT
echo "Uploading to Sentry..."
npm run sentry-cli -- releases files "$SENTRY_RELEASE_VERSION" upload-sourcemaps --strip-common-prefix release/embedded --rewrite --ext js --ext map --ext ts || fail "Sentry upload failed."
echo "Upload successful."
popd
fi
fi
@ -462,6 +489,16 @@ if [ $BUILD_UI = true ]; then
fi
fi
# Has its own flag due to complex logic. Should run if $DO_MINIFY && ($BUILD_COREWEB || $BUILD_UI)
# If only one of the two (COREWEB, UI) is run, we assume the un-run portion is 'current' and still upload it.
if [ $DO_NATIVE_SENTRY = true ]; then
pushd $WEB_OUTPUT
echo "Uploading to Sentry..."
npm run sentry-cli -- releases files "$SENTRY_RELEASE_VERSION" upload-sourcemaps --strip-common-prefix release/web/ --rewrite --ext js --ext map --ext ts || fail "Sentry upload failed."
echo "Upload successful."
popd
fi
if [ $BUILD_DEBUG_EMBED = true ]; then
# We currently have an issue with sourcemaps for minified versions.
# We should use the unminified one instead for now.
@ -470,4 +507,3 @@ if [ $BUILD_DEBUG_EMBED = true ]; then
cp $EMBED_OUTPUT_NO_MINI/keyman.js.map $EMBED_OUTPUT/keyman.js.map
echo Uncompiled embedded application saved as keyman.js
fi

View file

@ -372,7 +372,7 @@ namespace com.keyman.keyboards {
}
this.doBeforeKeyboardChange(PInternalName,PLgCode);
let p = this._SetActiveKeyboard(PInternalName,PLgCode,true);
let p: Promise<void> = this._SetActiveKeyboard(PInternalName,PLgCode,true);
if(this.keymanweb.domManager.getLastActiveElement() != null) {
this.keymanweb.domManager.focusLastActiveElement(); // TODO: Resolve without need for the cast.
}
@ -383,6 +383,14 @@ namespace com.keyman.keyboards {
// }
this.doKeyboardChange(PInternalName, PLgCode);
p.catch(function() {
// Rejection indicates a failure of the keyboard to load.
//
// In case p's rejection is never caught, throwing this error will generate logs that shows up
// in Sentry or in the console, with useful information for debugging either way.
throw new Error("Unable to load keyboard with internal name \"" + PInternalName + "\", language code \"" + PLgCode + "\".");
})
return p;
}

View file

@ -177,6 +177,25 @@ namespace com.keyman {
dom.DOMEventHandlers.states = new dom.CommonDOMStates();
}
/**
* Returns a generalized metadata object about the state of KMW for use with error reporting.
*/
['getDebugInfo']() {
let metadata = {
attachType: this.options.attachType,
device: this.util.device,
initialized: this.initialized,
isEmbedded: this.isEmbedded,
ui: this.ui ? this.ui.name : null
}
if(this.util.device.touchable) {
metadata.ui = 'touch';
}
return metadata;
}
/**
* Expose font testing to allow checking that SpecialOSK or custom font has
* been correctly loaded by browser

View file

@ -19,7 +19,7 @@
</style>
</head>
<body>
<h1>KeymanWeb 12 Testing</h1>
<h1>KeymanWeb 14 Testing</h1>
<h2><a href="./unminified.html">Test unminified Keymanweb</a></h2>
<h2><a href="./unminified - manual.html">Test unminified Keymanweb in manual-attachment mode.</a></h2>
<h2><a href="./keyboard-errors/">Tests keyboard error-handling functionality</a></h2>
@ -30,6 +30,7 @@
<h2><a href="./prediction-ui/">Prediction UI testing</a></h2>
<h2><a href="./toolbar/">Toolbar UI testing</a></h2>
<h2><a href="./build-visual-keyboard/">Tests keyboard documentation rendering.</a></h2>
<h2><a href="./sentry-integration/">Tests Sentry error-reporting functionality</a></h2>
<h1>Auto-attachment mode tests</h1>
<h2><a href="./issue29">Test desktop MutationObserver functionality</a></h2>
<h2><a href="./issue62">Light test for touch-based MutationObserver functionality</a></h2>

View file

@ -0,0 +1,42 @@
// JavaScript Document samplehdr.js: Keyboard management for KeymanWeb demonstration pages
/*
This script is designed to test KeymanWeb error message handling.
*/
function loadKeyboards()
{
var kmw=keyman;
// We start by adding a keyboard correctly. It's best to include a 'control' in our experiment.
kmw.addKeyboards({id:'us',name:'English',languages:{id:'en',name:'English'},
filename:'../us-1.0.js'});
// Insert a keyboard that cannot be found.
kmw.addKeyboards({id:'lao_2008_basic',name:'wrong-filename',
languages:{
id:'lo',name:'debugging',region:'Asia',
font:{family:'LaoWeb',source:['../font/saysettha_web.ttf','../font/saysettha_web.woff','../font/saysettha_web.eot']}
},
filename:'./missing_file.js' // Intentional error - the file doesn't exist, so the <script> tag will raise an error event.
});
// Insert a keyboard that will generate a timing error.
kmw.addKeyboards({id:'unparsable',name:'non-parsable',
languages:{
id:'lo',name:'debugging',region:'Asia',
font:{family:'LaoWeb',source:['../font/saysettha_web.ttf','../font/saysettha_web.woff','../font/saysettha_web.eot']}
},
filename:'./unparsable.js' // Intentional error - the file has no parsable keyboard, so while the <script> tag will load,
// registration will fail.
});
// Insert a keyboard that will generate a timing error.
kmw.addKeyboards({id:'timeout',name:'timeout',
languages:{
id:'lo',name:'debugging',region:'Asia',
font:{family:'LaoWeb',source:['../font/saysettha_web.ttf','../font/saysettha_web.woff','../font/saysettha_web.eot']}
},
filename:'./timeout.js' // Intentional (simulated) error - the file never loads, simulating a server timeout.
});
}

View file

@ -0,0 +1,106 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<!-- Set the viewport width to match phone and tablet device widths -->
<meta name="viewport" content="width=device-width,user-scalable=no" />
<!-- Allow KeymanWeb to be saved to the iPhone home screen -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- Enable IE9 Standards mode -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>KeymanWeb Sample Page - Unminified Source</title>
<!-- Your page CSS -->
<style type='text/css'>
body {font-family: Tahoma,helvetica;}
h3 {font-size: 1em;font-weight:normal;color: darkred; margin-bottom: 4px}
.test {font-size: 1.5em; width:80%; min-height:30px; border: 1px solid gray;}
#KeymanWebControl {width:50%;min-width:600px;}
</style>
<!-- Insert uncompiled KeymanWeb source scripts -->
<script src="../../release/web/keymanweb.js" type="application/javascript"></script>
<!--
For desktop browsers, a script for the user interface must be inserted here.
Standard UIs are toggle, button, float and toolbar.
The toolbar UI is best for any page designed to support keyboards for
a large number of languages.
-->
<script src="../../release/web/kmwuitoggle.js"></script>
<script src="../../node_modules/@keymanapp/web-sentry-manager/dist/index.js"></script>
<!-- Initialization: set paths to keyboards, resources and fonts as required -->
<script>
var kmw=window.keyman;
kmw.init({
attachType:'auto'
});
var sentryManager = new com.keyman.KeymanSentryManager();
sentryManager.init();
</script>
<!-- Add keyboard management script for local selection of keyboards to use -->
<script src="errorhdr.js"></script>
</head>
<!-- Sample page HTML -->
<body onload='loadKeyboards(1);'>
<h2>KeymanWeb Sample Page - Sentry Setup test host</h2>
<div>
<!--
The following DIV is used to position the Button or Toolbar User Interfaces on the page.
If omitted, those User Interfaces will appear at the top of the document body.
(It is ignored by other User Interfaces.)
-->
<div id='KeymanWebControl'></div>
<h3>Type in your language in this text area:</h3>
<textarea id='ta1' class='test' placeholder='Type here'></textarea>
<h3>or in this input field:</h3>
<input class='test' value='' placeholder='or here'/>
<!-- The following elements show how the language menu can be dynamically extended at any time -->
<h3>Add a keyboard by keyboard name:</h3>
<input type='input' id='kbd_id1' class='kmw-disabled' onkeypress="clickOnEnter(event,1);"/>
<input type='button' id='btn1' onclick='addKeyboard(1);' value='Add' />
<h3>Add a keyboard by BCP-47 language code:</h3>
<input type='input' id='kbd_id2' class='kmw-disabled' onkeypress="clickOnEnter(event,2);"/>
<input type='button' id='btn2' onclick='addKeyboard(2);' value='Add' />
<h3>Add a keyboard by language name:</h3>
<input type='input' id='kbd_id3' class='kmw-disabled' onkeypress="clickOnEnter(event,3);"/>
<input type='button' id='btn3' onclick='addKeyboard(3);' value='Add' />
<h3><a href="./">Return to testing home page</a></h3>
</div>
</body>
<!--
*** DEVELOPER NOTE -- FIREFOX CONFIGURATION FOR TESTING ***
*
* If the URL bar starts with <b>file://</b>, Firefox may not load the font used
* to display the special characters used in the On-Screen Keyboard.
*
* To work around this Firefox bug, navigate to <b>about:config</b>
* and set <b>security.fileuri.strict_origin_policy</b> to <b>false</b>
* while testing.
*
* Firefox resolves website-based CSS URI references correctly without needing
* any configuration change, so this change should only be made for file-based testing.
*
***
-->
</html>

View file

@ -0,0 +1,10 @@
(function() {
var me = document.currentScript;
console.log(me);
document.body.addEventListener('load', function(e) {
// Prevent the element's onload event from firing
if(e.srcElement == me || e.target == me) {
e.cancelBubble = true;
}
}, {capture: true});
})();

View file

@ -0,0 +1 @@
// As there is no parsable keyboard here, we need to report that we couldn't register the requested keyboard.

View file

@ -7,11 +7,12 @@
## START STANDARD BUILD SCRIPT INCLUDE
# adjust relative paths as necessary
THIS_SCRIPT="$(greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null || readlink -f "${BASH_SOURCE[0]}")"
SCRIPT_DIR="$(dirname "$THIS_SCRIPT")"
. "$(dirname "$THIS_SCRIPT")/../../../resources/build/build-utils.sh"
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
## END STANDARD BUILD SCRIPT INCLUDE
SCRIPT_DIR="$(dirname "$THIS_SCRIPT")"
# Ensure the dependencies are downloaded. --no-optional should help block fsevents warnings.
verify_npm_setup