/** * LibreBooking API Test Script * * Testet alle wichtigen API-Endpunkte mit echten Credentials */ import * as https from 'https'; import * as http from 'http'; const BASE_URL = 'https://librebooking.zell-cloud.de'; const USERNAME = 'sebastian.zell@zell-aufmass.de'; const PASSWORD = 'wanUQ4uVqU6lfP'; interface Session { sessionToken: string; userId: number; } interface TestResult { name: string; success: boolean; data?: any; error?: string; } const results: TestResult[] = []; /** * HTTP Request Helper */ function makeRequest( method: string, path: string, body?: any, session?: Session, qs?: Record ): Promise { return new Promise((resolve, reject) => { const url = new URL(path, BASE_URL); if (qs) { Object.entries(qs).forEach(([key, value]) => { if (value) url.searchParams.append(key, value); }); } const headers: Record = { 'Content-Type': 'application/json', }; if (session) { headers['X-Booked-SessionToken'] = session.sessionToken; headers['X-Booked-UserId'] = session.userId.toString(); } const options = { method, hostname: url.hostname, path: url.pathname + url.search, headers, }; const httpModule = url.protocol === 'https:' ? https : http; const req = httpModule.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { try { if (data) { resolve(JSON.parse(data)); } else { resolve({ success: true }); } } catch (e) { resolve({ rawData: data }); } }); }); req.on('error', (error) => { reject(error); }); if (body) { req.write(JSON.stringify(body)); } req.end(); }); } /** * Test Authentication */ async function testAuthentication(): Promise { console.log('\n=== 1. Testing Authentication ==='); try { const response = await makeRequest( 'POST', '/Web/Services/index.php/Authentication/Authenticate', { username: USERNAME, password: PASSWORD } ); if (response.isAuthenticated) { console.log('✅ Authentication successful'); console.log(` Session Token: ${response.sessionToken.substring(0, 20)}...`); console.log(` User ID: ${response.userId}`); console.log(` Session Expires: ${response.sessionExpires}`); results.push({ name: 'Authentication', success: true, data: { userId: response.userId } }); return { sessionToken: response.sessionToken, userId: response.userId }; } else { throw new Error('Authentication failed'); } } catch (error: any) { console.log('❌ Authentication failed:', error.message); results.push({ name: 'Authentication', success: false, error: error.message }); throw error; } } /** * Test Get Reservations */ async function testGetReservations(session: Session): Promise { console.log('\n=== 2. Testing Get Reservations ==='); try { // Test without date filters (should return next 2 weeks) const response = await makeRequest( 'GET', '/Web/Services/index.php/Reservations/', undefined, session ); console.log(`✅ Reservations fetched: ${response.reservations?.length || 0} found`); if (response.reservations && response.reservations.length > 0) { const res = response.reservations[0]; console.log(` Example: ${res.title || 'No title'} (${res.referenceNumber})`); console.log(` Start: ${res.startDate}`); console.log(` Resource: ${res.resourceName}`); } results.push({ name: 'Get Reservations (no filter)', success: true, data: { count: response.reservations?.length || 0 } }); // Test with date filter (Feb 7-14, 2026) console.log('\n Testing with date filter (2026-02-07 to 2026-02-14)...'); const responseFiltered = await makeRequest( 'GET', '/Web/Services/index.php/Reservations/', undefined, session, { startDateTime: '2026-02-07T00:00:00', endDateTime: '2026-02-14T23:59:59' } ); console.log(`✅ Filtered reservations: ${responseFiltered.reservations?.length || 0} found`); results.push({ name: 'Get Reservations (date filter)', success: true, data: { count: responseFiltered.reservations?.length || 0 } }); } catch (error: any) { console.log('❌ Get Reservations failed:', error.message); results.push({ name: 'Get Reservations', success: false, error: error.message }); } } /** * Test Get Resources */ async function testGetResources(session: Session): Promise { console.log('\n=== 3. Testing Get Resources ==='); try { const response = await makeRequest( 'GET', '/Web/Services/index.php/Resources/', undefined, session ); console.log(`✅ Resources fetched: ${response.resources?.length || 0} found`); let firstResourceId: number | null = null; if (response.resources && response.resources.length > 0) { const res = response.resources[0]; firstResourceId = res.resourceId; console.log(` Example: ${res.name} (ID: ${res.resourceId})`); console.log(` Schedule ID: ${res.scheduleId}`); console.log(` Custom Attributes: ${res.customAttributes?.length || 0}`); if (res.customAttributes && res.customAttributes.length > 0) { res.customAttributes.forEach((attr: any) => { console.log(` - ${attr.label}: ${attr.value || '(no value)'}`); }); } } results.push({ name: 'Get Resources', success: true, data: { count: response.resources?.length || 0 } }); return firstResourceId; } catch (error: any) { console.log('❌ Get Resources failed:', error.message); results.push({ name: 'Get Resources', success: false, error: error.message }); return null; } } /** * Test Get Single Resource (with custom attributes) */ async function testGetSingleResource(session: Session, resourceId: number): Promise { console.log('\n=== 4. Testing Get Single Resource (with custom attributes) ==='); try { const response = await makeRequest( 'GET', `/Web/Services/index.php/Resources/${resourceId}`, undefined, session ); console.log(`✅ Resource fetched: ${response.name}`); console.log(` Custom Attributes: ${response.customAttributes?.length || 0}`); if (response.customAttributes && response.customAttributes.length > 0) { response.customAttributes.forEach((attr: any) => { console.log(` - ID: ${attr.id}, Label: ${attr.label}, Value: ${attr.value || '(no value)'}`); }); } results.push({ name: 'Get Single Resource', success: true, data: { customAttributes: response.customAttributes?.length || 0 } }); } catch (error: any) { console.log('❌ Get Single Resource failed:', error.message); results.push({ name: 'Get Single Resource', success: false, error: error.message }); } } /** * Test Get Users */ async function testGetUsers(session: Session): Promise { console.log('\n=== 5. Testing Get Users ==='); try { const response = await makeRequest( 'GET', '/Web/Services/index.php/Users/', undefined, session ); console.log(`✅ Users fetched: ${response.users?.length || 0} found`); let firstUserId: number | null = null; if (response.users && response.users.length > 0) { const user = response.users[0]; firstUserId = user.id; console.log(` Example: ${user.firstName} ${user.lastName} (ID: ${user.id})`); } results.push({ name: 'Get Users', success: true, data: { count: response.users?.length || 0 } }); return firstUserId; } catch (error: any) { console.log('❌ Get Users failed:', error.message); results.push({ name: 'Get Users', success: false, error: error.message }); return null; } } /** * Test Get Single User (with custom attributes) */ async function testGetSingleUser(session: Session, userId: number): Promise { console.log('\n=== 6. Testing Get Single User (with custom attributes) ==='); try { const response = await makeRequest( 'GET', `/Web/Services/index.php/Users/${userId}`, undefined, session ); console.log(`✅ User fetched: ${response.firstName} ${response.lastName}`); console.log(` Custom Attributes: ${response.customAttributes?.length || 0}`); if (response.customAttributes && response.customAttributes.length > 0) { response.customAttributes.forEach((attr: any) => { console.log(` - ID: ${attr.id}, Label: ${attr.label}, Value: ${attr.value || '(no value)'}`); }); } results.push({ name: 'Get Single User', success: true, data: { customAttributes: response.customAttributes?.length || 0 } }); } catch (error: any) { console.log('❌ Get Single User failed:', error.message); results.push({ name: 'Get Single User', success: false, error: error.message }); } } /** * Test Get Schedules */ async function testGetSchedules(session: Session): Promise { console.log('\n=== 7. Testing Get Schedules ==='); try { const response = await makeRequest( 'GET', '/Web/Services/index.php/Schedules/', undefined, session ); console.log(`✅ Schedules fetched: ${response.schedules?.length || 0} found`); if (response.schedules && response.schedules.length > 0) { const schedule = response.schedules[0]; console.log(` Example: ${schedule.name} (ID: ${schedule.id})`); } results.push({ name: 'Get Schedules', success: true, data: { count: response.schedules?.length || 0 } }); } catch (error: any) { console.log('❌ Get Schedules failed:', error.message); results.push({ name: 'Get Schedules', success: false, error: error.message }); } } /** * Test Get Attributes by Category */ async function testGetAttributes(session: Session): Promise { console.log('\n=== 8. Testing Get Attributes by Category ==='); const categories = [ { id: 1, name: 'Reservation' }, { id: 2, name: 'User' }, { id: 4, name: 'Resource' }, { id: 5, name: 'Resource Type' }, ]; for (const cat of categories) { try { const response = await makeRequest( 'GET', `/Web/Services/index.php/Attributes/Category/${cat.id}`, undefined, session ); console.log(`✅ ${cat.name} Attributes: ${response.attributes?.length || 0} found`); if (response.attributes && response.attributes.length > 0) { response.attributes.forEach((attr: any) => { console.log(` - ID: ${attr.id}, Label: ${attr.label}, Type: ${attr.type}, Required: ${attr.required}`); }); } results.push({ name: `Get Attributes (${cat.name})`, success: true, data: { count: response.attributes?.length || 0 } }); } catch (error: any) { console.log(`❌ Get ${cat.name} Attributes failed:`, error.message); results.push({ name: `Get Attributes (${cat.name})`, success: false, error: error.message }); } } } /** * Test Create, Update, Delete Reservation */ async function testReservationCRUD(session: Session, resourceId: number): Promise { console.log('\n=== 9. Testing Reservation CRUD ==='); // Create console.log(' Creating test reservation...'); try { const createResponse = await makeRequest( 'POST', '/Web/Services/index.php/Reservations/', { title: 'API Test Reservation', description: 'Created by n8n node test script', resourceId: resourceId, startDateTime: '2026-02-07T10:00:00', endDateTime: '2026-02-07T11:00:00', userId: session.userId, termsAccepted: true, allowParticipation: false, }, session ); if (createResponse.referenceNumber) { console.log(`✅ Reservation created: ${createResponse.referenceNumber}`); results.push({ name: 'Create Reservation', success: true, data: { referenceNumber: createResponse.referenceNumber } }); const refNum = createResponse.referenceNumber; // Get the created reservation console.log(' Fetching created reservation...'); const getResponse = await makeRequest( 'GET', `/Web/Services/index.php/Reservations/${refNum}`, undefined, session ); console.log(`✅ Reservation fetched: ${getResponse.title}`); console.log(` Custom Attributes: ${getResponse.customAttributes?.length || 0}`); if (getResponse.customAttributes && getResponse.customAttributes.length > 0) { getResponse.customAttributes.forEach((attr: any) => { console.log(` - ID: ${attr.id}, Label: ${attr.label}, Value: ${attr.value || '(no value)'}`); }); } results.push({ name: 'Get Created Reservation', success: true }); // Update console.log(' Updating reservation...'); const updateResponse = await makeRequest( 'POST', `/Web/Services/index.php/Reservations/${refNum}?updateScope=this`, { title: 'API Test Reservation UPDATED', description: 'Updated by n8n node test script', resourceId: resourceId, startDateTime: '2026-02-07T10:00:00', endDateTime: '2026-02-07T12:00:00', termsAccepted: true, allowParticipation: false, }, session ); console.log(`✅ Reservation updated`); results.push({ name: 'Update Reservation', success: true }); // Delete console.log(' Deleting reservation...'); const deleteResponse = await makeRequest( 'DELETE', `/Web/Services/index.php/Reservations/${refNum}?updateScope=this`, undefined, session ); console.log(`✅ Reservation deleted`); results.push({ name: 'Delete Reservation', success: true }); } else { console.log('❌ Create Reservation failed - no reference number returned'); console.log(' Response:', JSON.stringify(createResponse, null, 2)); results.push({ name: 'Create Reservation', success: false, error: JSON.stringify(createResponse) }); } } catch (error: any) { console.log('❌ Reservation CRUD failed:', error.message); results.push({ name: 'Reservation CRUD', success: false, error: error.message }); } } /** * Test Groups */ async function testGetGroups(session: Session): Promise { console.log('\n=== 10. Testing Get Groups ==='); try { const response = await makeRequest( 'GET', '/Web/Services/index.php/Groups/', undefined, session ); console.log(`✅ Groups fetched: ${response.groups?.length || 0} found`); if (response.groups && response.groups.length > 0) { const group = response.groups[0]; console.log(` Example: ${group.name} (ID: ${group.id})`); } results.push({ name: 'Get Groups', success: true, data: { count: response.groups?.length || 0 } }); } catch (error: any) { console.log('❌ Get Groups failed:', error.message); results.push({ name: 'Get Groups', success: false, error: error.message }); } } /** * Test Accessories */ async function testGetAccessories(session: Session): Promise { console.log('\n=== 11. Testing Get Accessories ==='); try { const response = await makeRequest( 'GET', '/Web/Services/index.php/Accessories/', undefined, session ); console.log(`✅ Accessories fetched: ${response.accessories?.length || 0} found`); if (response.accessories && response.accessories.length > 0) { const acc = response.accessories[0]; console.log(` Example: ${acc.name} (ID: ${acc.id})`); } results.push({ name: 'Get Accessories', success: true, data: { count: response.accessories?.length || 0 } }); } catch (error: any) { console.log('❌ Get Accessories failed:', error.message); results.push({ name: 'Get Accessories', success: false, error: error.message }); } } /** * Test SignOut */ async function testSignOut(session: Session): Promise { console.log('\n=== 12. Testing Sign Out ==='); try { await makeRequest( 'POST', '/Web/Services/index.php/Authentication/SignOut', { userId: session.userId, sessionToken: session.sessionToken, } ); console.log('✅ Sign Out successful'); results.push({ name: 'Sign Out', success: true }); } catch (error: any) { console.log('❌ Sign Out failed:', error.message); results.push({ name: 'Sign Out', success: false, error: error.message }); } } /** * Print Summary */ function printSummary(): void { console.log('\n========================================'); console.log(' TEST SUMMARY'); console.log('========================================'); const passed = results.filter(r => r.success).length; const failed = results.filter(r => !r.success).length; console.log(`\nTotal Tests: ${results.length}`); console.log(`✅ Passed: ${passed}`); console.log(`❌ Failed: ${failed}`); if (failed > 0) { console.log('\nFailed Tests:'); results.filter(r => !r.success).forEach(r => { console.log(` - ${r.name}: ${r.error}`); }); } console.log('\n========================================\n'); } /** * Main Test Runner */ async function runTests(): Promise { console.log('========================================'); console.log(' LibreBooking API Test Suite'); console.log(` URL: ${BASE_URL}`); console.log(` User: ${USERNAME}`); console.log('========================================'); try { // Authentication const session = await testAuthentication(); // Get operations await testGetReservations(session); const resourceId = await testGetResources(session); if (resourceId) { await testGetSingleResource(session, resourceId); } const userId = await testGetUsers(session); if (userId) { await testGetSingleUser(session, userId); } await testGetSchedules(session); await testGetAttributes(session); await testGetGroups(session); await testGetAccessories(session); // CRUD operations if (resourceId) { await testReservationCRUD(session, resourceId); } // Sign out await testSignOut(session); } catch (error: any) { console.log('\n❌ Test suite failed:', error.message); } printSummary(); } // Run tests runTests().catch(console.error);