Skip to content

Latest commit

 

History

History
229 lines (150 loc) · 5.78 KB

ARCHITECTURE.md

File metadata and controls

229 lines (150 loc) · 5.78 KB

Architecture

This document describes the high level architecture of bespin.

High Level

CLI
|-> Config ----`config`----> Runtime
    |-> Components           |-> Locate Test Files (TestFileLocator)
    |   - TestFileLocator    |-> Parse Out Tests (TestFileParser)
    |   - TestFileParser     |-> Run Tests (Runner)
    |   - Runner             |-> Report Results (Reporter/s)
    |   - Reporter/s
    |-> Settings
    |-> Globals

CLI

The CLI is main consumer entry point for the framework. It's responsible for loading a Config, initializing the Runtime and reporting results to the terminal using it's own reporter.

Runtime

The Runtime contains all the frameworks core logic and is used by consumer implementations (e.g. cli). The run method envokes the runtime and returns an array of TestResult.

import { Config, Runtime } from "@testingrequired/bespin-core";

const config = await Config.load("bespin.config.js");
const runtime = new Runtime(config);
const results = await runtime.run();

Configuration

The Config is where the framework's behavior is defined. It's used by the Runtime to drive that behavior.

Config File

A javascript file exporting a config. Used by the cli during execution.

const { Config } = require("@testingrequired/bespin-core");

module.exports = new Config(__filename);

__filename

The Config constructor requires __filename to be passed to have a reference to it's own location.

Components

Components for locating, parsing, running and reporting are set here.

const { Config } = require("@testingrequired/bespin-core");

module.exports = new Config(__filename)
  .withLocator(new SomeLocator())
  .withParser(new SomeParser())
  .withRunner(new SomeRunner())
  .withReporter(new SomeReporter())
  .withReporter(new AnotherReporter());

Settings

Settings affect core framework functionality.

const { Config } = require("@testingrequired/bespin-core");

module.exports = new Config(__filename)
  .withSetting("randomizeTests", true)
  .withSettings({
    testFileFilter: "",
    testNameFilter: "",
  });
interface Settings {
  randomizeTests?: boolean;
  testFileFilter?: string;
  testNameFilter?: string;
}

Globals

Globals registered are exposed to test functions at runtime.

const { Config } = require("@testingrequired/bespin-core");
const someLib = require("someLib");

module.exports = new Config(__filename).withGlobal("someLib", someLib);

Load

A config file can be loaded from a path.

import { Config } from "@testingrequired/bespin-core";

const config = await Config.load("bespin.config.js");

ValidConfig

A ValidConfig is a Config with TestFileLocator, TestFileParser and Runner set.

import { Config } from "@testingrequired/bespin-core";

const config = new Config()
  .withLocator(new SomeLocator())
  .withParser(new SomeParser())
  .withRunner(new SomeRunner());

if (Config.isValid(config)) {
  // config is a ValidConfig in this if block
}

An error will be thrown if the loaded config is not valid.

Components

There are four types of components that can be configured: TestFileLocator, TestFileParser, Runner, & Reporter.

TestFileLocator

This component locates test files and returns an array of their paths.

Implementations

TestFileParser

This component parses a test file for tests.

getTests

The getTests method accepts a test file path and returns an array of TestInTestFile which has two properties: testFilePath and testName. This method also accepts a Record<string, any> of global variables exposed to test functions. These globals are configured on the Config.

TestInTestFile

interface TestInTestFile {
  public readonly testFilePath: string;
  public readonly testName: string;
  public readonly testFn: TestFunction;
}

type TestFunction = () => Promise<void>;

Implementations

Runner

This component accepts an array of TestInTestFile, runs them using the TestExecutor and returns an array of corresponding TestResult.

TestExecutor

The TestExecutor is a core framework function that accepts a TestFunction and returns a TestResult.

TestResult

interface TestResult {
  state: TestResultState;
  time: number;
  error?: Error;
  message?: string;
}

enum TestResultState {
  PASS = "PASS",
  FAIL = "FAIL",
  ERROR = "ERROR",
}

Events

runStart
testStart
testEnd
runEnd

Implementations

Reporter

One or more reporters can be registered to the config. They expose the following methods to implement reporting: onRunStart, onTestStart, onTestEnd, onRunEnd.

Run Start

Test Start

Test End

Run End

Implementations

Plugins

A Plugin is (currently) simply a class that is passed a Config in to it's constructor. This allows the plugin to configure components, settings and globals.