ewdev/tiniest

A minimal, portable testing library for Luau

This is a fork of https://github.com/dphfox/tiniest to redistribute the package on pesde.

tiniest

tiniest is a collection of minimal, portable testing libraries for Luau, built on a few principles:

  • Simple, idiomatic Luau throughout.
  • Zero external dependencies.
  • Small core, extend with plugins.
  • Runtime independence.
  • No opinions about project structure.

tiniest comes with pre-configured bundles for popular runtimes like Roblox and Lune, or pick and mix your own modules and plugins!

Features

  • test() and describe() callbacks
  • Clean, correctly-cropped stack traces
  • Declarative expect() API with line numbers and code visualisation
  • Pretty-formatted summaries of reports with emoji, Unicode, and colour
  • Benchmark how long tests run for
  • Extensible, lightweight plugin system
  • Snapshot testing for all quotable data types

Planned

  • Test discovery for Lune

Installation

Run pesde add ewdev/tiniest --dev.
It's then recommended that you go into your pesde.toml and switch the version to use an exact version (i.e switching ^0.0.0 to =0.0.0). This is because new versions may come with breaking changes.

As an alternative, you can go to https://github.com/dphfox/tiniest, where tiniest is distributed as a set of portable Luau files that sit next to each other. Drop them into your lib folder, keep the ones you need, and start using tiniest right away :)

Usage

๐ŸŽจ The printed reports come with colour - try it in your terminal!

Here's an example file written with tiniest_for_lune:

--!strict

local tiniest = require("@tiniest_for_lune").configure({
	snapshot_path = "./test/__snapshots__",
	save_snapshots = true
})

local function my_test_suite()
	local describe = tiniest.describe
	local test = tiniest.test
	local expect = tiniest.expect
	local snapshot = tiniest.snapshot

	describe("some cool features", function()
		test("it works", function()
			expect(2 + 2).is(4)
		end)

		test("snapshots", function()
			snapshot({
				hello = "world",
				foo = true,
				bar = 2
			})
		end)
	end)
end

local tests = tiniest.collect_tests(my_test_suite)
tiniest.run_tests(tests, {})

The above example generates a report like this and prints it to stdout:

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• Status of 2 test(s) โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

โœ… some cool features โ–ธ it works - 74.9ยตs
โœ… some cool features โ–ธ snapshots - 137.71ms

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 2 passed, 0 failed โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Time to run: 217.9ms

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Failures look like this:

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• Errors from 2 test(s) โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

โŒ some cool features โ–ธ it works
Expectation not met
   โ”‚
16 โ”‚ expect(4).is(5)
   โ”‚
[string "test/test_main"]:16

โŒ some cool features โ–ธ snapshots
Snapshot does not match
   โ”‚
78 โ”‚ snapshot({
   โ”‚   ["bar"] = 2;
   โ”‚   ["foo"] = true;
   โ”‚   ["hello"] = "world";
   โ”‚ })
   โ”‚
   โ”‚ -- snapshot on disk:
   โ”‚ snapshot({
   โ”‚   ["bar"] = 5;
   โ”‚   ["foo"] = false;
   โ”‚   ["hello"] = "earth";
   โ”‚ })
   โ”‚
[string "test/test_main"]:20

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• Status of 2 test(s) โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

โŒ some cool features โ–ธ it works - 111.6ms
โŒ some cool features โ–ธ snapshots - 174.9ms

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 0 passed, 2 failed โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Time to run: 292.81ms

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

License

Licensed the same way as all of my open source projects: BSD 3-Clause + Security Disclaimer.

As with all other projects, you accept responsibility for choosing and using this project.

See LICENSE or the license summary for details.