WFDASHDRIVER-APP/e2e/option_b.mjs
SJCoetz 85662380a2 feat: add order item photo uploads and fix PB bugs
- fix driver_locations schema mismatch: use `relation` instead of `driver` per live PB schema
- remove invalid `ready_for_collection` filter that caused silent 400 errors
- add order_item_attachments support for driver pickup photos with proper error handling:
  * replace legacy collection_photo field with new collection for multiple per-item files
  * upload photos after updating item status to avoid stranding assigned items
  * show warning toast if upload fails instead of success confirmation
  * update toast messages to reflect photo upload status
- add pre-build schema check script to catch invalid PB field references pre-deploy
- add corresponding npm scripts and prebuild hook for the schema check
- add e2e test scripts for collection and upload flows
- update type definitions and pocketbase SDK helpers for new schema and functionality
2026-07-08 01:35:26 +02:00

93 lines
3.3 KiB
JavaScript

// E2E: drive Collect flow via PB SDK to verify the B (toast) wiring.
import PocketBase from 'pocketbase';
import fs from 'node:fs';
const PB = 'https://pocketbase-gnqc88suy8fqk6wyryjjdpvl.169.239.180.130.sslip.io';
const pb = new PocketBase(PB);
const auth = await pb.collection('users').authWithPassword('david.els1@outlook.com', '1234567890');
const me = auth?.record?.id;
if (!me) { console.log('LOGIN FAILED — authStore=', JSON.stringify(pb.authStore)); process.exit(1); }
console.log('logged in as', me);
const items = await pb.collection('order_items').getFullList({
filter: `drv_id = "${me}" && item_status = "assigned"`,
perPage: 5,
});
if (items.length === 0) { console.log('NO ASSIGNED — abort'); process.exit(1); }
// === HAPPY PATH: PDF ===
const target = items[0];
await pb.collection('order_items').update(target.id, {
item_status: 'collected',
drv_status: 'collected',
drv_collected_at: new Date().toISOString(),
qty_collected: target.order_qty || target.quantity || 1,
});
try {
const pdfBytes = Buffer.from('%PDF-1.4\n%\xE2\xE3\xCF\xD3\ntest', 'utf-8');
const pdfFile = new File([pdfBytes], 'collect_proof.pdf', { type: 'application/pdf' });
const att = await pb.collection('order_item_attachments').create({
order_item: target.id,
filename: pdfFile.name,
file: pdfFile,
content_type: pdfFile.type,
size_bytes: String(pdfFile.size),
source: 'driver_proof',
notes: 'e2e collect test',
});
console.log('HAPPY OK: attachment', att.id);
} catch (e) {
console.log('HAPPY FAIL:', e.message);
}
await pb.collection('order_items').update(target.id, {
item_status: 'assigned',
drv_status: 'assigned',
drv_collected_at: null,
qty_collected: null,
});
// === BROKEN PATH: image (mime bug) ===
const target2 = items[1] || items[0];
await pb.collection('order_items').update(target2.id, {
item_status: 'collected',
drv_status: 'collected',
drv_collected_at: new Date().toISOString(),
qty_collected: target2.order_qty || target2.quantity || 1,
});
try {
// real JPEG header bytes — what a phone camera would produce
const jpegBytes = Buffer.from([
0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,
0x01,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,
]);
// pad to look more like a real photo
const padded = Buffer.concat([jpegBytes, Buffer.alloc(20000, 0x80)]);
const jpegFile = new File([padded], 'collect_photo.jpg', { type: 'image/jpeg' });
const r = await pb.collection('order_item_attachments').create({
order_item: target2.id,
filename: jpegFile.name,
file: jpegFile,
content_type: jpegFile.type,
size_bytes: String(jpegFile.size),
source: 'driver_proof',
});
console.log('BROKEN UNEXPECTED OK:', r.id);
} catch (e) {
// This is what page.tsx will receive — e.message contains the PB reason
console.log('BROKEN EXPECTED THROW — toast would render:');
console.log(' "Item collected — but photo upload failed (' + e.message + ')"');
}
await pb.collection('order_items').update(target2.id, {
item_status: 'assigned',
drv_status: 'assigned',
drv_collected_at: null,
qty_collected: null,
});
// verify clean state
const stuck = await pb.collection('order_items').getFullList({
filter: `item_status = "collected" && drv_id = "${me}"`,
});
console.log('Final assigned-to-david collected rows:', stuck.length, '(expect 0)');
process.exit(0);