karax/tests/domEventTests.nim

624 lines
21 KiB
Nim

import times, jstrutils, strutils, kdom, karax, karaxdsl, vdom, tables
var
results: seq[cstring]
dragEventsCompleted = initTable[DragEventTypes, bool]()
testRunning: array[13, bool]
testCompleted: array[13, bool]
test2ImageDrop = false
dblClickCount = 0
test6ClickCount = 0
test8Failure = false
test10inputFocusCount = 0
test12Failure = false
proc getLogText(text: string): cstring =
result = "[$#]: $#" % [format(getLocalTime(getTime()), "HH:mm:ss"), $text]
proc log(text: string, clear: bool = false) =
if clear:
results = @[]
results.add getLogText(text)
echo text
redrawSync()
# Scroll to top after adding text using JQuery
discard window.setTimeout("$('#results').animate({ scrollTop: 0 }, 100);", 100)
proc check(cond: bool, msg: string) =
if not cond:
log "FAIL: " & msg
doAssert(cond, msg)
proc check(cond: bool, msg: string, warn: bool): bool =
if not cond:
if warn:
log "WARNING: " & msg
else:
log "FAIL: " & msg
doAssert(cond, msg)
result = cond
proc dragDivDragStart(ev: kdom.Event) =
dragEventsCompleted[DragStart] = true
var dgev = cast[DragEvent](ev)
var dragDiv = document.getElementById("dragDiv")
if dragDiv != nil:
var style = window.getComputedStyle(dgev.target)
var dataX = $(parseInt(style.left) - dgev.clientX)
var dataY = $(parseInt(style.top) - dgev.clientY)
dgev.dataTransfer.setData("text/plain", dataX & "," & dataY)
var img = (ImageElement)document.createElement("img")
img.src ="https://nim-lang.org/assets/img/logo.svg"
dgev.dataTransfer.setDragImage(img, 0, 0)
proc dragDivDragOver(ev: kdom.Event) =
dragEventsCompleted[DragOver] = true
ev.preventDefault()
proc checkAllTests() =
var allTestsPassed = true
for a in testCompleted:
if not a:
allTestsPassed = false
break
if allTestsPassed:
log "All tests completed successfully!"
else:
log "Some tests failed. Check the log."
proc completeTest13() =
testRunning[12] = false
testCompleted[12] = true
log "Test 13 completed successfully."
checkAllTests()
proc test13() =
testRunning[12] = true
log "Test 13 started."
log "This test verifies KeyboardEvent getModifierState functionality."
log "To continue, press the left CTRL key."
proc test12focus1(ev: kdom.Event) =
ev.stopImmediatePropagation()
proc test12focus2(ev: kdom.Event) =
test12Failure = true
check false, "Unexpected listener invocation."
proc test12focus3(ev: kdom.Event) =
test12Failure = true
check false, "Unexpected listener invocation."
proc completeTest12() =
if not test12Failure:
var elmt = document.getElementById("test12input")
elmt.style.visibility = "hidden"
testRunning[11] = false
testCompleted[11] = true
log "Test 12 completed successfully."
test13()
proc test12() =
testRunning[11] = true
log "Test 12 started."
log "This test verifies stopImmediatePropagation functionality."
var elmt = document.getElementById("test12input")
elmt.style.visibility = "visible"
elmt.addEventListener($Focus, test12focus1)
elmt.addEventListener($Focus, test12focus2)
elmt.addEventListener($Focus, test12focus3)
elmt.focus()
discard setTimeout(completeTest12, 500)
proc completeTest11() =
document.querySelector("h3").style.visibility = "hidden"
testRunning[10] = false
testCompleted[10] = true
log "Test 11 completed."
test12()
proc test11() =
testRunning[10] = true
log "Test 11 started."
log "This test checks querySelector and querySelectorAll."
document.getElementById("test11h3").style.visibility = "visible"
var elmt = document.querySelector("h3")
check elmt != nil, "querySelector returned nil."
log "text: " & $elmt.innerHTML
check $elmt.innerHTML == "test 11", "Unexpected h3 value."
var elmts = document.querySelectorAll("h3")
log "elmts len: " & $elmts.len
check elmts.len == 1, "Unexpected elmts len."
log "text: " & $elmts[0].innerHTML
check $elmts[0].innerHTML == "test 11", "Unexpected h3 value."
discard setTimeout(completeTest11, 500)
proc completeTest10() =
testRunning[9] = false
testCompleted[9] = true
var test10input1 = document.getElementById("test10input1")
var test10input2 = document.getElementById("test10input2")
test10input1.style.visibility = "hidden"
test10input2.style.visibility = "hidden"
log "Test 10 completed."
test11()
proc test10inputOnfocus(ev: kdom.Event) =
if testRunning[9]:
inc test10inputFocusCount
if test10inputFocusCount > 3:
discard setTimeout(completeTest10, 500)
proc test10() =
log "Test 10 started."
log "This test checks element.focus()."
testRunning[9] = true
var test10input1 = document.getElementById("test10input1")
var test10input2 = document.getElementById("test10input2")
test10input1.style.visibility = "visible"
test10input2.style.visibility = "visible"
test10input1.addEventListener($DomEvent.Focus, test10inputOnfocus)
test10input2.addEventListener($DomEvent.Focus, test10inputOnfocus)
test10input1.focus()
test10input2.focus()
test10input1.focus()
test10input2.focus()
proc completeTest9() =
var test9Value = $document.getElementById("test9value").value
doAssert(test9Value == "[test9]", "Unexpected test9 value.")
testRunning[8] = false
testCompleted[8] = true
test10()
proc test9() =
log "Test 9 started."
log "This tests the setTimeout(w: Window, code: cstring, pause: int) proc."
testRunning[8] = true
discard window.setTimeout("document.getElementById('test9value').value = '[test9]';", 500)
discard window.setTimeout(completeTest9, 1000)
proc completeTest8() =
if not test8Failure:
log "Test 8 completed successfully."
testRunning[7] = false
testCompleted[7] = true
test9()
else:
log "Test 8 failed."
proc failTest8() =
test8Failure = true
check(false, "ClearTimeout failed.")
proc test8() =
log "Test 8 started."
log "This test checks that clearTimeout() works correctly."
testRunning[7] = true
var timeout = setTimeout(failTest8, 1000)
clearTimeout(timeout)
discard setTimeout(completeTest8, 1200)
proc test7() =
log "Test 7 started."
log "This test ensures that mouse events correctly pass button and key modifier information."
log "To continue, right-click while holding SHIFT."
testRunning[6] = true
# A mouseMove handler is needed (even if empty) so mouseDown will have a value for movementX and movementY
proc mouseMove(ev: kdom.Event) =
discard
proc mouseDown(ev: kdom.Event) =
var me = (MouseEvent)ev
if testRunning[5]:
log "[ME] button: " & $me.button
log "[ME] buttons: " & $me.buttons
log "[ME] altKey: " & $me.altKey
log "[ME] ctrlKey: " & $me.ctrlKey
log "[ME] metaKey: " & $me.metaKey
log "[ME] shiftKey: " & $me.shiftKey
log "[ME] clientX: " & $me.clientX
check me.clientX > 0, "Unexpected clientX value."
log "[ME] clientY: " & $me.clientY
check me.clientY > 0, "Unexpected clientY value."
log "[ME] movementX: " & $me.movementX
check me.movementX > 0, "Unexpected movementX value."
log "[ME] movementY: " & $me.movementY
check me.movementY > 0, "Unexpected movementY value."
log "[ME] offsetX: " & $me.offsetX
check me.offsetX > 0, "Unexpected offsetX value."
log "[ME] offsetY: " & $me.offsetY
check me.offsetY > 0, "Unexpected offsetY value."
log "[ME] pageX: " & $me.pageX
check me.pageX > 0, "Unexpected pageX value."
log "[ME] pageY: " & $me.pageY
check me.pageY > 0, "Unexpected pageY value."
log "[ME] relatedTarget == nil: " & $(me.relatedTarget == nil)
log "[ME] screenX: " & $me.screenX
check me.screenX > 0, "Unexpected screenX value."
log "[ME] screenY: " & $me.screenY
check me.screenY > 0, "Unexpected screenY value."
log "[ME] x: " & $me.x
check me.x > 0, "Unexpected x value."
log "[ME] y: " & $me.y
check me.y > 0, "Unexpected y value."
if dblClickCount == 1:
inc test6ClickCount
if test6ClickCount > 1:
testRunning[5] = false
testCompleted[5] = true
log "Test 6 completed successfully."
test7()
elif testRunning[6]:
log "[ME] buttons: " & $me.buttons
var passed = check(me.buttons == (int)SecondaryButton, "Unexpected buttons value.", true)
log "[ME] shiftKey: " & $me.shiftKey
passed = passed and check(me.shiftKey, "Unexpected shiftKey value.", true)
var isShiftPressed = me.getModifierState($KeyboardEventKey.Shift)
log "[ME] getModifierState shift result: " & $isShiftPressed
passed = passed and check(isShiftPressed, "Unexpected getModifierState shift result.", true)
if passed:
log "Test 7 completed successfully."
testRunning[6] = false
testCompleted[6] = true
ev.preventDefault()
if testCompleted[6]:
test8()
proc dblClick(ev: kdom.Event) =
inc dblClickCount
check dblClickCount == 1, "Unexpected double-click event invocation."
log "Try double-clicking again."
proc test6() =
log "Test 6 started."
log "This test validates that addEventListener can be called by passing AddEventListenerOptions, and the options work correctly."
log "To continue, try double-clicking the mouse."
var options = AddEventListenerOptions(once:true)
document.addEventListener($DomEvent.DblClick, dblClick, options)
testRunning[5] = true
proc test5() =
log "Test 5 started."
log "This test validates the newly added properties: window.screen.width, window.scren.height, element.clientWidth, and element.clientHeight."
log "window.screen.width: " & $window.screen.width
check(window.screen.width > 0, "Unexpected value for window.screen.width.")
log "window.screen.height: " & $window.screen.height
check(window.screen.height > 0, "Unexpected value for window.screen.height.")
var elem = document.getElementById("results")
log "results div clientWidth: " & $elem.clientWidth
check(elem.clientWidth > 0, "Unexpected value for clientWidth.")
log "results div clientHeight: " & $elem.clientHeight
check(elem.clientHeight > 0, "Unexpected value for clientHeight.")
testRunning[4] = false
testCompleted[4] = true
log "Test 5 completed successfully."
test6()
proc keyDown(ev: kdom.Event) =
var kbev = ((KeyboardEvent)ev)
if testRunning[2]:
log "[KB] altKey: " & $kbev.altKey
log "[KB] ctrlKey: " & $kbev.ctrlKey
log "[KB] metaKey: " & $kbev.metaKey
log "[KB] shiftKey: " & $kbev.shiftKey
log "[KB] code: " & $kbev.code
log "[KB] isComposing: " & $kbev.isComposing
log "[KB] key: " & $kbev.key
log "[KB] keyCode: " & $kbev.keyCode
log "[KB] location: " & $kbev.location
log "Test 3 completed successfully."
testRunning[2] = false
testCompleted[2] = true
testRunning[3] = true
log "Test 4 started."
log "This test ensures the child events have access to base event settings."
log "[KB] event.bubbles: " & $kbev.bubbles
check kbev.bubbles, "Unexpected event.bubbles value."
log "[KB] event.cancelBubble: " & $kbev.cancelBubble
check kbev.cancelBubble == false, "Unexpected event.cancelBubble value."
log "[KB] event.cancelable: " & $kbev.cancelable
check kbev.cancelable, "Unexpected event.cancelable value."
log "[KB] event.composed: " & $kbev.composed
check kbev.composed, "Unexpected event.composed value."
log "[KB] event.currentTarget.nodeName: " & $kbev.currentTarget.nodeName
check kbev.currentTarget.nodeName == "#document", "Unexpected event.currentTarget.nodeName value."
log "[KB] event.defaultPrevented: " & $kbev.defaultPrevented
check kbev.defaultPrevented == false, "Unexpected event.defaultPrevented value."
log "[KB] event.eventPhase: " & $kbev.eventPhase
check EventPhase(kbev.eventPhase) == BubblingPhase, "Unexpected event.eventPhase value."
log "[KB] event.isTrusted: " & $kbev.isTrusted
check kbev.isTrusted, "Unexpected event.isTrusted value."
log "[UI] kbev.detail: " & $kbev.detail
log "[UI] kbev.view.outerHeight: " & $kbev.view.outerHeight
check kbev.view.outerHeight > 0, "Unexpected view.outerHeight value."
log "[UI] kbev.view.outerWidth: " & $kbev.view.outerWidth
check kbev.view.outerWidth > 0, "Unexpected view.outerWidth value."
testRunning[3] = false
testCompleted[3] = true
log "Test 4 completed."
test5()
elif testRunning[12]:
if kbev.code == "ControlLeft":
log "[KB] altKey: " & $kbev.altKey
log "[KB] ctrlKey: " & $kbev.ctrlKey
log "[KB] metaKey: " & $kbev.metaKey
log "[KB] shiftKey: " & $kbev.shiftKey
log "[KB] code: " & $kbev.code
log "[KB] isComposing: " & $kbev.isComposing
log "[KB] key: " & $kbev.key
log "[KB] keyCode: " & $kbev.keyCode
log "[KB] location: " & $kbev.location
var isControl = kbev.getModifierState($KeyboardEventKey.Control)
log "[KB] getModifierState result: " & $isControl
check isControl, "Unexpected getModifierState return value."
completeTest13()
proc test3() =
log "Test 3 started."
log "This test validates KeyboardEvent handling."
log "Click on the browser to focus, and then press any key."
testRunning[2] = true
proc dragDivDrop(ev: kdom.Event) =
dragEventsCompleted[Drop] = true
var dgev = cast[DragEvent](ev)
var dragDiv = document.getElementById("dragDiv")
var data = $dgev.dataTransfer.getData("text/plain")
var dt = dgev.dataTransfer
if not test2ImageDrop:
var offset = data.split(",")
var newLeft = dgev.clientX + parseInt(offset[0])
var newTop = dgev.clientY + parseInt(offset[1])
if newLeft < 0: newLeft = 0
if newTop < 0: newTop = 0
if newLeft + dragDiv.clientWidth > window.outerWidth: newLeft = window.outerWidth - dragDiv.clientWidth
if newTop + dragDiv.clientHeight > window.outerHeight: newTop = window.outerHeight - dragDiv.clientHeight
dragDiv.style.left = $newLeft & "px"
dragDiv.style.top = $newTop & "px"
if testRunning[0]:
log "[drop] Drop coords: $#, $#" % [$newLeft, $newTop]
if testCompleted[0] and not testCompleted[1] and not testRunning[1]:
testRunning[1] = true
log "Test 2 started."
log "This test validates the DataTransfer and DataTransferItem objects passed as part of the drag events."
var isChrome = ($navigator.userAgent).contains("Chrome")
log "[DT] effectAllowed: " & $dt.effectAllowed
var expectedEffectAllowed = $Uninitialized
if isChrome:
expectedEffectAllowed = if test2ImageDrop: $DataTransferEffectAllowed.Copy else: $DataTransferEffectAllowed.All
check(dt.effectAllowed == $expectedEffectAllowed, "Unexpected effectAllowed value.")
if not test2ImageDrop:
log "[DT] dropEffect: " & $dt.dropEffect
var expectedDropEffect = if isChrome: $DataTransferDropEffect.None else: $DataTransferDropEffect.Move
check(dt.dropEffect == $expectedDropEffect, "Unexpected dropEffect value.")
var expectedFilesLen = if test2ImageDrop: 1 else: 0
log "[DT] files len: " & $dt.files.len
check(dt.files.len == expectedFilesLen, "Unexpected files length.")
var expectedItemsLen = 1
log "[DT] items len: " & $dt.items.len
check(dt.items.len == expectedItemsLen, "Unexpected items length.")
var expectedItemKind = if test2ImageDrop: $DataTransferItemKind.File else: $DataTransferItemKind.String
log "[DT] items[0].kind: " & $dt.items[0].kind
check(dt.items[0].kind == expectedItemKind, "Unexpected item kind.")
var expectedItemType = if test2ImageDrop: "image/png" else: "text/plain"
log "[DT] items[0].type: " & $dt.items[0].`type`
check(dt.items[0].`type` == expectedItemType, "Unexpected item type.")
var expectedTypesLen = if not isChrome and test2ImageDrop: 2 else: 1
log "[DT] types len: " & $dt.types.len
check(dt.types.len == expectedTypesLen, "Unexpected types length.")
if test2ImageDrop:
log "[DT] types[0]: " & $dt.types[0]
if isChrome:
check(dt.types[0] == "Files", "Unexpected type value.")
else:
log "[DT] types[1]: " & $dt.types[1]
check(dt.types[0] == "application/x-moz-file", "Unexpected type value.")
check(dt.types[1] == "Files", "Unexpected type value.")
if test2ImageDrop:
test2ImageDrop = false
# TODO: Determine why getAsString() does invoke callback
# proc getAsString*(dti: DataTransferItem, callback: proc(data: cstring))
var jfile = dt.items[0].getAsFile()
log "[DT] file name: " & $jfile.name
check(jfile.name.len > 0, "Unexpected file name length.")
testCompleted[1] = true
testRunning[1] = false
log "Test 2 completed successfully."
test3()
ev.preventDefault()
return
document.getElementById("dragDiv").style.visibility = "hidden"
log "To continue, drag a .PNG file (file type matters) anywhere on this page."
log "NOTE: If the browser redirects to the image, then consider this test as failed."
test2ImageDrop = true
testRunning[1] = false
ev.preventDefault()
proc dragDivDrag(ev: kdom.Event) =
dragEventsCompleted[Drag] = true
ev.preventDefault()
proc dragDivDragLeave(ev: kdom.Event) =
dragEventsCompleted[DragLeave] = true
if testRunning[0]:
log "[dragLeave]"
ev.preventDefault()
proc dragDivDragExit(ev: kdom.Event) =
dragEventsCompleted[DragExit] = true
if testRunning[0]:
log "[dragExit]"
ev.preventDefault()
proc dragDivDragEnd(ev: kdom.Event) =
dragEventsCompleted[DragEnd] = true
if testRunning[0]:
log "[dragEnd]"
ev.preventDefault()
proc dragDivDragEnter(ev: kdom.Event) =
dragEventsCompleted[DragEnter] = true
if testRunning[0]:
log "[dragEnter]"
ev.preventDefault()
proc initDragEvents() =
log "Drag event initialization started."
var dragDiv = document.getElementById("dragDiv")
document.addEventListener($DragEventTypes.DragOver, dragDivDragOver, false)
document.addEventListener($DragEventTypes.Drop, dragDivDrop, false)
document.addEventListener($DragEventTypes.Drag, dragDivDrag, false)
dragDiv.addEventListener($DragEventTypes.DragStart, dragDivDragStart, false)
dragDiv.addEventListener($DragEventTypes.DragExit, dragDivDragExit, false)
dragDiv.addEventListener($DragEventTypes.DragLeave, dragDivDragLeave, false)
dragDiv.addEventListener($DragEventTypes.DragEnd, dragDivDragEnd, false)
dragDiv.addEventListener($DragEventTypes.DragEnter, dragDivDragEnter, false)
log "Drag event initialization complete."
log "Drag the div to continue the test. Make sure you drag the div over another element."
log "Then click the \"Check test 1 status\" button."
proc initMouseEvents() =
log "Mouse event initialization started."
document.addEventListener($DomEvent.MouseDown, mouseDown, false)
document.addEventListener($DomEvent.MouseMove, mouseMove, false)
log "Mouse event initialization complete."
proc initKbEvents() =
log "KB event initialization started."
document.addEventListener($DomEvent.KeyDown, keyDown, false)
log "KB event initialization complete."
proc startTests() =
log "[Disclaimer: these tests have been tested successfully on Linux with Firefox and Chromium. Your results may vary.]"
log "Note: these tests require some manual steps, which will be shown here."
log "Note: new entries appear in this text area at the top, so read in this direction."
log " | | | | | | | | | | | | | | | | | | | | | |"
log " / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\"
log "Test 1 started."
log "This test checks that drag events are fired."
testRunning[0] = true
for evt in [Drag, DragEnd, DragEnter, DragExit, DragLeave, DragOver, DragStart, Drop]:
dragEventsCompleted.add(evt, false)
initKbEvents()
initMouseEvents()
initDragEvents()
proc checkTest1Status() =
var evtsCompleted = true
# Chrome doesn't seem to send DragExit, so ignore this
if (($navigator.userAgent).contains("Chrome")):
dragEventsCompleted[DragExit] = true
for evt, completed in dragEventsCompleted:
if not completed:
evtsCompleted = false
break
if evtsCompleted:
testRunning[0] = false
log "Test 1 completed successfully. Drag the div anywhere to start the next test."
testCompleted[0] = true
document.getElementById("checkTest1").style.visibility = "hidden"
else:
log "Test 1 has not completed yet. Make sure you drag the div over another element."
log "Status:"
for evt, completed in dragEventsCompleted:
log $evt & ": " & $completed
proc createDom(): VNode =
result = buildHtml(tdiv()):
tdiv(id="dragDiv", draggable="true"):
tdiv(class="divcontent"):
text "draggable div"
tdiv(id="results"):
for i in countdown(results.len - 1, 0):
tdiv:
text $results[i]
tdiv(id="checkTest1"):
button(onclick=checkTest1Status):
text "Check test 1 status"
input(`type`="hidden", id="test9value")
input(`type`="text", id="test10input1")
input(`type`="text", id="test10input2")
h3(id="test11h3"):
text "test 11"
input(`type`="text", id="test12input")
proc onload() =
startTests()
setRenderer createDom
onload()