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"
+ ]
+}