Files
privacy.sexy/tests/unit/application/Parser/ApplicationParser.spec.ts
undergroundwires a54e16488c Change slogan and refactor project info naming
The project's slagon has been updated back to "Privacy is sexy" from
"Now you have the choice" for enhanced brand clarity and memorability.

This change also reflects the community's preference and aligns with the
project's established identity.

This commit also refactors naming and structure of project information
(metadata) struct to enhance clarity and maintainability in relation to
changing the slogan.

Key changes include:

- Update UI components to display the revised slogan.
- Remove period from project slogan in code area for consistency with a
  explanatory comment for future maintainability.
- Refactor header container and class names for clarity.
- Standardize project metadata usage in `TheCodeArea.vue` to ensure
  consistency.
- Improve code clarity by renaming `IProjectInformation` to
  `ProjectDetails` and `ProjectInformation` to `GitHubProjectDetails`.
- Organize `ProjectDetails` under a dedicated `Project` directory within
  the domain layer for better structure.

These changes are expected to improve the project's appeal and
streamline future maintenance and development efforts.
2024-02-10 18:50:56 +01:00

229 lines
9.0 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import type { CollectionData } from '@/application/collections/';
import { parseProjectDetails } from '@/application/Parser/ProjectDetailsParser';
import { CategoryCollectionParserType, parseApplication } from '@/application/Parser/ApplicationParser';
import { IAppMetadata } from '@/infrastructure/EnvironmentVariables/IAppMetadata';
import WindowsData from '@/application/collections/windows.yaml';
import MacOsData from '@/application/collections/macos.yaml';
import LinuxData from '@/application/collections/linux.yaml';
import { OperatingSystem } from '@/domain/OperatingSystem';
import { CategoryCollectionStub } from '@tests/unit/shared/Stubs/CategoryCollectionStub';
import { CollectionDataStub } from '@tests/unit/shared/Stubs/CollectionDataStub';
import { getAbsentCollectionTestCases } from '@tests/unit/shared/TestCases/AbsentTests';
import { AppMetadataStub } from '@tests/unit/shared/Stubs/AppMetadataStub';
import { EnvironmentVariablesFactory } from '@/infrastructure/EnvironmentVariables/EnvironmentVariablesFactory';
import { CategoryCollectionParserStub } from '@tests/unit/shared/Stubs/CategoryCollectionParserStub';
import { ProjectDetailsParserStub } from '@tests/unit/shared/Stubs/ProjectDetailsParserStub';
import { ProjectDetailsStub } from '@tests/unit/shared/Stubs/ProjectDetailsStub';
describe('ApplicationParser', () => {
describe('parseApplication', () => {
describe('categoryParser', () => {
it('returns result from the parser', () => {
// arrange
const os = OperatingSystem.macOS;
const data = new CollectionDataStub();
const expected = new CategoryCollectionStub()
.withOs(os);
const parser = new CategoryCollectionParserStub()
.withReturnValue(data, expected)
.getStub();
const sut = new ApplicationParserBuilder()
.withCategoryCollectionParser(parser)
.withCollectionsData([data]);
// act
const app = sut.parseApplication();
// assert
const actual = app.getCollection(os);
expect(expected).to.equal(actual);
});
});
describe('projectDetails', () => {
it('projectDetailsParser is used to create the instance', () => {
// arrange
const expectedProjectDetails = new ProjectDetailsStub();
const projectDetailsParserStub = new ProjectDetailsParserStub()
.withReturnValue(expectedProjectDetails);
const sut = new ApplicationParserBuilder()
.withProjectDetailsParser(projectDetailsParserStub.getStub());
// act
const app = sut.parseApplication();
// assert
const actualProjectDetails = app.projectDetails;
expect(expectedProjectDetails).to.deep.equal(actualProjectDetails);
});
it('projectDetailsParser is used to parse collection', () => {
// arrange
const expectedProjectDetails = new ProjectDetailsStub();
const projectDetailsParserStub = new ProjectDetailsParserStub()
.withReturnValue(expectedProjectDetails);
const collectionParserStub = new CategoryCollectionParserStub();
const sut = new ApplicationParserBuilder()
.withProjectDetailsParser(projectDetailsParserStub.getStub())
.withCategoryCollectionParser(collectionParserStub.getStub());
// act
sut.parseApplication();
// assert
expect(collectionParserStub.arguments).to.have.length.above(0);
const actuallyUsedInfos = collectionParserStub.arguments.map((arg) => arg.projectDetails);
expect(actuallyUsedInfos.every(
(actualProjectDetails) => actualProjectDetails === expectedProjectDetails,
)).to.equal(true);
});
});
describe('metadata', () => {
it('used to parse expected metadata', () => {
// arrange
const expectedMetadata = new AppMetadataStub();
const projectDetailsParser = new ProjectDetailsParserStub();
// act
new ApplicationParserBuilder()
.withMetadata(expectedMetadata)
.withProjectDetailsParser(projectDetailsParser.getStub())
.parseApplication();
// assert
expect(projectDetailsParser.arguments).to.have.lengthOf(1);
expect(projectDetailsParser.arguments[0]).to.equal(expectedMetadata);
});
it('defaults to metadata from factory', () => {
// arrange
const expectedMetadata: IAppMetadata = EnvironmentVariablesFactory.Current.instance;
const projectDetailsParser = new ProjectDetailsParserStub();
// act
new ApplicationParserBuilder()
.withMetadata(undefined) // force using default
.withProjectDetailsParser(projectDetailsParser.getStub())
.parseApplication();
// assert
expect(projectDetailsParser.arguments).to.have.lengthOf(1);
expect(projectDetailsParser.arguments[0]).to.equal(expectedMetadata);
});
});
describe('collectionsData', () => {
describe('set as expected', () => {
// arrange
const testCases = [
{
name: 'single collection',
input: [new CollectionDataStub()],
output: [new CategoryCollectionStub().withOs(OperatingSystem.macOS)],
},
{
name: 'multiple collections',
input: [
new CollectionDataStub().withOs('windows'),
new CollectionDataStub().withOs('macos'),
],
output: [
new CategoryCollectionStub().withOs(OperatingSystem.macOS),
new CategoryCollectionStub().withOs(OperatingSystem.Windows),
],
},
];
// act
for (const testCase of testCases) {
it(testCase.name, () => {
let categoryParserStub = new CategoryCollectionParserStub();
for (let i = 0; i < testCase.input.length; i++) {
categoryParserStub = categoryParserStub
.withReturnValue(testCase.input[i], testCase.output[i]);
}
const sut = new ApplicationParserBuilder()
.withCategoryCollectionParser(categoryParserStub.getStub())
.withCollectionsData(testCase.input);
// act
const app = sut.parseApplication();
// assert
expect(app.collections).to.deep.equal(testCase.output);
});
}
});
it('defaults to expected data', () => {
// arrange
const expected = [WindowsData, MacOsData, LinuxData];
const categoryParserStub = new CategoryCollectionParserStub();
const sut = new ApplicationParserBuilder()
.withCollectionsData(undefined)
.withCategoryCollectionParser(categoryParserStub.getStub());
// act
sut.parseApplication();
// assert
const actual = categoryParserStub.arguments.map((args) => args.data);
expect(actual).to.deep.equal(expected);
});
describe('throws when data is invalid', () => {
// arrange
const testCases = [
...getAbsentCollectionTestCases<CollectionData>(
{
excludeUndefined: true,
excludeNull: true,
},
).map((testCase) => ({
name: `given absent collection "${testCase.valueName}"`,
value: testCase.absentValue,
expectedError: 'missing collections',
})),
];
for (const testCase of testCases) {
it(testCase.name, () => {
const sut = new ApplicationParserBuilder()
.withCollectionsData(testCase.value);
// act
const act = () => sut.parseApplication();
// assert
expect(act).to.throw(testCase.expectedError);
});
}
});
});
});
});
class ApplicationParserBuilder {
private categoryCollectionParser
: CategoryCollectionParserType = new CategoryCollectionParserStub().getStub();
private projectDetailsParser
: typeof parseProjectDetails = new ProjectDetailsParserStub().getStub();
private metadata: IAppMetadata | undefined = new AppMetadataStub();
private collectionsData: CollectionData[] | undefined = [new CollectionDataStub()];
public withCategoryCollectionParser(
categoryCollectionParser: CategoryCollectionParserType,
): this {
this.categoryCollectionParser = categoryCollectionParser;
return this;
}
public withProjectDetailsParser(
projectDetailsParser: typeof parseProjectDetails,
): this {
this.projectDetailsParser = projectDetailsParser;
return this;
}
public withMetadata(
metadata: IAppMetadata | undefined,
): this {
this.metadata = metadata;
return this;
}
public withCollectionsData(collectionsData: CollectionData[] | undefined): this {
this.collectionsData = collectionsData;
return this;
}
public parseApplication(): ReturnType<typeof parseApplication> {
return parseApplication(
this.categoryCollectionParser,
this.projectDetailsParser,
this.metadata,
this.collectionsData,
);
}
}