Skip to content

Show the test suite some 💋💋💋 #591

Open
milesnash wants to merge 30 commits intolightning-js:masterfrom
milesnash:fix/tests
Open

Show the test suite some 💋💋💋 #591
milesnash wants to merge 30 commits intolightning-js:masterfrom
milesnash:fix/tests

Conversation

@milesnash
Copy link

@milesnash milesnash commented Jan 30, 2026

Ok, bear with me on this one, let me explain.

I wanted to PR a minor, one-line fix but, whilst doing that, I wanted to add a test for it. Sooo, in order to do that I started by running the tests; and that's where this whole thing got started.

Running npm run test on the current master outputs a bunch of lint and type errors, says 162 tests passed, 0 failed and exits with code 1. Running npm run test:run also outputs the errors, say 311 tests passed, 0 failed and exits with code 1. npm run test:ci basically runs test:run. I was a bit confused.

I wanted to make this better first and started investigating why there were errors and an error exit code. Long story short, I found that difficult and also discovered that the test runner, tape, hasn't had much code activity in the past year and the tap reporter, tap-diff, is archived and hasn't had any activity on it in 10 years.

So I thought it might be a good idea to find another tool that met the following criteria:

  • actively maintained;
  • good docs; and
  • zero to minimal API difference to the current suite.

I landed on tap, which seemed to fulfil these criteria nicely.

This is obviously tap-compatible but a few things needed to be tweaked, including:

  • import statement of the module
  • assert.true|false weren't functions in tap, so I refactored them to the assert.equal equivalent
  • assert.notEqual -> assert.not
  • assert.deepEqual -> assert.same
  • assert.equals -> assert.equal

After this I still found that a bunch of tests just would not pass. They were failing in ways that really made me question what the current test suite was actually running. This included:

  • src/component/base/methods.test.js: the dependency tree stemming from this file caused keyMap to be accessed before it was initialised. To fix this, I had to move keyMap to its own module and change how we access it.
  • scripts/prepublishOnly.test.js: this was trying to assert that an "orig" file existed, but it didn't.
  • src/component/setup/computed.test.js, src/focus.test.js & src/router/router.test.js: these were failing because they tested files that attempted to call methods of Log when it hadn't been initialised
  • src/components/Sprite.test.js: this was failing because the tested component was calling set on undefined
  • src/engines/L3/element.test.js: this was failing because it was instantiating classes before they were defined
  • src/lib/codegenerator/generator.test.js: this was failing because the generated code was different since ___wrapper got introduced

After all that tests run with tap passed! 🎉

I then did a bit of console capturing and removal of spurious console logging in the test files to get noise out of the test output. The result is much, much better-looking test output imo 😍

tap

Next, I updated the test commands in the package.json. The ci tests and the scary-looking output parsing scripts in them should continue to work, as the output is still standard tap output for that command.

Finally, I removed the now-unused dev dependencies from the repo 😅

@github-actions
Copy link

github-actions bot commented Feb 2, 2026

Test Results: ❌ FAILED

Run at: 2026-02-02T05:51:04.743Z

Summary:
Test execution encountered errors. No tests were run.

Error Output:


> @lightningjs/blits@1.47.0 test:ci
> tap --node-arg="--import=global-jsdom/register" --allow-incomplete-coverage --no-color

TAP version 14
1..27
(node:2299) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
(node:2380) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
# Subtest: scripts/prepublishOnly.test.js
    # Subtest: Setup
        ok 1 - precompileComponents function loaded
        ok 2 - processDirectory function loaded
        ok 3 - processFile function loaded
        ok 4 - formatFileWithESLint function loaded
        1..4
    ok 1 - Setup # time=132.599ms
    
    # Subtest: precompileComponents - should log start and end messages
        ok 1 - Should log checking message
        ok 2 - Should log completion message
        1..2
    ok 2 - precompileComponents - should log start and end messages # time=5.252ms
    
    # Subtest: processDirectory - should process JS files in directory
        ok 1 - Should read directory
        ok 2 - Should check file stats
        ok 3 - Should read file
        ok 4 - Should write compiled file
        ok 5 - Should create backup
        1..5
    ok 3 - processDirectory - should process JS files in directory # time=4.608ms
    
    # Subtest: processDirectory - should process TS files in directory
        ok 1 - Should read TS file
        1..1
    ok 4 - processDirectory - should process TS files in directory # time=3.777ms
    
    # Subtest: processDirectory - should skip .orig.js files
        ok 1 - Should only read one file
        ok 2 - Should process Helper.js
        ok 3 - Should not process .orig.js
        1..3
    ok 5 - processDirectory - should skip .orig.js files # time=3.785ms
    
    # Subtest: processDirectory - should skip .orig.ts files
        ok 1 - Should only read one file
        ok 2 - Should not process .orig.ts
        1..2
    ok 6 - processDirectory - should skip .orig.ts files # time=3.083ms
    
    # Subtest: processDirectory - should skip non-JS/TS files
        ok 1 - Should only process JS file
        ok 2 - Should process Component.js
        1..2
    ok 7 - processDirectory - should skip non-JS/TS files # time=2.921ms
    
    # Subtest: processDirectory - should recursively process subdirectories
        ok 1 - Should read 2 directories
        ok 2 - Should process 2 files
        1..2
    ok 8 - processDirectory - should recursively process subdirectories # time=2.041ms
    
    # Subtest: processDirectory - should handle empty directory
        ok 1 - Should read directory once
        ok 2 - Should not check any stats
        1..2
    ok 9 - processDirectory - should handle empty directory # time=1.031ms
    
    # Subtest: processFile - should create backup with .orig.js extension
        ok 1 - Should create .orig.js backup
        1..1
    ok 10 - processFile - should create backup with .orig.js extension # time=1.119ms
    
    # Subtest: processFile - should create backup with .orig.ts extension
        ok 1 - Should create .orig.ts backup
        1..1
    ok 11 - processFile - should create backup with .orig.ts extension # time=1.042ms
    
    # Subtest: processFile - should read and compile file
        ok 1 - Should read file with utf-8
        1..1
    ok 12 - processFile - should read and compile file # time=0.991ms
    
    # Subtest: processFile - should write compiled result
        ok 1 - Should write compiled code
        1..1
    ok 13 - processFile - should write compiled result # time=1.227ms
    
    # Subtest: processFile - should handle compiler returning object with code property
        ok 1 - Should extract code from object
        1..1
    ok 14 - processFile - should handle compiler returning object with code property # time=1.056ms
    
    # Subtest: processFile - should format file when source changes
        ok 1 - Should write compiled file
        ok 2 - Should create backup
        1..2
    ok 15 - processFile - should format file when source changes # time=2.322ms
    
    # Subtest: processFile - should NOT format file when source unchanged
        ok 1 - Should still create backup
        1..1
    ok 16 - processFile - should NOT format file when source unchanged # time=1.559ms
    
    # Subtest: processFile - should log precompiling message
        ok 1 - Should log precompiling message
        1..1
    ok 17 - processFile - should log precompiling message # time=1.843ms
    
    # Subtest: formatFileWithESLint - should accept file path
        ok 1 - Should accept file path without throwing
        1..1
    ok 18 - formatFileWithESLint - should accept file path # time=11.044ms
    
    # Subtest: formatFileWithESLint - should handle file path parameter
        ok 1 - Should handle file path parameter
        1..1
    ok 19 - formatFileWithESLint - should handle file path parameter # time=7.646ms
    
    # Subtest: formatFileWithESLint - should be callable
        ok 1 - Should be a function
        1..1
    ok 20 - formatFileWithESLint - should be callable # time=7.363ms
    
    # Subtest: formatFileWithESLint - should execute without errors
        ok 1 - Should execute without errors
        1..1
    ok 21 - formatFileWithESLint - should execute without errors # time=14.984ms
    
    1..21
ok 1 - scripts/prepublishOnly.test.js # time=6625.907ms

# Subtest: src/announcer/announcer.test.js
    # Subtest: Announcer 1 Second Pause
        # start 1 second pause
        ok 1 - pause finished
        1..1
    ok 1 - Announcer 1 Second Pause # time=1125.555ms
    
    # Subtest: Announcer 1 Second Pause Remove
        # start 1 second pause
        # remove pause
        ok 1 - removed pause
        1..1
    ok 2 - Announcer 1 Second Pause Remove # time=5.072ms
    
    # Subtest: Announcer disable/enable/toggle
        ok 1 - Disabled returns same noop object
        ok 2 - Enabled returns real promise, not noop
        ok 3 - Each enabled message gets unique promise
        ok 4 - Toggle off returns same noop
        ok 5 - Toggle on returns real promise
        ok 6 - Disabled messages are NOT processed
        ok 7 - Enabled messages are queued for processing
        1..7
    ok 3 - Announcer disable/enable/toggle # time=103.586ms
    
    # Subtest: Announcer methods exist
        ok 1 - Stop method exists
        ok 2 - Clear method exists
        ok 3 - Polite method exists
        ok 4 - Assertive method exists
        ok 5 - Speak method exists
        ok 6 - Pause method exists
        1..6
    ok 4 - Announcer methods exist # time=1.392ms
    
    # Subtest: Announcer politeness affects queue order
        ok 1 - Assertive message processes first
        ok 2 - Off message processes second
        ok 3 - Polite message processes third
        1..3
    ok 5 - Announcer politeness affects queue order # time=1192.023ms
    
    # Subtest: Announcer announcement methods
        ok 1 - Has cancel method
        ok 2 - Has remove method
        ok 3 - Has stop method
        ok 4 - Cancel resolves with canceled status
        ok 5 - Remove resolves with canceled status
        1..5
    ok 6 - Announcer announcement methods # time=1.193ms
    
    # Subtest: Announcer stop interrupts processing
        ok 1 - Stop interrupts (or unavailable if no speechSynthesis)
        1..1
    ok 7 - Announcer stop interrupts processing # time=700.335ms
    
    # Subtest: Announcer queue behavior
        ok 1 - Has cancel method
        ok 2 - Has remove method
        ok 3 - Has stop method
        ok 4 - First message queued
        ok 5 - Second message queued
        ok 6 - Third message queued
        ok 7 - Removed message resolves with canceled
        ok 8 - First message processes
        ok 9 - Third message processes after removal
        1..9
    ok 8 - Announcer queue behavior # time=707.895ms
    
    1..8
ok 2 - src/announcer/announcer.test.js # time=6798.323ms

# Subtest: src/component.test.js
    # Subtest: Type
        ok 1 - Component should be a function
        1..1
    ok 1 - Type # time=4.383ms
    
    # Subtest: Component - Factory function
        ok 1 - Component should be a factory function (i.e. return a function)
        1..1
    ok 2 - Component - Factory function # time=0.856ms
    
    # Subtest: Component - Factory requires a name to be passed
        ok 1 - Throw an error when no name argument has been passed
        1..1
    ok 3 - Component - Factory requires a name to be passed # time=0.678ms
    
    # Subtest: Component - Factory requires a config to be passed
        ok 1 - Throw an error when no config argument has been passed
        1..1
    ok 4 - Component - Factory requires a config to be passed # time=1.133ms
    
    # Subtest: Component - Instance should create internal id
        ok 1 - Button instance object should have correct internal id
        ok 2 - Heading instance object should have correct internal id
        1..2
    ok 5 - Component - Instance should create internal id # time=6.397ms
    
    # Subtest: Component - Instance should create component Id
        ok 1 - First Foo instance should have correct id
        ok 2 - Second Foo instance should have correct id
        ok 3 - First Bar instance should have correct id
        1..3
    ok 6 - Component - Instance should create component Id # time=0.885ms
    
    # Subtest: Component - Instance should initiate lifecycle object
        ok 1 - Lifecycle object should be initialized
        ok 2 - Lifecycle object should have a reference to foo instance
        ok 3 - Lifecycle object should have previous state not initialized
        ok 4 - Lifecycle object should have initial current state
        1..4
    ok 7 - Component - Instance should initiate lifecycle object # time=2.029ms
    
    # Subtest: Component - Instance should set a parent reference
        ok 1 - Foo instance object should have parent component object reference
        ok 2 - Foo instance object should have parent element object reference
        1..2
    ok 8 - Component - Instance should set a parent reference # time=1.647ms
    
    # Subtest: Component - Instance should set a root reference
        ok 1 - Foo instance object should have root component object reference
        1..1
    ok 9 - Component - Instance should set a root reference # time=0.885ms
    
    # Subtest: Component - Instance should initialize reactive props
        ok 1 - Foo instance should have props defined
        ok 2 - Foo instance props should be proxy
        ok 3 - should be equal
        1..3
    ok 10 - Component - Instance should initialize reactive props # time=1.001ms
    
    # Subtest: Component - Instance should initialize timeouts array
        ok 1 - Foo instance timeouts should be an array
        1..1
    ok 11 - Component - Instance should initialize timeouts array # time=0.976ms
    
    # Subtest: Component - Instance should initialize intervals array
        ok 1 - Foo instance intervals should be an array
        1..1
    ok 12 - Component - Instance should initialize intervals array # time=0.995ms
    
    # Subtest: Component - Instance should initialize originalState
        ok 1 - Foo instance should store originalState properties
        ok 2 - Foo instance should store originalState hasFocus property
        1..2
    ok 13 - Component - Instance should initialize originalState # time=0.678ms
    
    # Subtest: Component - Instance should initialize reactive state
        ok 1 - Foo instance should have state defined
        ok 2 - Foo instance state should be proxy
        ok 3 - should be equal
        1..3
    ok 14 - Component - Instance should initialize reactive state # time=0.932ms
    
    # Subtest: Component - Instance should initialize children
        ok 1 - Foo instance children should be an array
        ok 2 - Children should be an expected array
        ok 3 - Render should be called with parent parameter
        ok 4 - Render should be called with Foo component instance
        ok 5 - Render should be called with config parameter
        ok 6 - Render should be called with global components object
        1..6
    ok 15 - Component - Instance should initialize children # time=7.076ms
    
    # Subtest: Component - Instance should initialize wrapper
        ok 1 - Wrapper should be a first element of the children
        1..1
    ok 16 - Component - Instance should initialize wrapper # time=1.089ms
    
    # Subtest: Component - Instance should initialize slots
        ok 1 - Slots should be an array
        ok 2 - Slot should be a expected element of the children
        1..2
    ok 17 - Component - Instance should initialize slots # time=1.299ms
    
    ok 18 - Component - Instance should initialize hook events # SKIP
    # Subtest: Component - Instance should execute all side effects
        ok 1 - Effect should be invoked with foo component instance
        ok 2 - Effect should be invoked with component`s children
        ok 3 - Effect should be invoked with config object
        ok 4 - Effect should be invoked with global components object
        ok 5 - Effect should be invoked with root component
        ok 6 - Effect should be invoked with effect function
        1..6
    ok 19 - Component - Instance should execute all side effects # time=1.833ms
    
    # Subtest: Component - Instance should have all symbols configured
        ok 1 - effects should be be enumerable
        ok 2 - effects should be configurable
        ok 3 - holder should be be enumerable
        ok 4 - holder should be configurable
        ok 5 - id should be be enumerable
        ok 6 - id should be configurable
        ok 7 - props should be be enumerable
        ok 8 - props should be configurable
        ok 9 - timeouts should be be enumerable
        ok 10 - timeouts should be configurable
        ok 11 - intervals should be be enumerable
        ok 12 - intervals should be configurable
        ok 13 - debounces should be be enumerable
        ok 14 - debounces should be configurable
        ok 15 - originalState should be be enumerable
        ok 16 - originalState should be configurable
        ok 17 - state should be be enumerable
        ok 18 - state should be configurable
        ok 19 - children should be be enumerable
        ok 20 - children should be configurable
        ok 21 - cleanup should be be enumerable
        ok 22 - cleanup should be configurable
        ok 23 - wrapper should be be enumerable
        ok 24 - wrapper should be configurable
        ok 25 - slots should be be enumerable
        ok 26 - slots should be configurable
        ok 27 - rendererEventListeners should be be enumerable
        ok 28 - rendererEventListeners should be configurable
        1..28
    ok 20 - Component - Instance should have all symbols configured # time=7.04ms
    
    # Subtest: Component - Instance should have ready state after the next process tick
        1..1
        ok 1 - Foo component lifecycle should be eventually in a ready state
    ok 21 - Component - Instance should have ready state after the next process tick # time=3.655ms
    
    # Subtest: Component - Configure input events
        ok 1 - Foo instance should have input events defined
        ok 2 - Foo instance should have `up` input event defined
        ok 3 - Foo instance should have `down` input event defined
        1..3
    ok 22 - Component - Configure input events # time=1.587ms
    
    # Subtest: Component - Warn non-function input events
        ok 1 - Foo instance should have input events defined
        ok 2 - Should log two warning messages
        ok 3 - Should log foo is not a function warning message
        ok 4 - Should log 123 is not a function warning message
        1..4
    ok 23 - Component - Warn non-function input events # time=3.915ms
    
    # Subtest: Component - Configure methods
        ok 1 - Foo instance should have methods keys defined
        ok 2 - Foo instance should have two method keys defined
        ok 3 - First method key should be `foo`
        ok 4 - Second method key should be `bar`
        ok 5 - Foo instance should have `foo` method defined
        ok 6 - Foo instance should have `bar` method defined
        1..6
    ok 24 - Component - Configure methods # time=2.277ms
    
    # Subtest: Component - Warn non-function methods
        ok 1 - Foo instance should have method keys defined
        ok 2 - Should log two warning messages
        ok 3 - Should log foo is not a function warning message
        ok 4 - Should log bar is not a function warning message
        1..4
    ok 25 - Component - Warn non-function methods # time=4.493ms
    
    # Subtest: Component - Warn when method name matches prop name
        ok 1 - Foo instance should have method keys defined
        ok 2 - Should log one error message
        ok 3 - Should log prop/method name clash error message
        1..3
    ok 26 - Component - Warn when method name matches prop name # time=2.756ms
    
    1..26
ok 3 - src/component.test.js # time=3471.838ms

# Subtest: src/component/base/methods.test.js
    # Subtest: Methods - Should contain all the defined methods
        ok 1 - should have focus method
        ok 2 - should have $focus method
        ok 3 - should have unfocus method
        ok 4 - should have destroy method
        ok 5 - should have removeGlobalEffects method
        ok 6 - should have trigger method
        ok 7 - should have $trigger method
        ok 8 - should have select method
        ok 9 - should have $select method
        ok 10 - should have $shader method
        1..10
    ok 1 - Methods - Should contain all the defined methods # time=5.74ms
    
    # Subtest: Methods - Validate focus method behavior
        ok 1 - should be equal
        ok 2 - Should log warning message
        ok 3 - lifecycle state should be focus
        1..3
    ok 2 - Methods - Validate focus method behavior # time=103.524ms
    
    # Subtest: Methods - Validate $focus and unfocus method behavior
        ok 1 - hasFocus should be false by the time focus hook is called
        ok 2 - lifecycle state should be focus
        ok 3 - focus hook should be called
        ok 4 - hasFocus should be true only after focus hook is called
        ok 5 - hasFocus should be false by the time unfocus hook is called
        ok 6 - lifecycle state should be unfocus
        ok 7 - unfocus hook should be called
        1..7
    ok 3 - Methods - Validate $focus and unfocus method behavior # time=202.57ms
    
    # Subtest: Methods - Refocus already focused component
        ok 1 - lifecycle state should be focus
        ok 2 - lifecycle state should be focus
        1..2
    ok 4 - Methods - Refocus already focused component # time=100.775ms
    
    # Subtest: Methods - Validate select method behavior
        ok 1 - select should return the correct child
        ok 2 - should be equal
        ok 3 - Should log warning message
        ok 4 - select should return null for nonexistent child
        1..4
    ok 5 - Methods - Validate select method behavior # time=4.325ms
    
    # Subtest: Methods - Validate $select method behavior
        ok 1 - $select should return the correct child
        ok 2 - $select should return null for nonexistent child
        1..2
    ok 6 - Methods - Validate $select method behavior # time=0.713ms
    
    # Subtest: Methods - Validate $select method with nested array of children structure
        ok 1 - $select should find child in array
        ok 2 - $select should find single child object
        ok 3 - $select should return null for nonexistent child
        1..3
    ok 7 - Methods - Validate $select method with nested array of children structure # time=0.527ms
    
    # Subtest: Methods - Validate $select method with object of children structure
        ok 1 - $select should find child in object
        ok 2 - $select should find another child in object
        ok 3 - $select should return null for nonexistent child
        1..3
    ok 8 - Methods - Validate $select method with object of children structure # time=0.932ms
    
    # Subtest: Methods - Validate shader method behavior
        ok 1 - shader should return an object
        ok 2 - shader object should have correct type
        ok 3 - shader object should have correct prop1
        ok 4 - shader object should have correct prop2
        1..4
    ok 9 - Methods - Validate shader method behavior # time=0.976ms
    
    # Subtest: Methods - Validate removeGlobalEffects method behavior
        ok 1 - removeGlobalEffects should execute without error
        1..1
    ok 10 - Methods - Validate removeGlobalEffects method behavior # time=0.531ms
    
    # Subtest: Methods - Validate destroy method behavior
        ok 1 - Component should be marked as end of life
        ok 2 - Lifecycle state should be destroy
        ok 3 - symbol state should be deleted
        ok 4 - Renderer event listeners should be cleared
        ok 5 - All timeouts should be cleared
        ok 6 - All intervals should be cleared
        ok 7 - symbol props should be cleared
        ok 8 - symbol effects should be deleted
        ok 9 - symbol computed should be deleted
        ok 10 - parent should be deleted
        ok 11 - rootParent should be deleted
        ok 12 - symbol wrapper should be deleted
        ok 13 - symbol originalState should be deleted
        ok 14 - symbol children should be deleted
        ok 15 - symbol slots should be deleted
        ok 16 - componentId should be deleted
        ok 17 - symbol id should be deleted
        ok 18 - ref should be deleted
        ok 19 - symbol holder should be deleted
        ok 20 - symbol cleanup should be deleted
        ok 21 - symbol holder should be deleted
        ok 22 - symbol cleanup should be deleted
        ok 23 - Cleanup function should be called
        ok 24 - Holder destroy method should be called
        ok 25 - All children destroy methods should be called
        1..25
    ok 11 - Methods - Validate destroy method behavior # time=6.476ms
    
    1..11
ok 4 - src/component/base/methods.test.js # time=4123.22ms

(node:2413) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
# Subtest: src/component/base/timeouts_intervals.test.js
    # Subtest: Type
        ok 1 - timeoutsIntervals should be an object
        1..1
    ok 1 - Type # time=5.438ms
    
    # Subtest: $setTimeout method
        ok 1 - Should return timeout ID
        ok 2 - Should add timeout to array
        1..2
    ok 2 - $setTimeout method # time=1.849ms
    
    # Subtest: $setTimeout method when eol is true
        ok 1 - Should return undefined when eol is true
        ok 2 - Should not add timeout when eol is true
        1..2
    ok 3 - $setTimeout method when eol is true # time=1.229ms
    
    # Subtest: $clearTimeout method
        ok 1 - Removes timeout from array
        ok 2 - Timeout does not execute after clear
        1..2
    ok 4 - $clearTimeout method # time=102.404ms
    
    # Subtest: $clearTimeouts method
        ok 1 - Clears all timeouts from array
        ok 2 - First timeout does not execute
        ok 3 - Second timeout does not execute
        1..3
    ok 5 - $clearTimeouts method # time=101.596ms
    
    # Subtest: $setInterval method
        ok 1 - Should return interval ID
        ok 2 - Should add interval to array
        1..2
    ok 6 - $setInterval method # time=1.942ms
    
    # Subtest: $setInterval method when eol is true
        ok 1 - Should return undefined when eol is true
        ok 2 - Should not add interval when eol is true
        1..2
    ok 7 - $setInterval method when eol is true # time=0.616ms
    
    # Subtest: $clearInterval method
        ok 1 - Removes interval from array
        ok 2 - Interval does not execute after clear
        1..2
    ok 8 - $clearInterval method # time=152.314ms
    
    # Subtest: $clearIntervals method
        ok 1 - Clears all intervals from array
        ok 2 - First interval does not execute
        ok 3 - Second interval does not execute
        1..3
    ok 9 - $clearIntervals method # time=151.775ms
    
    # Subtest: Multiple timeouts management
        ok 1 - Should store multiple timeouts
        ok 2 - Should store first timeout
        ok 3 - Should store second timeout
        ok 4 - Should store third timeout
        ok 5 - Should remove only the specified timeout
        ok 6 - Should keep first timeout
        ok 7 - Should keep third timeout
        1..7
    ok 10 - Multiple timeouts management # time=2.044ms
    
    # Subtest: Multiple intervals management
        ok 1 - Should store multiple intervals
        ok 2 - Should store first interval
        ok 3 - Should store second interval
        ok 4 - Should store third interval
        ok 5 - Should remove only the specified interval
        ok 6 - Should keep first interval
        ok 7 - Should keep third interval
        1..7
    ok 11 - Multiple intervals management # time=1.394ms
    
    1..11
ok 5 - src/component/base/timeouts_intervals.test.js # time=2798.258ms

# Subtest: src/component/base/utils.test.js
    # Subtest: Type
        ok 1 - utils should be an object
        1..1
    ok 1 - Type # time=3.698ms
    
    # Subtest: $size method with dimensions
        ok 1 - Should set width
        ok 2 - Should set height
        1..2
    ok 2 - $size method with dimensions # time=0.725ms
    
    # Subtest: $size method with default values
        ok 1 - Should set default width
        ok 2 - Should set default height
        1..2
    ok 3 - $size method with default values # time=0.611ms
    
    # Subtest: $size method with undefined dimensions
        ok 1 - Should set default width when no dimensions
        ok 2 - Should set default height when no dimensions
        1..2
    ok 4 - $size method with undefined dimensions # time=0.583ms
    
    # Subtest: renderer getter
        ok 1 - Should return renderer object
        1..1
    ok 5 - renderer getter # time=0.382ms
    
    # Subtest: getChildren method with no children
        ok 1 - Should return empty array when no children
        1..1
    ok 6 - getChildren method with no children # time=0.477ms
    
    # Subtest: getChildren method with children
        ok 1 - Should return children array
        ok 2 - Should include first child
        ok 3 - Should include second child
        1..3
    ok 7 - getChildren method with children # time=0.761ms
    
    # Subtest: getChildren method with parent
        ok 1 - Should return empty array when parent returns empty
        1..1
    ok 8 - getChildren method with parent # time=0.448ms
    
    # Subtest: getChildren method with rootParent
        ok 1 - Should return empty array when rootParent returns empty
        1..1
    ok 9 - getChildren method with rootParent # time=0.467ms
    
    # Subtest: getChildren method with undefined children
        ok 1 - Should return empty array when children is undefined
        1..1
    ok 10 - getChildren method with undefined children # time=0.41ms
    
    1..10
ok 6 - src/component/base/utils.test.js # time=2276.895ms

# Subtest: src/component/setup/computed.test.js
    # Subtest: Basic computed functionality
        ok 1 - Should store computed keys
        ok 2 - fullName should compute correctly
        ok 3 - isAdult should compute correctly
        1..3
    ok 1 - Basic computed functionality # time=6.411ms
    
    # Subtest: Conflict detection
        ok 1 - Only non-conflicting computed added
        ok 2 - Valid computed works
        1..2
    ok 2 - Conflict detection # time=1.107ms
    
    # Subtest: Non-function computeds
        ok 1 - All keys should be included
        ok 2 - Valid function computes correctly
        1..2
    ok 3 - Non-function computeds # time=0.913ms
    
    # Subtest: Edge cases & empty
        ok 1 - Empty computeds produce empty keys
        ok 2 - Single computed added
        ok 3 - Computed works correctly
        1..3
    ok 4 - Edge cases & empty # time=1.028ms
    
    # Subtest: Dynamic updates
        ok 1 - fullName should compute correctly
        ok 2 - description should compute correctly
        ok 3 - fullName should compute correctly
        ok 4 - description should compute correctly
        1..4
    ok 5 - Dynamic updates # time=0.935ms
    
    1..5
ok 7 - src/component/setup/computed.test.js # time=2126.716ms

(node:2449) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
(node:2461) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
# Subtest: src/component/setup/props.test.js
    # Subtest: Type props function
        ok 1 - props should be a function
        1..1
    ok 1 - Type props function # time=6.075ms
    
    # Subtest: Has correct symbols
        ok 1 - Component should have a propKey symbol
        1..1
    ok 2 - Has correct symbols # time=1.215ms
    
    # Subtest: Pass props as an array
        ok 1 - All passed props should be stored on propKeys
        ok 2 - All passed props should be stored on propKeys
        ok 3 - A getter should have been created for property index
        ok 4 - A getter should have been created for property img
        ok 5 - A getter should have been created for property url
        ok 6 - A getter should have been created for property ref
        1..6
    ok 3 - Pass props as an array # time=2.465ms
    
    # Subtest: Get value of props
        ok 1 - The correct value of index should be returned via the getter
        ok 2 - The correct value of index should be returned via the getter
        ok 3 - The correct value of img should be returned via the getter
        ok 4 - The correct value of img should be returned via the getter
        ok 5 - The correct value of url should be returned via the getter
        ok 6 - The correct value of url should be returned via the getter
        ok 7 - The correct value of ref should be returned via the getter
        ok 8 - The correct value of ref should be returned via the getter
        ok 9 - Undefined should be returned if a prop doesn't exist
        1..9
    ok 4 - Get value of props # time=2.111ms
    
    # Subtest: Passing props as an object
        ok 1 - All passed props should be stored on propKeys
        ok 2 - All passed props should be stored on propKeys
        ok 3 - A getter should have been created for property [object Object]
        ok 4 - A getter should have been created for property [object Object]
        ok 5 - A getter should have been created for property [object Object]
        ok 6 - A getter should have been created for property ref
        1..6
    ok 5 - Passing props as an object # time=2.314ms
    
    # Subtest: Passing props as an object mixed with single keys
        ok 1 - All passed props should be stored on propKeys
        ok 2 - All passed props should be stored on propKeys
        ok 3 - A getter should have been created for property [object Object]
        ok 4 - A getter should have been created for property img
        ok 5 - A getter should have been created for property [object Object]
        ok 6 - A getter should have been created for property ref
        1..6
    ok 6 - Passing props as an object mixed with single keys # time=1.671ms
    
    # Subtest: Casting props to a type
        ok 1 - Should cast prop value to a Number
        ok 2 - Should cast prop value to a String
        ok 3 - Should cast prop value to a Boolean
        ok 4 - Should cast according to a custom function
        1..4
    ok 7 - Casting props to a type # time=1.678ms
    
    # Subtest: Setting default value for undefined props
        ok 1 - Should return default prop value when undefined
        1..1
    ok 8 - Setting default value for undefined props # time=1.238ms
    
    # Subtest: Required props with default
        ok 1 - Should return default prop value when undefined
        1..1
    ok 9 - Required props with default # time=1.006ms
    
    # Subtest: Required props without default
        ok 1 - Should return undefined prop value when undefined
        ok 2 - should be equal
        ok 3 - Should log warning message
        1..3
    ok 10 - Required props without default # time=4.562ms
    
    # Subtest: Setting prop value directly
        ok 1 - Should be possible to mutate the property
        ok 2 - should be equal
        ok 3 - Should log warning message
        1..3
    ok 11 - Setting prop value directly # time=4.97ms
    
    1..11
ok 8 - src/component/setup/props.test.js # time=2263.048ms

# Subtest: src/component/setup/routes.test.js
    # Subtest: Type
        ok 1 - routes should be a function
        1..1
    ok 1 - Type # time=5.772ms
    
    # Subtest: Array routes with default options
        ok 1 - Should set correct number of routes
        ok 2 - Should apply default options when none specified
        ok 3 - Should override default options when specified
        1..3
    ok 2 - Array routes with default options # time=4.375ms
    
    # Subtest: Object routes with hooks
        ok 1 - Should set router hooks
        ok 2 - Should set routes from object data
        ok 3 - Should set correct route path
        1..3
    ok 3 - Object routes with hooks # time=6.204ms
    
    # Subtest: Empty routes array
        ok 1 - Should initialize routes as array
        ok 2 - Should handle empty routes array
        1..2
    ok 4 - Empty routes array # time=0.716ms
    
    1..4
ok 9 - src/component/setup/routes.test.js # time=2544.5ms

# Subtest: src/components/Sprite.test.js
    # Subtest: Sprite - Type
        ok 1 - Sprite should be a function
        ok 2 - Sprite() should return a function
        1..2
    ok 1 - Sprite - Type # time=5.237ms
    
    # Subtest: Sprite - Initialization
        ok 1 - image prop should be undefined initially
        ok 2 - spriteTexture should be null initially
        ok 3 - currentSrc should be null initially
        1..3
    ok 2 - Sprite - Initialization # time=9.585ms
    
    # Subtest: Sprite - Texture returns null for invalid inputs
        ok 1 - texture should be null when image is undefined
        ok 2 - texture should be null when image is null
        ok 3 - texture should be null when renderer.createTexture is missing
        1..3
    ok 3 - Sprite - Texture returns null for invalid inputs # time=3.041ms
    
    # Subtest: Sprite - Texture creates and reuses ImageTexture
        ok 1 - texture should not be null when image is set
        ok 2 - currentSrc should be set to image path
        ok 3 - createTexture should be called once for first image
        ok 4 - createTexture should be called again when image changes
        1..4
    ok 4 - Sprite - Texture creates and reuses ImageTexture # time=2.847ms
    
    # Subtest: Sprite - Texture creates SubTexture with map and frame
        ok 1 - texture should be SubTexture when map and frame are set
        ok 2 - currentSrc should remain unchanged
        ok 3 - ImageTexture should be created only once
        ok 4 - spriteTexture should be reused
        ok 5 - texture should be SubTexture when map and frame are set
        ok 6 - currentSrc should remain unchanged
        ok 7 - ImageTexture should be created only once
        ok 8 - spriteTexture should be reused
        ok 9 - texture should be SubTexture when map and frame are set
        ok 10 - currentSrc should remain unchanged
        ok 11 - ImageTexture should be created only once
        ok 12 - spriteTexture should be reused
        ok 13 - texture should be SubTexture when map and frame are set
        ok 14 - currentSrc should remain unchanged
        ok 15 - ImageTexture should be created only once
        ok 16 - spriteTexture should be reused
        1..16
    ok 5 - Sprite - Texture creates SubTexture with map and frame # time=3.902ms
    
    # Subtest: Sprite - Texture returns spriteTexture when no frame
        ok 1 - texture should not be null when no frame is set
        ok 2 - should not create SubTexture when no frame
        ok 3 - should NOT create SubTexture for nonexistent frame in map.frames structure
        ok 4 - texture should not be null
        ok 5 - should NOT create additional SubTexture for nonexistent frame in direct map
        1..5
    ok 6 - Sprite - Texture returns spriteTexture when no frame # time=1.926ms
    
    1..6
ok 10 - src/components/Sprite.test.js # time=2624.168ms

(node:2486) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
# Subtest: src/engines/L3/element.test.js
    # Subtest: Type
        ok 1 - Element should be a factory function
        1..1
    ok 1 - Type # time=5.784ms
    
    # Subtest: Destroy
        ok 1 - Node destroy should be invoked
        1..1
    ok 2 - Destroy # time=3.202ms
    
    # Subtest: NodeId
        ok 1 - NodeId should be correct
        1..1
    ok 3 - NodeId # time=0.581ms
    
    # Subtest: Ref
        ok 1 - Ref should be correct
        1..1
    ok 4 - Ref # time=0.984ms
    
    # Subtest: Parent
        ok 1 - Parent should be correct
        1..1
    ok 5 - Parent # time=0.977ms
    
    # Subtest: Children
        ok 1 - Children amount should be correct
        ok 2 - Children should be correct
        1..2
    ok 6 - Children # time=2.989ms
    
    # Subtest: Element - Set `w` property
        ok 1 - Node width parameter should be set
        ok 2 - Props width parameter should be set
        ok 3 - Props' raw map entry should be added
        1..3
    ok 7 - Element - Set `w` property # time=2.74ms
    
    # Subtest: Element- Set `w` property in percentage
        ok 1 - Node width parameter should be set to 960
        ok 2 - Props width parameter should be set
        ok 3 - Props' raw map entry should be added
        1..3
    ok 8 - Element- Set `w` property in percentage # time=2.209ms
    
    # Subtest: Element - Set `h` property
        ok 1 - Node height parameter should be set
        ok 2 - Props height parameter should be set
        ok 3 - Props' raw map entry should be added
        1..3
    ok 9 - Element - Set `h` property # time=2.951ms
    
    # Subtest: Element- Set `h` property in percentage
        ok 1 - Node width parameter should be set to 540
        ok 2 - Props width parameter should be set
        ok 3 - Props' raw map entry should be added
        1..3
    ok 10 - Element- Set `h` property in percentage # time=1.534ms
    
    # Subtest: Element - Set `x` property
        ok 1 - Node x parameter should be set
        ok 2 - Props x parameter should be set
        ok 3 - Props' raw map entry should be added
        1..3
    ok 11 - Element - Set `x` property # time=2.457ms
    
    # Subtest: Element- Set `x` property in percentage
        ok 1 - Node x parameter should be set to 960
        ok 2 - Props x parameter should be set
        ok 3 - Props' raw map entry should be added
        1..3
    ok 12 - Element- Set `x` property in percentage # time=2.284ms
    
    # Subtest: Element - Set `y` property
        ok 1 - Node y parameter should be set
        ok 2 - Props y parameter should be set
        ok 3 - Props' raw map entry should be added
        1..3
    ok 13 - Element - Set `y` property # time=2.075ms
    
    # Subtest: Element- Set `y` property in percentage
        ok 1 - Node y parameter should be set to 540
        ok 2 - Props y parameter should be set
        ok 3 - Props' raw map entry should be added
        1..3
    ok 14 - Element- Set `y` property in percentage # time=1.876ms
    
    # Subtest: Element - Set `mount` property
        ok 1 - Node mountX parameter should be set
        ok 2 - Node mountY parameter should be set
        ok 3 - Props mountX parameter should be set
        ok 4 - Props mountY parameter should be set
        ok 5 - Props' raw map entry should be added
        1..5
    ok 15 - Element - Set `mount` property # time=3.07ms
    
    # Subtest: Element - Set `color` property
        ok 1 - Node color parameter should be set
        ok 2 - Props color parameter should be set
        ok 3 - Props' raw map entry should be added
        1..3
    ok 16 - Element - Set `color` property # time=2.325ms
    
    # Subtest: Element - Set `src` property
        ok 1 - Node src parameter should be set
        ok 2 - Props src parameter should be set
        ok 3 - Props' raw map entry should be added
        ok 4 - Props default color parameter should be set
        1..4
    ok 17 - Element - Set `src` property # time=3.096ms
    
    # Subtest: Element - Set `texture` property
        ok 1 - Node texture parameter should be set
        ok 2 - Props texture parameter should be set
        ok 3 - Props' raw map entry should be added
        ok 4 - Props default color parameter should be set
        1..4
    ok 18 - Element - Set `texture` property # time=2.28ms
    
    # Subtest: Element - Set `fit` property with a string type value
        ok 1 - textureOptions should be an object
        ok 2 - resizeMode should be an object
        ok 3 - Node resizeMode "type" parameter should be set
        ok 4 - Props textureOptions parameter should be set
        ok 5 - Props' raw map entry should be added
        1..5
    ok 19 - Element - Set `fit` property with a string type value # time=2.217ms
    
    # Subtest: Element - Set `fit` property with an object type value
        ok 1 - Node resizeMode "type" parameter should be set
        ok 2 - Props textureOptions parameter should be set
        ok 3 - Node resizeMode "clipX" parameter should be set to correct value
        ok 4 - Node resizeMode "clipY" parameter should be set to correct value
        ok 5 - Props' raw map entry should be added
        1..5
    ok 20 - Element - Set `fit` property with an object type value # time=6.285ms
    
    # Subtest: Element - Set `fit` property with position key as a string type value
        ok 1 - Node resizeMode "type" parameter should be set
        ok 2 - Props textureOptions parameter should be set
        ok 3 - Node resizeMode "clipX" parameter should be set to correct value
        ok 4 - Node resizeMode "clipY" parameter should be set to correct value
        ok 5 - Props' raw map entry should be added
        1..5
    ok 21 - Element - Set `fit` property with position key as a string type value # time=2.16ms
    
    # Subtest: Element - Set `fit` property should not set not required keys
        ok 1 - Node resizeMode "type" parameter should be set
        ok 2 - Props resizeMode "dummy1" parameter should not be set
        ok 3 - Props resizeMode "dummy2" parameter should not be set
        1..3
    ok 22 - Element - Set `fit` property should not set not required keys # time=1.376ms
    
    # Subtest: Element - Set `placement` property with value `center`
        ok 1 - Node mountX parameter should set to 0.5
        ok 2 - Props mountX parameter should set to 0.5
        ok 3 - Node x parameter should set to half of parent node width, 960
        ok 4 - props x parameter should be set to 960
        ok 5 - Node Y parameter should not be modified from default value
        1..5
    ok 23 - Element - Set `placement` property with value `center` # time=2.689ms
    
    # Subtest: Element - Set `placement` property with value `right`
        ok 1 - Node mountX parameter should set to 1
        ok 2 - Props mountX parameter should set to 1
        ok 3 - Node x parameter should set to parent node full width, 1920
        ok 4 - props x parameter should be set to 1920
        ok 5 - Node Y parameter should not be modified from default value
        1..5
    ok 24 - Element - Set `placement` property with value `right` # time=3.162ms
    
    # Subtest: Element - Set `placement` property with value `middle`
        ok 1 - Node mountY parameter should set to 0.5
        ok 2 - Props mountY parameter should set to 0.5
        ok 3 - Node Y parameter should set to half of parent node height, 540
        ok 4 - props Y parameter should be set to 540
        ok 5 - Node X parameter should not be modified from default value
        1..5
    ok 25 - Element - Set `placement` property with value `middle` # time=2.868ms
    
    # Subtest: Element - Set `placement` property with value `bottom`
        ok 1 - Node mountY parameter should set to 1
        ok 2 - Props mountY parameter should set to 1
        ok 3 - Node Y parameter should set to parent node full height, 1080
        ok 4 - props Y parameter should be set to 1080
        ok 5 - Node X parameter should not be modified from default value
        1..5
    ok 26 - Element - Set `placement` property with value `bottom` # time=4.218ms
    
    # Subtest: Element - Set `placement` property with value `bottom` & x = 300
        ok 1 - Node mountY parameter should set to 1
        ok 2 - Props mountY parameter should set to 1
        ok 3 - Node Y parameter should set to parent node full height, 1080
        ok 4 - props Y parameter should be set to 1080
        ok 5 - Node x parameter should set custom value 300
        1..5
    ok 27 - Element - Set `placement` property with value `bottom` & x = 300 # time=2.943ms
    
    # Subtest: Element - Set `placement` property with object value `{x:"center", y:"middle"}`
        ok 1 - Node mountX parameter should set to 0.5
        ok 2 - Props mountX parameter should set to 0.5
        ok 3 - Node x parameter should set to half of parent node width, 960
        ok 4 - Node mountY parameter should set to 0.5
        ok 5 - Props mountY parameter should set to 0.5
        ok 6 - Node Y parameter should set to half of parent node height, 540
        1..6
    ok 28 - Element - Set `placement` property with object value `{x:"center", y:"middle"}` # time=3.484ms
    
    # Subtest: Element - Set `placement` property with object value `{x:"center", y:"bottom"}`
        ok 1 - Node mountX parameter should set to 0.5
        ok 2 - Props mountX parameter should set to 0.5
        ok 3 - Node x parameter should set to half of parent node width, 960
        ok 4 - Node mountY parameter should set to 1
        ok 5 - Props mountY parameter should set to 1
        ok 6 - Node Y parameter should set to parent node full height , 1080
        1..6
    ok 29 - Element - Set `placement` property with object value `{x:"center", y:"bottom"}` # time=1.795ms
    
    # Subtest: Element - Set `placement` property with object value `{x:"right", y:"middle"}`
        ok 1 - Node mountX parameter should set to 1
        ok 2 - Props mountX parameter should set to 1
        ok 3 - Node x parameter should set to parent node full width, 1920
        ok 4 - Node mountY parameter should set to 0.5
        ok 5 - Props mountY parameter should set to 0.5
        ok 6 - Node Y parameter should set to half of parent node height, 540
        1..6
    ok 30 - Element - Set `placement` property with object value `{x:"right", y:"middle"}` # time=2.654ms
    
    # Subtest: Element - Set `placement` property with object value `{x:"right", y:"bottom"}`
        ok 1 - Node mountX parameter should set to 1
        ok 2 - Props mountX parameter should set to 1
        ok 3 - Node x parameter should set to parent node full width, 1920
        ok 4 - Node mountY parameter should set to 1
        ok 5 - Props mountY parameter should set to 1
        ok 6 - Node Y parameter should set to parent node height, 1080
        1..6
    ok 31 - Element - Set `placement` property with object value `{x:"right", y:"bottom"}` # time=1.651ms
    
    # Subtest: Element - Set `float` property with value `unknown`
        ok 1 - Node mountX parameter should not be changed
        ok 2 - Props mountX parameter should not be changed
        ok 3 - Node x parameter should not get updated
        ok 4 - props x parameter should not be changed
        1..4
    ok 32 - Element - Set `float` property with value `unknown` # time=3.424ms
    
    # Subtest: Element - Set `show` property as false
        ok 1 - Node alpha parameter should set to 0
        ok 2 - Props alpha parameter should set
        1..2
    ok 33 - Element - Set `show` property as false # time=2.292ms
    
    # Subtest: Element - Set `show` property as false
        ok 1 - Node alpha parameter should be set
        ok 2 - Props alpha parameter should be set
        ok 3 - Node width parameter should be set
        ok 4 - Node height parameter should be set
        1..4
    ok 34 - Element - Set `show` property as false # time=1.764ms
    
    # Subtest: Element - Set `w` property through transition
        ok 1 - Props width parameter should be set
        1..1
    ok 35 - Element - Set `w` property through transition # time=2.444ms
    
    # Subtest: Element - Listen to transition start callback on `w` prop changes
        ok 1 - Props width parameter should be set
        ok 2 - Transition start callback should be called once
        ok 3 - Transition start callback should be called with three arguments
        ok 4 - Transition start callback first argument should be element itself
        ok 5 - Transition start callback second argument should be `width` property
        ok 6 - Transition start callback third argument value should be an initial value of `0`
        1..6
    ok 36 - Element - Listen to transition start callback on `w` prop changes # time=3.646ms
    
    # Subtest: Element - Cancel transition running on same prop `W` 
        ok 1 - Props width parameter should be set
        1..1
    ok 37 - Element - Cancel transition running on same prop `W` # time=1.614ms
    
    # Subtest: Element - Layout with horizontal direction layout use cases
        ok 1 - Child 1 Node width parameter should be set
        ok 2 - Child 1 Props width parameter should be set
        ok 3 - Child 2 Node X parameter should be layout gap + child 1 width
        ok 4 - Layout updated callback should be called 3 times
        ok 5 - Layout updated callback should be called with 2 arguments
        ok 6 - Layout width should be equal to Child1 width
        ok 7 - Layout height should be equal to Child1 or Child 2 height
        ok 8 - Child 2 Node width parameter should be set
        ok 9 - Child 2 Props width parameter should be set
        ok 10 - Layout updated callback call count should be 4
        ok 11 - Layout width should be equal to Child1 width + gap + Child2 width
        ok 12 - Layout height should be equal to Child1 or Child 2 height
        1..12
    ok 38 - Element - Layout with horizontal direction layout use cases # time=7.404ms
    
    # Subtest: Element - Layout with vertical direction use case
        ok 1 - Child 1 Node height parameter should be set
        ok 2 - Child 1 Props height parameter should be set
        ok 3 - Child 2 Node y parameter should be layout gap + Child 1 height
        ok 4 - Layout updated callback should be called 3 times
        ok 5 - Layout updated callback should be called with 2 arguments
        ok 6 - Layout height should be equal to Child1 height
        ok 7 - Layout width should be equal to Child1 or Child 2 width
        ok 8 - Child 2 Node height parameter should be set
        ok 9 - Child 2 Props height parameter should be set
        ok 10 - Layout updated callback call count should be 4
        ok 11 - Layout height should be equal to Child1 height + gap + Child2 height
        ok 12 - Layout w should be equal to Child1 or Child 2 width
        1..12
    ok 39 - Element - Layout with vertical direction use case # time=5.064ms
    
    # Subtest: Element - Create Text Node
        ok 1 - Node text parameter should be set
        ok 2 - Props text parameter should be set
        ok 3 - Props' raw map entry should be added
        1..3
    ok 40 - Element - Create Text Node # time=2.338ms
    
    # Subtest: Element - Create Text Node with supported props
        ok 1 - Node text parameter should be set
        ok 2 - Props text parameter should be set
        ok 3 - Node textoverflow parameter should be set
        ok 4 - Props textoverflow parameter should be set
        ok 5 - Node letterSpacing parameter should be set
        ok 6 - Props letterSpacing parameter should be set
        ok 7 - Node lineHeight parameter should be set
        ok 8 - Props lineHeight parameter should be set
        1..8
    ok 41 - Element - Create Text Node with supported props # time=2.159ms
    
    # Subtest: Element - Create Text Node with supported props 2
        ok 1 - Node height parameter should be set
        ok 2 - Props textoverflow parameter should be set
        ok 3 - Node contain parameter should be set
        ok 4 - Props contain parameter should be set
        ok 5 - Node contain parameter should be set
        ok 6 - Props contain parameter should be set
        ok 7 - Node maxLines parameter should be set
        ok 8 - Props maxLines parameter should be set
        ok 9 - Node textAlign parameter should be set
        ok 10 - Props textAlign parameter should be set
        1..10
    ok 42 - Element - Create Text Node with supported props 2 # time=2.563ms
    
    # Subtest: Element - Create Text Node with supported props 3
        ok 1 - Node width parameter should be set
        ok 2 - Props width parameter should be set
        ok 3 - Node contain parameter should be set
        ok 4 - Props contain parameter should be set
        ok 5 - Node width parameter should be set
        ok 6 - Props width parameter should be set
        ok 7 - Node contain parameter should be set
        ok 8 - Props contain parameter should be set
        ok 9 - Node clipping parameter should be set
        ok 10 - Props clipping parameter should be set
        ok 11 - overflow attribute should set node clipping parameter
        ok 12 - Props clipping parameter should be set
        1..12
    ok 43 - Element - Create Text Node with supported props 3 # time=5.236ms
    
    # Subtest: Element - Transition an element property with progress callback
        ok 1 - Props width parameter should be set
        1..1
    ok 44 - Element - Transition an element property with progress callback # time=1.577ms
    
    # Subtest: Element - Transition an element property with end callback
        ok 1 - Props width parameter should be set
        1..1
    ok 45 - Element - Transition an element property with end callback # time=1.877ms
    
    # Subtest: Element - Destroy created Element node
        ok 1 - Node should set to null
        ok 2 - Component should be deleted from element
        ok 3 - Props should be deleted from element
        ok 4 - Config should be deleted from element
        ok 5 - TriggerLayout should be deleted from element
        1..5
    ok 46 - Element - Destroy created Element node # time=1.51ms
    
    # Subtest: Element - Element with error callback
        ok 1 - Props @error parameter should be set
        ok 2 - Prop's raw map entry should be added
        ok 3 - error callback should be called once
        1..3
    ok 47 - Element - Element with error callback # time=2.46ms
    
    # Subtest: Element - Element with loaded callback
        ok 1 - Props @loaded parameter should be set
        ok 2 - Prop's raw map entry should be added
        1..2
    ok 48 - Element - Element with loaded callback # time=1.845ms
    
    1..48
ok 11 - src/engines/L3/element.test.js # time=6877.864ms

# Subtest: src/focus.test.js
    # Subtest: Focus type
        ok 1 - Component should be a function
        1..1
    ok 1 - Focus type # time=4.124ms
    
    # Subtest: Public methods on focus object
        ok 1 - Focus should have a get method
        ok 2 - Focus should have a set method
        ok 3 - Focus should have an input method
        1..3
    ok 2 - Public methods on focus object # time=0.783ms
    
    # Subtest: Setting focus
        ok 1 - Focused component should be set as new focused component
        ok 2 - Focused component should have the lifecycle state "focus"
        1..2
    ok 3 - Setting focus # time=2.662ms
    
    # Subtest: Focussing along focus path
        ok 1 - Focused component should have the lifecycle state "focus"
        ok 2 - Parent of focused component should also have the lifecycle state "focus" (as part of the focus chain)
        1..2
    ok 4 - Focussing along focus path # time=2.963ms
    
    # Subtest: Unfocus focus chain
        ok 1 - Focused component should have the lifecycle state "focus"
        ok 2 - Focused component should have the lifecycle state "focus"
        ok 3 - Previously focused component should have the lifecycle state "focus"
        ok 4 - Parent of previously focused component should also have the lifecycle state "unfocus" (as part of the focus chain)
        1..4
    ok 5 - Unfocus focus chain # time=6.664ms
    
    # Subtest: Unfocus partial focus chain
        ok 1 - Focused component should have the lifecycle state "focus"
        ok 2 - Focused component should have the lifecycle state "focus"
        ok 3 - Previously focused component should have the lifecycle state "focus"
        ok 4 - Grandparent of previously focused component should still have the lifecycle state "focus" (as part of the new focus chain)
        1..4
    ok 6 - Unfocus partial focus chain # time=3.321ms
    
    1..6
ok 12 - src/focus.test.js # time=2565.528ms

# Subtest: src/helpers/deepEqualArray.test.js
    # Subtest: Type
        ok 1 - deepEqual should be a function
        1..1
    ok 1 - Type # time=3.438ms
    
    # Subtest: The same arrays
        ok 1 - deepEqual should return true if the values are the same reference
        1..1
    ok 2 - The same arrays # time=0.597ms
    
    # Subtest: Equal simple arrays
        ok 1 - deepEqual should return true if simple arrays are equal
        1..1
    ok 3 - Equal simple arrays # time=0.49ms
    
    # Subtest: Not equal simple arrays
        ok 1 - deepEqual should return false if simple arrays are not equal
        1..1
    ok 4 - Not equal simple arrays # time=0.407ms
    
    # Subtest: Not Equal simple arrays (different length)
        ok 1 - deepEqual should return false if simple arrays are equal
        1..1
    ok 5 - Not Equal simple arrays (different length) # time=0.384ms
    
    # Subtest: Equal nested arrays
        ok 1 - deepEqual should return true if nested arrays are equal
        1..1
    ok 6 - Equal nested arrays # time=0.389ms
    
    # Subtest: Not equal nested arrays
        ok 1 - deepEqual should return false if nested arrays are not equal
        1..1
    ok 7 - Not equal nested arrays # time=0.419ms
    
    # Subtest: Equal arrays with objects
        ok 1 - deepEqual should return true if arrays with objects are equal
        1..1
    ok 8 - Equal arrays with objects # time=0.875ms
    
    # Subtest: Not equal arrays with objects (keys
        ok 1 - deepEqual should return false if arrays with objects are not equal
        1..1
    ok 9 - Not equal arrays with objects (keys # time=0.792ms
    
    # Subtest: Equal arrays with mixed values
        ok 1 - deepEqual should return true if arrays with mixed values are equal
        1..1
    ok 10 - Equal arrays with mixed values # time=0.517ms
    
    # Subtest: Not Equal arrays with mixed values
        ok 1 - deepEqual should return true if arrays with mixed values are not equal
        1..1
    ok 11 - Not Equal arrays with mixed values # time=0.456ms
    
    1..11
ok 13 - src/helpers/deepEqualArray.test.js # time=2207.664ms

# Subtest: src/lib/codegenerator/generator.test.js
    # Subtest: Type
        ok 1 - Generator should be a function
        1..1
    ok 1 - Type # time=3.589ms
    
    # Subtest: Returns an object with a render function and a context object
        ok 1 - Generator should return an object
        ok 2 - Generated object should have a render key
        ok 3 - Generated object should have an effects key
        ok 4 - Generated object should have a context key
        1..4
    ok 2 - Returns an object with a render function and a context object # time=1.398ms
    
    # Subtest: The render key is a function
        ok 1 - Render key should return a function
        1..1
    ok 3 - The render key is a function # time=0.496ms
    
    # Subtest: The effects key is an array (of functions)
        ok 1 - Update key should return an Array
        1..1
    ok 4 - The effects key is an array (of functions) # time=0.417ms
    
    # Subtest: The contex key is an object
        ok 1 - Context key should return an object
        1..1
    ok 5 - The contex key is an object # time=0.448ms
    
    # Subtest: Generate render and effect code for an empty template
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 6 - Generate render and effect code for an empty template # time=0.786ms
    
    # Subtest: Generate render and effect code for a template with a single simple element
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 7 - Generate render and effect code for a template with a single simple element # time=1.109ms
    
    # Subtest: Generate code for a template with a simple element and a simple nested element
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 8 - Generate code for a template with a simple element and a simple nested element # time=0.809ms
    
    # Subtest: Generate code for a template with a single element with attributes
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 9 - Generate code for a template with a single element with attributes # time=1.071ms
    
    # Subtest: Generate code for a template with a single element with attributes with a boolean like value
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 10 - Generate code for a template with a single element with attributes with a boolean like value # time=0.802ms
    
    # Subtest: Generate code for a template with a single element with attributes with numeric & alpha numeric value
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 11 - Generate code for a template with a single element with attributes with numeric & alpha numeric value # time=0.908ms
    
    # Subtest: Generate code for a template with attributes and a nested element with attributes
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 12 - Generate code for a template with attributes and a nested element with attributes # time=0.83ms
    
    # Subtest: Generate code for a template with attributes and 2 nested elements with attributes
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 13 - Generate code for a template with attributes and 2 nested elements with attributes # time=0.855ms
    
    # Subtest: Generate code for a template with attributes and deep nested elements with attributes
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 14 - Generate code for a template with attributes and deep nested elements with attributes # time=1.064ms
    
    # Subtest: Generate code for a template with simple dynamic attributes
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an effects array with 2 items
        ok 3 - Generator should return first render function with the correct code
        ok 4 - Generator should return second render function with the correct code
        1..4
    ok 15 - Generate code for a template with simple dynamic attributes # time=1.575ms
    
    # Subtest: Generate code for a template with an attribute with a dash
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 16 - Generate code for a template with an attribute with a dash # time=1.293ms
    
    # Subtest: Generate code for a template with dynamic attributes with code to be evaluated
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an effects array with 3 items
        ok 3 - Generator should return first effect function with the correct code
        ok 4 - Generator should return second effect function with the correct code
        ok 5 - Generator should return third effect function with the correct code
        1..5
    ok 17 - Generate code for a template with dynamic attributes with code to be evaluated # time=1.552ms
    
    # Subtest: Generate code for a template with attribute (object)
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 18 - Generate code for a template with attribute (object) # time=0.903ms
    
    # Subtest: Generate code for a template with dynamic attribute (object)
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 19 - Generate code for a template with dynamic attribute (object) # time=1.212ms
    
    # Subtest: Generate code for a template with attribute (object) with mixed dynamic & static value
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 20 - Generate code for a template with attribute (object) with mixed dynamic & static value # time=0.88ms
    
    # Subtest: Generate code for a template with @-listeners
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 21 - Generate code for a template with @-listeners # time=0.864ms
    
    # Subtest: Generate code for a template with custom components
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 22 - Generate code for a template with custom components # time=1.448ms
    
    # Subtest: Generate code for a template with an unregistered custom component
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 23 - Generate code for a template with an unregistered custom component # time=1.139ms
    
    # Subtest: Generate code for a template with custom components with arguments
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 24 - Generate code for a template with custom components with arguments # time=1.368ms
    
    # Subtest: Generate code for a template with custom components with argument value as numeric & alpha numeric
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 25 - Generate code for a template with custom components with argument value as numeric & alpha numeric # time=1.196ms
    
    # Subtest: Generate code for a template with custom components with reactive props
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an effects array with 4 functions
        ok 3 - Generator should return an effect function that sets the value on the node
        ok 4 - Generator should return an effect function that updates a prop on the first custom component
        ok 5 - Generator should return an effect function that sets the value on the node
        ok 6 - Generator should return an effect function that updates a prop on the second custom component
        1..6
    ok 26 - Generate code for a template with custom components with reactive props # time=2.126ms
    
    # Subtest: Generate code for a template with a transition attributes
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should not return an empty effects array
        1..2
    ok 27 - Generate code for a template with a transition attributes # time=0.892ms
    
    # Subtest: Generate code for a template with slot content
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an effects array with 1 item
        ok 3 - Generator should return an effect function for the reactive rotation attribute
        1..3
    ok 28 - Generate code for a template with slot content # time=1.382ms
    
    # Subtest: Generate code for a template with slot content, using a named slot
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 29 - Generate code for a template with slot content, using a named slot # time=1.209ms
    
    # Subtest: Generate code for a template with a slot
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 30 - Generate code for a template with a slot # time=1.153ms
    
    # Subtest: Generate code for a template with inline Text
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 31 - Generate code for a template with inline Text # time=0.964ms
    
    # Subtest: Generate code for a template with inline dynamic Text
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 32 - Generate code for a template with inline dynamic Text # time=0.774ms
    
    # Subtest: Generate code for a template with inline dynamic Text embedded in static text
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 33 - Generate code for a template with inline dynamic Text embedded in static text # time=0.852ms
    
    # Subtest: Generate code for a template with a single element with attributes with percentages
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 34 - Generate code for a template with a single element with attributes with percentages # time=0.784ms
    
    # Subtest: Generate code for a template with a simple for-loop on an Element
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effect array
        1..2
    ok 35 - Generate code for a template with a simple for-loop on an Element # time=1.783ms
    
    # Subtest: Generate code for a template with a simple for-loop on an Element, Using data from appState plugin
        ok 1 - Generator should return a render function with the correct code using data from appState plugin
        ok 2 - Generator should return an empty effect array
        1..2
    ok 36 - Generate code for a template with a simple for-loop on an Element, Using data from appState plugin # time=1.141ms
    
    # Subtest: Generate code for a template with a simple for-loop on an Element, Using data from nested state property
        ok 1 - Generator should return a render function with the correct code using data from nested state property
        ok 2 - Generator should return an empty effect array
        1..2
    ok 37 - Generate code for a template with a simple for-loop on an Element, Using data from nested state property # time=1.037ms
    
    # Subtest: Generate code for a template with a simple for-loop on an Element with a custom index key
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 38 - Generate code for a template with a simple for-loop on an Element with a custom index key # time=1.052ms
    
    # Subtest: Generate code for a template with a simple for-loop on an Element with a key attribute
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 39 - Generate code for a template with a simple for-loop on an Element with a key attribute # time=1.029ms
    
    # Subtest: Generate code for a template with a simple for-loop on a Component with a key attribute and a custom index
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 40 - Generate code for a template with a simple for-loop on a Component with a key attribute and a custom index # time=1.236ms
    
    # Subtest: Generate code for a template with a simple for-loop on an Element with an automatic ref attribute
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an effects array with 1 function
        1..2
    ok 41 - Generate code for a template with a simple for-loop on an Element with an automatic ref attribute # time=1.038ms
    
    # Subtest: Generate code for a template with double $$ (i.e. referencing a Blits plugin)
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an effects array with 1 item
        ok 3 - Generator should return first render function with the correct code
        1..3
    ok 42 - Generate code for a template with double $$ (i.e. referencing a Blits plugin) # time=0.96ms
    
    # Subtest: Generate code for a template with verification of dynamic attributes
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an empty effects array
        1..2
    ok 43 - Generate code for a template with verification of dynamic attributes # time=1.047ms
    
    # Subtest: Generate code for a template with verification of reactive attributes
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an effects array with 2 item
        ok 3 - Generator should return an effect function for the reactive eWidth attribute
        ok 4 - Generator should return an effect function for the reactive eHeight attribute
        1..4
    ok 44 - Generate code for a template with verification of reactive attributes # time=1.363ms
    
    # Subtest: Generate code for a template with attribute values verified against a nested state object
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an effects array with 2 item
        ok 3 - Generator should return an effect function for the reactive eWidth attribute
        ok 4 - Generator should return an effect function for the reactive eHeight attribute
        1..4
    ok 45 - Generate code for a template with attribute values verified against a nested state object # time=1.188ms
    
    # Subtest: Generate code for a template with verification of attributes with Math calculations
        ok 1 - Generator should return a render function with the correct code
        ok 2 - Generator should return an effects array with 2 item
        ok 3 - Generator should return an effect function for the reactive width attribute
        ok 4 - Generator should return an effect function for the reactive height attribute
        1..4
    ok 46 - Generate code for a template with verification of attributes with Math calculations # time=1.703ms
    
    1..46
ok 14 - src/lib/codegenerator/generator.test.js # time=1930.526ms

# Subtest: src/lib/colors/colors.test.js
    # Subtest: Object
        ok 1 - Colors should be an object
        1..1
    ok 1 - Object # time=3.992ms
    
    # Subtest: 6 character hex
        ok 1 - A 6 character hex code should return the correct color in rgba format
        1..1
    ok 2 - 6 character hex # time=1.897ms
    
    # Subtest: 3 character hex
        ok 1 - A 3 character hex code should return the correct color in rgba format
        1..1
    ok 3 - 3 character hex # time=0.421ms
    
    # Subtest: 8 character hex (rgba)
        ok 1 - A 8 character hex (rgba) code should return the correct color in rgba format
        1..1
    ok 4 - 8 character hex (rgba) # time=0.419ms
    
    # Subtest: Invalid hex values
        ok 1 - Invalid hex values should return white color as the default color
        1..1
    ok 5 - Invalid hex values # time=0.749ms
    
    # Subtest: RGB colors
        ok 1 - RGB codes should return the correct color in rgba format
        1..1
    ok 6 - RGB colors # time=0.438ms
    
    # Subtest: Invalid RGB colors
        ok 1 - Invalid RGB codes should return white color in rgba format
        1..1
    ok 7 - Invalid RGB colors # time=0.382ms
    
    # Subtest: RGBA colors
        ok 1 - RGBA codes should return the correct color in rgba format
        1..1
    ok 8 - RGBA colors # time=0.417ms
    
    # Subtest: Invalid RGBA colors
        ok 1 - Invalid RGBA codes should return white color in rgba format
        1..1
    ok 9 - Invalid RGBA colors # time=0.399ms
    
    # Subtest: HTML colors
        ok 1 - HTML color codes should return the correct color in rgba format
        1..1
    ok 10 - HTML colors # time=0.534ms
    
    # Subtest: Invalid HTML colors
        ok 1 - Invalid HTML color codes should return white color in rgba format
        1..1
    ok 11 - Invalid HTML colors # time=0.521ms
    
    1..11
ok 15 - src/lib/colors/colors.test.js # time=1852.195ms

# Subtest: src/lib/componentId.test.js
    # Subtest: Type createHumandReadableId
        ok 1 - createHumanReadableId should be a function
        1..1
    ok 1 - Type createHumandReadableId # time=4.792ms
    
    # Subtest: Returns a readable id, based on a counter and component name
        ok 1 - createHumanReadableId should return correct ID
        1..1
    ok 2 - Returns a readable id, based on a counter and component name # time=0.543ms
    
    # Subtest: Returns a readable id with incremented count
        ok 1 - createHumanReadableId should return correct ID
        1..1
    ok 3 - Returns a readable id with incremented count # time=0.463ms
    
    # Subtest: Has a seperate count per component name
        ok 1 - createHumanReadableId should return correct ID
        1..1
    ok 4 - Has a seperate count per component name # time=0.371ms
    
    # Subtest: Type createInternalId
        ok 1 - createInternalId should be a function
        1..1
    ok 5 - Type createInternalId # time=0.469ms
    
    # Subtest: Returns an internal id, disregarding the component name
        ok 1 - createInternalId should return correct ID
        1..1
    ok 6 - Returns an internal id, disregarding the component name # time=1.554ms
    
    # Subtest: Returns an id with incremented counter
        ok 1 - createInternalId should return correct ID
        1..1
    ok 7 - Returns an id with incremented counter # time=0.406ms
    
    # Subtest: Uses the same counter for all components
        ok 1 - createInternalId should return correct ID
        1..1
    ok 8 - Uses the same counter for all components # time=0.378ms
    
    1..8
ok 16 - src/lib/componentId.test.js # time=1697.657ms

# Subtest: src/lib/eventListeners.test.js
    # Subtest: registerListener
        ok 1 - Should not throw exception when registering a listener
        ok 2 - Should not throw exception when registering a listener with priority
        ok 3 - Should not throw exception when registering multiple components for the same event
        1..3
    ok 1 - registerListener # time=5.075ms
    
    # Subtest: executeListeners - no listeners
        ok 1 - Should return true when no listeners are registered
        1..1
    ok 2 - executeListeners - no listeners # time=1.13ms
    
    # Subtest: executeListeners - with listeners
        ok 1 - Should return true when all listeners execute successfully
        ok 2 - Should call all registered callbacks
        1..2
    ok 3 - executeListeners - with listeners # time=1.124ms
    
    # Subtest: executeListeners - priority order
        ok 1 - Should execute callbacks in priority order
        1..1
    ok 4 - executeListeners - priority order # time=2.28ms
    
    # Subtest: executeListeners - stop propagation
        ok 1 - Should return false when propagation is stopped
        ok 2 - Should stop calling callbacks after one returns false
        1..2
    ok 5 - executeListeners - stop propagation # time=0.572ms
    
    # Subtest: deregisterListener
        ok 1 - Should return true when no listeners are registered after deregistration
        ok 2 - Should not call deregistered callback
        1..2
    ok 6 - deregisterListener # time=0.579ms
    
    # Subtest: deregisterListener - only deregisters specified component listener
        ok 1 - Should return true when listeners are still registered after deregistering one
        ok 2 - Should not call deregistered callback
        ok 3 - Should call remaining registered callback
        1..3
    ok 7 - deregisterListener - only deregisters specified component listener # time=0.656ms
    
    # Subtest: removeListeners
        ok 1 - Should still return true for event1 as another component is registered
        ok 2 - Should return true for event2 as no listeners remain
        1..2
    ok 8 - removeListeners # time=0.517ms
    
    # Subtest: cache invalidation
        ok 1 - Should invalidate cache when new listener is added
        ok 2 - Should invalidate cache when listeners are removed
        1..2
    ok 9 - cache invalidation # time=0.793ms
    
    # Subtest: deregisterListener when no listeners are registered
        ok 1 - Should still return true for event1 as another component is registered
        1..1
    ok 10 - deregisterListener when no listeners are registered # time=0.778ms
    
    1..10
ok 17 - src/lib/eventListeners.test.js # time=1785.182ms

# Subtest: src/lib/reactivity/effect.test.js
    # Subtest: Trigger - type
        ok 1 - Trigger should be a function
        1..1
    ok 1 - Trigger - type # time=11.279ms
    
    # Subtest: Track type
        ok 1 - Track should be a function
        1..1
    ok 2 - Track type # time=0.645ms
    
    # Subtest: Effect - Basic Effect
        ok 1 - Effect should run once initially and increment count
        1..1
    ok 3 - Effect - Basic Effect # time=0.77ms
    
    1..3
ok 18 - src/lib/reactivity/effect.test.js # time=2309.244ms

# Subtest: src/lib/reactivity/reactive.test.js
    # Subtest: Type
        ok 1 - Reactive should be a function
        1..1
    ok 1 - Type # time=4.286ms
    
    # Subtest: Reactive - Basic Object Reactivity
        ok 1 - Effect should run once initially and increment counter
        ok 2 - Effect should run again after modifying a property and increment counter
        ok 3 - Effect should NOT run again after modifying a property to the same value
        ok 4 - Effect should run again after modifying a property and increment counter
        1..4
    ok 2 - Reactive - Basic Object Reactivity # time=1.569ms
    
    # Subtest: Reactive - Nested Object Reactivity
        ok 1 - Effect should run once initially and increment counter
        ok 2 - Effect should run again after modifying a nested property and increment counter
        ok 3 - Effect should NOT run again after modifying a nested property to the same value
        ok 4 - Effect should run again after modifying a nested property and increment counter
        1..4
    ok 3 - Reactive - Nested Object Reactivity # time=0.792ms
    
    # Subtest: Reactive - Array Reactivity
        ok 1 - Effect should run once initially and increment counter
        ok 2 - Effect should run again after modifying an array and increment counter
        ok 3 - Effect should run again after modifying an array and increment counter
        ok 4 - Effect should run again after modifying an array and increment counter
        ok 5 - Effect should run again after modifying an array item and increment counter
        ok 6 - Effect should NOT run again after modifying an array item to the same value
        ok 7 - Effect should run again after replacing the array and increment counter
        1..7
    ok 4 - Reactive - Array Reactivity # time=1.442ms
    
    # Subtest: Reactive - Effect with specific keys
        ok 1 - Effect should run once initially and increment counter
        ok 2 - Effect should run again after modifying the tracked property and increment counter
        ok 3 - Effect should NOT run again after modifying an untracked property
        ok 4 - Effect should run again after modifying the tracked property and increment counter
        1..4
    ok 5 - Reactive - Effect with specific keys # time=0.786ms
    
    # Subtest: Reactive - Multiple effects Tracking & Triggering for same object
        ok 1 - Both effects should run once initially and increment counter
        ok 2 - Both effects should run again after modifying a property and increment counter
        1..2
    ok 6 - Reactive - Multiple effects Tracking & Triggering for same object # time=0.542ms
    
    # Subtest: Reactive - Assign new object to reactive property
        ok 1 - Effect should run once initially and increment counter
        ok 2 - Effect should run again after assigning a new object to a reactive property and increment counter
        1..2
    ok 7 - Reactive - Assign new object to reactive property # time=0.541ms
    
    # Subtest: Reactive - Get raw object from proxy
        ok 1 - Should return the original object from the proxy using the raw symbol
        ok 2 - Original object should not be equal to proxied object
        1..2
    ok 8 - Reactive - Get raw object from proxy # time=1.53ms
    
    # Subtest: Reactive - Check reactive object is a proxy or not
        ok 1 - Reactive object should be a proxy
        1..1
    ok 9 - Reactive - Check reactive object is a proxy or not # time=0.383ms
    
    # Subtest: Reactive - Non object prototype should not be converted to Proxy
        ok 1 - Reactive should return the original object
        1..1
    ok 10 - Reactive - Non object prototype should not be converted to Proxy # time=0.376ms
    
    # Subtest: Reactive - Effect with multiple specific keys
        ok 1 - Effect should run once initially and increment counter
        ok 2 - Effect should run again after modifying a tracked property and increment counter
        ok 3 - Effect should run again after modifying a tracked property and increment counter
        ok 4 - Effect should NOT run again after modifying an untracked property
        ok 5 - Effect should run again after modifying a tracked property and increment counter
        1..5
    ok 11 - Reactive - Effect with multiple specific keys # time=0.995ms
    
    # Subtest: Reactive- Pause/Resume Tracking
        ok 1 - Effect should run once initially and increment counter
        ok 2 - Effect should run again after modifying a property and increment counter
        ok 3 - Effect should NOT run again after modifying a property while tracking is paused
        ok 4 - Effect should run again after modifying a property and increment counter
        1..4
    ok 12 - Reactive- Pause/Resume Tracking # time=0.995ms
    
    # Subtest: Reactive - Basic object reactivity using defineProperty mode
        ok 1 - Effect should run once initially and increment counter
        ok 2 - Effect should run again after modifying a property and increment counter
        ok 3 - Effect should NOT run again after modifying a property to the same value
        ok 4 - Effect should run again after modifying a property and increment counter
        1..4
    ok 13 - Reactive - Basic object reactivity using defineProperty mode # time=1.056ms
    
    # Subtest: Reactive - Array reactivity using defineProperty mode
        ok 1 - Effect should run once initially and increment counter
        ok 2 - Effect should run again after modifying an array and increment counter to 2
        ok 3 - Effect should run again after modifying an array and increment counter to 3
        ok 4 - Effect should run again after modifying an array and increment counter to 4
        1..4
    ok 14 - Reactive - Array reactivity using defineProperty mode # time=0.819ms
    
    # Subtest: Reactive - Nested object reactivity using defineProperty mode
        ok 1 - Effect should run once initially and increment counter
        ok 2 - Effect should run again after modifying a nested property and increment counter
        ok 3 - Effect should NOT run again after modifying a nested property to the same value
        ok 4 - Effect should run again after modifying a nested property and increment counter
        1..4
    ok 15 - Reactive - Nested object reactivity using defineProperty mode # time=1.281ms
    
    1..15
ok 19 - src/lib/reactivity/reactive.test.js # time=2268.837ms

# Subtest: src/lib/reactivityguard/computedprops.test.js
    # Subtest: Skips comments and processes computed methods
        ok 1 - should not throw with comments
        ok 2 - processes methods, skips comments
        1..2
    ok 1 - Skips comments and processes computed methods # time=7.173ms
    
    # Subtest: Deterministic replacements for identical computed methods
        ok 1 - should not throw for duplicates
        ok 2 - processes both identical methods
        1..2
    ok 2 - Deterministic replacements for identical computed methods # time=1.049ms
    
    # Subtest: Does not process non-method computed syntaxes
        ok 1 - should not throw for mixed syntaxes
        ok 2 - only processes method shorthand
        1..2
    ok 3 - Does not process non-method computed syntaxes # time=0.748ms
    
    1..3
ok 20 - src/lib/reactivityguard/computedprops.test.js # time=2161.21ms

# Subtest: src/lib/templateparser/parser.test.js
    # Subtest: Type
        ok 1 - Parser should be a function
        1..1
    ok 1 - Type # time=5.462ms
    
    # Subtest: Returns an object
        ok 1 - Parser should return an object
        ok 2 - Parser should return an object with a children key
        ok 3 - Children key returned by parser should be an array
        1..3
    ok 2 - Returns an object # time=1.647ms
    
    # Subtest: Parse simple single tag
        ok 1 - Parser should return object representation of template
        1..1
    ok 3 - Parse simple single tag # time=3.625ms
    
    # Subtest: Parse simple tag and simple nested tag
        ok 1 - Parser should return object representation of template
        1..1
    ok 4 - Parse simple tag and simple nested tag # time=0.917ms
    
    # Subtest: Parse simple single tag with static attributes
        ok 1 - Parser should return object representation of template
        1..1
    ok 5 - Parse simple single tag with static attributes # time=0.797ms
    
    # Subtest: Parse tag with attributes and nested tag with attributes
        ok 1 - Parser should return object representation of template
        1..1
    ok 6 - Parse tag with attributes and nested tag with attributes # time=0.67ms
    
    # Subtest: Parse tag with attributes and 2 nested tags with attributes
        ok 1 - Parser should return object representation of template
        1..1
    ok 7 - Parse tag with attributes and 2 nested tags with attributes # time=0.834ms
    
    # Subtest: Parse tag with attributes and deep nested tag with attributes
        ok 1 - Parser should return object representation of template
        1..1
    ok 8 - Parse tag with attributes and deep nested tag with attributes # time=0.833ms
    
    # Subtest: Parse simple single tag with dynamic attributes
        ok 1 - Parser should return object representation of template
        1..1
    ok 9 - Parse simple single tag with dynamic attributes # time=0.699ms
    
    # Subtest: Parse tag with attributes and reactive attributes
        ok 1 - Parser should return object representation of template
        1..1
    ok 10 - Parse tag with attributes and reactive attributes # time=0.685ms
    
    # Subtest: Parse simple single tag where one of the attributes has a dash in it's name
        ok 1 - Parser should return object representation of template
        1..1
    ok 11 - Parse simple single tag where one of the attributes has a dash in it's name # time=0.622ms
    
    # Subtest: Parse nested self closing tag
        ok 1 - Parser should return object representation of template
        1..1
    ok 12 - Parse nested self closing tag # time=0.592ms
    
    # Subtest: Parse multiple nested self closing tags
        ok 1 - Parser should return object representation of template
        1..1
    ok 13 - Parse multiple nested self closing tags # time=0.611ms
    
    # Subtest: Parse attributes which values have spaces in it
        ok 1 - Parser should return object representation of template
        1..1
    ok 14 - Parse attributes which values have spaces in it # time=0.605ms
    
    # Subtest: Parse attributes with an expression in it
        ok 1 - Parser should return object representation of template
        1..1
    ok 15 - Parse attributes with an expression in it # time=0.678ms
    
    # Subtest: Parse template with commented tag (and skip it)
        ok 1 - Parser should return object representation of template
        1..1
    ok 16 - Parse template with commented tag (and skip it) # time=1.221ms
    
    # Subtest: Parse template with comment spanned across multiple tags (and skip it)
        ok 1 - Parser should return object representation of template
        1..1
    ok 17 - Parse template with comment spanned across multiple tags (and skip it) # time=1.064ms
    
    # Subtest: Parse template with enclosing comment (and skip it)
        ok 1 - Parser should return object representation of template
        1..1
    ok 18 - Parse template with enclosing comment (and skip it) # time=1.2ms
    
    # Subtest: Parse template with for loop
        ok 1 - Parser should return object representation of template
        1..1
    ok 19 - Parse template with for loop # time=0.786ms
    
    # Subtest: Parse template with a conditional (if-statement)
        ok 1 - Parser should return object representation of template
        1..1
    ok 20 - Parse template with a conditional (if-statement) # time=0.716ms
    
    # Subtest: Parse template with a visibility toggle (show-statement)
        ok 1 - Parser should return object representation of template
        1..1
    ok 21 - Parse template with a visibility toggle (show-statement) # time=0.778ms
    
    # Subtest: Parse template with a nameless tag
        ok 1 - Parser should return object representation of template
        1..1
    ok 22 - Parse template with a nameless tag # time=0.812ms
    
    # Subtest: Parse template with a transition argument (single value)
        ok 1 - Parser should return object representation of template
        1..1
    ok 23 - Parse template with a transition argument (single value) # time=0.97ms
    
    # Subtest: Parse template with a transition argument (object)
        ok 1 - Parser should return object representation of template
        1..1
    ok 24 - Parse template with a transition argument (object) # time=1.095ms
    
    # Subtest: Parse template with a different modifier
        ok 1 - Parser should return object representation of template
        1..1
    ok 25 - Parse template with a different modifier # time=1.087ms
    
    # Subtest: Parse template with a full transition object (without the transition modifier)
        ok 1 - Parser should return object representation of template
        1..1
    ok 26 - Parse template with a full transition object (without the transition modifier) # time=1.015ms
    
    # Subtest: Parse template with attributes with values spread over multiple lines
        ok 1 - Parser should return object representation of template
        1..1
    ok 27 - Parse template with attributes with values spread over multiple lines # time=1.555ms
    
    # Subtest: Parse template with inline text between tags
        ok 1 - Parser should return object representation of template
        1..1
    ok 28 - Parse template with inline text between tags # time=0.904ms
    
    # Subtest: Parse template with multiple inline texts between different tags
        ok 1 - Parser should return object representation of template
        1..1
    ok 29 - Parse template with multiple inline texts between different tags # time=1.349ms
    
    # Subtest: Parse template with attribute name starts with @ character
        ok 1 - Parser should return object representation of template
        1..1
    ok 30 - Parse template with attribute name starts with @ character # time=1.091ms
    
    # Subtest: Parse template with attribute values with delimited either single or double quotes
        ok 1 - Parser should return object representation of template
        1..1
    ok 31 - Parse template with attribute values with delimited either single or double quotes # time=1.112ms
    
    # Subtest: Parse template with multiple top level elements and parsing should fail
        ok 1 - Parser should throw TemplateStructureError
        ok 2 - Parser should throw TemplateStructureError:MultipleTopLevelTags
        1..2
    ok 32 - Parse template with multiple top level elements and parsing should fail # time=1.617ms
    
    # Subtest: Parse template with unclosed tag and parsing should fail
        ok 1 - Parser should throw TemplateStructureError
        ok 2 - Parser should throw TemplateStructureError:MismatchedClosingTag
        1..2
    ok 33 - Parse template with unclosed tag and parsing should fail # time=0.727ms
    
    # Subtest: Parse template with multiple unclosed tags and parsing should fail
        ok 1 - Parser should throw TemplateStructureError
        ok 2 - Parser should throw TemplateStructureError:MismatchedClosingTag
        1..2
    ok 34 - Parse template with multiple unclosed tags and parsing should fail # time=0.862ms
    
    # Subtest: Parse template with an unclosed tag and parsing should fail
        ok 1 - Parser should throw TemplateStructureError
        ok 2 - Parser should throw TemplateStructureError:UnclosedTags
        1..2
    ok 35 - Parse template with an unclosed tag and parsing should fail # time=0.852ms
    
    # Subtest: Parse template with an invalid closing tag and parsing should fail
        ok 1 - Parser should throw TemplateParseError
        ok 2 - Parser should throw TemplateParseError:InvalidClosingTag
        1..2
    ok 36 - Parse template with an invalid closing tag and parsing should fail # time=0.847ms
    
    # Subtest: Parse template with multiple self-closing tags at the top level and parsing should fail
        ok 1 - Parser should throw TemplateStructureError
        ok 2 - Parser should throw TemplateStructureError:MultipleTopLevelTags
        1..2
    ok 37 - Parse template with multiple self-closing tags at the top level and parsing should fail # time=0.716ms
    
    # Subtest: Parse template with a closing tag at the beginning and parsing should fail
        ok 1 - Parser should throw TemplateStructureError
        ok 2 - Parser should throw TemplateStructureError:MismatchedClosingTag
        1..2
    ok 38 - Parse template with a closing tag at the beginning and parsing should fail # time=0.831ms
    
    # Subtest: Parse template with a closing tag that has attributes and parsing should fail
        ok 1 - Parser should throw TemplateParseError
        ok 2 - Parser should throw TemplateParseError:AttributesInClosingTag
        1..2
    ok 39 - Parse template with a closing tag that has attributes and parsing should fail # time=0.781ms
    
    # Subtest: Parse template with an invalid tag and parsing should fail
        ok 1 - Parser should throw TemplateParseError
        ok 2 - Parser should throw TemplateParseError:InvalidTag
        1..2
    ok 40 - Parse template with an invalid tag and parsing should fail # time=0.792ms
    
    # Subtest: Parse template with an invalid attribute value and parsing should fail
        ok 1 - Parser should throw TemplateParseError
        ok 2 - Parser should throw TemplateParseError:MissingOrInvalidAttributeValue
        1..2
    ok 41 - Parse template with an invalid attribute value and parsing should fail # time=0.865ms
    
    # Subtest: Parse template with an invalid attribute name and parsing should fail
        ok 1 - Parser should throw TemplateParseError
        ok 2 - Parser should throw TemplateParseError:InvalidAttribute
        1..2
    ok 42 - Parse template with an invalid attribute name and parsing should fail # time=0.705ms
    
    # Subtest: Parse template with an invalid attribute name by providing parent component and parsing should fail
        ok 1 - Parser should throw TemplateParseError
        ok 2 - Parser should throw TemplateParseError:InvalidAttribute
        ok 3 - Error message should contain the component hierarchy
        1..3
    ok 43 - Parse template with an invalid attribute name by providing parent component and parsing should fail # time=0.87ms
    
    # Subtest: Parse template with an invalid attribute name by providing parent component without component name and parsing should fail
        ok 1 - Parser should throw TemplateParseError
        ok 2 - Parser should throw TemplateParseError:InvalidAttribute
        ok 3 - Error message should contain the component hierarchy without the component name
        1..3
    ok 44 - Parse template with an invalid attribute name by providing parent component without component name and parsing should fail # time=0.986ms
    
    # Subtest: Parse template with an invalid attribute name by providing component file path and parsing should fail
        ok 1 - Parser should throw TemplateParseError
        ok 2 - Parser should throw TemplateParseError:InvalidAttribute
        ok 3 - Error message should contain the component file path
        1..3
    ok 45 - Parse template with an invalid attribute name by providing component file path and parsing should fail # time=0.867ms
    
    # Subtest: Parse template with color and effects attributes and parsing should convert color values
        ok 1 - Parser should return object representation of template with color values converted
        ok 2 - should be equal
        ok 3 - Should log warning message about hsla
        1..3
    ok 46 - Parse template with color and effects attributes and parsing should convert color values # time=11.723ms
    
    # Subtest: Parse template with :for attribute on root element and parsing should fail
        ok 1 - Parser should throw TemplateStructureError
        ok 2 - Parser should throw TemplateStructureError:ForAttributeOnRootElement
        1..2
    ok 47 - Parse template with :for attribute on root element and parsing should fail # time=0.635ms
    
    1..47
ok 21 - src/lib/templateparser/parser.test.js # time=2420.873ms

# Subtest: src/plugin.test.js
    # Subtest: Function plugin registration
        ok 1 - Function plugin registered correctly with default options
        ok 2 - Function plugin registered with custom options
        1..2
    ok 1 - Function plugin registration # time=7.274ms
    
    # Subtest: Function plugin errors
        ok 1 - Function plugin without name throws error
        ok 2 - Function plugin with options as name throws error
        1..2
    ok 2 - Function plugin errors # time=1.613ms
    
    # Subtest: Object plugin registration
        ok 1 - Object plugins registered correctly with name resolution, options, and default log plugin exists
        1..1
    ok 3 - Object plugin registration # time=0.451ms
    
    1..3
ok 22 - src/plugin.test.js # time=2230.728ms

# Subtest: src/plugins/storage/localCookie.test.js
    # Subtest: Local Storage - Functions
        ok 1 - Local Storage should be an object
        ok 2 - Should have a setItem function
        ok 3 - Should have a removeItem function
        ok 4 - Should have a clear function
        ok 5 - Should have a keys function
        1..5
    ok 1 - Local Storage - Functions # time=6.548ms
    
    # Subtest: Local Storage - setItem key/value "a" with value "b"
        ok 1 - Local Storage setItem function return should be undefined
        ok 2 - Should return the same value "b" for key "a"
        1..2
    ok 2 - Local Storage - setItem key/value "a" with value "b" # time=0.94ms
    
    # Subtest: Local Storage - Remove item "a"
        ok 1 - Local storage removeItem function should return undefined
        ok 2 - Should return a null value for key "a"
        1..2
    ok 3 - Local Storage - Remove item "a" # time=0.681ms
    
    # Subtest: Local Storage - Should store a number as a string
        ok 1 - Should store a number as a string
        1..1
    ok 4 - Local Storage - Should store a number as a string # time=0.461ms
    
    # Subtest: Local Storage - Clear items 
        ok 1 - Local storage clear function should return undefined
        ok 2 - Should not have a value for key "a"
        ok 3 - Should not have a value for key "b"
        1..3
    ok 5 - Local Storage - Clear items # time=0.829ms
    
    # Subtest: Local Storage - keys
        ok 1 - Keys length should be equal to 2
        ok 2 - First key should be "a"
        ok 3 - Second key should be "b"
        1..3
    ok 6 - Local Storage - keys # time=0.935ms
    
    # Subtest: Cookies - Functions
        ok 1 - Cookies should be an object
        ok 2 - Cookies should have a setItem function
        ok 3 - Cookies should have a removeItem function
        ok 4 - Cookies should have a clear function
        ok 5 - Should have a keys function
        1..5
    ok 7 - Cookies - Functions # time=0.923ms
    
    # Subtest: Cookies - setItem key/value "a" with value "b"
        ok 1 - Cookies setItem function return should be undefined
        ok 2 - Should return the same value "b" for key "a"
        1..2
    ok 8 - Cookies - setItem key/value "a" with value "b" # time=20.48ms
    
    # Subtest: Cookies - Remove item "a"
        ok 1 - Cookies removeItem function should return undefined
        ok 2 - Should return a null value for key "a"
        1..2
    ok 9 - Cookies - Remove item "a" # time=1.423ms
    
    # Subtest: Cookies- Should store a number as a string
        ok 1 - Should store a number as a string
        1..1
    ok 10 - Cookies- Should store a number as a string # time=1.536ms
    
    # Subtest: Cookies - Clear items 
        ok 1 - Cookies clear function should return undefined
        ok 2 - Should not have a value for key "a"
        ok 3 - Should not have a value for key "b"
        1..3
    ok 11 - Cookies - Clear items # time=2.341ms
    
    # Subtest: Cookies - Keys
        ok 1 - Keys length should be equal to 2
        ok 2 - First key should be "a"
        ok 3 - Second key should be "b"
        1..3
    ok 12 - Cookies - Keys # time=1.713ms
    
    1..12
ok 23 - src/plugins/storage/localCookie.test.js # time=2282.351ms

(node:2653) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
# Subtest: src/plugins/storage/storage.test.js
    # Subtest: Storage - get non existent key
        ok 1 - Get method should return null for non-existent key
        1..1
    ok 1 - Storage - get non existent key # time=6.009ms
    
    # Subtest: Storage - set key value pair
        ok 1 - Set should return true for valid key-value pair
        1..1
    ok 2 - Storage - set key value pair # time=1.001ms
    
    # Subtest: Storage - set with value that throws error
        ok 1 - Set should return false for value that throws error
        1..1
    ok 3 - Storage - set with value that throws error # time=0.867ms
    
    # Subtest: Storage - get existing key
        ok 1 - Get should return the correct value for existing key
        1..1
    ok 4 - Storage - get existing key # time=1.877ms
    
    # Subtest: Storage - remove key
        ok 1 - Remove should delete the key-value pair
        1..1
    ok 5 - Storage - remove key # time=0.942ms
    
    # Subtest: Storage - clear
        ok 1 - Clear should delete the first key-value pair
        ok 2 - Clear should delete the second key-value pair
        1..2
    ok 6 - Storage - clear # time=0.691ms
    
    # Subtest: Storage - set with value that cannot be stringified
        ok 1 - Set should return false for value that cannot be stringified
        1..1
    ok 7 - Storage - set with value that cannot be stringified # time=0.885ms
    
    1..7
ok 24 - src/plugins/storage/storage.test.js # time=2350.403ms

# Subtest: src/plugins/theme.test.js
    # Subtest: Empty Theme creation
        ok 1 - someColor should be undefined
        1..1
    ok 1 - Empty Theme creation # time=8.161ms
    
    # Subtest: Basic theme creation & usage
        ok 1 - someColor should be pink
        ok 2 - someSizes.tile should be 200
        1..2
    ok 2 - Basic theme creation & usage # time=0.861ms
    
    # Subtest: Advanced theme creation & usage
        ok 1 - someColor should be orange
        ok 2 - someSizes.tile should be 200
        ok 3 - someColor should be pink
        ok 4 - someSizes.tile should be 50
        1..4
    ok 3 - Advanced theme creation & usage # time=1.98ms
    
    # Subtest: Applying theme variant
        ok 1 - should get width from partner1 theme
        ok 2 - should get gradient 1 from partner1 theme
        ok 3 - should get gradient 2 from base theme
        ok 4 - should get gradient 1 from high contrast theme
        ok 5 - should get gradient 2 from high contrast theme
        1..5
    ok 4 - Applying theme variant # time=3.115ms
    
    1..4
ok 25 - src/plugins/theme.test.js # time=2424.693ms

# Subtest: src/router/router.test.js
    # Subtest: Type of matchHash
        ok 1 - matchhash should be a function
        1..1
    ok 1 - Type of matchHash # time=4.298ms
    
    # Subtest: Match paths with static routes that have an exact match
        ok 1 - Should return the correct route object
        ok 2 - Should return the correct route object
        ok 3 - Should return the correct route object
        ok 4 - Should return the correct route object
        ok 5 - Should return the correct route object
        1..5
    ok 2 - Match paths with static routes that have an exact match # time=1.86ms
    
    # Subtest: Match paths with dynamic route parts
        ok 1 - Should return the correct route object
        ok 2 - Should return the correct route object
        ok 3 - Should return the correct route object
        ok 4 - Should return the correct route object
        ok 5 - Should return the correct route object
        ok 6 - Should return the correct route object
        1..6
    ok 3 - Match paths with dynamic route parts # time=1.503ms
    
    # Subtest: Match paths with a wildcard asterix
        ok 1 - Should return the correct route object
        ok 2 - Should return the correct route object
        ok 3 - Should return the correct route object
        ok 4 - Should return the correct route object
        ok 5 - Should return the correct route object
        ok 6 - Should return the correct route object
        1..6
    ok 4 - Match paths with a wildcard asterix # time=1.35ms
    
    # Subtest: Add params to route for dynamic route matches
        ok 1 - Should return the correct params object
        ok 2 - Should return the correct route object
        ok 3 - Should return the correct route object
        1..3
    ok 5 - Add params to route for dynamic route matches # time=2.54ms
    
    # Subtest: Add remaining path as param for wild card routes
        ok 1 - Should return the correct route object
        ok 2 - Should return the correct params object
        ok 3 - Should return the correct params object
        ok 4 - Should return the correct params object
        1..4
    ok 6 - Add remaining path as param for wild card routes # time=1.201ms
    
    # Subtest: Work with trailing slashes
        ok 1 - Should return the correct route object
        ok 2 - Should return the correct route object
        ok 3 - Should return the correct route object
        ok 4 - Should return the correct route object
        ok 5 - Should return the correct route object
        1..5
    ok 7 - Work with trailing slashes # time=1.153ms
    
    # Subtest: Work with and without leading slashes
        ok 1 - Should return the correct route object
        ok 2 - Should return the correct route object
        ok 3 - Should return the correct route object
        ok 4 - Should return the correct route object
        ok 5 - Should return the correct route object
        1..5
    ok 8 - Work with and without leading slashes # time=1.034ms
    
    # Subtest: Match routes case insensitive
        ok 1 - Should return the correct route object
        ok 2 - Should return the correct route object
        ok 3 - Should return the correct route object
        ok 4 - Should return the correct route object
        ok 5 - Should return the correct route object
        1..5
    ok 9 - Match routes case insensitive # time=1.022ms
    
    # Subtest: Match routes case insensitive, but pass props with original casing
        ok 1 - Should return the correct params object
        ok 2 - Should return the correct params object
        ok 3 - Should return the correct params object
        1..3
    ok 10 - Match routes case insensitive, but pass props with original casing # time=0.88ms
    
    # Subtest: Match paths with dynamic route parts along with query string params
        ok 1 - Should return correct hash
        ok 2 - Should return the correct route path
        ok 3 - Should return the correct route object
        ok 4 - Should contain the correct query parameter key with value
        ok 5 - Should contain the correct query parameter key with value
        1..5
    ok 11 - Match paths with dynamic route parts along with query string params # time=1.426ms
    
    # Subtest: Get the hash from the URL
        ok 1 - The result object should contain a hash key with the correct location hash
        ok 2 - The result object should contain a path key with the hash (stripped the \# symbol)
        1..2
    ok 12 - Get the hash from the URL # time=0.468ms
    
    # Subtest: Get the hash from the URL and handle query params
        ok 1 - The result object should contain a hash key with the correct location hash without the query params
        ok 2 - The result object should contain a path key with the hash (stripped the \# symbol)
        ok 3 - The result object should contain a queryParams key with an URLSearchParams object
        ok 4 - The result object should contain a queryParams key with the correct route query param values
        ok 5 - The result object should contain a queryParams key with the correct route query param values
        1..5
    ok 13 - Get the hash from the URL and handle query params # time=0.826ms
    
    # Subtest: Get route object from Match hash when navigating using to() method
        ok 1 - The result object should contain a path key with path hash
        ok 2 - The results object should contain a params key with zero props
        ok 3 - The results object should contain a data key with zero props
        ok 4 - The results object should contain the default options object
        ok 5 - The results object should contain the default options object
        1..5
    ok 14 - Get route object from Match hash when navigating using to() method # time=3.074ms
    
    # Subtest: Get route object from Match hash when navigating using to() method with options
        ok 1 - The result object should contain a path key with path hash
        ok 2 - The results object should contain a options key with keep alive as True
        1..2
    ok 15 - Get route object from Match hash when navigating using to() method with options # time=0.957ms
    
    # Subtest: Get Hash from URL when navigating using to() method
        ok 1 - The result object key property should contain correct location hash
        ok 2 - The result object should contain a path key with hash without \#
        1..2
    ok 16 - Get Hash from URL when navigating using to() method # time=0.489ms
    
    # Subtest: Router updates state.path, state.params, and state.data correctly
        ok 1 - state.path matches route definition
        ok 2 - state.params extracted correctly
        ok 3 - state.data merged correctly (route + navigation + query)
        1..3
    ok 17 - Router updates state.path, state.params, and state.data correctly # time=6.634ms
    
    # Subtest: Before hook route object redirect
        ok 1 - Should redirect to new path
        1..1
    ok 18 - Before hook route object redirect # time=0.857ms
    
    # Subtest: BeforeEach hook route object redirect
        ok 1 - Should redirect via beforeEach hook
        1..1
    ok 19 - BeforeEach hook route object redirect # time=0.854ms
    
    # Subtest: Route meta data is accessible in route object
        ok 1 - Should have access to route meta data
        1..1
    ok 20 - Route meta data is accessible in route object # time=0.504ms
    
    1..20
ok 26 - src/router/router.test.js # time=2597.975ms

# Subtest: src/settings.test.js
    # Subtest: Settings - Set a new key 
        ok 1 - set and get a new key should work correctly
        1..1
    ok 1 - Settings - Set a new key # time=3.474ms
    
    # Subtest: Settings - Set an existing key 
        ok 1 - set and get an existing key should work correctly
        1..1
    ok 2 - Settings - Set an existing key # time=0.407ms
    
    # Subtest: Settings - Set multiple keys 
        ok 1 - get should return the correct value for key b
        ok 2 - get should return the correct value for key c
        1..2
    ok 3 - Settings - Set multiple keys # time=0.426ms
    
    # Subtest: Settings - Get a non-existing key 
        ok 1 - get a non-existing key returns null by default
        ok 2 - get a non-existing key returns the provided default value
        1..2
    ok 4 - Settings - Get a non-existing key # time=0.397ms
    
    1..4
ok 27 - src/settings.test.js # time=1549.056ms

-------------------------------|---------|----------|---------|---------|---------------------------
File                           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s         
-------------------------------|---------|----------|---------|---------|---------------------------
All files                      |    83.5 |    83.93 |   76.01 |    83.5 |                           
 blits                         |     100 |    33.33 |     100 |     100 |                           
  eslint.config.cjs            |     100 |    33.33 |     100 |     100 | 62-63                     
 blits/scripts                 |   88.17 |    58.82 |     100 |   88.17 |                           
  prepublishOnly.js            |   88.17 |    58.82 |     100 |   88.17 | ...6-78,80-81,83-84,90-91 
 blits/src                     |   84.61 |    86.36 |   63.63 |   84.61 |                           
  component.js                 |   84.96 |    79.16 |   85.71 |   84.96 | ...51-356,363-365,401-404 
  focus.js                     |   77.12 |       80 |    62.5 |   77.12 | ...,81-98,122-131,148-152 
  keymap.js                    |   85.71 |      100 |       0 |   85.71 | 11-12                     
  launch.js                    |   79.03 |      100 |       0 |   79.03 | 50-62,112-124             
 blits/src/announcer           |   56.11 |    78.72 |   55.55 |   56.11 |                           
  announcer.js                 |   89.61 |    80.95 |      65 |   89.61 | ...93-194,203-208,217-218 
  speechSynthesis.js           |   24.27 |       60 |   28.57 |   24.27 | ...38-207,212-215,223-237 
 blits/src/component/base      |   85.63 |    91.66 |   57.57 |   85.63 |                           
  events.js                    |   89.88 |      100 |       0 |   89.88 | 34-37,53-55,69,83         
  methods.js                   |   86.34 |    87.09 |      75 |   86.34 | ...34-138,241-242,253-263 
  router.js                    |   89.36 |      100 |       0 |   89.36 | 27,30,33,36,39            
  timeouts_intervals.js        |    78.7 |    93.33 |   77.77 |    78.7 | ...01-124,132-136,147-148 
  utils.js                     |   77.77 |      100 |     100 |   77.77 | 45-53,57-63               
 blits/src/component/setup     |    96.6 |    89.23 |   93.75 |    96.6 |                           
  index.js                     |     100 |       75 |     100 |     100 | 55-56                     
  routes.js                    |   95.45 |       75 |     100 |   95.45 | 28-29                     
  state.js                     |   89.23 |    72.72 |     100 |   89.23 | 32-34,47-48,53-54         
  watch.js                     |   88.57 |    66.66 |      50 |   88.57 | 26-27,32-33               
 blits/src/components          |   78.85 |    94.59 |   46.66 |   78.85 |                           
  Circle.js                    |   96.77 |      100 |      50 |   96.77 | 28                        
  FPScounter.js                |   58.67 |      100 |   33.33 |   58.67 | 66-96,100-118             
  RouterView.js                |      70 |      100 |   16.66 |      70 | ...7,41-46,49,52-54,59-66 
  Sprite.js                    |      98 |     93.1 |     100 |      98 | 76-77                     
 blits/src/engines/L3          |    71.3 |    78.49 |   65.57 |    71.3 |                           
  element.js                   |   79.28 |    78.02 |   72.72 |   79.28 | ...14-717,732-733,742-745 
  fontLoader.js                |   13.15 |      100 |       0 |   13.15 | 6-38                      
  launch.js                    |   37.09 |      100 |       0 |   37.09 | 33-37,40-44,47-65,76-124  
  shaderLoader.js              |   33.33 |      100 |       0 |   33.33 | 5-12                      
 blits/src/lib                 |   94.58 |    81.57 |    91.3 |   94.58 |                           
  eventListeners.js            |   88.07 |    95.45 |   66.66 |   88.07 | 24-26,28-40,102-103       
  hooks.js                     |     100 |    85.71 |     100 |     100 | 43                        
  lifecycle.js                 |   94.78 |    58.82 |     100 |   94.78 | 98,100-101,108,110-111    
  log.js                       |    92.3 |    79.16 |     100 |    92.3 | 93-101                    
 blits/src/lib/codegenerator   |      91 |    88.28 |     100 |      91 |                           
  generator.js                 |      91 |    88.28 |     100 |      91 | ...81-596,658-691,716-717 
 blits/src/lib/precompiler     |   36.58 |    66.66 |     100 |   36.58 |                           
  precompiler.js               |   36.58 |    66.66 |     100 |   36.58 | 29-80                     
 blits/src/lib/reactivity      |   89.83 |    94.25 |   93.75 |   89.83 |                           
  effect.js                    |   88.17 |    92.59 |     100 |   88.17 | 36-44,50-51               
  reactive.js                  |   90.56 |       95 |      90 |   90.56 | 61-66,193-194,201-212     
 blits/src/lib/reactivityguard |   95.28 |    74.57 |     100 |   95.28 |                           
  computedprops.js             |   95.28 |    74.57 |     100 |   95.28 | ...01-202,273-275,289-290 
 blits/src/plugins             |   95.89 |    78.12 |   85.71 |   95.89 |                           
  theme.js                     |   95.04 |    76.66 |   83.33 |   95.04 | 97-98,106-107,116-117     
 blits/src/plugins/storage     |   93.95 |    85.71 |     100 |   93.95 |                           
  localCookie.js               |   93.23 |    85.18 |     100 |   93.23 | 54-56,58-60,62-64         
  storage.js                   |   95.91 |     87.5 |     100 |   95.91 | 30-31                     
 blits/src/router              |   63.95 |    55.12 |   76.92 |   63.95 |                           
  router.js                    |   63.95 |    55.12 |   76.92 |   63.95 | ...59-598,603-613,629-671 
-------------------------------|---------|----------|---------|---------|---------------------------
# { total: 1002, pass: 1001, skip: 1 }
# time=26801.746ms

@github-actions
Copy link

github-actions bot commented Feb 2, 2026

Test Results: ✅ PASSED

Run at: 2026-02-02T09:23:29.449Z

Summary:

{ total: 1002, pass: 1001, skip: 1 }

@github-actions
Copy link

github-actions bot commented Feb 2, 2026

Test Results: ✅ PASSED

Run at: 2026-02-02T09:45:47.989Z

Summary:

{ total: 1002, pass: 1001, skip: 1 }

@milesnash
Copy link
Author

@michielvandergeest I'd be grateful for any feedback you might have about this work 🙏

@github-actions
Copy link

Test Results: ✅ PASSED

Run at: 2026-02-18T09:43:45.853Z

Summary:
passed: 1042 failed: NaN skipped: 1 of 1043 tests

@github-actions
Copy link

Test Results: ✅ PASSED

Run at: 2026-02-19T06:05:59.870Z

Summary:
passed: 1042 failed: 0 skipped: 1 of 1043 tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant