content: add approved public portfolio projection

This commit is contained in:
2026-09-02 01:00:36 +03:00
parent 6428b5dcd6
commit 49a4f75c8d
11 changed files with 460 additions and 11 deletions

View File

@@ -20,7 +20,10 @@ type MutableContentFixture = {
contact: { social: Array<{ service: string; url: string }> };
projects: {
selected: Array<{ visibility: string; url?: string; assetIds: string[]; title: string }>;
additional: Array<{ assetIds: string[] }>;
};
toolkit: Array<{ technologies: Array<{ assetId?: string }> }>;
metadata: { socialPreviewAssetId?: string };
};
const cloneContent = (): MutableContentFixture => structuredClone(validContent) as MutableContentFixture;
@@ -32,6 +35,45 @@ describe('content schemas', () => {
expect(parseSiteConfig(validSite).environment).toBe('preview');
});
it('accepts an empty manifest before Phase 3 assets are prepared', () => {
expect(parsePublicAssetManifest({ assets: [] })).toEqual({ assets: [] });
});
it('accepts the approved generic private project titles', () => {
for (const title of [
'Private self-hosted medication tracker',
'Private healthcare platform',
'Private game prototype',
]) {
const content = cloneContent();
content.projects.selected[0]!.title = title;
expect(() => parsePortfolioContent(content)).not.toThrow();
}
});
it('permits omitted Phase 3 asset references while retaining supplied-reference checks', () => {
const content = cloneContent();
content.projects.selected[0]!.title = 'Private self-hosted medication tracker';
for (const project of [...content.projects.selected, ...content.projects.additional]) project.assetIds = [];
delete content.toolkit[0]!.technologies[0]!.assetId;
delete content.metadata.socialPreviewAssetId;
expect(() => validateProductionInputs(content, { assets: [] }, validSite, new URL('file:///prepared/'))).not.toThrow();
});
it('rejects supplied toolkit and metadata asset references absent from the manifest', () => {
const content = cloneContent();
content.projects.selected[0]!.title = 'Private self-hosted medication tracker';
for (const project of [...content.projects.selected, ...content.projects.additional]) project.assetIds = [];
content.toolkit[0]!.technologies[0]!.assetId = 'missing-toolkit-asset';
expect(() => validateProductionInputs(content, { assets: [] }, validSite, new URL('file:///prepared/')))
.toThrow(/unmanifested asset reference: missing-toolkit-asset/i);
delete content.toolkit[0]!.technologies[0]!.assetId;
content.metadata.socialPreviewAssetId = 'missing-social-preview';
expect(() => validateProductionInputs(content, { assets: [] }, validSite, new URL('file:///prepared/')))
.toThrow(/unmanifested asset reference: missing-social-preview/i);
});
it('rejects a public link on a private project', () => {
const input = cloneContent();
input.projects.selected[0]!.visibility = 'private';