Skip to content

Commit 27cc24b

Browse files
committed
refactor(idevaffiliate): refactor to ease tests and understanding
1 parent 2595d75 commit 27cc24b

File tree

4 files changed

+100
-62
lines changed

4 files changed

+100
-62
lines changed

src/foxy/FoxyWebhook.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ function validFoxyRequest(requestEvent) {
185185
try {
186186
JSON.parse(requestEvent.body);
187187
} catch (e) {
188-
console.log('body' , requestEvent.body);
189188
err = 'Payload is not valid JSON.';
190189
}
191190
return err;

src/functions/cart/cart.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,10 @@ cartRouter.get(
184184
return;
185185
}
186186
setup();
187-
if (!req.params.cartId) {
188-
throw createError(400, `cartId not found.`);
189-
}
187+
// This code is never executed
188+
//if (!req.params.cartId) {
189+
// throw createError(400, `cartId not found.`);
190+
//}
190191
await getCart(req.params.cartId)
191192
.then(async (cart) => {
192193
if (!validateCart(cart)) {

src/functions/idevaffiliate-marketplace/idevaffiliate-marketplace.js

Lines changed: 47 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,92 +4,89 @@ const fetch = require("node-fetch");
44
const FoxyWebhook = require("../../foxy/FoxyWebhook.js");
55

66
const { URLSearchParams } = require("url");
7-
const { FoxyApi } = require("@foxy.io/node-api");
8-
97

108
const idevApiUrl = config.idevAffiliate.apiUrl || "";
119
const idevSecretKey = config.idevAffiliate.secretKey || "";
1210
const foxyWebhookEncryptionKey = config.foxy.webhook.encryptionKey || "";
1311

14-
const getFoxyApi = () => new FoxyApi();
15-
1612
const getAffiliateIdFromProduct = (productCode) => {
17-
if (productCode.match(/\-a(\d+)$/i)) {
18-
return productCode.match(/\-a(\d+)$/i)[1];
19-
}
20-
return null;
13+
const m = productCode.match(/-a(\d+)$/i)
14+
return m ? m[1] : null;
2115
};
2216

2317
// TODO: Use this method instead of just referencing the `price`,
2418
// as `price` doesn't include discounts, modifiers, coupons, etc.
2519
const getProductNetPrice = (productCode, webhook) => {};
2620

27-
const pushToIdev = async (item, webhook) => {
21+
/**
22+
* Push a single item to Idev affiliate
23+
*
24+
* @param {Object} item to be pushed
25+
* @param {string|number} webhookId the id of the webhook.
26+
* @returns {Promise} that resolves to the response of the posting to Idev.
27+
*/
28+
function pushToIdev (item, webhookId) {
2829
if (!item.name || !item.code || !item.price) {
2930
return false;
3031
}
3132
const params = new URLSearchParams();
3233
params.append("affiliate_id", getAffiliateIdFromProduct(item.code));
3334
params.append("idev_saleamt", item.price);
34-
params.append("idev_ordernum", webhook.id);
35+
params.append("idev_ordernum", webhookId);
3536
// TODO: Check an existing attribute to see if this has already been done.
3637
// Upsert a Foxy API attribute on the product after pushing so it's not duplicated
3738
// with a re-run of the webhook.
3839
return fetch(idevApiUrl, {
39-
method: "POST",
4040
body: params,
41+
method: "POST",
4142
});
42-
};
43+
}
4344

44-
const processTransaction = async (message) => {
45-
const promises = [];
46-
try {
47-
for (let i = 0; i < message._embedded["fx:items"].length; i++) {
48-
const item = message._embedded["fx:items"][i];
49-
promises.push(pushToIdev(item, message));
50-
}
51-
} catch (error) {
52-
console.log("ERROR in processTransaction:", error);
53-
console.log(message);
54-
}
55-
return Promise.all(promises);
56-
};
45+
/**
46+
* Processes all transactions within a message.
47+
*
48+
* @param {Object} message to be processed
49+
* @returns {Promise} that resolves to the completion of the processes of all
50+
* transactions.
51+
*/
52+
async function processTransaction (message) {
53+
return Promise.all(message._embedded["fx:items"]
54+
.map(i => pushToIdev(i, message.id))
55+
);
56+
}
5757

5858
/**
5959
* Verifies the request as a valid Foxy webhook.
6060
* @param (string) - The message payload, described here: https://wiki.foxycart.com/v/2.0/webhooks#example_payload
6161
*/
62-
63-
exports.handler = async (event, context) => {
64-
const foxy = getFoxyApi();
65-
const err = FoxyWebhook.validFoxyRequest(event);
62+
exports.handler = async (requestEvent) => {
63+
const err = FoxyWebhook.validFoxyRequest(requestEvent);
6664
if (err) {
67-
return FoxyWebhook.response(err);
65+
return FoxyWebhook.response(err, 400);
6866
}
69-
const payload = JSON.parse(event.body);
67+
const payload = JSON.parse(requestEvent.body);
7068
// Make sure everything looks ok
69+
if (requestEvent.headers["foxy-webhook-event"] !== "transaction/created") {
70+
return FoxyWebhook.response('Unsupported event.', 501);
71+
}
7172
if (
72-
event.headers["foxy-webhook-event"] !== "transaction/created" ||
7373
!payload._embedded ||
7474
!payload._embedded["fx:items"] ||
7575
!payload._embedded["fx:items"].length > 0
7676
) {
77-
return FoxyWebhook.response("Invalid payload.");
77+
return FoxyWebhook.response("Invalid payload.", 400);
7878
}
79-
return processTransaction(payload)
80-
.then((data) => {
81-
return {
82-
statusCode: 200,
83-
body: JSON.stringify({ message: "success." }),
84-
};
85-
})
86-
.catch((err) => {
87-
console.log("ERROR:");
88-
console.log(err);
89-
console.log(payload);
90-
return {
91-
statusCode: 400,
92-
body: JSON.stringify({ message: "error. check logs." }),
93-
};
94-
});
95-
};
79+
try {
80+
await processTransaction(payload);
81+
return {
82+
body: JSON.stringify({ message: "success." }),
83+
statusCode: 200,
84+
};
85+
} catch (e) {
86+
console.error("ERROR:", err);
87+
return {
88+
body: JSON.stringify({ message: "error. check logs." }),
89+
statusCode: 400,
90+
};
91+
}
92+
}
Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
const { after, afterEach, before, beforeEach, describe, it } = require("mocha");
22
const {expect} = require("chai");
33
const rewire = require("rewire");
4+
const MockFoxyRequests = require("../../MockFoxyRequests.js");
45

56

67
const chaiHttp = require('chai-http');
7-
const handler = rewire('../../../src/functions/idevaffiliate-marketplace/idevaffiliate-marketplace.js');
8-
const config = handler.__get__('config');
8+
const IdevAffiliate = rewire('../../../src/functions/idevaffiliate-marketplace/idevaffiliate-marketplace.js');
9+
const config = IdevAffiliate.__get__('config');
910

10-
11-
12-
function setConfig() {
13-
}
11+
let sentRequests = [];
12+
IdevAffiliate.__set__('fetch', function () {
13+
sentRequests.push(arguments);
14+
});
1415

1516
describe("Idev Affiliate", function() {
1617

@@ -20,9 +21,49 @@ describe("Idev Affiliate", function() {
2021
}
2122
);
2223

23-
it ("Should require Foxy Client Id", async function () {
24-
expect(async () => {await handler({})}).to.throw;
24+
beforeEach(
25+
function () {
26+
sentRequests = [];
27+
}
28+
);
29+
30+
it ("Should validate requests", async function () {
31+
const response = await IdevAffiliate.handler({});
32+
expect(response.statusCode).to.equal(400);
33+
expect(JSON.parse(response.body).details).to.equal("Payload is not valid JSON.");
2534
});
2635

36+
it ("Should inform of unsupported evets", async function () {
37+
const request = MockFoxyRequests.validRequest();
38+
request.headers['foxy-webhook-event'] = 'validation/payment';
39+
const response = await IdevAffiliate.handler(request);
40+
expect(response.statusCode).to.equal(501);
41+
expect(JSON.parse(response.body).details).to.equal("Unsupported event.");
42+
});
43+
44+
it ("Should send items to Idev Affiliate", async function () {
45+
const request = MockFoxyRequests.validRequest({
46+
_embedded: {
47+
'fx:items': [
48+
{code: 'foo', name: 'foo', price: 1},
49+
{code: 'bar', name: 'bar', price: 2},
50+
]
51+
}
52+
});
53+
request.headers['foxy-webhook-event'] = 'transaction/created';
54+
const response = await IdevAffiliate.handler(request);
55+
expect(sentRequests.map(i => i[1].body)
56+
.every(i => i.has('affiliate_id') &&
57+
i.has('idev_saleamt') &&
58+
i.has('idev_ordernum')
59+
)).to.be.true;
60+
expect(response.statusCode).to.equal(200);
61+
});
62+
63+
64+
65+
66+
67+
2768

2869
});

0 commit comments

Comments
 (0)