107 lines
4.5 KiB
JavaScript
107 lines
4.5 KiB
JavaScript
const { test, expect } = require('@playwright/test');
|
||
|
||
const economics = {
|
||
model: 'standard_overhead_profit_v1',
|
||
materialTotal: 1000,
|
||
rentalTotal: 14000,
|
||
laborTotal: 44080,
|
||
subtotal: 59080,
|
||
overheadPercentage: 15,
|
||
overheadAmount: 8862,
|
||
subtotalWithOverhead: 67942,
|
||
profitPercentage: 20,
|
||
profitAmount: 13588.4,
|
||
totalExclVat: 81530.4,
|
||
vatPercentage: 25,
|
||
vatAmount: 20382.6,
|
||
totalInclVat: 101913
|
||
};
|
||
|
||
test('labor survives a full reload with the single-object API contract', async ({ page }) => {
|
||
let laborReads = 0;
|
||
await page.addInitScript(() => {
|
||
window.localStorage.setItem('accessToken', 'labor-reload-test-token');
|
||
window.localStorage.setItem('user', JSON.stringify({ username: 'labor-reload-test' }));
|
||
window.localStorage.setItem('tilbudgivern_current_view', 'projects');
|
||
});
|
||
|
||
await page.route('**/api/**', async route => {
|
||
const request = route.request();
|
||
const url = new URL(request.url());
|
||
const path = url.pathname;
|
||
const fulfill = body => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(body) });
|
||
|
||
if (path.endsWith('/api/customer-projects/projects')) {
|
||
return fulfill({ success: true, projects: [{
|
||
id: 392,
|
||
project_name: 'Røsevangen 44 – betontag',
|
||
customer_name: 'Testkunde',
|
||
customer_address: 'Røsevangen 44, 3520 Farum',
|
||
project_description: 'Udskiftning af betontag',
|
||
project_status: 'review_pending',
|
||
updated_at: '2026-08-10T10:00:00Z'
|
||
}] });
|
||
}
|
||
if (path.endsWith('/api/customer-projects/392')) {
|
||
return fulfill({ success: true, project: {
|
||
id: 392,
|
||
project_name: 'Røsevangen 44 – betontag',
|
||
customer_name: 'Testkunde',
|
||
customer_address: 'Røsevangen 44, 3520 Farum',
|
||
project_description: 'Udskiftning af betontag',
|
||
project_status: 'review_pending'
|
||
} });
|
||
}
|
||
if (path.endsWith('/392/geometry')) {
|
||
return fulfill({ success: true, geometry: {
|
||
roof_type: 'skraat_tag', frontend_roof_type: 'sadeltag', width: 6, length: 10,
|
||
roof_pitch: 30, total_area: 60, roof_covering_area: 69.28
|
||
} });
|
||
}
|
||
if (path.endsWith('/392/labor')) {
|
||
laborReads += 1;
|
||
return fulfill({ success: true, labor: {
|
||
total_work_hours: '76.00', hourly_rate: '580.00', total_labor_cost: '44080.00',
|
||
work_breakdown: JSON.stringify([
|
||
{ task: 'Nedtagning', hours: 20, rate: 580, cost: 11600 },
|
||
{ task: 'Montering', hours: 56, rate: 580, cost: 32480 }
|
||
])
|
||
} });
|
||
}
|
||
if (path.endsWith('/392/materials')) {
|
||
return fulfill({ success: true, materials: [{ material_name: 'Betontagsten', quantity: 10, unit: 'stk', unit_price: 100 }] });
|
||
}
|
||
if (path.endsWith('/projects/392/rentals')) {
|
||
return fulfill({ success: true, rentals: [{ rental_name: 'Stillads', quantity: 1, unit: 'sum', unit_price: 14000 }] });
|
||
}
|
||
if (path.endsWith('/392/packages')) {
|
||
return fulfill({ success: true, packages: [{ id: 1, name: 'Betontag', materials: [] }] });
|
||
}
|
||
if (path.endsWith('/392/calculation')) return fulfill({ success: true, data: economics });
|
||
if (path.endsWith('/392/calculate')) return fulfill({ success: true, data: economics });
|
||
if (path.includes('/order-suggestions')) return fulfill({ success: true, matches: [] });
|
||
if (path.includes('/material-price-status')) return fulfill({ success: true, sources: [] });
|
||
return fulfill({ success: true, data: null });
|
||
});
|
||
|
||
const openFinalReview = async () => {
|
||
const projectLoaded = page.waitForResponse(response => response.url().endsWith('/api/customer-projects/392'));
|
||
await page.locator('.project-resume-panel button').click();
|
||
await projectLoaded;
|
||
await expect(page.getByRole('heading', { name: /Røsevangen 44 – betontag/ })).toBeVisible();
|
||
await expect(page.locator('.loading-overlay')).toHaveCount(0);
|
||
await page.locator('.step').filter({ hasText: 'Final Review' }).click();
|
||
await expect(page.getByRole('heading', { name: /Timer & Opgaver \(2 opgaver\)/ })).toBeVisible();
|
||
await expect(page.getByText('76 timer', { exact: true })).toBeVisible();
|
||
await expect(page.getByText('44.080,00 kr', { exact: true }).first()).toBeVisible();
|
||
};
|
||
|
||
await page.goto('/', { waitUntil: 'domcontentloaded' });
|
||
await openFinalReview();
|
||
|
||
await page.evaluate(() => window.sessionStorage.clear());
|
||
await page.reload({ waitUntil: 'domcontentloaded' });
|
||
await openFinalReview();
|
||
expect(laborReads).toBeGreaterThanOrEqual(2);
|
||
});
|