i see this pattern used a lot in tests:
eg
https://github.com/nim-lang/Nim/blob/devel/tests/js/tstring_assignment.nim
- discard """
- output: '''true
asdfasekjkler''' """
instead of echo main("asdfasekjkleräöü") why not: doAssert main("asdfasekjkleräöü") == ... ?
seems cleaner. maybe in some cases discard+output pattern is simpler, but seems to me in large majority of cases using asserts is cleaner/simpler and gives more localized errors etc. if assert is unacceptable another pattern is expect which increases error count (and logs) without stopping execution on error.

- instead of using doAssert from system, why not define macros specific to unittesting (more flexible in case we want to customize behaviors just for tests without affecting doAssert , eg add logging etc); so a test could import testing (or unittesting...) to have these macros and not have restrictions imposed on system (so no need to add magic builtins in this case)
- Furthermore, tests should distinguish between tests that immediately fail, or tests that increment an error count but keep going (eg to avoid stopping on 1st error):
=> expect instead of assert eg, see https://testing.googleblog.com/2008/07/tott-expect-vs-assert.html as in google C++ testing framework.
- Furthermore, I wrote a simple macro that spits out LHS vs RHS in case of binary expressions, eg:
assert2 a+b < fun(2) will print: assert a+b < fun(2) failed: lhs:a+b=3; rhs: fun(2)=2
(only drawback is if it fails AND has side effects, lhs and rhs will be evaluated twice and can lead to different results)
it's nice to have ability to use macros to customize behavior of tests (such as assert2 above) without having to resort to builtins.