diff --git a/.travis.yml b/.travis.yml index d5dde227..83cc2f86 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,17 @@ language: node_js node_js: - "node" +install: + - npm install -g codecov script: - - npm run test +- npm run test -- --coverage +- istanbul cover ./node_modules/mocha/bin/_mocha --reporter lcovonly -- -R spec +- codecov after_success: - wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh - chmod +x send.sh - ./send.sh success $WEBHOOK_URL + - bash <(curl -s https://codecov.io/bash) after_failure: - wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh - chmod +x send.sh diff --git a/src/demo/tests/App.test.js b/src/demo/tests/App.test.js new file mode 100644 index 00000000..4e5c0b2f --- /dev/null +++ b/src/demo/tests/App.test.js @@ -0,0 +1,67 @@ +import TestUtility from '../../lib/tests/TestUtility'; +import Index from '../index'; +import App from '../App'; + +let testUtil = new TestUtility(); + +it('Demo will load', () => { + testUtil.setDOM(); + + let demo = new App(); +}); + +it('Demo onDOMLoaded will work', () => { + testUtil.setDOM(); + + let demo = new App(); + demo.onDOMLoaded(); + + expect(demo.keyboard).toBeTruthy(); +}); + +it('Demo onChange will work', () => { + testUtil.setDOM(); + + let demo = new App(); + demo.onDOMLoaded(); + + demo.onChange("test"); + + expect(document.body.querySelector('.input').value).toBe("test"); +}); + +it('Demo onChange will work', () => { + testUtil.setDOM(); + + let demo = new App(); + demo.onDOMLoaded(); + + demo.keyboard.getButtonElement("q").onclick(); + + expect(document.body.querySelector('.input').value).toBe("q"); +}); + +it('Demo input change will work', () => { + testUtil.setDOM(); + + let demo = new App(); + demo.onDOMLoaded(); + + document.body.querySelector('.input').value = "test"; + document.body.querySelector('.input').dispatchEvent(new Event('change')); + + expect(demo.keyboard.getInput()).toBe("test"); +}); + +it('Demo handleShiftButton will work', () => { + testUtil.setDOM(); + + let demo = new App(); + demo.onDOMLoaded(); + + demo.keyboard.getButtonElement("{shift}")[0].onclick(); + expect(demo.keyboard.options.layoutName).toBe("shift"); + + demo.keyboard.getButtonElement("{shift}")[0].onclick(); + expect(demo.keyboard.options.layoutName).toBe("default"); +}); \ No newline at end of file diff --git a/src/lib/components/Keyboard.test.js b/src/lib/components/Keyboard.test.js deleted file mode 100644 index 71b5ada3..00000000 --- a/src/lib/components/Keyboard.test.js +++ /dev/null @@ -1,107 +0,0 @@ -import Keyboard from './Keyboard'; - -let keyboard; -let keyboardOptions = { - onChange: input => input, - onKeyPress: button => button, - layout: { - 'default': [ - '` 1 2 3 4 5 6 7 8 9 0 - = {bksp}', - '{tab} q w e r t y u i o p [ ] \\', - '{lock} a s d f g h j k l ; \' {enter}', - '{shift} z x c v b n m , . / {shift}', - '.com @ {space}' - ], - 'shift': [ - '~ ! @ # $ % ^ & * ( ) _ + {bksp}', - '{tab} Q W E R T Y U I O P { } |', - '{lock} A S D F G H J K L : " {enter}', - '{shift} Z X C V B N M < > ? {shift}', - '.com @ {space}' - ] - }, - layoutName: "default", - display: { - '{bksp}': 'delete', - '{enter}': 'submit', - '{shift}': 'shift' - }, - mergeDisplay: true, - theme: "hg-theme-default testie", - buttonTheme: [ - { - class: "myCustomClass", - buttons: "Q W E R T Y q w e r t y" - }, - { - class: "anotherCustomClass", - buttons: "Q q" - } - ], - newLineOnEnter: true, - tabCharOnTab: true, - maxLength: 10, - syncInstanceInputs: true, - onRender: () => console.log("simple-keyboard RENDERED"), - onInit: () => console.log("simple-keyboard READY") -}; - -it('Keyboard renders without crashing', () => { - const div = document.createElement('div'); - - div.className += "simple-keyboard"; - document.body.appendChild(div); - - keyboard = new Keyboard(keyboardOptions); -}); - -it('Keyboard standard buttons are working', () => { - testLayoutStdButtons(); - - keyboard.setOptions({ - layoutName: "shift", - maxLength: 42 - }); - - testLayoutStdButtons(); -}); - -function testLayoutStdButtons(){ - let rows = document.body.querySelector('.simple-keyboard').children; - let stdBtnCount = 0; - let fullInput = ''; - - Array.from(rows).forEach(row => { - Array.from(row.children).forEach((button) => { - let label = button.getAttribute("data-skbtn"); - - if(label.includes("{")) - return false; - - // Click all standard buttons, respects maxLength - button.onclick(); - - // Recording fullInput, bypasses maxLength - fullInput = keyboard.utilities.getUpdatedInput(label, fullInput, keyboard.options, null); - - stdBtnCount += label.length; - }); - }); - - /** - * Check if maxLength is respected - */ - if(keyboard.getInput().length !== keyboard.options.maxLength) - throw "MAX_LENGTH_ISSUE"; - else - console.log("MAX_LENGTH PASSED:", keyboard.options.layoutName, keyboard.getInput().length, keyboard.options.maxLength); - - /** - * Check if all standard buttons are inputting something - * (Regardless of maxLength) - */ - if(stdBtnCount !== fullInput.length) - throw "STANDARD_BUTTONS_ISSUE"; - else - console.log("STANDARD_BUTTONS PASSED:", keyboard.options.layoutName, stdBtnCount, fullInput.length); -} diff --git a/src/lib/components/tests/Keyboard.test.js b/src/lib/components/tests/Keyboard.test.js new file mode 100644 index 00000000..d968409c --- /dev/null +++ b/src/lib/components/tests/Keyboard.test.js @@ -0,0 +1,709 @@ +import Keyboard from '../Keyboard'; +import TestUtility from '../../tests/TestUtility'; + +let testUtil = new TestUtility(); + +it('Keyboard will not render without target element', () => { + try { + new Keyboard(); + expect(true).toBe(false); + } catch (e) { + expect(e.message).toBe("KEYBOARD_DOM_ERROR"); + } +}); + +it('Keyboard will run without options', () => { + // Prepare target DOM element + testUtil.setDOM(); + + // No options + new Keyboard(); +}); + +it('Keyboard will run with empty options', () => { + // Prepare target DOM element + testUtil.setDOM(); + + // No options + new Keyboard({}); +}); + +it('Keyboard will run with custom DOM target', () => { + testUtil.setDOM("myTestDiv"); + + new Keyboard(".myTestDiv"); + expect(document.body.querySelector(".myTestDiv")).toBeDefined(); +}); + +it('Keyboard will run with debug option set', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + debug: true + }); + + expect(keyboard.options.debug).toBeTruthy(); +}); + +it('Keyboard standard buttons will work', () => { + testUtil.setDOM(); + let keyboard = new Keyboard({ + maxLength: { + "default": 10 + } + }); + + testUtil.testLayoutStdButtons(keyboard); +}); + + +it('Keyboard shift buttons will work', () => { + testUtil.setDOM(); + let keyboard = new Keyboard(); + + keyboard.setOptions({ + layoutName: "shift", + maxLength: 42 + }); + + testUtil.testLayoutStdButtons(keyboard); +}); + +it('Keyboard setOptions will work without a param', () => { + testUtil.setDOM(); + let keyboard = new Keyboard(); + + keyboard.setOptions(); +}); + +it('Keyboard empty buttons wont do anything as expected', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + layout: { + default: [ + "{//} {button} d", + "a b c d e f g h i j", + ] + } + }); + + keyboard.getButtonElement("{//}").onclick(); +}); + +it('Keyboard onKeyPress will work', () => { + testUtil.setDOM(); + + let pressed = false; + + let keyboard = new Keyboard({ + onKeyPress: () => { + pressed = true; + }, + debug: true + }); + + keyboard.getButtonElement("q").onclick(); + + expect(pressed).toBeTruthy(); +}); + +it('Keyboard standard function buttons will not change input', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + testUtil.iterateButtons((button) => { + if(button.getAttribute("data-skbtn") === "{shift}"){ + button.onclick(); + } + }); + + expect(keyboard.getInput()).toBeFalsy(); +}); + +it('Keyboard syncInstanceInputs will work', () => { + testUtil.clear(); + + document.body.innerHTML = ` +
+ + `; + + let sharedOptions = { + syncInstanceInputs: true + }; + + let keyboard1 = new Keyboard(".keyboard1", sharedOptions); + let keyboard2 = new Keyboard(".keyboard2", sharedOptions); + + keyboard1.getButtonElement("q").onclick(); + + expect(keyboard2.getInput()).toBe("q"); +}); + +it('Keyboard onChange will work', () => { + testUtil.setDOM(); + + let output = false; + + let keyboard = new Keyboard({ + onChange: (input) => { + output = input; + } + }); + + keyboard.getButtonElement("q").onclick(); + + expect(output).toBe("q"); +}); + +it('Keyboard clearInput will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + keyboard.input = { + "default": "hello" + }; + + keyboard.clearInput(); + + expect(keyboard.getInput()).toBeFalsy(); +}); + +it('Keyboard clearInput will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + /** + * Avoid setInput for this test + */ + keyboard.input = { + "default": "hello" + }; + + keyboard.clearInput(); + + expect(keyboard.getInput()).toBeFalsy(); +}); + +it('Keyboard clearInput will work with syncInstanceInputs', () => { + testUtil.clear(); + + document.body.innerHTML = ` + + + `; + + let sharedOptions = { + syncInstanceInputs: true + }; + + let keyboard1 = new Keyboard(".keyboard1", sharedOptions); + let keyboard2 = new Keyboard(".keyboard2", sharedOptions); + + /** + * Avoid setInput for this test + */ + keyboard1.input = { + "default": "hello" + }; + + keyboard2.clearInput(); + + expect(keyboard1.getInput()).toBeFalsy(); +}); + +it('Keyboard setInput will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + keyboard.setInput("hello"); + + expect(keyboard.getInput()).toBe("hello"); +}); + +it('Keyboard setInput will work with syncInstanceInputs', () => { + testUtil.clear(); + + document.body.innerHTML = ` + + + `; + + let sharedOptions = { + syncInstanceInputs: true + }; + + let keyboard1 = new Keyboard(".keyboard1", sharedOptions); + let keyboard2 = new Keyboard(".keyboard2", sharedOptions); + + keyboard1.setInput("hello"); + + expect(keyboard2.getInput()).toBe("hello"); +}); + +it('Keyboard dispatch will work', () => { + testUtil.setDOM(); + + document.body.innerHTML = ` + + + `; + + let keyboard1 = new Keyboard(".keyboard1"); + let keyboard2 = new Keyboard(".keyboard2"); + + keyboard1.dispatch(instance => { + instance.setOptions({ + buttonTheme: [ + { + class: "myCustomClass", + buttons: "Q" + } + ] + }) + }); + + expect(keyboard2.options.buttonTheme[0].class).toBe("myCustomClass"); +}); + +it('Keyboard dispatch will not work without SimpleKeyboardInstances', () => { + testUtil.setDOM(); + + document.body.innerHTML = ` + + + `; + + let keyboard1 = new Keyboard(".keyboard1"); + let keyboard2 = new Keyboard(".keyboard2"); + + window['SimpleKeyboardInstances'] = null; + + try { + keyboard1.dispatch(instance => { + instance.setOptions({ + buttonTheme: [ + { + class: "myCustomClass", + buttons: "Q" + } + ] + }) + }); + + expect(true).toBe(false); + } catch (e) { + expect(e.message).toBe("INSTANCES_VAR_ERROR"); + } +}); + +it('Keyboard addButtonTheme will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + let returnVal = keyboard.addButtonTheme("q", "test"); + + expect(keyboard.options.buttonTheme[0].class).toBe("test"); +}); + +it('Keyboard addButtonTheme will not work without params', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + let returnVal = keyboard.addButtonTheme(); + + expect(returnVal).toBeFalsy(); +}); + +it('Keyboard addButtonTheme will amend a buttonTheme', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: "test", + buttons: "s" + } + ] + }); + + keyboard.addButtonTheme("q", "test"); + + expect(keyboard.options.buttonTheme[0].class).toBe("test"); +}); + +it('Keyboard addButtonTheme will create a buttonTheme', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: "blurb", + buttons: "s" + } + ] + }); + + keyboard.addButtonTheme("q", "test"); + + expect(keyboard.options.buttonTheme[1].class).toBe("test"); +}); + +it('Keyboard addButtonTheme will ignore a repeated buttonTheme', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: "test", + buttons: "s a" + } + ] + }); + + keyboard.addButtonTheme("a", "test"); + + expect(keyboard.options.buttonTheme[0].buttons).toBe("s a"); +}); + +it('Keyboard addButtonTheme will amend a buttonTheme', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: "test", + buttons: "s" + } + ] + }); + + keyboard.addButtonTheme("q", "test"); + + expect(keyboard.options.buttonTheme[0].buttons).toBe("s q"); +}); + + +it('Keyboard removeButtonTheme without params will remove all button themes', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: "test", + buttons: "s" + } + ] + }); + + keyboard.removeButtonTheme(); + + expect(keyboard.options.buttonTheme.length).toBe(0); +}); + + +it('Keyboard removeButtonTheme will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: "test", + buttons: "s" + } + ] + }); + + keyboard.removeButtonTheme("s", "test"); + + expect(keyboard.options.buttonTheme.length).toBe(0); +}); + +it('Keyboard removeButtonTheme will work wihtout a class', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: "test", + buttons: "s" + } + ] + }); + + keyboard.removeButtonTheme("s"); + + expect(keyboard.options.buttonTheme.length).toBe(0); +}); + +it('Keyboard removeButtonTheme will do nothing without a button param', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: "test", + buttons: "s" + } + ] + }); + + keyboard.removeButtonTheme(null, "test"); + + expect(keyboard.options.buttonTheme.length).toBe(1); +}); + +it('Keyboard removeButtonTheme does nothing if req button doesnt have a buttonTheme', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: "test", + buttons: "a" + } + ] + }); + + keyboard.removeButtonTheme("s", "test"); + + expect(keyboard.options.buttonTheme.length).toBe(1); +}); + +it('Keyboard removeButtonTheme does nothing if buttonTheme class does not exist', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: "testy", + buttons: "a" + } + ] + }); + + keyboard.removeButtonTheme("a", "test"); + + expect(keyboard.options.buttonTheme.length).toBe(1); +}); + +it('Keyboard removeButtonTheme does nothing if buttonTheme doesnt have the requested buttons', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: "test", + buttons: "a b c d e f" + } + ] + }); + + keyboard.removeButtonTheme("g", "test"); + + expect(keyboard.options.buttonTheme[0].buttons).toBe("a b c d e f"); +}); + +it('Keyboard getButtonElement will not return anything if empty match', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + layout: { + default: [ + "{//} {button} d", + "a b c d e f g h i j", + ] + } + }); + + expect(keyboard.getButtonElement("{waldo}")).toBeFalsy(); +}); + +it('Keyboard getButtonElement will return multiple matched buttons', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + expect(keyboard.getButtonElement("{shift}").length).toBe(2); +}); + +it('Keyboard will receive physical keyboard events', () => { + testUtil.setDOM(); + + new Keyboard({ + debug: true, + physicalKeyboardHighlight: true + }); + + document.dispatchEvent(new KeyboardEvent('keyup', { + charCode: 0, + code: "KeyF", + key: "f", + which: 70, + target: { + tagName: "input" + } + })); +}); + +it('Keyboard caretEventHandler will detect input, textarea focus', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + keyboard.caretEventHandler({ + charCode: 0, + code: "KeyF", + key: "f", + which: 70, + target: { + tagName: "input", + selectionStart: 3 + } + }); + + expect(keyboard.caretPosition).toBe(3); +}); + +it('Keyboard caretEventHandler ignore positioning if input, textarea is blur', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + keyboard.caretEventHandler({ + charCode: 0, + code: "KeyF", + key: "f", + which: 70, + target: { + tagName: "div", + selectionStart: 4 + } + }); + + expect(keyboard.caretPosition).toBeFalsy(); +}); + +it('Keyboard caretEventHandler will work with debug', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + debug: true + }); + + keyboard.caretEventHandler({ + charCode: 0, + code: "KeyF", + key: "f", + which: 70, + target: { + tagName: "input", + selectionStart: 3 + } + }); + + expect(keyboard.caretPosition).toBe(3); +}); + +it('Keyboard onInit will work', () => { + testUtil.setDOM(); + + let passed = false; + + let keyboard = new Keyboard({ + onInit: () => { + passed = true + } + }); + + expect(passed).toBeTruthy(); +}); + +it('Keyboard onRender will work', () => { + testUtil.setDOM(); + + let passed = false; + + let keyboard = new Keyboard({ + onRender: () => { + passed = true + } + }); + + expect(passed).toBeTruthy(); +}); + +it('Keyboard buttonTheme that is invalid will be ignored and not throw', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: null, + buttons: null + } + ] + }); +}); + +it('Keyboard buttonTheme buttons that are invalid will be ignored and not throw', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: null, + buttons: undefined + } + ] + }); +}); + +it('Keyboard buttonTheme will be ignored if buttons param not a string', () => { + testUtil.setDOM(); + + new Keyboard({ + buttonTheme: [ + { + class: "test", + buttons: { + wrong: true + } + } + ] + }); +}); + +it('Keyboard buttonTheme will be ignored if already added', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + buttonTheme: [ + { + class: "test", + buttons: "a b c" + }, + { + class: "test", + buttons: "c" + }, + { + class: "anotherclass", + buttons: "c" + }, + { + class: "yetAnotherclass", + buttons: "c" + }, + { + class: "anotherclass", + buttons: "c" + }, + ] + }); +}); \ No newline at end of file diff --git a/src/lib/services/tests/PhysicalKeyboard.test.js b/src/lib/services/tests/PhysicalKeyboard.test.js new file mode 100644 index 00000000..863651f3 --- /dev/null +++ b/src/lib/services/tests/PhysicalKeyboard.test.js @@ -0,0 +1,118 @@ +import Keyboard from '../../components/Keyboard'; +import TestUtility from '../../tests/TestUtility'; + +let testUtil = new TestUtility(); + +it('PhysicalKeyboard keydown will be handled with physicalKeyboardHighlight', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + physicalKeyboardHighlight: true + }); + + document.dispatchEvent(new KeyboardEvent('keydown', { + code: "KeyF", + key: "f", + target: { + tagName: "input" + } + })); +}); + +it('PhysicalKeyboard keydown will be handled without physicalKeyboardHighlight', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + physicalKeyboardHighlight: false + }); + + document.dispatchEvent(new KeyboardEvent('keydown', { + code: "KeyF", + key: "f", + target: { + tagName: "input" + } + })); +}); + +it('PhysicalKeyboard keydown will not style non-existent buttons', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + physicalKeyboardHighlight: true + }); + + document.dispatchEvent(new KeyboardEvent('keydown', { + code: "WRONG", + key: "WRONG", + target: { + tagName: "input" + } + })); +}); + +it('PhysicalKeyboard keyup will be handled with physicalKeyboardHighlight', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + physicalKeyboardHighlight: true + }); + + document.dispatchEvent(new KeyboardEvent('keyup', { + code: "KeyF", + key: "f", + target: { + tagName: "input" + } + })); +}); + +it('PhysicalKeyboard keyup will be handle special buttons', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + physicalKeyboardHighlight: true + }); + + document.dispatchEvent(new KeyboardEvent('keyup', { + code: "Shift", + key: "Shift", + target: { + tagName: "input" + } + })); +}); + +it('PhysicalKeyboard keyup will not style non-existent buttons', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + physicalKeyboardHighlight: true, + debug: true + }); + + document.dispatchEvent(new KeyboardEvent('keyup', { + code: "WRONG", + key: "WRONG", + target: { + tagName: "input" + } + })); +}); + +it('PhysicalKeyboard will work with F1-F12 keys', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + physicalKeyboardHighlight: true, + debug: true + }); + + document.dispatchEvent(new KeyboardEvent('keyup', { + code: "F12", + key: "F12", + target: { + tagName: "input" + } + })); +}); \ No newline at end of file diff --git a/src/lib/services/tests/Utilities.test.js b/src/lib/services/tests/Utilities.test.js new file mode 100644 index 00000000..a4d45b86 --- /dev/null +++ b/src/lib/services/tests/Utilities.test.js @@ -0,0 +1,456 @@ +import Keyboard from '../../components/Keyboard'; +import TestUtility from '../../tests/TestUtility'; + +let testUtil = new TestUtility(); + +it('Keyboard mergeDisplay will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + mergeDisplay: true, + display: { + "q": "qreplaced" + } + }); + + expect(keyboard.getButtonElement("q").getAttribute("data-displaylabel")).toBe("qreplaced"); +}); + +it('Keyboard function buttons will work', () => { + testUtil.setDOM(); + + new Keyboard(); + + testUtil.testLayoutFctButtons((fctBtnCount, fctBtnHasOnclickCount) => { + expect(fctBtnCount).toBe(fctBtnHasOnclickCount); + }); +}); + +it('Keyboard {bksp} button will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + let output = keyboard.utilities.getUpdatedInput("{bksp}", "test", keyboard.options); + + expect(output).toBe("tes"); +}); + +it('Keyboard {space} button will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + let output = keyboard.utilities.getUpdatedInput("{space}", "test", keyboard.options); + + expect(output).toBe("test "); +}); + +it('Keyboard {tab} button will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + let output = keyboard.utilities.getUpdatedInput("{tab}", "test", keyboard.options); + + expect(output).toBe("test\t"); +}); + +it('Keyboard {tab} button will work with tabCharOnTab:false', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + tabCharOnTab: false + }); + + let output = keyboard.utilities.getUpdatedInput("{tab}", "test", keyboard.options); + + expect(output).toBe("test"); +}); + +it('Keyboard {enter} button will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + let output = keyboard.utilities.getUpdatedInput("{enter}", "test", keyboard.options); + + expect(output).toBe("test"); +}); + +it('Keyboard {enter} button will work with newLineOnEnter:true', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + newLineOnEnter: true + }); + + let output = keyboard.utilities.getUpdatedInput("{enter}", "test", keyboard.options); + + expect(output).toBe("test\n"); +}); + +it('Keyboard {numpadX} buttons will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + for(let i = 0;i<=9;i++){ + let output = keyboard.utilities.getUpdatedInput(`{numpad${i}}`, "test", keyboard.options); + expect(output).toBe(`test${i}`); + } +}); + +it('Keyboard {numpaddivide} button will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + let output = keyboard.utilities.getUpdatedInput("{numpaddivide}", "test", keyboard.options); + + expect(output).toBe("test/"); +}); + +it('Keyboard {numpadmultiply} button will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + let output = keyboard.utilities.getUpdatedInput("{numpadmultiply}", "test", keyboard.options); + + expect(output).toBe("test*"); +}); + +it('Keyboard {numpadsubtract} button will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + let output = keyboard.utilities.getUpdatedInput("{numpadsubtract}", "test", keyboard.options); + + expect(output).toBe("test-"); +}); + +it('Keyboard {numpadadd} button will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + let output = keyboard.utilities.getUpdatedInput("{numpadadd}", "test", keyboard.options); + + expect(output).toBe("test+"); +}); + +it('Keyboard {numpadadd} button will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + let output = keyboard.utilities.getUpdatedInput("{numpadadd}", "test", keyboard.options); + + expect(output).toBe("test+"); +}); + +it('Keyboard {numpaddecimal} button will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + let output = keyboard.utilities.getUpdatedInput("{numpaddecimal}", "test", keyboard.options); + + expect(output).toBe("test."); +}); + +it('Keyboard custom function buttons will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + layout: { + default: [ + "{randombuttontest}" + ] + } + }); + + let output = keyboard.utilities.getUpdatedInput("{randombuttontest}", "test", keyboard.options); + + expect(output).toBe("test"); + expect(keyboard.getButtonElement("{randombuttontest}").onclick).toBeTruthy(); +}); + +it('Keyboard "{" button will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + let output = keyboard.utilities.getUpdatedInput("{", "test", keyboard.options); + + expect(output).toBe("test{"); +}); + +it('Keyboard "}" button will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + let output = keyboard.utilities.getUpdatedInput("}", "test", keyboard.options); + + expect(output).toBe("test}"); +}); + +it('Keyboard standard button will affect input', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + for (let i = 65; i <= 90; i++) { + let char = String.fromCharCode(i); + let output = keyboard.utilities.getUpdatedInput(char, "test", keyboard.options); + expect(output).toBe(`test${char}`); + } +}); + +it('Keyboard updateCaretPos will work with minus', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + keyboard.caretPosition = 5; + keyboard.utilities.updateCaretPos(2, true); + + expect(keyboard.caretPosition).toBe(3); +}); + +it('Keyboard updateCaretPos will work with plus', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + keyboard.caretPosition = 5; + keyboard.utilities.updateCaretPos(2); + + expect(keyboard.caretPosition).toBe(7); +}); + +it('Keyboard addStringAt will work with debug', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + debug: true + }); + + keyboard.getButtonElement("q").onclick(); + + expect(keyboard.getInput()).toBe("q"); +}); + +it('Keyboard addStringAt will work with position', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + debug: true + }); + + keyboard.setInput("test"); + keyboard.caretPosition = 4; + + keyboard.getButtonElement("q").onclick(); + + expect(keyboard.getInput()).toBe("testq"); +}); + +it('Keyboard addStringAt will respect maxLength', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + debug: true, + maxLength: 4 + }); + + keyboard.setInput("test"); + keyboard.caretPosition = 4; + + keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq") + keyboard.utilities.addStringAt("test", "q", 4); + + expect(keyboard.caretPosition).toBe(4); +}); + +it('Keyboard handleMaxLength will exit out on same updatedInput', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + debug: true + }); + + keyboard.setInput("test"); + + let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "test") + + expect(output).toBeFalsy(); +}); + +it('Keyboard handleMaxLength will work with object maxLength', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + maxLength: { + default: 4 + } + }); + + keyboard.setInput("test"); + + let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); + + expect(output).toBeTruthy(); +}); + +it('Keyboard handleMaxLength will work with object maxLength and debug', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + maxLength: { + default: 4 + }, + debug: true + }); + + keyboard.setInput("test"); + + let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); + + expect(output).toBeTruthy(); +}); + +it('Keyboard handleMaxLength will return false if obj maxLength not reached', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + maxLength: { + default: 7 + } + }); + + keyboard.setInput("test"); + + let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); + + expect(output).toBeFalsy(); +}); + + +it('Keyboard handleMaxLength will work without debug', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + maxLength: 4 + }); + + keyboard.setInput("test"); + + let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); + + expect(output).toBeTruthy(); +}); + + +it('Keyboard handleMaxLength will work with numeric maxLength', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + maxLength: 3 + }); + + keyboard.setInput("test"); + + let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); + + expect(output).toBeFalsy(); +}); + +it('Keyboard handleMaxLength wont work with non numeric or object maxLength', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + maxLength: "wrong" + }); + + keyboard.setInput("test"); + + let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); + + expect(output).toBeFalsy(); +}); + +it('Keyboard handleMaxLength wont work with non numeric or object maxLength (with debug)', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + maxLength: "wrong", + debug: true + }); + + keyboard.setInput("test"); + + let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); + + expect(output).toBeFalsy(); +}); + +it('Keyboard isMaxLengthReached will work', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard({ + maxLength: 5 + }); + + let output = keyboard.utilities.isMaxLengthReached(); + + expect(output).toBeFalsy(); +}); + +it('Keyboard removeAt will exit out on caretPosition:0', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + keyboard.setInput("test"); + + keyboard.caretPosition = 0; + keyboard.utilities.removeAt(keyboard.getInput(), 0); + + expect(keyboard.getInput()).toBe("test"); +}); + +it('Keyboard removeAt will remove multi-byte unicodes with caretPos>0', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + keyboard.caretPosition = 6; + let output = keyboard.utilities.removeAt("test\uD83D\uDE00", 6); + + expect(output).toBe("test"); +}); + +it('Keyboard removeAt will not remove multi-byte unicodes with caretPos:0', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + let output = keyboard.utilities.removeAt("\uD83D\uDE00"); + + expect(output).toBeFalsy(); +}); + +it('Keyboard removeAt will remove regular strings', () => { + testUtil.setDOM(); + + let keyboard = new Keyboard(); + + keyboard.caretPosition = 6; + let output = keyboard.utilities.removeAt("testie", 6); + + expect(output).toBe("testi"); +}); \ No newline at end of file diff --git a/src/lib/tests/TestUtility.js b/src/lib/tests/TestUtility.js new file mode 100644 index 00000000..464d35cd --- /dev/null +++ b/src/lib/tests/TestUtility.js @@ -0,0 +1,93 @@ +export default class TestUtility { + /** + * FUNCTIONS + */ + + setDOM = (divClass) => { + this.clear(); + const div = document.createElement('div'); + div.className += divClass || "simple-keyboard"; + document.body.appendChild(div); + } + + clear = () => { + document.body.innerHTML = ""; + } + + testLayoutStdButtons = (keyboard) => { + let stdBtnCount = 0; + let fullInput = ''; + + this.iterateButtons((button) => { + let label = button.getAttribute("data-skbtn"); + + if(label.includes("{")) + return false; + + // Click all standard buttons, respects maxLength + button.onclick(); + + // Recording fullInput, bypasses maxLength + fullInput = keyboard.utilities.getUpdatedInput(label, fullInput, keyboard.options, null); + + stdBtnCount += label.length; + }); + + /** + * Check if maxLength is respected + */ + if( + ( + typeof keyboard.options.maxLength === "object" && + keyboard.getInput().length !== keyboard.options.maxLength[keyboard.options.layoutName] + ) || + ( + typeof keyboard.options.maxLength !== "object" && + keyboard.getInput().length !== keyboard.options.maxLength + ) + ) + throw new Error("MAX_LENGTH_ISSUE"); + else + console.log("MAX_LENGTH PASSED:", keyboard.options.layoutName, keyboard.getInput().length, keyboard.options.maxLength); + + /** + * Check if all standard buttons are inputting something + * (Regardless of maxLength) + */ + if(stdBtnCount !== fullInput.length) + throw new Error("STANDARD_BUTTONS_ISSUE"); + else + console.log("STANDARD_BUTTONS PASSED:", keyboard.options.layoutName, stdBtnCount, fullInput.length); + } + + testLayoutFctButtons = (callback) => { + let fctBtnCount = 0; + let fctBtnHasOnclickCount = 0; + + this.iterateButtons((button) => { + let label = button.getAttribute("data-skbtn"); + + if(!label.includes("{") && !label.includes("}")) + return false; + + fctBtnCount++; + + if(button.onclick){ + button.onclick(); + fctBtnHasOnclickCount++; + } + + callback(fctBtnCount, fctBtnHasOnclickCount); + }); + } + + iterateButtons = (callback, selector) => { + let rows = document.body.querySelector(selector || '.simple-keyboard').children; + + Array.from(rows).forEach(row => { + Array.from(row.children).forEach((button) => { + callback(button); + }); + }); + } +} \ No newline at end of file