fix(api): close v2 mobile contract gaps

This commit is contained in:
zouantchaw
2026-03-17 22:37:45 +01:00
parent afcd896b47
commit 008dd7efb1
14 changed files with 1315 additions and 54 deletions

View File

@@ -87,6 +87,70 @@ async function uploadFile(path, token, {
return payload;
}
async function finalizeVerifiedUpload({
token,
uploadCategory,
filename,
contentType,
content,
finalizePath,
finalizeMethod = 'PUT',
verificationType,
subjectId,
rules = {},
finalizeBody = {},
}) {
const uploaded = await uploadFile('/upload-file', token, {
filename,
contentType,
content,
fields: {
visibility: 'private',
category: uploadCategory,
},
});
const signed = await apiCall('/create-signed-url', {
method: 'POST',
token,
body: {
fileUri: uploaded.fileUri,
expiresInSeconds: 300,
},
});
const verification = await apiCall('/verifications', {
method: 'POST',
token,
body: {
type: verificationType,
subjectType: 'worker',
subjectId,
fileUri: uploaded.fileUri,
rules,
},
expectedStatus: 202,
});
const finalized = await apiCall(finalizePath, {
method: finalizeMethod,
token,
body: {
...finalizeBody,
verificationId: verification.verificationId,
fileUri: signed.signedUrl,
photoUrl: signed.signedUrl,
},
});
return {
uploaded,
signed,
verification,
finalized,
};
}
async function signInClient() {
return apiCall('/auth/client/sign-in', {
method: 'POST',
@@ -210,6 +274,10 @@ async function main() {
token: ownerSession.sessionToken,
});
assert.ok(Array.isArray(clientReorders.items));
if (clientReorders.items[0]) {
assert.equal(typeof clientReorders.items[0].hourlyRateCents, 'number');
assert.equal(typeof clientReorders.items[0].totalPriceCents, 'number');
}
logStep('client.reorders.ok', { count: clientReorders.items.length });
const billingAccounts = await apiCall('/client/billing/accounts', {
@@ -317,6 +385,10 @@ async function main() {
token: ownerSession.sessionToken,
});
assert.ok(Array.isArray(viewedOrders.items));
if (viewedOrders.items[0]) {
assert.ok(viewedOrders.items[0].clientName);
assert.equal(typeof viewedOrders.items[0].hourlyRate, 'number');
}
logStep('client.orders.view.ok', { count: viewedOrders.items.length });
const reorderPreview = await apiCall(`/client/orders/${fixture.orders.completed.id}/reorder-preview`, {
@@ -519,7 +591,7 @@ async function main() {
assert.ok(createdPermanentOrder.orderId);
logStep('client.orders.create-permanent.ok', createdPermanentOrder);
const editedOrderCopy = await apiCall(`/client/orders/${fixture.orders.completed.id}/edit`, {
const editedOrderCopy = await apiCall(`/client/orders/${createdRecurringOrder.orderId}/edit`, {
method: 'POST',
token: ownerSession.sessionToken,
idempotencyKey: uniqueKey('order-edit'),
@@ -528,6 +600,7 @@ async function main() {
},
});
assert.ok(editedOrderCopy.orderId);
assert.notEqual(editedOrderCopy.orderId, createdRecurringOrder.orderId);
logStep('client.orders.edit-copy.ok', editedOrderCopy);
const cancelledOrder = await apiCall(`/client/orders/${createdOneTimeOrder.orderId}/cancel`, {
@@ -538,6 +611,7 @@ async function main() {
reason: 'Smoke cancel validation',
},
});
assert.equal(cancelledOrder.futureOnly, true);
logStep('client.orders.cancel.ok', cancelledOrder);
const coverageReview = await apiCall('/client/coverage/reviews', {
@@ -609,6 +683,14 @@ async function main() {
token: staffAuth.idToken,
});
assert.ok(Array.isArray(staffDashboard.recommendedShifts));
if (staffDashboard.todaysShifts[0]) {
assert.ok(staffDashboard.todaysShifts[0].clientName);
assert.equal(typeof staffDashboard.todaysShifts[0].totalRate, 'number');
}
if (staffDashboard.recommendedShifts[0]) {
assert.ok(staffDashboard.recommendedShifts[0].clientName);
assert.equal(typeof staffDashboard.recommendedShifts[0].totalRate, 'number');
}
logStep('staff.dashboard.ok', {
todaysShifts: staffDashboard.todaysShifts.length,
recommendedShifts: staffDashboard.recommendedShifts.length,
@@ -693,12 +775,22 @@ async function main() {
token: staffAuth.idToken,
});
assert.ok(Array.isArray(completedShifts.items));
if (completedShifts.items[0]) {
assert.ok(completedShifts.items[0].clientName);
assert.ok(completedShifts.items[0].date);
assert.ok(completedShifts.items[0].startTime);
assert.ok(completedShifts.items[0].endTime);
assert.equal(typeof completedShifts.items[0].hourlyRate, 'number');
assert.equal(typeof completedShifts.items[0].totalRate, 'number');
}
logStep('staff.shifts.completed.ok', { count: completedShifts.items.length });
const shiftDetail = await apiCall(`/staff/shifts/${openShift.shiftId}`, {
token: staffAuth.idToken,
});
assert.equal(shiftDetail.shiftId, openShift.shiftId);
assert.equal(typeof shiftDetail.latitude, 'number');
assert.equal(typeof shiftDetail.longitude, 'number');
logStep('staff.shifts.detail.ok', shiftDetail);
const profileSections = await apiCall('/staff/profile/sections', {
@@ -727,6 +819,7 @@ async function main() {
token: staffAuth.idToken,
});
assert.ok(Array.isArray(profileDocumentsBefore.items));
assert.ok(profileDocumentsBefore.items.every((item) => item.documentType !== 'ATTIRE'));
logStep('staff.profile.documents-before.ok', { count: profileDocumentsBefore.items.length });
const attireChecklistBefore = await apiCall('/staff/profile/attire', {
@@ -1054,6 +1147,17 @@ async function main() {
assert.ok(clockOut.securityProofId);
logStep('staff.clock-out.ok', clockOut);
const submittedCompletedShift = await apiCall(`/staff/shifts/${fixture.shifts.assigned.id}/submit-for-approval`, {
method: 'POST',
token: staffAuth.idToken,
idempotencyKey: uniqueKey('staff-shift-submit-approval'),
body: {
note: 'Smoke approval submission',
},
});
assert.equal(submittedCompletedShift.submitted, true);
logStep('staff.shifts.submit-for-approval.ok', submittedCompletedShift);
const requestedSwap = await apiCall(`/staff/shifts/${fixture.shifts.assigned.id}/request-swap`, {
method: 'POST',
token: staffAuth.idToken,
@@ -1072,35 +1176,63 @@ async function main() {
assert.ok(uploadedProfilePhoto.fileUri);
logStep('staff.profile.photo.upload.ok', uploadedProfilePhoto);
const uploadedGovId = await uploadFile(`/staff/profile/documents/${fixture.documents.governmentId.id}/upload`, staffAuth.idToken, {
const uploadedGovId = await finalizeVerifiedUpload({
token: staffAuth.idToken,
uploadCategory: 'staff-document',
filename: 'government-id.jpg',
contentType: 'image/jpeg',
content: Buffer.from('fake-government-id'),
finalizePath: `/staff/profile/documents/${fixture.documents.governmentId.id}/upload`,
finalizeMethod: 'PUT',
verificationType: 'government_id',
subjectId: fixture.documents.governmentId.id,
rules: {
documentId: fixture.documents.governmentId.id,
},
});
assert.equal(uploadedGovId.documentId, fixture.documents.governmentId.id);
logStep('staff.profile.document.upload.ok', uploadedGovId);
assert.equal(uploadedGovId.finalized.documentId, fixture.documents.governmentId.id);
logStep('staff.profile.document.upload.ok', uploadedGovId.finalized);
const uploadedAttire = await uploadFile(`/staff/profile/attire/${fixture.documents.attireBlackShirt.id}/upload`, staffAuth.idToken, {
const uploadedAttire = await finalizeVerifiedUpload({
token: staffAuth.idToken,
uploadCategory: 'staff-attire',
filename: 'black-shirt.jpg',
contentType: 'image/jpeg',
content: Buffer.from('fake-black-shirt'),
finalizePath: `/staff/profile/attire/${fixture.documents.attireBlackShirt.id}/upload`,
finalizeMethod: 'PUT',
verificationType: 'attire',
subjectId: fixture.documents.attireBlackShirt.id,
rules: {
dressCode: 'Black shirt',
},
});
assert.equal(uploadedAttire.documentId, fixture.documents.attireBlackShirt.id);
logStep('staff.profile.attire.upload.ok', uploadedAttire);
assert.equal(uploadedAttire.finalized.documentId, fixture.documents.attireBlackShirt.id);
logStep('staff.profile.attire.upload.ok', uploadedAttire.finalized);
const certificateType = `ALCOHOL_SERVICE_${Date.now()}`;
const uploadedCertificate = await uploadFile('/staff/profile/certificates', staffAuth.idToken, {
const uploadedCertificate = await finalizeVerifiedUpload({
token: staffAuth.idToken,
uploadCategory: 'staff-certificate',
filename: 'certificate.pdf',
contentType: 'application/pdf',
content: Buffer.from('fake-certificate'),
fields: {
finalizePath: '/staff/profile/certificates',
finalizeMethod: 'POST',
verificationType: 'certification',
subjectId: certificateType,
rules: {
certificateName: 'Alcohol Service Permit',
certificateIssuer: 'Demo Issuer',
},
finalizeBody: {
certificateType,
name: 'Alcohol Service Permit',
issuer: 'Demo Issuer',
},
});
assert.equal(uploadedCertificate.certificateType, certificateType);
logStep('staff.profile.certificate.upload.ok', uploadedCertificate);
assert.equal(uploadedCertificate.finalized.certificateType, certificateType);
logStep('staff.profile.certificate.upload.ok', uploadedCertificate.finalized);
const profileDocumentsAfter = await apiCall('/staff/profile/documents', {
token: staffAuth.idToken,