Skip to content

Commit

Permalink
Merge pull request #251 from inversify/test/add-e2e-bind-rule
Browse files Browse the repository at this point in the history
Add e2e bind rule
  • Loading branch information
notaphplover authored Jan 6, 2025
2 parents 7d936f9 + 1a694cc commit e391072
Show file tree
Hide file tree
Showing 17 changed files with 214 additions and 6 deletions.
2 changes: 1 addition & 1 deletion packages/container/tools/e2e-tests/.gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Typescript compiled files
/lib/**

/tsconfig.tsbuildinfo
/tsconfig.cjs.tsbuildinfo

# node modules
/node_modules/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ function getConfiguration(parallel) {
/** @type {!import("@cucumber/cucumber/lib/configuration").IConfiguration} */
const config = {
...getBaseConfiguration(parallel),
require: ['lib/cjs/*/step-definitions/*.js', 'lib/cjs/app/hooks/*.js'],
require: [
'lib/cjs/*/parameters/*.js',
'lib/cjs/*/step-definitions/*.js',
'lib/cjs/app/hooks/*.js',
],
};

return config;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ function getConfiguration(parallel) {
/** @type {!import("@cucumber/cucumber/lib/configuration").IConfiguration} */
const config = {
...getBaseConfiguration(parallel),
require: ['src/*/step-definitions/*.ts', 'src/app/hooks/*.ts'],
require: [
'src/*/parameters/*.ts',
'src/*/step-definitions/*.ts',
'src/app/hooks/*.ts',
],
requireModule: ['ts-node/register'],
};

Expand Down
15 changes: 15 additions & 0 deletions packages/container/tools/e2e-tests/features/container/bind.feature
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,18 @@ Feature: Bind
Given a service "service-id" binding to constant value
When binding is bound to container
Then container acknowledges binding to be bound

Rule: container binds in the expected scope

Scenario: A binding is bound to a container and two requests are resolved according to the binding scope
Given a service "service-id" binding to dynamic value in <binding_scope> scope
When binding is bound to container
And container gets a "first" value for service "service-id"
And container gets a "second" value for service "service-id"
Then "first" and "second" values are <equality>

Examples:
| binding_scope | equality |
| "Request" | distinct |
| "Singleton" | equal |
| "Transient" | distinct |
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { InversifyWorld } from '../../common/models/InversifyWorld';
import { Writable } from '../../common/models/Writable';

export function initializeWorld(this: Writable<Partial<InversifyWorld>>): void {
this.containerRequests = {
get: new Map(),
};
this.entities = {
bindings: new Map(),
containers: new Map(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { ConstantValueBindingParameter } from './ConstantValueBindingParameter';
import { DynamicValueBindingParameter } from './DynamicValueBindingParameter';

export type BindingParameter = ConstantValueBindingParameter;
export type BindingParameter =
| ConstantValueBindingParameter
| DynamicValueBindingParameter;
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export enum BindingParameterKind {
constantValue,
dynamicValue,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { BaseBindingParameter } from './BaseBindingParameter';
import { BindingParameterKind } from './BindingParameterKind';

export type DynamicValueBindingParameter =
BaseBindingParameter<BindingParameterKind.dynamicValue>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineParameterType } from '@cucumber/cucumber';
import { BindingScope, bindingScopeValues } from '@inversifyjs/core';

defineParameterType({
name: 'bindingScope',
regexp: new RegExp(`"(${Object.values(bindingScopeValues).join('|')})"`),
transformer: function (bindingScope: string): BindingScope {
return bindingScope as BindingScope;
},
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Given } from '@cucumber/cucumber';
import { Container } from '@inversifyjs/container';
import { BindInWhenOnFluentSyntax, Container } from '@inversifyjs/container';
import { BindingScope, bindingScopeValues } from '@inversifyjs/core';

import { defaultAlias } from '../../common/models/defaultAlias';
import { InversifyWorld } from '../../common/models/InversifyWorld';
Expand All @@ -24,9 +25,47 @@ function givenBindingToConstantValue(
});
}

function givenBindingToDynamicValue(
this: InversifyWorld,
serviceId: string,
scope: BindingScope,
bindingAlias?: string,
): void {
const parsedBindingAlias: string = bindingAlias ?? defaultAlias;

setBinding.bind(this)(parsedBindingAlias, {
bind: (container: Container): void => {
const bindSyntax: BindInWhenOnFluentSyntax<unknown> = container
.bind(serviceId)
.toDynamicValue(() => Symbol());

switch (scope) {
case bindingScopeValues.Request:
bindSyntax.inRequestScope();
break;
case bindingScopeValues.Singleton:
bindSyntax.inSingletonScope();
break;
case bindingScopeValues.Transient:
bindSyntax.inTransientScope();
break;
}
},
kind: BindingParameterKind.dynamicValue,
serviceIdentifier: serviceId,
});
}

Given<InversifyWorld>(
'a service {string} binding to constant value',
function (serviceId: string): void {
givenBindingToConstantValue.bind(this)(serviceId);
},
);

Given<InversifyWorld>(
'a service {string} binding to dynamic value in {bindingScope} scope',
function (serviceId: string, scope: BindingScope): void {
givenBindingToDynamicValue.bind(this)(serviceId, scope);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ export interface EntitiesMap {
containers: Map<string, Container>;
}

export interface ContainerRequests {
get: Map<string, unknown>;
}

export interface InversifyWorld extends IWorld {
readonly containerRequests: ContainerRequests;
readonly entities: EntitiesMap;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineParameterType } from '@cucumber/cucumber';

defineParameterType({
name: 'stringList',
regexp: /("\w+"(?:(?:, "\w+")* and "\w+")?)/,
transformer: function (stringList: string): string[] {
return stringList
.split(/ and |, /)
.map((item: string): string => item.replaceAll('"', ''));
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { InversifyWorld } from '../../common/models/InversifyWorld';

export function setContainerGetRequest(
this: InversifyWorld,
alias: string,
result: unknown,
): void {
this.containerRequests.get.set(alias, result);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { InversifyWorld } from '../../common/models/InversifyWorld';

export function getContainerGetRequestOrFail(
this: InversifyWorld,
alias: string,
): unknown {
if (!this.containerRequests.get.has(alias)) {
throw new Error(
`Expected "${alias}" aliased container get request not found`,
);
}

return this.containerRequests.get.get(alias);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import assert from 'node:assert/strict';

import { Then } from '@cucumber/cucumber';

import { InversifyWorld } from '../../common/models/InversifyWorld';
import { getContainerGetRequestOrFail } from '../calculations/getContainerGetRequestOrFail';

function getValues(this: InversifyWorld, valueAliases: string[]): unknown[] {
return valueAliases.map((valueAlias: string): unknown =>
getContainerGetRequestOrFail.bind(this)(valueAlias),
);
}

function thenValuesAreDistinct(
this: InversifyWorld,
valueAliases: string[],
): void {
assert.ok(
getValues
.bind(this)(valueAliases)
.every(
(value: unknown, index: number, array: unknown[]): boolean =>
array.at(index - 1) !== value,
),
);
}

function thenValuesAreEqual(
this: InversifyWorld,
valueAliases: string[],
): void {
assert.ok(
getValues
.bind(this)(valueAliases)
.every(
(value: unknown, index: number, array: unknown[]): boolean =>
array.at(index - 1) === value,
),
);
}

Then<InversifyWorld>(
'{stringList} values are distinct',
function (valueAliases: string[]): void {
thenValuesAreDistinct.bind(this)(valueAliases);
},
);

Then<InversifyWorld>(
'{stringList} values are equal',
function (valueAliases: string[]): void {
thenValuesAreEqual.bind(this)(valueAliases);
},
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { When } from '@cucumber/cucumber';

import { defaultAlias } from '../../common/models/defaultAlias';
import { InversifyWorld } from '../../common/models/InversifyWorld';
import { setContainerGetRequest } from '../actions/setContainerGetRequest';
import { getContainerOrFail } from '../calculations/getContainerOrFail';

function whenContainerGetsValueForService(
this: InversifyWorld,
serviceId: string,
containerAlias?: string,
valueAlias?: string,
): void {
const parsedContainerAlias: string = containerAlias ?? defaultAlias;
const parsedValueAlias: string = valueAlias ?? defaultAlias;

setContainerGetRequest.bind(this)(
parsedValueAlias,
getContainerOrFail.bind(this)(parsedContainerAlias).get(serviceId),
);
}

When<InversifyWorld>(
'container gets a {string} value for service {string}',
function (valueAlias: string, serviceId: string): void {
whenContainerGetsValueForService.bind(this)(
serviceId,
undefined,
valueAlias,
);
},
);

This file was deleted.

0 comments on commit e391072

Please sign in to comment.