Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Octopodo/kt-testing-suite-core/llms.txt

Use this file to discover all available pages before exploring further.

The runner is the component that takes the registered suites and actually executes them. KT Testing Suite Core ships two entry points: runTests(), a convenience function suitable for the common case, and TestRunner, a class you can instantiate directly when you need finer-grained control over the reporter or filter. Both drive the same execution engine that calls lifecycle hooks, catches test errors, and dispatches events to the reporter at each stage of the run.

runTests()

function runTests(
    suites: Suite[] = getSuites(),
    reporter?: TestReporter,
    filter?: string
): void
Convenience wrapper that constructs a TestRunner instance and immediately calls run() on it. For most scripts this is the only runner API you need.
suites
Suite[]
The array of root suites to execute. Defaults to the return value of getSuites(), which contains every suite registered through describe() up to this point in the script. Pass an explicit array when you want to run a subset of suites.
reporter
TestReporter
The reporter instance that receives lifecycle events. Defaults to a new ConsoleReporter. Pass a JSONReporter or your own custom reporter to change the output format.
filter
string
An optional case-insensitive substring. When provided, only tests whose full name (all ancestor suite descriptions concatenated with the test name, separated by spaces) contains this substring are executed. Tests that do not match are silently skipped—they are not counted in the totals and do not appear in the reporter output.

Examples

import { runTests } from 'kt-testing-suite-core';

// Uses getSuites(), ConsoleReporter, no filter
runTests();

TestRunner class

class TestRunner {
    constructor(reporter?: TestReporter, filter?: string)
    run(suites: Suite[]): void
}
The TestRunner class encapsulates the full execution lifecycle. Instantiate it directly when you need to reuse the same reporter across multiple run() calls, keep a reference for later inspection, or integrate the runner into a larger automation script.

constructor()

reporter
TestReporter
The reporter that receives lifecycle events during the run. Defaults to a new ConsoleReporter instance if omitted.
filter
string
Case-insensitive substring filter applied to the full test name ("<suite> ... <test>"). Tests whose full name does not contain this string are skipped. Omit or pass undefined to run all tests.

run()

run(suites: Suite[]): void
Executes the provided array of root suites in order. Triggers the full reporter lifecycle: onStart before any suite, one onSuiteStart / onSuiteEnd pair per suite (including nested suites), one onTestStart / onTestEnd pair per test, and onFinished with aggregate statistics at the very end.
suites
Suite[]
required
The root suites to run. Child suites are traversed recursively—there is no need to flatten the tree before calling run().

Internal counters

Two private counters are maintained across the run and included in the onFinished payload:
passedTests
number
Incremented each time a test function returns without throwing.
failedTests
number
Incremented each time a test function throws any error.

Execution Flow

The diagram below describes the sequence of operations the runner performs for each suite. Nested suites follow the same flow recursively within the parent’s test loop.
onStart()

└─ for each root suite:

   ├─ onSuiteStart(suite)
   ├─ runSuiteHooks(suite, 'beforeAll')   ← suite-scoped, no inheritance

   ├─ for each test in suite.tests:
   │   │
   │   ├─ [shouldSkip check]             ← skipped silently if filter set
   │   ├─ onTestStart(test)
   │   ├─ runHooks(suite, 'beforeEach', parent→child)
   │   ├─ test.fn()                       ← assertion errors caught here
   │   ├─ runHooks(suite, 'afterEach', child→parent)  ← runs in finally
   │   └─ onTestEnd(test, result)

   ├─ for each child suite:
   │   └─ [recurse with updated parentDescription]

   ├─ runSuiteHooks(suite, 'afterAll')    ← runs in finally
   └─ onSuiteEnd(suite)

onFinished({ passed, failed, total })

Test Filtering

The private shouldSkip() method implements filtering:
private shouldSkip(fullName: string): boolean {
    if (!this.filter) return false;
    return fullName.toLowerCase().indexOf(this.filter.toLowerCase()) === -1;
}
The fullName is the concatenation of all ancestor suite descriptions plus the test name, separated by spaces. The match is a case-insensitive substring search—no glob or regex syntax is supported.
Because filtering is applied at the individual test level, onSuiteStart and onSuiteEnd are still called for suites that contain no matching tests. All tests within those suites are silently skipped. This mirrors Jest’s --testNamePattern behaviour.

Error Handling

The runner distinguishes between test errors and hook errors:
SourceBehaviour
test.fn() throwsCaught; failedTests incremented; onTestEnd called with status: 'failed' and the error object
beforeEach / afterEach throwsCaught in runHooks; logged to $.writeln as ⚠️ Error in beforeEach: …; run continues
beforeAll / afterAll throwsCaught in runSuiteHooks; logged to $.writeln as ⚠️ Error in beforeAll: …; run continues
The afterEach hooks always run in a finally block, so they execute even when the test or beforeEach threw.

Full Example

import {
    describe,
    it,
    beforeAll,
    afterEach,
    expect,
    getSuites,
    TestRunner,
    JSONReporter
} from 'kt-testing-suite-core';

describe('Document export', () => {
    let doc: Document;

    beforeAll(() => {
        doc = app.documents.add();
    });

    afterEach(() => {
        // Clean up any exported files
    });

    it('exports as PNG', () => {
        expect(doc).toBeDefined();
    });

    it('has the correct name', () => {
        expect(doc.name).toBeString();
    });
});

// Run with JSON output and filter to only "exports" tests
const reporter = new JSONReporter('/tmp/export-results.json');
const runner = new TestRunner(reporter, 'exports');
runner.run(getSuites());

Build docs developers (and LLMs) love