Files
privacy.sexy/tests/unit/application/Context/State/Selection/UserSelectionFacade.spec.ts
undergroundwires 48d6dbd700 Refactor to use string IDs for executables #262
This commit unifies the concepts of executables having same ID
structure. It paves the way for more complex ID structure and using IDs
in collection files as part of new ID solution (#262). Using string IDs
also leads to more expressive test code.

This commit also refactors the rest of the code to adopt to the changes.

This commit:

- Separate concerns from entities for data access (in repositories) and
  executables. Executables use `Identifiable` meanwhile repositories use
  `RepositoryEntity`.
- Refactor unnecessary generic parameters for enttities and ids,
  enforcing string gtype everwyhere.
- Changes numeric IDs to string IDs for categories to unify the
  retrieval and construction for executables, using pseudo-ids (their
  names) just like scripts.
- Remove `BaseEntity` for simplicity.
- Simplify usage and construction of executable objects.
  Move factories responsible for creation of category/scripts to domain
  layer. Do not longer export `CollectionCategorY` and
  `CollectionScript`.
- Use named typed for string IDs for better differentation of different
  ID contexts in code.
2024-07-08 23:23:05 +02:00

134 lines
5.1 KiB
TypeScript

import { describe, it } from 'vitest';
import type { SelectedScript } from '@/application/Context/State/Selection/Script/SelectedScript';
import { UserSelectionFacade } from '@/application/Context/State/Selection/UserSelectionFacade';
import type { ICategoryCollection } from '@/domain/Collection/ICategoryCollection';
import { CategoryCollectionStub } from '@tests/unit/shared/Stubs/CategoryCollectionStub';
import type { ScriptsFactory, CategoriesFactory } from '@/application/Context/State/Selection/UserSelectionFacade';
import { ScriptSelectionStub } from '@tests/unit/shared/Stubs/ScriptSelectionStub';
import { CategorySelectionStub } from '@tests/unit/shared/Stubs/CategorySelectionStub';
import { expectExists } from '@tests/shared/Assertions/ExpectExists';
import { SelectedScriptStub } from '@tests/unit/shared/Stubs/SelectedScriptStub';
import { ScriptStub } from '@tests/unit/shared/Stubs/ScriptStub';
import type { ScriptSelection } from '@/application/Context/State/Selection/Script/ScriptSelection';
describe('UserSelectionFacade', () => {
describe('ctor', () => {
describe('scripts', () => {
it('constructs with expected collection', () => {
// arrange
const expectedCollection = new CategoryCollectionStub();
let actualCollection: ICategoryCollection | undefined;
const factoryMock: ScriptsFactory = (collection) => {
actualCollection = collection;
return new ScriptSelectionStub();
};
const builder = new UserSelectionFacadeBuilder()
.withCollection(expectedCollection)
.withScriptsFactory(factoryMock);
// act
builder.construct();
// assert
expectExists(actualCollection);
expect(actualCollection).to.equal(expectedCollection);
});
it('constructs with expected selected scripts', () => {
// arrange
const expectedScripts: readonly SelectedScript[] = [
new SelectedScriptStub(new ScriptStub('1')),
];
let actualScripts: readonly SelectedScript[] | undefined;
const factoryMock: ScriptsFactory = (_, scripts) => {
actualScripts = scripts;
return new ScriptSelectionStub();
};
const builder = new UserSelectionFacadeBuilder()
.withSelectedScripts(expectedScripts)
.withScriptsFactory(factoryMock);
// act
builder.construct();
// assert
expectExists(actualScripts);
expect(actualScripts).to.equal(expectedScripts);
});
});
describe('categories', () => {
it('constructs with expected collection', () => {
// arrange
const expectedCollection = new CategoryCollectionStub();
let actualCollection: ICategoryCollection | undefined;
const factoryMock: CategoriesFactory = (_, collection) => {
actualCollection = collection;
return new CategorySelectionStub();
};
const builder = new UserSelectionFacadeBuilder()
.withCollection(expectedCollection)
.withCategoriesFactory(factoryMock);
// act
builder.construct();
// assert
expectExists(actualCollection);
expect(actualCollection).to.equal(expectedCollection);
});
it('constructs with expected scripts', () => {
// arrange
const expectedScriptSelection = new ScriptSelectionStub();
let actualScriptsSelection: ScriptSelection | undefined;
const categoriesFactoryMock: CategoriesFactory = (selection) => {
actualScriptsSelection = selection;
return new CategorySelectionStub();
};
const scriptsFactoryMock: ScriptsFactory = () => {
return expectedScriptSelection;
};
const builder = new UserSelectionFacadeBuilder()
.withCategoriesFactory(categoriesFactoryMock)
.withScriptsFactory(scriptsFactoryMock);
// act
builder.construct();
// assert
expectExists(actualScriptsSelection);
expect(actualScriptsSelection).to.equal(expectedScriptSelection);
});
});
});
});
class UserSelectionFacadeBuilder {
private collection: ICategoryCollection = new CategoryCollectionStub();
private selectedScripts: readonly SelectedScript[] = [];
private scriptsFactory: ScriptsFactory = () => new ScriptSelectionStub();
private categoriesFactory: CategoriesFactory = () => new CategorySelectionStub();
public withCollection(collection: ICategoryCollection): this {
this.collection = collection;
return this;
}
public withSelectedScripts(selectedScripts: readonly SelectedScript[]): this {
this.selectedScripts = selectedScripts;
return this;
}
public withScriptsFactory(scriptsFactory: ScriptsFactory): this {
this.scriptsFactory = scriptsFactory;
return this;
}
public withCategoriesFactory(categoriesFactory: CategoriesFactory): this {
this.categoriesFactory = categoriesFactory;
return this;
}
public construct(): UserSelectionFacade {
return new UserSelectionFacade(
this.collection,
this.selectedScripts,
this.scriptsFactory,
this.categoriesFactory,
);
}
}