← back to Dw Signup Fulfillment
scripts/sample-ledger-test.js
63 lines
#!/usr/bin/env node
'use strict';
process.env.DRY_RUN = '1';
const assert = require('assert/strict');
const crypto = require('crypto');
const config = require('../lib/config');
const {
SampleUsageLedger, countDiscountedSamples, isApprovedTradeTags, verifyShopifyHmac,
} = require('../lib/sample-ledger');
function order({ amount = '12.75', title = 'Free sample' } = {}) {
return {
id: 10, customer: { id: 20 }, discount_applications: [{ title }],
line_items: [{ quantity: 4, price: '4.25', variant_title: 'Sample', sku: 'ABC-Sample', discount_allocations: [{ amount, discount_application_index: 0 }] }],
};
}
async function main() {
const raw = Buffer.from('{"id":10}');
const sig = crypto.createHmac('sha256', 'secret').update(raw).digest('base64');
assert.equal(verifyShopifyHmac(raw, sig, 'secret'), true);
assert.equal(verifyShopifyHmac(raw, 'bad', 'secret'), false);
assert.equal(countDiscountedSamples(order()), 3);
assert.equal(countDiscountedSamples(order({ title: 'DW Free Samples (auto)' })), 3); // title-agnostic now
assert.equal(countDiscountedSamples(order({ amount: '0' })), 0); // undiscounted sample never counts
assert.equal(isApprovedTradeTags('trade, trade_approved'), true);
assert.equal(isApprovedTradeTags('trade, designer'), false);
const calls = [];
const ledger = new SampleUsageLedger(async (query, variables) => {
calls.push({ query, variables });
if (query.includes('query SampleUsageState')) return { order: { counted: null }, customer: { tags: [], used: { value: '1', compareDigest: 'd1' } } };
return { metafieldsSet: { userErrors: [] } };
});
assert.deepEqual(await ledger.process(order()), { status: 'counted', increment: 2, used: 3 });
assert.equal(calls[1].variables.metafields[0].compareDigest, 'd1');
const duplicate = new SampleUsageLedger(async () => ({ order: { counted: { value: 'true' } }, customer: { tags: [], used: { value: '2' } } }));
assert.deepEqual(await duplicate.process(order()), { status: 'duplicate', increment: 0 });
const trade = new SampleUsageLedger(async () => ({ order: { counted: null }, customer: { tags: ['trade_approved'], used: null } }));
assert.deepEqual(await trade.process(order()), { status: 'approved_trade', increment: 0 });
// HTTP integration: raw-body HMAC gate, signed invalid JSON, and signed ignored order.
assert.ok(config.SHOPIFY_SIGNUP_APP_CLIENT_SECRET, 'installed signup app secret must be routed');
const app = require('../server');
const server = app.listen(0, '127.0.0.1');
await new Promise((resolve) => server.once('listening', resolve));
const url = `http://127.0.0.1:${server.address().port}/webhooks/orders-paid`;
async function post(body, signature) {
return fetch(url, { method: 'POST', headers: { 'content-type': 'application/json', 'x-shopify-hmac-sha256': signature }, body });
}
assert.equal((await post('{"id":10}', 'bad')).status, 401);
const broken = Buffer.from('{');
assert.equal((await post(broken, crypto.createHmac('sha256', config.SHOPIFY_SIGNUP_APP_CLIENT_SECRET).update(broken).digest('base64'))).status, 400);
const ignored = Buffer.from('{"id":10,"customer":null}');
const ignoredResponse = await post(ignored, crypto.createHmac('sha256', config.SHOPIFY_SIGNUP_APP_CLIENT_SECRET).update(ignored).digest('base64'));
assert.equal(ignoredResponse.status, 200);
assert.equal((await ignoredResponse.json()).status, 'ignored');
await new Promise((resolve) => server.close(resolve));
console.log('sample-ledger: all checks passed');
}
main().catch((error) => { console.error(error); process.exit(1); });