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 => 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'); }); });