Files
Portfolio/tests/integration/public-content.test.ts

166 lines
7.8 KiB
TypeScript

import { readFile } from 'node:fs/promises';
import { describe, expect, it } from 'vitest';
import { parsePortfolioContent, validateProductionInputs } from '@/content/schemas';
const repositoryRoot = process.cwd();
const readJson = async (relativePath: string): Promise<unknown> =>
JSON.parse(await readFile(`${repositoryRoot}/${relativePath}`, 'utf8')) as unknown;
describe('approved public portfolio projection', () => {
it('attaches only the approved project evidence in its reviewed presentation order', async () => {
const content = parsePortfolioContent(await readJson('content/public/portfolio-content.json'));
const medication = content.projects.selected[0]!;
const footy = content.projects.selected[1]!;
const opinion = content.projects.selected[2]!;
const currency = content.projects.additional.find((project) => project.id === 'currency-converter')!;
expect(medication).toMatchObject({
id: 'private-medication-tracker',
mediaLayout: 'portrait-strip',
assetIds: [
'medication-mobile-logs',
'medication-mobile-data-settings',
'medication-mobile-notification-settings',
],
});
expect(medication.media).toHaveLength(3);
expect(medication.media?.every(({ alt }) => /fictional|demo/iu.test(alt))).toBe(true);
expect(medication.url).toBeUndefined();
expect(footy.assetIds).toEqual([]);
expect(footy.media).toBeUndefined();
expect(footy.mediaLayout).toBeUndefined();
expect(opinion).toMatchObject({
mediaLayout: 'chart-pair',
assetIds: ['opinion-polarization-chart', 'opinion-final-distribution-chart'],
});
expect(opinion.media).toHaveLength(2);
expect(opinion.media?.every(({ kind }) => kind === 'chart')).toBe(true);
expect(opinion.media?.[0]).toMatchObject({
kind: 'chart',
assetId: 'opinion-polarization-chart',
chart: {
table: {
columns: ['Step', 'Polarization index'],
rows: [['0', '0.765'], ['14', '0.932']],
},
},
});
expect(opinion.media?.[1]).toMatchObject({
kind: 'chart',
assetId: 'opinion-final-distribution-chart',
});
if (opinion.media?.[1]?.kind === 'chart') expect(opinion.media[1].chart.table).toBeUndefined();
expect(currency).toMatchObject({
mediaLayout: 'single',
assetIds: ['currency-converter-interface'],
media: [{ kind: 'image', assetId: 'currency-converter-interface' }],
});
expect(content.metadata.socialPreviewAssetId).toBe('social-preview-nightdrive');
});
it('contains approved identity and balanced evidence without prohibited surfaces', async () => {
const { content, manifest, site } = validateProductionInputs(
await readJson('content/public/portfolio-content.json'),
await readJson('content/public/asset-manifest.json'),
await readJson('config/site.preview.json'),
new URL('file:///prepared-assets/'),
);
expect(content.identity).toMatchObject({
name: 'Luca Pîslaru',
role: 'System Administrator & Full-Stack Developer',
location: { city: 'Bucharest', country: 'Romania', countryCode: 'RO' },
});
expect(content.experience[0]).toMatchObject({
organization: 'Trupa lui Răzuș',
role: 'Full-Stack Developer & Hosting Administrator (Collaborator)',
});
expect(content.infrastructure.featuredOperation.outcome).toMatch(/without data loss.*roughly a year/iu);
expect(content.projects.selected.map(({ id }) => id)).toEqual([
'private-medication-tracker',
'footy-tracker',
'opinion-dynamics-simulation',
]);
expect(content.projects.selected[1]?.contribution).toMatch(/collaborator/iu);
expect(content.projects.selected[1]?.outcome).toMatch(/0\.942 mAP@0\.5.*0\.198/iu);
expect(content.projects.selected[0]?.outcome).toContain('further work needed before a wider release.');
expect(content.systemsOperations.title).toBe('Professional systems operations');
expect(content.infrastructure.title).toBe('Secure self-hosted platform and lifecycle');
expect(content.projects.selected).toHaveLength(3);
expect(content.projects.selected.filter((project) => project.visibility === 'private')
.every((project) => project.url === undefined)).toBe(true);
expect(content.projects.selected.find((project) => project.visibility === 'private')?.title)
.toBe('Private self-hosted medication tracker');
expect(content.projects.additional.find((project) => project.id === 'private-game-prototype')?.title)
.toBe('Private game prototype');
expect(content.toolkit.flatMap((group) => group.technologies).map((technology) => technology.name))
.toEqual(expect.arrayContaining(['Linux', 'Docker', 'Python', 'Vue.js', 'Java']));
expect(content.contact).toEqual(expect.objectContaining({ email: { localPart: 'luca.pislaru', domain: 'gmail.com' } }));
expect(content.contact.social.map((link) => link.url)).toEqual([
'https://linkedin.com/in/luca-pisl',
'https://github.com/LucaPisl',
'https://gitlab.com/luca_pisl',
]);
const publishedReferences = [
content.contact.avatarAssetId,
...content.projects.selected.flatMap((project) => project.assetIds),
...content.projects.additional.flatMap((project) => project.assetIds),
...content.toolkit.flatMap((group) => group.technologies.flatMap((technology) =>
technology.assetId === undefined ? [] : [technology.assetId])),
...(content.metadata.socialPreviewAssetId === undefined ? [] : [content.metadata.socialPreviewAssetId]),
...(content.soundtrack === undefined ? [] : [
content.soundtrack.intro.opusAssetId,
content.soundtrack.intro.mp3AssetId,
content.soundtrack.main.opusAssetId,
content.soundtrack.main.mp3AssetId,
content.soundtrack.afterglow.opusAssetId,
content.soundtrack.afterglow.mp3AssetId,
content.soundtrack.driveLift.opusAssetId,
content.soundtrack.driveLift.mp3AssetId,
]),
];
expect([...publishedReferences].sort()).toEqual(manifest.assets.map((asset) => asset.id).sort());
expect(site).toEqual({
environment: 'preview',
canonicalUrl: 'https://portfolio.localhost/',
buildId: 'preview-semantic-v1',
});
expect(JSON.stringify(content)).not.toMatch(
/Arch Linux|Mihai Razus PFA|DevOps collaborator|CV download|heatmap|fully secure|expert|percent/iu,
);
});
it('publishes only the four verified owner repositories and no private project links', async () => {
const { content } = validateProductionInputs(
await readJson('content/public/portfolio-content.json'),
await readJson('content/public/asset-manifest.json'),
await readJson('config/site.preview.json'),
new URL('file:///prepared-assets/'),
);
const expected = new Map([
['footy-tracker', 'https://github.com/LucaPisl/footy-tracker'],
['opinion-dynamics-simulation', 'https://github.com/LucaPisl/opinion-dynamics-simulation'],
['currency-converter', 'https://github.com/LucaPisl/CurrencyConverterAvalonia'],
['linux-modding-guide', 'https://github.com/LucaPisl/LinuxModdingGuide'],
]);
const projects = [...content.projects.selected, ...content.projects.additional];
expect(new Map(projects.flatMap((project) => project.url === undefined ? [] : [[project.id, project.url]]))).toEqual(expected);
for (const project of projects) {
if (project.visibility === 'private') expect(project.url).toBeUndefined();
if (project.url !== undefined) {
const url = new URL(project.url);
expect(url.protocol).toBe('https:');
expect(url.hostname).toBe('github.com');
expect(url.pathname.startsWith('/LucaPisl/')).toBe(true);
expect(url.search).toBe('');
expect(url.hash).toBe('');
}
}
expect(JSON.stringify(content)).not.toContain('CurrencyConverterAvaloniaProject');
});
});