-
Notifications
You must be signed in to change notification settings - Fork 0
testframework
This framework is compatible with Skript’s native quickTest and test-action systems, but with important limitations.
When using Skript’s native test suite:
- Skript’s own
testevent overrides the framework’sskriptTestevent - Only features that exist in Skript’s native test environment are available
- Framework-specific extensions become unavailable
As a result:
- Core assertions such as:
assert <condition>
remain usable
- Framework-specific features such as:
stop auto test execution here
are not usable under quickTest or native test-action
- Extended event-values (
event-test, autorun flag, script scoping) may be missing or incomplete
To regain full framework behavior, simply prefix your existing test with devdinc:
devdinc test "<name>"
This forces execution through the framework’s custom event pipeline and restores:
- Full event-values
- Autorun vs manual execution control
- Reflection-backed features
-
Prefer Skript’s native test suite when possible for maximum compatibility
-
Use
devdinc testonly when you need:- Script scoping n * Autorun control
- Parser / log inspection
- Extended lifecycle hooks
This document describes a runtime testing framework for Skript implemented entirely in Skript using custom events, reflection, and controlled parser interaction.
The framework is designed to mirror key aspects of Skript’s internal development test suite while remaining:
- Safe to execute at runtime
- Deterministic and event-driven
- Compatible with production servers
- Capable of testing syntax, parsing, and runtime behavior
All framework state is stored under the namespace:
-test.sk::*
The framework is intentionally strict and explicit.
It aims to:
- Allow tests to be written directly in
.skfiles - Associate tests with the script they originate from
- Support both automatic (autorun) and manual execution paths
- Provide before/after hooks at both per-test and per-script levels
- Prevent state leakage between tests
- Enable parser-level testing via reflection
The framework is built around the following principles:
-
Tests are custom events (
skriptTest) - Tests are registered at parse time
- Execution is scheduled, not inline (scheduler + proxy Runnable)
- Each test is scoped to its source script
- Failures are tracked per test, per script
Execution is fully event-driven and never relies on direct control flow from the script loader.
devdinc test "<test name>" [when <condition>]:
<test body>
- Tests are registered automatically during parsing
-
when <condition>is evaluated immediately before execution - Each test is associated with its originating script
devdinc test "<test name>" [when <condition>]:
<test body>
- Tests are registered automatically during parsing
-
when <condition>is evaluated immediately before execution - Each test is associated with its originating script
Each test is uniquely identified by both its name and its source script.
Internal representation:
[event-string, event-script]
This ensures:
- No collisions between scripts
- Deterministic execution order
- Correct isolation and error attribution
Internally, each test is stored as a pair:
[<test name>, <script>]
This enables:
- Multiple scripts defining tests with identical names
- Script-scoped test execution
- Accurate isolation and error tracking
Tests are registered during the parse phase, not execution.
Registration format:
-test.sk::tests::<script>::<test name> = [<test name>, <script>]
A hidden sentinel test is used during load to guarantee full registration before autorun begins.
On script load:
- Global test state is cleared
- A sentinel test establishes autorun context
- All tests across all scripts are discovered
- Tests are executed in load order
Autorun tests receive:
event-boolean = true
run test(s) %objects%
- Accepts one or more
[test name, script]objects - Runs tests with:
event-boolean = false
- Autorun-only tests may opt out (see below)
all tests [with test name %-string%] [[in] %-script%]
- No arguments → all tests from all scripts
-
with test name→ exact match -
in <script>→ restricts to a single script
Return type:
[test name, script]
Assertions validate runtime conditions and record failures.
assert true: <condition>
assert false: <condition>
assert <condition> to fail
-
without halting– records failure but continues -
with error message "<msg>"– prints formatted output -
with no error message– suppresses console output
Assertions are only valid inside skriptTest.
fail test
fail test with error message "<msg>"
- Records a failure immediately
- Halts execution unless
without haltingis used
Errors are tracked per test + script:
-test.sk::errors::<script>::<test name>::*
test errors [for %-objects%]
- Without arguments → current test
- With objects → aggregated errors
Errors are cleared before each test and never leak.
Every test and lifecycle hook executed by this framework exposes the following event-values:
| Event Value | Type | Meaning |
|---|---|---|
event-string |
string | Test name |
event-script |
script | Script that defines the test |
event-boolean |
boolean | Autorun flag |
event-test |
object | [event-string, event-script] |
- All values are guaranteed when using
devdinc test - Under Skript native tests, availability depends on Skript’s test runner
---------------|----------|--------|
| event-string | string | Test name |
| event-script | script | Originating script |
| event-boolean | boolean | Autorun flag |
| event-test | object | [event-string, event-script] |
These values are guaranteed only when using devdinc test.
They are undefined when running via quickTest or native test-action.
event-test is autorun
event-test is not autorun
-
trueduring load-time execution -
falseduring manual execution
The flag is immutable and scoped to the test event.
stop auto test execution here
- Halts the current test only if autorun is active
- No effect during manual execution
Typical usage:
if event-test is autorun:
stop auto test execution here
The framework provides structured lifecycle hooks that integrate with both framework and native execution.
before each test
after each test
before all tests
after all tests
Inside all lifecycle hooks, event-script refers to:
The script whose tests are currently executing
Examples:
before all tests:
broadcast "Running tests for %event-script%"
after each test:
delete {-tmp::%event-script%::*}
This allows:
- Per-script setup and teardown
- Shared resources scoped to a script
- Accurate cleanup even when multiple scripts define tests
-
before all tests/after all testsrun once per script -
before each test/after each testrun per test, withevent-stringset
The framework supports parser-level testing using reflection.
parse:
<skript code>
- Uses
ParserInstanceto parse nodes - Does not execute code
- Fully restores parser state afterward
last parse logs
- Captures
SkriptLoggeroutput - Enables assertions against expected parser errors
Failures are forwarded to Skript’s internal TestTracker.
- Native reporting tools can observe results
- CI-style environments can consume output
- Experimental and version-dependent
- No compatibility guarantees
You must use:
devdinc test "<name>"
Native test syntax is not supported.
The framework provides controlled fixtures:
-
test-world–skripttestor fallback world -
test-location– fixed offset location -
test-block– temporary block (auto-restored) -
test-offline-player– generated offline player
These utilities guarantee cleanup after each test.
- World state is shared across tests
- This is intentional for performance and safety
Users may implement isolation manually via hooks:
before each test:
# snapshot world
after each test:
# restore world
No built-in snapshotting is provided.
Failures are printed as:
[Skript] [TEST FAILURE] <test name> <optional message>
Output is suppressed when with no error message is used.
The framework guarantees:
- Deterministic registration and execution
- Script-scoped test isolation
- No state leakage between tests
- Reliable autorun vs manual distinction
- Parser state is always restored
The following must not be relied upon:
- Sentinel test mechanics
- Internal variable layout
- Scheduler timing assumptions
- Reflection internals
These may change without notice.
Reflection is used for:
-
ParserInstancemanipulation - Condition parsing
- Log capture
- Native
TestTrackerforwarding
- All reflected state is backed up and restored
- No permanent mutation of Skript internals
- Binary compatibility across versions
- Stability under obfuscation
- Support on modified Skript forks
Reflection-backed features are best-effort and may degrade gracefully.