diff --git a/.idea/ceb.iml b/.idea/ceb.iml index 19fd1d84..eda2d7fd 100644 --- a/.idea/ceb.iml +++ b/.idea/ceb.iml @@ -25,8 +25,10 @@ + + - + \ No newline at end of file diff --git a/README.typedoc.md b/README.typedoc.md index cebde1b8..b7815a1f 100644 --- a/README.typedoc.md +++ b/README.typedoc.md @@ -26,6 +26,8 @@ A built-in implementation of the Inversion of Control principle: - [ceb-inversion](modules/_tmorin_ceb_inversion.html) - [ceb-inversion-builder](modules/_tmorin_ceb_inversion_builder.html) +- [ceb-inversion-testing-core](modules/_tmorin_ceb_inversion_testing_core.html) +- [ceb-inversion-testing-mocha](modules/_tmorin_ceb_inversion_testing_mocha.html) A built-in implementation of the Event/Message architecture: @@ -40,6 +42,7 @@ The helper packages: - [ceb-utilities](modules/_tmorin_ceb_utilities.html) - [ceb-testing](modules/_tmorin_ceb_testing.html) +- [ceb-testing](modules/_tmorin_ceb_testing.html) - [ceb](modules/_tmorin_ceb.html) : a bundle of `ceb-core`, `ceb-builders`, `ceb-templating-builder` and `ceb-templating-literal` ## License diff --git a/lerna.json b/lerna.json index 36502c0e..1f44bee8 100644 --- a/lerna.json +++ b/lerna.json @@ -7,6 +7,8 @@ "packages/ceb-builders", "packages/ceb-inversion", "packages/ceb-inversion-builder", + "packages/ceb-inversion-testing-core", + "packages/ceb-inversion-testing-mocha", "packages/ceb-messaging-adapter-electron", "packages/ceb-messaging-builder-core", "packages/ceb-messaging-builder-inversion", diff --git a/packages/ceb-inversion-testing-mocha/README.md b/packages/ceb-inversion-testing-mocha/README.md new file mode 100644 index 00000000..6d6b7514 --- /dev/null +++ b/packages/ceb-inversion-testing-mocha/README.md @@ -0,0 +1,22 @@ +# @tmorin/ceb-inversion-testing-core + +[![npm version](https://badge.fury.io/js/%40tmorin%2Fceb-inversion.svg)](https://badge.fury.io/js/%40tmorin%2Fceb-inversion-testing-core) +[![api](https://img.shields.io/badge/-api-informational.svg)](https://tmorin.github.io/ceb/api/modules/_tmorin_ceb_inversion_testing_core.html) + +> The package is part of the `` library. +> It provides a model to test IOC containers. + +## Install + +The NPM package is compliant [CommonJs](https://flaviocopes.com/commonjs) and [ES Module](https://flaviocopes.com/es-modules). + +```bash +npm install @tmorin/ceb-inversion-testing-core +``` + +## License + +Released under the [MIT license]. + +[Custom Elements (v1)]: https://html.spec.whatwg.org/multipage/custom-elements.html +[MIT license]: http://opensource.org/licenses/MIT diff --git a/packages/ceb-inversion-testing-mocha/package.json b/packages/ceb-inversion-testing-mocha/package.json new file mode 100644 index 00000000..0c1dc245 --- /dev/null +++ b/packages/ceb-inversion-testing-mocha/package.json @@ -0,0 +1,62 @@ +{ + "name": "@tmorin/ceb-inversion-testing-mocha", + "version": "5.0.0", + "license": "MIT", + "description": "The package is part of the `` library. It provides an implementation of the testing model for IOC containers based on mocha.", + "keywords": [ + "custom-element-builder", + "custom-elements-v1", + "custom-elements", + "custom-element", + "typescript", + "typescript-library", + "javascript-library", + "inversion-of-control", + "ioc", + "injection", + "testing", + "mocha" + ], + "homepage": "https://tmorin.github.io/ceb", + "bugs": { + "url": "https://github.com/tmorin/ceb/issues" + }, + "repository": { + "type": "git", + "url": "git@github.com:tmorin/ceb.git" + }, + "author": { + "name": "Thibault Morin", + "url": "https://tmorin.github.io" + }, + "publishConfig": { + "access": "public" + }, + "exports": { + ".": { + "import": "./dist/mjs/index.js", + "require": "./dist/cjs/index.js" + } + }, + "types": "dist/types/index.d.ts", + "main": "dist/cjs/index.js", + "module": "dist/mjs/index.js", + "files": [ + "dist" + ], + "scripts": { + "build": "npm run build:lib && npm run build:module && npm run build:fix", + "build:fix": "../../scripts/fix-dist.js", + "build:lib": "tsc -p tsconfig.build.json --module CommonJS --outDir dist/cjs --declaration --declarationDir dist/types", + "build:module": "tsc -p tsconfig.build.json --module ESNext --outDir dist/mjs", + "test": "mocha --require ts-node/register src/**/*.spec.ts", + "test:watch": "npm test -- --watch --watch-files '**/*.ts'" + }, + "dependencies": { + "@tmorin/ceb-inversion": "^5.0.0", + "@tmorin/ceb-inversion-testing-core": "^5.0.0" + }, + "peerDependencies": { + "mocha": "*" + } +} diff --git a/packages/ceb-inversion-testing-mocha/src/index.spec.ts b/packages/ceb-inversion-testing-mocha/src/index.spec.ts new file mode 100644 index 00000000..e0efb996 --- /dev/null +++ b/packages/ceb-inversion-testing-mocha/src/index.spec.ts @@ -0,0 +1,35 @@ +import {SinonSpy, spy} from "sinon"; +import {TestScenarioBuilder, TestSuiteBuilder} from "@tmorin/ceb-inversion-testing-core"; +import {MochaTestSuiteExecutorBuilder} from "./index"; +import assert from "assert"; + +describe("inversion/testing/mocha", function () { + const spyList = new Set() + const createSyp = () => { + const aSpy: SinonSpy = spy() + spyList.add(aSpy) + return aSpy + } + + const scenario = TestScenarioBuilder.get("test scenario") + .configure(createSyp()) + .before(createSyp()) + .execute(createSyp()) + .after(createSyp()) + .build() + + const suite = TestSuiteBuilder.get("test suite") + .scenario(scenario) + .build() + + MochaTestSuiteExecutorBuilder.get(suite) + .before(createSyp()) + .configure(createSyp()) + .after(createSyp()) + .test() + .afterAll(() => { + for (const aSpy of spyList) { + assert.ok(aSpy) + } + }) +}) diff --git a/packages/ceb-inversion-testing-mocha/src/index.ts b/packages/ceb-inversion-testing-mocha/src/index.ts new file mode 100644 index 00000000..ba69efba --- /dev/null +++ b/packages/ceb-inversion-testing-mocha/src/index.ts @@ -0,0 +1,127 @@ +import {Suite} from "mocha" +import { + AbstractTestSuiteExecutor, + AbstractTestSuiteExecutorBuilder, + Callback, + CallbackWithContainerBuilder, + ContainerBuilderProvider, + TestSuite, + TestSuiteBuilder, + TestSuiteExecutor +} from "@tmorin/ceb-inversion-testing-core" +import {Container, ContainerBuilder} from "@tmorin/ceb-inversion"; + +/** + * An implementation of {@link AbstractTestSuiteExecutor} dedicated for Mocha. + * + * Instances should be created using the builder {@link MochaTestSuiteExecutorBuilder}. + */ +export class MochaTestSuiteExecutor extends AbstractTestSuiteExecutor { + constructor( + suite: TestSuite, + before?: Callback, + provider?: ContainerBuilderProvider, + configurer?: CallbackWithContainerBuilder, + after?: Callback, + ) { + super(suite, before, provider, configurer, after) + } + + execute(): Suite { + return describe(this.suite.name, () => { + for (const scenario of this.suite.scenarios) { + describe(scenario.name, () => { + let containerBuilder: ContainerBuilder + let container: Container + before("before scenario", async () => { + if (this.before) { + await this.before() + } + }) + before("create the container builder", async () => { + containerBuilder = this.provide() + }) + before("configure the builder with executor configuration", async () => { + if (this.configure) { + await Promise.resolve(this.configure(containerBuilder)) + } + }) + before("configure the builder with scenario configuration", async () => { + if (scenario.configure) { + await Promise.resolve(scenario.configure(containerBuilder)) + } + }) + before("initialize the container", async () => { + container = await containerBuilder.build().initialize() + }) + before("before execution", async () => { + if (scenario.before) { + await scenario.before(container) + } + }) + it("execution", async () => { + await scenario.execute(container) + }) + after("after execution", async () => { + if (scenario.after) { + await scenario.after(container) + } + }) + after("dispose the container", async () => { + await container.dispose() + }) + after("after scenario", async () => { + if (this.after) { + await this.after() + } + }) + }) + } + }) + } +} + +/** + * An extension of {@link AbstractTestSuiteExecutorBuilder} dedicated for Mocha. + * + * @example run a test suite with an dummy scenario + * ```typescript + * import {TestScenarioBuilder, TestSuiteBuilder} from "@tmorin/ceb-inversion-testing-core"; + * import {MochaTestSuiteExecutor} from "@tmorin/ceb-inversion-testing-mocha" + * MochaTestSuiteExecutorBuilder.get( + * TestSuiteBuilder.get("test suite").scenario( + * TestScenarioBuilder.get("test scenario") + * ) + * ).test() + * ``` + */ +export class MochaTestSuiteExecutorBuilder extends AbstractTestSuiteExecutorBuilder { + + protected constructor(suite: TestSuite) { + super(suite); + } + + /** + * Create a builder. + * @param suite the suite + */ + static get(suite: TestSuite | TestSuiteBuilder) { + if (suite instanceof TestSuiteBuilder) { + return new MochaTestSuiteExecutorBuilder(suite.build()) + } + return new MochaTestSuiteExecutorBuilder(suite) + } + + /** + * Build the executor. + */ + build(): TestSuiteExecutor { + return new MochaTestSuiteExecutor( + this._suite, + this._before, + this._provider, + this._configurer, + this._after, + ); + } +} diff --git a/packages/ceb-inversion-testing-mocha/tsconfig.build.json b/packages/ceb-inversion-testing-mocha/tsconfig.build.json new file mode 100644 index 00000000..3a564a82 --- /dev/null +++ b/packages/ceb-inversion-testing-mocha/tsconfig.build.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.build.json", + "include": [ + "src" + ] +} diff --git a/packages/ceb-inversion-testing-mocha/tsconfig.json b/packages/ceb-inversion-testing-mocha/tsconfig.json new file mode 100644 index 00000000..2e690402 --- /dev/null +++ b/packages/ceb-inversion-testing-mocha/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.json", + "include": [ + "src" + ] +}