From 9ea26806d0724735e6fabf13832907dc9ab120b7 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Thu, 13 Aug 2026 01:18:37 +0800 Subject: [PATCH] fix(fleetops): take the QR content from the API, not an npm decoder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Post-response script decoded the QR PNG with pm.require('npm:jsqr@1.4.0') and 'npm:fast-png@6.2.0'. The contract runs a local Schema 3 collection under Postman CLI 1.46.0, where npm packages do not resolve: QR decode unavailable: Cannot find package 'npm:jsqr@1.4.0' The script caught that and logged it, so {{qr_code}} was never set and the next request sent the literal "{{qr_code}}" as its code — which the endpoint answered with a 500. Two failures wearing one disguise: a silent setup failure, reported as an API fault. Create a Tracking Number now reads qr_code_content, which the API returns beside the PNG in debug mode (fleetbase/fleetops 2130c86d). No decoding, no external package, and the value is the same one the image was generated from. It asserts rather than logs: qr_code must be a non-empty base64 PNG, and qr_code_content must be present and non-empty. A missing field is now a visible failed test instead of a variable that quietly stays unset. Decode Tracking Number QR gains a beforeRequest guard that fails and aborts when qr_code is unset or still matches placeholder syntax, so the request is never sent with a literal. Verified against CLI 1.46.0: the assertion fails, the request is NOT sent, and it counts as failed rather than skipped. Its response is now asserted too — a 2xx carrying a resource whose id matches {{order_id}}, the tracking number's owner. Note for future scripts: `prerequest` is NOT a valid Schema 3 script type. It fails the whole collection with "Invalid input for model" at load, taking every request with it. The correct type is `beforeRequest`. Co-Authored-By: Claude Opus 5 --- .../Create a Tracking Number.request.yaml | 47 +++++++------------ .../Decode Tracking Number QR.request.yaml | 37 +++++++++++++++ 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/postman/collections/Fleetbase API/Tracking Numbers/Create a Tracking Number.request.yaml b/postman/collections/Fleetbase API/Tracking Numbers/Create a Tracking Number.request.yaml index 1cb2da2..34cd81c 100644 --- a/postman/collections/Fleetbase API/Tracking Numbers/Create a Tracking Number.request.yaml +++ b/postman/collections/Fleetbase API/Tracking Numbers/Create a Tracking Number.request.yaml @@ -19,38 +19,25 @@ scripts: let cv = pm.environment; cv.set("tracking_number_id", json_response.id); - // Decode the QR image to recover the value a scanner would read. - // - // qr_code is a base64 PNG produced from the tracking number's owner uuid, and the - // QR endpoints are the one documented place the API takes a uuid — that is exactly - // what a scanner sends. Decoding it here mirrors what a device does, instead of - // asking the API to hand out the raw uuid. - // - // Guarded: if the runtime cannot resolve the packages, the rest of the run should - // continue rather than abort, and the two QR requests fail visibly on their own. - try { - const jsQR = pm.require('npm:jsqr@1.4.0'); - const { decode } = pm.require('npm:fast-png@6.2.0'); - const { Buffer } = require('buffer'); + // The QR image encodes the tracking number's owner uuid, and that is what the + // /from-qr and capture-qr endpoints match on. A scanner reads it from the image; a + // collection run cannot, so a debug build returns the same value beside the PNG as + // qr_code_content. No image decoding, and no external package. + pm.test("Create a Tracking Number returns a QR image", function () { + pm.expect(json_response.qr_code, "qr_code missing").to.be.a('string').and.not.empty; + // base64 PNG: the signature bytes encode to this prefix. + pm.expect(json_response.qr_code, "qr_code is not a base64 PNG").to.match(/^iVBORw0KGgo/); + }); - const base64 = String(json_response.qr_code || '').replace(/^data:image\/png;base64,/, ''); - const image = decode(Buffer.from(base64, 'base64')); - const pixels = new Uint8ClampedArray( - image.data.buffer, - image.data.byteOffset, - image.data.byteLength - ); - const qr = jsQR(pixels, image.width, image.height); + pm.test("Create a Tracking Number returns the QR content", function () { + pm.expect( + json_response.qr_code_content, + "qr_code_content missing — the API must run with debug enabled for this contract" + ).to.be.a('string').and.not.empty; + }); - pm.test('Create a Tracking Number returns a decodable QR code', function () { - pm.expect(qr, 'no QR code detected in qr_code').to.not.be.null; - }); - - if (qr) { - cv.set('qr_code', qr.data); - } - } catch (e) { - console.log('QR decode unavailable:', e.message); + if (json_response.qr_code_content) { + cv.set("qr_code", json_response.qr_code_content); } language: text/javascript examples: ./.resources/Create a Tracking Number.resources/examples diff --git a/postman/collections/Fleetbase API/Tracking Numbers/Decode Tracking Number QR.request.yaml b/postman/collections/Fleetbase API/Tracking Numbers/Decode Tracking Number QR.request.yaml index d50c90a..1baeeb9 100644 --- a/postman/collections/Fleetbase API/Tracking Numbers/Decode Tracking Number QR.request.yaml +++ b/postman/collections/Fleetbase API/Tracking Numbers/Decode Tracking Number QR.request.yaml @@ -9,4 +9,41 @@ body: "code": "{{qr_code}}" } +scripts: + - type: beforeRequest + code: |- + // Fail loudly rather than sending "{{qr_code}}" as the code. An unresolved Postman + // variable is sent literally, so the endpoint would receive the placeholder text and + // answer for it — which reads as an API fault rather than a missing prerequisite. + const code = pm.environment.get("qr_code"); + const unresolved = !code || /^\{\{.*\}\}$/.test(String(code)); + + if (unresolved) { + pm.test("qr_code is resolved before decoding", function () { + pm.expect.fail( + "qr_code is unset or still a placeholder (" + code + "). " + + "Create a Tracking Number must run first and return qr_code_content." + ); + }); + + throw new Error("Aborting Decode Tracking Number QR: qr_code is not resolved."); + } + language: text/javascript + - type: afterResponse + code: |- + // The decoded value is the tracking number's owner uuid, so this must resolve back to + // the order the tracking number was created for. + pm.test("Decode Tracking Number QR resolves the owning resource", function () { + pm.expect(pm.response.code, "expected a 2xx").to.be.oneOf([200, 201]); + + const json = pm.response.json(); + pm.expect(json, "no resource returned").to.be.an('object'); + pm.expect(json.id, "resolved resource has no id").to.be.a('string').and.not.empty; + + const orderId = pm.environment.get("order_id"); + if (orderId) { + pm.expect(json.id, "resolved a different resource than the tracking number's owner").to.eql(orderId); + } + }); + language: text/javascript order: 1500