[READ-ONLY] Mirror of https://github.com/mrgnw/cv.
1#!/usr/bin/env node
2import { readFileSync } from 'fs';
3import { join, dirname } from 'path';
4import { fileURLToPath } from 'url';
5import JSON5 from 'json5';
6
7const __dirname = dirname(fileURLToPath(import.meta.url));
8
9// Colors for output
10const colors = {
11 reset: '\x1b[0m',
12 red: '\x1b[31m',
13 green: '\x1b[32m',
14 yellow: '\x1b[33m',
15 blue: '\x1b[34m',
16 cyan: '\x1b[36m',
17 bold: '\x1b[1m'
18};
19
20function log(message, color = 'reset') {
21 console.log(`${colors[color]}${message}${colors.reset}`);
22}
23
24function loadJsonFile(filePath) {
25 try {
26 const content = readFileSync(filePath, 'utf-8');
27 const cleanContent = content.replace(/^\uFEFF/, ''); // Remove BOM
28 return JSON5.parse(cleanContent);
29 } catch (error) {
30 log(`❌ Error loading ${filePath}: ${error.message}`, 'red');
31 return null;
32 }
33}
34
35function testExperienceData() {
36 log('\n🔍 Testing Experience Data Integration', 'bold');
37 log('=====================================\n');
38
39 // Load the files
40 const mainJsonPath = join(__dirname, 'src/lib/versions/main.json');
41 const experienceJsonPath = join(__dirname, 'src/lib/Experience.json5');
42 const bitpandaJsonPath = join(__dirname, 'src/lib/versions/data/bitpanda.json5');
43
44 const mainData = loadJsonFile(mainJsonPath);
45 const experienceData = loadJsonFile(experienceJsonPath);
46 const bitpandaData = loadJsonFile(bitpandaJsonPath);
47
48 if (!mainData || !experienceData) {
49 log('❌ Failed to load required files', 'red');
50 return false;
51 }
52
53 let allTestsPassed = true;
54
55 // Test 1: Check if main.json has the correct National Care Dental end date
56 log('📋 Test 1: National Care Dental End Date in main.json', 'cyan');
57 const mainNCD = mainData.experience.find(exp => exp.company === 'National Care Dental');
58 if (mainNCD) {
59 if (mainNCD.end === '2025-03-17') {
60 log(`✅ National Care Dental end date is correct: ${mainNCD.end}`, 'green');
61 } else {
62 log(`❌ National Care Dental end date is incorrect: ${mainNCD.end} (expected: 2025-03-17)`, 'red');
63 allTestsPassed = false;
64 }
65 } else {
66 log('❌ National Care Dental not found in main.json', 'red');
67 allTestsPassed = false;
68 }
69
70 // Test 2: Check if Experience.json5 has the correct National Care Dental end date
71 log('\n📋 Test 2: National Care Dental End Date in Experience.json5', 'cyan');
72 const expNCD = experienceData.experience.find(exp => exp.company === 'National Care Dental');
73 if (expNCD) {
74 if (expNCD.end === '2025-03-17') {
75 log(`✅ National Care Dental end date is correct: ${expNCD.end}`, 'green');
76 } else {
77 log(`❌ National Care Dental end date is incorrect: ${expNCD.end} (expected: 2025-03-17)`, 'red');
78 allTestsPassed = false;
79 }
80 } else {
81 log('❌ National Care Dental not found in Experience.json5', 'red');
82 allTestsPassed = false;
83 }
84
85 // Test 3: Compare data between main.json and Experience.json5
86 log('\n📋 Test 3: Data Consistency Between Files', 'cyan');
87 const mainCompanies = mainData.experience.map(exp => exp.company);
88 const expCompanies = experienceData.experience.map(exp => exp.company);
89
90 log(`Main.json companies: ${mainCompanies.join(', ')}`);
91 log(`Experience.json5 companies: ${expCompanies.join(', ')}`);
92
93 // Check if there's overlap
94 const hasOverlap = mainCompanies.some(company => expCompanies.includes(company));
95 if (hasOverlap) {
96 log('✅ Files have overlapping companies', 'green');
97 } else {
98 log('⚠️ Files have no overlapping companies - Experience.json5 might not be integrated', 'yellow');
99 }
100
101 // Test 4: Check chronological order
102 log('\n📋 Test 4: Chronological Order in main.json', 'cyan');
103 let chronologicallyCorrect = true;
104 for (let i = 1; i < mainData.experience.length; i++) {
105 const current = new Date(mainData.experience[i].start);
106 const previous = new Date(mainData.experience[i-1].start);
107
108 if (current > previous) {
109 log(`❌ Chronological order error: ${mainData.experience[i].company} (${mainData.experience[i].start}) should not be after ${mainData.experience[i-1].company} (${mainData.experience[i-1].start})`, 'red');
110 chronologicallyCorrect = false;
111 allTestsPassed = false;
112 }
113 }
114 if (chronologicallyCorrect) {
115 log('✅ Experience entries are in correct chronological order (newest first)', 'green');
116 }
117
118 // Test 5: Check if CGI is the current role
119 log('\n📋 Test 5: Current Role Verification', 'cyan');
120 const currentRole = mainData.experience[0]; // Should be the first (most recent) entry
121 if (currentRole.company === 'CGI' && !currentRole.end) {
122 log(`✅ Current role is correct: ${currentRole.title} at ${currentRole.company} (started ${currentRole.start})`, 'green');
123 } else {
124 log(`❌ Current role issue: ${currentRole.title} at ${currentRole.company} (end: ${currentRole.end || 'ongoing'})`, 'red');
125 allTestsPassed = false;
126 }
127
128 // Test 6: Required fields validation
129 log('\n📋 Test 6: Required Fields Validation', 'cyan');
130 let fieldsValid = true;
131 mainData.experience.forEach((exp, index) => {
132 const required = ['title', 'company', 'start', 'achievements'];
133 required.forEach(field => {
134 if (!exp[field]) {
135 log(`❌ Missing ${field} in experience[${index}] (${exp.company || 'unknown'})`, 'red');
136 fieldsValid = false;
137 allTestsPassed = false;
138 }
139 });
140
141 if (exp.achievements && !Array.isArray(exp.achievements)) {
142 log(`❌ Achievements should be an array in experience[${index}] (${exp.company})`, 'red');
143 fieldsValid = false;
144 allTestsPassed = false;
145 }
146 });
147 if (fieldsValid) {
148 log('✅ All required fields are present and valid', 'green');
149 }
150
151 // Test 7: Bitpanda version integration
152 if (bitpandaData) {
153 log('\n📋 Test 7: Bitpanda Version Integration', 'cyan');
154 log(`Bitpanda version has company: ${bitpandaData.company}`);
155 log(`Bitpanda version has title: ${bitpandaData.title}`);
156 log(`Bitpanda version has ${bitpandaData.experience ? bitpandaData.experience.length : 0} experience entries`);
157
158 if (bitpandaData.company === 'Bitpanda' && bitpandaData.title) {
159 log('✅ Bitpanda version has correct company and title customization', 'green');
160 } else {
161 log('⚠️ Bitpanda version customization might be incomplete', 'yellow');
162 }
163 }
164
165 // Summary
166 log('\n🏁 Test Summary', 'bold');
167 log('==============');
168 if (allTestsPassed) {
169 log('✅ All tests passed! Experience data appears to be correctly configured.', 'green');
170 } else {
171 log('❌ Some tests failed. There may be issues with experience data integration.', 'red');
172 }
173
174 // Recommendations
175 log('\n💡 Integration Analysis', 'bold');
176 log('======================');
177
178 if (mainNCD && expNCD) {
179 if (mainNCD.end === expNCD.end) {
180 log('✅ National Care Dental end dates are consistent between files', 'green');
181 } else {
182 log('⚠️ National Care Dental end dates differ between main.json and Experience.json5', 'yellow');
183 log(` main.json: ${mainNCD.end}`, 'yellow');
184 log(` Experience.json5: ${expNCD.end}`, 'yellow');
185 }
186 }
187
188 if (!hasOverlap) {
189 log('\n🔧 Recommendation: Experience.json5 Integration', 'yellow');
190 log(' Experience.json5 appears to be a separate data source that is not');
191 log(' being used in the main CV rendering. Consider either:');
192 log(' 1. Updating main.json to match Experience.json5');
193 log(' 2. Modifying versionReader.ts to use Experience.json5 as the base');
194 log(' 3. Creating a script to sync data between files');
195 }
196
197 return allTestsPassed;
198}
199
200// Run the tests
201const success = testExperienceData();
202process.exit(success ? 0 : 1);