diff --git a/test/in-plain-html-js/karma.conf.js b/test/in-plain-html-js/karma.conf.js index ed37b08..1b85883 100644 --- a/test/in-plain-html-js/karma.conf.js +++ b/test/in-plain-html-js/karma.conf.js @@ -60,7 +60,11 @@ module.exports = function(config) { // level of logging // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO, + logLevel: config.LOG_WARN, + + browserConsoleLogOptions: { + terminal: false, + }, // enable / disable watching file and executing tests whenever any file changes diff --git a/test/in-plain-html-js/test/index.spec.js b/test/in-plain-html-js/test/index.spec.js index f4d568a..542ab6e 100644 --- a/test/in-plain-html-js/test/index.spec.js +++ b/test/in-plain-html-js/test/index.spec.js @@ -110,7 +110,7 @@ describe('interactive demo', () => { it('should move cursor before "c"', () => { expect(firstInput.selectionStart).toBe(2, 'start'); expect(firstInput.selectionEnd).toBe(2, 'end'); - expect(firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/, 'direction')); + expect(firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/), 'direction'); }); }); @@ -121,7 +121,7 @@ describe('interactive demo', () => { it('should move cursor to the beginning', () => { expect(firstInput.selectionStart).toBe(0, 'start'); expect(firstInput.selectionEnd).toBe(0, 'end'); - expect(firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/, 'direction')); + expect(firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/), 'direction'); }); }); @@ -137,7 +137,7 @@ describe('interactive demo', () => { it('should move cursor behind "b"', () => { expect(firstInput.selectionStart).toBe(2, 'start'); expect(firstInput.selectionEnd).toBe(2, 'end'); - expect(firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/, 'direction')); + expect(firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/), 'direction'); }); }); @@ -148,7 +148,7 @@ describe('interactive demo', () => { it('should move cursor to the end', () => { expect(firstInput.selectionStart).toBe(3, 'start'); expect(firstInput.selectionEnd).toBe(3, 'end'); - expect(firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/, 'direction')); + expect(firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/), 'direction'); }); }); @@ -160,7 +160,7 @@ describe('interactive demo', () => { expect(firstInput.value).toBe('bc', 'value'); expect(firstInput.selectionStart).toBe(0, 'start'); expect(firstInput.selectionEnd).toBe(0, 'end'); - expect(firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/, 'direction')); + expect(firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/), 'direction'); }); }); @@ -172,7 +172,7 @@ describe('interactive demo', () => { expect(firstInput.value).toBe('ac', 'value'); expect(firstInput.selectionStart).toBe(1, 'start'); expect(firstInput.selectionEnd).toBe(1, 'end'); - expect(firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/, 'direction')); + expect(firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/), 'direction'); }); }); }); @@ -187,6 +187,15 @@ describe('interactive demo', () => { it('should *not* show control backspace', () => expect(testElement(id.control.backspace).offsetHeight).toBe(0)); it('should show control delete', () => expect(testElement(id.control.delete).offsetHeight).toBeGreaterThan(0)); + describe('twice', () => { + beforeEach(() => emulateKey.mouse.hover(testElement(id.control.shift))); + + it('should show control tab', () => expect(testElement(id.control.tab).offsetHeight).toBeGreaterThan(0)); + it('should *not* show control shift-tab', () => expect(testElement(id.control.shiftTab).offsetHeight).toBe(0)); + it('should show control backspace', () => expect(testElement(id.control.backspace).offsetHeight).toBeGreaterThan(0)); + it('should *not* show control delete', () => expect(testElement(id.control.delete).offsetHeight).toBe(0)); + }); + describe(', focus first input', () => { let firstInput; diff --git a/test/in-plain-html-js/test/init-spec.js b/test/in-plain-html-js/test/init-spec.js index d1127e4..2e0f111 100644 --- a/test/in-plain-html-js/test/init-spec.js +++ b/test/in-plain-html-js/test/init-spec.js @@ -4,7 +4,7 @@ function waitFor(description, test, retryDelay = [0, 1, 5, 10, 20, 100, 200, 500 const ready = test(); if (ready) return done(); if (currentTry > 3) { - console.log('css not ready (' + (currentTry + 1) + ')'); + console.log(description + ' not ready (' + (currentTry + 1) + ')'); } const delay = retryDelay[currentTry++]; if (typeof delay !== 'number') { diff --git a/test/in-typescript-requirejs/karma-proxies.js b/test/in-typescript-requirejs/karma-proxies.js new file mode 100644 index 0000000..f8bd310 --- /dev/null +++ b/test/in-typescript-requirejs/karma-proxies.js @@ -0,0 +1,13 @@ +const karmaProxies = { + '/base/emulate-tab.js': '/base/node_modules/emulate-tab/dist/bundles/emulate-tab.amd.js', + '/base/emulate-key-in-browser.js': '/base/node_modules/emulate-key-in-browser/dist/bundles/emulate-key-in-browser.amd.js', + '/base/tslib.js': '/base/node_modules/tslib/tslib.js', + '/assets/': '/base/dist/assets/', + '/scripts/': '/base/src/', + '/styles/': '/base/src/', + '/app/': 'http://localhost:4300/', +}; + +if (typeof module !== 'undefined') { + module.exports = karmaProxies; +} \ No newline at end of file diff --git a/test/in-typescript-requirejs/karma.conf.js b/test/in-typescript-requirejs/karma.conf.js index f58b16f..737f6d7 100644 --- a/test/in-typescript-requirejs/karma.conf.js +++ b/test/in-typescript-requirejs/karma.conf.js @@ -1,8 +1,11 @@ // Karma configuration -// Generated on Thu Jun 18 2020 08:31:24 GMT+0200 (GMT+02:00) +// Generated on Tue Jun 30 2020 12:52:45 GMT+0200 (GMT+02:00) + +const withCoverage = true && process.env.COVERAGE; +const tsConfig = require('./tsconfig.json'); module.exports = function(config) { - console.log('orig config', config); + tsConfig.compilerOptions.module = 'amd'; config.set({ // base path that will be used to resolve all patterns (eg. files, exclude) @@ -11,42 +14,28 @@ module.exports = function(config) { // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['jasmine', 'fixture', 'karma-typescript'], + frameworks: ['jasmine', 'requirejs', 'fixture', 'karma-typescript'], karmaTypescriptConfig: { - ...require('./tsconfig.json'), + ...tsConfig, coverageOptions: { - instrumentation: false + instrumentation: withCoverage } }, - plugins: [ - 'karma-fixture', - 'karma-typescript', - 'karma-jasmine', - 'karma-chrome-launcher', - 'karma-firefox-launcher', - 'karma-jasmine-html-reporter', - 'karma-mocha-reporter', - // require('karma-coverage-istanbul-reporter'), - 'karma-html2js-preprocessor', - ], - // list of files / patterns to load in the browser files: [ - { pattern: 'node_modules/requirejs/require.js', included: false, watched: false }, - { pattern: 'dist/assets/*.*', included: false }, + { pattern: 'src/**/*.html', included: true }, + { pattern: 'src/**/*.ts', included: false }, { pattern: 'src/**/*.css', included: false }, - 'src/**/*.html', - 'src/**/*.@(spec|model|controller).@(ts|js)', + { pattern: 'dist/assets/*.*', included: false }, + { pattern: 'node_modules/emulate-key-in-browser/dist/bundles/emulate-key-in-browser.amd.js', included: false }, + { pattern: 'node_modules/emulate-tab/dist/bundles/emulate-tab.amd.js', included: false }, + { pattern: 'node_modules/tslib/tslib.js', included: false }, + 'karma-proxies.js', + 'test-main.js', ], - proxies: { - '/assets/': '/base/dist/assets/', - '/scripts/require.js': '/base/node_modules/requirejs/require.js', - '/scripts/': '/base/src/', - '/styles/': '/base/src/', - '/app/': 'http://localhost:4300/', - }, + proxies: require('./karma-proxies'), // list of files / patterns to exclude exclude: [ @@ -56,10 +45,8 @@ module.exports = function(config) { // preprocess matching files before serving them to the browser // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { - ...config.preprocessors, - '**/*.js': [], '**/*.html': ['html2js'], - "**/*.ts": "karma-typescript" // *.tsx for React Jsx + "**/*.ts": "karma-typescript", }, // test results reporter to use @@ -81,7 +68,11 @@ module.exports = function(config) { // level of logging // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO, + logLevel: config.LOG_WARN, + + browserConsoleLogOptions: { + terminal: false, + }, // enable / disable watching file and executing tests whenever any file changes diff --git a/test/in-typescript-requirejs/package.json b/test/in-typescript-requirejs/package.json index 2a9a5c4..d884d60 100644 --- a/test/in-typescript-requirejs/package.json +++ b/test/in-typescript-requirejs/package.json @@ -4,17 +4,14 @@ "description": "test emulate-key-in-browser in typescript with requirejs", "main": "test.js", "scripts": { + "prebuild": "npm i ../../tmp/emulate-key-in-browser.latest.tgz", "build": "DEBUG=demo-build* node build.js", "prestart": "npm run build", "start": "node -r ts-node/register src/app.ts", "start_watch": "npm-watch start", "test": "karma start", - "install-emulate-key-in-browser": "npm i ../../tmp/emulate-key-in-browser.latest.tgz", - "uninstall-emulate-key-in-browser": "npm i ../../tmp/emulate-key-in-browser.latest.tgz", - "reinstall-emulate-key-in-browser": "npm run uninstall-emulate-key-in-browser", - "postreinstall-emulate-key-in-browser": "npm run install-emulate-key-in-browser", - "precoverage": "npm run reinstall-emulate-key-in-browser", - "coverage": "karma start --browsers=ChromeHeadless,FirefoxHeadless --single-run" + "precoverage": "npm run build", + "coverage": "COVERAGE=true karma start --browsers=ChromeHeadless,FirefoxHeadless --single-run" }, "watch": { "start": { @@ -44,6 +41,7 @@ "karma-jasmine": "^3.3.1", "karma-jasmine-html-reporter": "^1.5.4", "karma-mocha-reporter": "^2.2.5", + "karma-requirejs": "^1.1.0", "karma-typescript": "^5.0.3", "npm-watch": "^0.6.0", "ts-node": "^8.10.2", diff --git a/test/in-typescript-requirejs/src/app.spec.ts b/test/in-typescript-requirejs/src/app.spec.ts index 3901245..cfead9c 100644 --- a/test/in-typescript-requirejs/src/app.spec.ts +++ b/test/in-typescript-requirejs/src/app.spec.ts @@ -1,5 +1,5 @@ import { EventCheckController } from "./event-check.controller"; -import { waitFor } from './wait-for.model'; +import { waitFor } from './wait-for.controller'; xdescribe('demo app', () => { let appFrame: HTMLIFrameElement; @@ -19,7 +19,7 @@ xdescribe('demo app', () => { appFrame.style.height = '100vh'; const loadedListener = () => { appFrame.removeEventListener('load', loadedListener); - waitFor('event check', () => !!(eventCheck = appFrame.contentWindow['eventCheck']), 100, 20).then(done); + waitFor('event check', () => !!(eventCheck = appFrame.contentWindow['eventCheck'])).then(done); }; appFrame.addEventListener('load', loadedListener); fixture.el.appendChild(appFrame); diff --git a/test/in-typescript-requirejs/src/event-check.ts b/test/in-typescript-requirejs/src/event-check-init.ts similarity index 100% rename from test/in-typescript-requirejs/src/event-check.ts rename to test/in-typescript-requirejs/src/event-check-init.ts diff --git a/test/in-typescript-requirejs/src/event-check.controller.ts b/test/in-typescript-requirejs/src/event-check.controller.ts index a3b74c4..1af8461 100644 --- a/test/in-typescript-requirejs/src/event-check.controller.ts +++ b/test/in-typescript-requirejs/src/event-check.controller.ts @@ -1,19 +1,53 @@ import { emulateKey } from 'emulate-key-in-browser'; +export const controlIds = { + container: 'controls', + shift: 'control-shift', + tab: 'control-tab', + shiftTab: 'control-shift-tab', + backspace: 'control-backspace', + delete: 'control-delete', + arrowUp: 'control-arrow-up', + arrowLeft: 'control-arrow-left', + arrowRight: 'control-arrow-right', + arrowDown: 'control-arrow-down', + writeA: 'control-write-a', + writeB: 'control-write-b', + writeC: 'control-write-c', + writeLeeroy: 'control-write-leeroy', + writeJenkins: 'control-write-jenkins', + writeLoremIpsum: 'control-write-lorem-ipsum', +} + +export const viewIds = { + eventLog: 'event-log', + parentOfFirstInput: 'parent-of-first-input', + firstInput: 'first-input', + parentOfSecondInput: 'parent-of-second-input', + secondInput: 'second-input', + button: 'button', + parentOfHiddenInput: 'parent-of-hidden-input', + hiddenInput: 'hidden-input', +} + +export type EventCheckControls = { + [key in keyof typeof controlIds]: HTMLDivElement; +}; + +export interface EventCheckView { + eventLog: HTMLPreElement, + parentOfFirstInput: HTMLDivElement, + firstInput: HTMLInputElement, + parentOfSecondInput: HTMLDivElement, + secondInput: HTMLInputElement, + button: HTMLButtonElement, + parentOfHiddenInput: HTMLDivElement, + hiddenInput: HTMLInputElement, +} + export class EventCheckController { - public view: { - eventLog: HTMLPreElement, - parentOfFirstInput: HTMLDivElement, - firstInput: HTMLInputElement, - parentOfSecondInput: HTMLDivElement, - secondInput: HTMLInputElement, - button: HTMLButtonElement, - control: { - container: HTMLDivElement, - shift: HTMLDivElement, - tab: HTMLDivElement, - shiftTab: HTMLDListElement, - } + public view: EventCheckView & { + control: EventCheckControls, }; private cleanupTasks = new Array<() => PromiseLike | any>(); @@ -24,8 +58,10 @@ export class EventCheckController { const classList = this.view.control.container.classList; if (isActive) { classList.add('shift'); + this.activateShiftBehavior(); } else { classList.remove('shift'); + this.activateDefaultBehavior(); } } @@ -33,23 +69,21 @@ export class EventCheckController { private parent = document, ) { this.view = { - eventLog: this.getElementById('event-log'), - parentOfFirstInput: this.getElementById('parent-of-first-input'), - firstInput: this.getElementById('first-input'), - parentOfSecondInput: this.getElementById('parent-of-second-input'), - secondInput: this.getElementById('second-input'), - button: this.getElementById('button'), - control: { - container: this.getElementById('controls'), - shift: this.getElementById('control-shift'), - tab: this.getElementById('control-tab'), - shiftTab: this.getElementById('control-shift-tab') - } + ...this.getElementsByIds(viewIds), + control: this.getElementsByIds(controlIds), }; } + private getElementsByIds(ids: { [key in keyof U]: string }): U { + return Object.entries(ids).reduce( + (mapped, [key, id]) => Object.assign(mapped, { [key]: this.getElementById(id) }), + {} as U + ); + } + private getElementById(id: string): any { const element = this.parent.getElementById(id); + /* istanbul ignore if */ if (!element) { throw new Error(`element with id '${id}' not found`); } @@ -91,18 +125,44 @@ export class EventCheckController { private initControls() { const control = this.view.control; - control.tab.onmouseover = () => { - console.log('emulate tab'); - emulateKey.tab(); - } - control.shiftTab.onmouseover = () => { - console.log('emulate shift tab'); - emulateKey.shiftTab(); - } control.shift.onmouseover = () => { this.isShiftActive = !this.isShiftActive; } + control.tab.onmouseover = () => emulateKey.tab(); + control.shiftTab.onmouseover = () => emulateKey.shiftTab(); + control.backspace.onmouseover = () => emulateKey.backspace(); + control.delete.onmouseover = () => emulateKey.delete(); + control.writeLeeroy.onmouseover = () => emulateKey.writeText('Leeroy'); + control.writeJenkins.onmouseover = () => emulateKey.writeText('Jenkins'); + control.writeLoremIpsum.onmouseover = () => emulateKey.writeText(loremIpsum); + this.activateDefaultBehavior(); + } + + private activateDefaultBehavior() { + const control = this.view.control; + control.arrowUp.onmouseover = () => emulateKey.arrow.up(); + control.arrowLeft.onmouseover = () => emulateKey.arrow.left(); + control.arrowRight.onmouseover = () => emulateKey.arrow.right(); + control.arrowDown.onmouseover = () => emulateKey.arrow.down(); + control.writeA.onmouseover = () => emulateKey.writeText('a'); + control.writeB.onmouseover = () => emulateKey.writeText('b'); + control.writeC.onmouseover = () => emulateKey.writeText('c'); + } + + private activateShiftBehavior() { + const control = this.view.control; + control.arrowUp.onmouseover = () => emulateKey.shiftArrow.up(); + control.arrowLeft.onmouseover = () => emulateKey.shiftArrow.left(); + control.arrowRight.onmouseover = () => emulateKey.shiftArrow.right(); + control.arrowDown.onmouseover = () => emulateKey.shiftArrow.down(); + control.writeA.onmouseover = () => emulateKey.writeText('A'); + control.writeB.onmouseover = () => emulateKey.writeText('B'); + control.writeC.onmouseover = () => emulateKey.writeText('C'); + } + + public destroy() { + this.cleanupTasks.forEach((cleanUpTask) => cleanUpTask()); } } -export default "bla"; \ No newline at end of file +const loremIpsum = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.'; \ No newline at end of file diff --git a/test/in-typescript-requirejs/src/event-check.html b/test/in-typescript-requirejs/src/event-check.html index 4a5793b..ca0306b 100644 --- a/test/in-typescript-requirejs/src/event-check.html +++ b/test/in-typescript-requirejs/src/event-check.html @@ -41,6 +41,10 @@

demo form

+
+ + +
@@ -49,4 +53,4 @@

demo form

event log


 
- \ No newline at end of file + \ No newline at end of file diff --git a/test/in-typescript-requirejs/src/event-check.spec.ts b/test/in-typescript-requirejs/src/event-check.spec.ts index d0f1e9f..903c6cf 100644 --- a/test/in-typescript-requirejs/src/event-check.spec.ts +++ b/test/in-typescript-requirejs/src/event-check.spec.ts @@ -1,9 +1,11 @@ -import { EventCheckController } from './event-check.controller'; +import { emulateKey } from 'emulate-key-in-browser'; +import { EventCheckController, EventCheckControls, EventCheckView } from './event-check.controller'; +import { waitFor } from './wait-for.controller'; describe('event check', () => { let eventCheck: EventCheckController; - let origLog: any; - let logSpy: jasmine.Spy; + let control: EventCheckControls; + let view: EventCheckView; function getEventLog(): string { return eventCheck.view.eventLog.innerHTML; @@ -15,37 +17,268 @@ describe('event check', () => { }); beforeEach(() => { - origLog = console.log; - logSpy = spyOn(console, 'log'); fixture.cleanup(); fixture.load('event-check.html'); eventCheck = new EventCheckController(); eventCheck.init(); + control = eventCheck.view.control; + view = eventCheck.view; + return waitFor('css', () => { + return view.hiddenInput && view.hiddenInput.offsetHeight === 0; + }); }); afterEach(() => { - console.log = origLog; - }) + eventCheck.destroy(); + }); it('should start', () => expect().nothing()); - describe('after write "a" into first input', () => { + describe('after hover tab', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.tab)); + + it('should focus first input', () => expect(document.activeElement).toBe(view.firstInput)); + }); + + describe('after hover shift-tab', () => { + beforeEach(() => emulateKey.mouse.hover(control.shiftTab)); + + it('should focus first input', () => expect(document.activeElement).toBe(view.button)) + }); + + describe('after focus first input', () => { + beforeEach(() => { - const firstInput = eventCheck.view.firstInput; - firstInput.value = 'a'; - const event = new KeyboardEvent('keydown', { code: 'keyA' }); - console.log('event', event); - firstInput.dispatchEvent(event); - return new Promise(done => setTimeout(done, 10)); + view.firstInput.focus(); + }); + + it('should focus first input', () => expect(document.activeElement).toBe(view.firstInput)); + describe('and hover write-a', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.writeA)); + + it('should write "a" into first input', () => expect(view.firstInput.value).toBe('a')); }); - it('log should contain entries', () => expect(getEventLog()).toContain('keyA')); + describe('and hover write-b', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.writeB)); + + it('should write "b" into first input', () => expect(view.firstInput.value).toBe('b')); + }); + + describe('and hover write-c', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.writeC)); + + it('should write "c" into first input', () => expect(view.firstInput.value).toBe('c')); + }); + + describe('and hover write-leeroy', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.writeLeeroy)); + + it('should write "Leeroy" into first input', () => expect(view.firstInput.value).toBe('Leeroy')); + }); + + describe('and hover write-jenkins', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.writeJenkins)); + + it('should write "Jenkins" into first input', () => expect(view.firstInput.value).toBe('Jenkins')); + }); + + describe('and hover write-lorem-ipsum', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.writeLoremIpsum)); + + it('should write lorem ipsum into first input', () => { + expect(view.firstInput.value).toEqual(jasmine.stringMatching(/^Lorem ipsum.{100,}/)); + }); + }); + + describe('then writing abc', () => { + beforeEach(() => view.firstInput.value = 'abc'); + + describe('and hover arrow-left', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.arrowLeft)); + + it('should move cursor before "c"', () => { + expect(view.firstInput.selectionStart).toBe(2, 'start'); + expect(view.firstInput.selectionEnd).toBe(2, 'end'); + expect(view.firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/), 'direction'); + }); + }); + + describe('and hover arrow-up', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.arrowUp)); + + it('should move cursor to the beginning', () => { + expect(view.firstInput.selectionStart).toBe(0, 'start'); + expect(view.firstInput.selectionEnd).toBe(0, 'end'); + expect(view.firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/), 'direction'); + }); + }); + + describe('then moving cursor after a', () => { + beforeEach(() => { + view.firstInput.selectionStart = view.firstInput.selectionEnd = 1; + }); + + describe('and hover arrow-right', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.arrowRight)); + + it('should move cursor behind "b"', () => { + expect(view.firstInput.selectionStart).toBe(2, 'start'); + expect(view.firstInput.selectionEnd).toBe(2, 'end'); + expect(view.firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/), 'direction'); + }); + }); + + describe('and hover arrow-down', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.arrowDown)); + + it('should move cursor to the end', () => { + expect(view.firstInput.selectionStart).toBe(3, 'start'); + expect(view.firstInput.selectionEnd).toBe(3, 'end'); + expect(view.firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/), 'direction'); + }); + }); + + describe('and hover backspace', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.backspace)); + + it('should remove "a"', () => { + expect(view.firstInput.value).toBe('bc', 'value'); + expect(view.firstInput.selectionStart).toBe(0, 'start'); + expect(view.firstInput.selectionEnd).toBe(0, 'end'); + expect(view.firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/), 'direction'); + }); + }); + + describe('and hover delete', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.delete)); + + it('should remove "b"', () => { + expect(view.firstInput.value).toBe('ac', 'value'); + expect(view.firstInput.selectionStart).toBe(1, 'start'); + expect(view.firstInput.selectionEnd).toBe(1, 'end'); + expect(view.firstInput.selectionDirection).toEqual(jasmine.stringMatching(/none|forward/), 'direction'); + }); + }); + }); + }) + }); + + describe('after hover shift', () => { + beforeEach(() => emulateKey.mouse.hover(control.shift)); + + it('should *not* show control tab', () => expect(control.tab.offsetHeight).toBe(0)); + it('should show control shift-tab', () => expect(control.shiftTab.offsetHeight).toBeGreaterThan(0)); + it('should *not* show control backspace', () => expect(control.backspace.offsetHeight).toBe(0)); + it('should show control delete', () => expect(control.delete.offsetHeight).toBeGreaterThan(0)); + + describe('twice', () => { + beforeEach(() => emulateKey.mouse.hover(control.shift)); + + it('should show control tab', () => expect(control.tab.offsetHeight).toBeGreaterThan(0)); + it('should *not* show control shift-tab', () => expect(control.shiftTab.offsetHeight).toBe(0)); + it('should show control backspace', () => expect(control.backspace.offsetHeight).toBeGreaterThan(0)); + it('should *not* show control delete', () => expect(control.delete.offsetHeight).toBe(0)); + }) + + describe(', focus first input', () => { + + beforeEach(() => view.firstInput.focus()); + + describe('and hover write-a', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.writeA)); + + it('should write "a" into first input', () => expect(view.firstInput.value).toBe('A')); + }); + + describe('and hover write-b', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.writeB)); + + it('should write "b" into first input', () => expect(view.firstInput.value).toBe('B')); + }); + + describe('and hover write-c', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.writeC)); + + it('should write "c" into first input', () => expect(view.firstInput.value).toBe('C')); + }); + + describe('then writing abc', () => { + beforeEach(() => view.firstInput.value = 'abc'); + + describe('and hover arrow-left', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.arrowLeft)); + + it('should select "c"', () => { + expect(view.firstInput.selectionStart).toBe(2, 'start'); + expect(view.firstInput.selectionEnd).toBe(3, 'end'); + expect(view.firstInput.selectionDirection).toBe('backward', 'direction'); + }); + }); + + describe('and hover arrow-up', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.arrowUp)); + + it('should select all up to the beginning', () => { + expect(view.firstInput.selectionStart).toBe(0, 'start'); + expect(view.firstInput.selectionEnd).toBe(3, 'end'); + expect(view.firstInput.selectionDirection).toBe('backward', 'direction'); + }); + }); + + describe('then moving cursor after a', () => { + beforeEach(() => { + view.firstInput.selectionStart = view.firstInput.selectionEnd = 1; + }); + + describe('and hover arrow-right', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.arrowRight)); + + it('should select "b"', () => { + expect(view.firstInput.selectionStart).toBe(1, 'start'); + expect(view.firstInput.selectionEnd).toBe(2, 'end'); + expect(view.firstInput.selectionDirection).toBe('forward', 'direction'); + }); + }); + + describe('and hover arrow-down', () => { + shouldLog(); + beforeEach(() => emulateKey.mouse.hover(control.arrowDown)); + + it('should select all to the end', () => { + expect(view.firstInput.selectionStart).toBe(1, 'start'); + expect(view.firstInput.selectionEnd).toBe(3, 'end'); + expect(view.firstInput.selectionDirection).toBe('forward', 'direction'); + }); + }); + }); + }); + }); }); describe('after emulating tab', () => { beforeEach(() => { eventCheck.view.firstInput.focus(); - eventCheck.view.control.tab.onmouseover(new MouseEvent('mouseover')); + emulateKey.mouse.hover(eventCheck.view.control.tab); return new Promise(done => setTimeout(done, 10)); }); @@ -62,7 +295,7 @@ describe('event check', () => { `); expect(actualEventLog).toEqual(expectedEventLog); expect(eventCount(actualEventLog)).toEqual(eventCount(expectedEventLog)); - }) + }); }); }); @@ -76,4 +309,23 @@ function normalizeEventLog(log: string) { function eventCount(normalizedLog: string) { return normalizedLog.split('\n').length - 1; -} \ No newline at end of file +} + +function shouldLog(matcher?: jasmine.MatchableArgs[]) { + let origLog; + let logSpy; + + beforeEach(() => { + origLog = console.log; + logSpy = spyOn(console, 'log'); + }); + + afterEach(() => { + console.log = origLog; + if (matcher) { + expect(logSpy).toHaveBeenCalledWith(...matcher); + } else { + expect(logSpy).toHaveBeenCalled(); + } + }); +} diff --git a/test/in-typescript-requirejs/src/sample-form.spec.ts b/test/in-typescript-requirejs/src/sample-form.spec.ts index 474cbb4..52e1906 100644 --- a/test/in-typescript-requirejs/src/sample-form.spec.ts +++ b/test/in-typescript-requirejs/src/sample-form.spec.ts @@ -1,5 +1,5 @@ import { emulateKey } from 'emulate-key-in-browser'; -import { waitFor } from './wait-for.model'; +import { waitFor } from './wait-for.controller'; describe('sample form', () => { beforeAll(() => { diff --git a/test/in-typescript-requirejs/src/wait-for.controller.ts b/test/in-typescript-requirejs/src/wait-for.controller.ts new file mode 100644 index 0000000..ef4c77b --- /dev/null +++ b/test/in-typescript-requirejs/src/wait-for.controller.ts @@ -0,0 +1,18 @@ +export function waitFor(description: string, test: () => boolean, retryDelay = [0, 1, 5, 10, 20, 100, 200, 500, 1000]) { + let currentTry = 0; + const waitLonger = (done) => { + const ready = test(); + if (ready) return done(); + /* istanbul ignore if */ + if (currentTry > 3) { + console.log(description + ' not ready (' + (currentTry + 1) + ')'); + } + const delay = retryDelay[currentTry++]; + /* istanbul ignore if */ + if (typeof delay !== 'number') { + throw new Error(`failed to wait for ${description} (tested ${currentTry} times)`); + } + setTimeout(() => waitLonger(done), delay); + } + return new Promise(resolve => waitLonger(resolve)); +} diff --git a/test/in-typescript-requirejs/src/wait-for.model.ts b/test/in-typescript-requirejs/src/wait-for.model.ts deleted file mode 100644 index f01cf34..0000000 --- a/test/in-typescript-requirejs/src/wait-for.model.ts +++ /dev/null @@ -1,15 +0,0 @@ -export function waitFor(description: string, test: () => boolean, retryLimit = 20, milliseconsBetweenRetries = 200): Promise { - let currentTry = 1; - const waitLonger = (done) => { - const ready = test(); - if (ready) return done(); - if (currentTry > 3) { - console.log(description + ' not ready (' + currentTry + ')'); - } - if (++currentTry > retryLimit) { - throw new Error('failed to wait for ' + description); - } - setTimeout(() => waitLonger(done), milliseconsBetweenRetries); - } - return new Promise(resolve => waitLonger(resolve)); -} diff --git a/test/in-typescript-requirejs/test-main.js b/test/in-typescript-requirejs/test-main.js new file mode 100644 index 0000000..8225158 --- /dev/null +++ b/test/in-typescript-requirejs/test-main.js @@ -0,0 +1,30 @@ +var allTestFiles = [] +var TEST_REGEXP = /(spec|test)\.js$/i + +// Get a list of all the test files to include +Object.keys(window.__karma__.files).forEach(function (file) { + if (TEST_REGEXP.test(file)) { + // Normalize paths to RequireJS module names. + // If you require sub-dependencies of test files to be loaded as-is (requiring file extension) + // then do not normalize the paths + var normalizedTestModule = file.replace(/^\/base\/|\.js$/g, '') + allTestFiles.push(normalizedTestModule) + } +}) + +Object.entries(karmaProxies).forEach(([from, to]) => { + if (from.startsWith('/base') && to.startsWith('/base')) { + window.__karma__.files[from] = window.__karma__.files[to]; + } +}); + +require.config({ + // Karma serves files under /base, which is the basePath from your config file + baseUrl: '/base', + + // dynamically load all test files + deps: allTestFiles, + + // we have to kickoff jasmine, as it is asynchronous + callback: window.__karma__.start +})