Skip to content

Commit

Permalink
Refactoring code to follow Zapier CLI best practices.
Browse files Browse the repository at this point in the history
  • Loading branch information
tech-consortium committed Dec 16, 2023
1 parent ca410ff commit 0e7f8b6
Show file tree
Hide file tree
Showing 5 changed files with 239 additions and 299 deletions.
13 changes: 11 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const {
// Actions

// Searches
const getCaseGoodsLotId =
require('./searches/get_casegoods_lotid');

// Fields
const listWineriesDropdown =
Expand All @@ -20,6 +22,9 @@ const listAnalysisTypesDropdown =
const listDryGoodsDropdown =
require('./fields/list_drygoodtypes_dropdown');

// Creates
const createCaseGoodsAdjustment =
require('./creates/create_casegoods_adjustment');

// Triggers

Expand Down Expand Up @@ -52,10 +57,14 @@ const App = {
},

// If you want your searches to show up, you better include it here!
searches: {},
searches: {
[getCaseGoodsLotId.key]: getCaseGoodsLotId,
},

// If you want your creates to show up, you better include it here!
creates: {},
creates: {
[createCaseGoodsAdjustment.key]: createCaseGoodsAdjustment,
},
};

// Finally, export the app.
Expand Down
81 changes: 81 additions & 0 deletions searches/get_casegoods_lotid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* Retrieves the ID of a case goods lot from the API.
*
* @param {Object} z - The Zapier core object.
* @param {Object} bundle - The Zapier bundle object.
* @return {Promise} - A promise that resolves to an array with the lot ID object.
* @throws {Error} - Throws an error for invalid JSON response or unexpected status codes.
*/
const getCaseGoodsLotId = async (z, bundle) => {
const headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Access-Token ${bundle.authData.accessToken}`,
};

const url = `https://sutter.innovint.us/api/v1/wineries/${bundle.inputData.wineryId}/lots`;
const responseData = await z.request(url, 'GET',
{limit: 1, q: bundle.inputData.caseGoodsName}, headers);

if (responseData) {
if (responseData.status === 200) {
// Check if the responseData.data is undefined (invalid JSON response)
if (!responseData.data) {
throw new Error('Invalid JSON response');
}

// Handle a successful response (HTTP 200)
const lotData = responseData.data.results[0]?.data;
if (lotData && lotData.id) {
return [{id: lotData.id}]; // Return an array with the lot ID object
} else {
throw new Error(
'No lot found with the provided name, or the data structure is unexpected.');
}
} else if (responseData.status === 400) {
// Handle a Bad Request (HTTP 400) response
if (responseData.data && responseData.data.errors &&
responseData.data.errors.length > 0) {
const firstError = responseData.data.errors[0];
const errorMessage = firstError.details || 'Bad Request';
throw new Error(errorMessage);
} else {
throw new Error('Bad Request: The request parameters are invalid.');
}
} else if (responseData.status === 500) {
// Handle a Server Error (HTTP 500) response
if (responseData.data && responseData.data.errors &&
responseData.data.errors.length > 0) {
const firstError = responseData.data.errors[0];
const errorMessage = firstError.details || 'Internal Server Error';
throw new Error(errorMessage);
} else {
throw new Error(
'Internal Server Error: An internal server error occurred.');
}
} else {
// Handle other response status codes if needed
throw new Error(`Request failed with status ${responseData.status}`);
}
} else {
// Handle unexpected response data (null or undefined)
throw new Error('Unexpected response data from the API.');
}
};

module.exports = {
key: 'getCaseGoodsLotId',
noun: 'Lot ID',
display: {
label: 'Get Lot By Case Goods Name',
description: 'Gets a lot ID based on the provided case goods name.',
},
operation: {
perform: getCaseGoodsLotId,
inputFields: [
{key: 'wineryId', required: true, type: 'string'},
{key: 'caseGoodsName', required: true, type: 'string'},
],
sample: {id: 'lot_Z1LPW8OQMY23L6QM3KXJD45Y'},
},
};
71 changes: 0 additions & 71 deletions searches/get_lotid.js

This file was deleted.

147 changes: 147 additions & 0 deletions test/unit/searches/get_casegoods_lotid.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
const zapier = require('zapier-platform-core');
const nock = require('nock');
const should = require('should');
const App = require('../../../index'); // Adjust this path as necessary
/**
* Creates a testing instance for the specified Zapier app.
*
* @param {Object} App - The Zapier app object.
* @returns {Object} - The testing instance for the app.
*/
const appTester = zapier.createAppTester(App);
const {bundle} = require('../../_bundle');

describe('getCaseGoodsLotId', function() {
afterEach(() => {
nock.cleanAll();
});

it('should handle HTTP errors', async () => {
nock(bundle.baseUrl)
.get(`/api/v1/wineries/${bundle.inputData.wineryId}/lots`)
.query(true)
.reply(400, {});

try {
await appTester(App.searches.getCaseGoodsLotId.operation.perform, bundle);
should.fail('No error', 'Error', 'No error was thrown', 'should.fail');
} catch (error) {
const errorObject = JSON.parse(error.message);
should(errorObject.status).be.equal(400);
}
});

it('should fetch the correct Lot ID', async () => {
const lotIdResponse = {
results: [{data: {id: 'lot_Z1LPW8OQMY23L6QM3KXJD45Y'}}], // Mock response structure
};

nock(bundle.baseUrl)
.get(`/api/v1/wineries/${bundle.inputData.wineryId}/lots`)
.query(true)
.reply(200, lotIdResponse);

const result = await appTester(
App.searches.getCaseGoodsLotId.operation.perform, bundle);
should(result[0]).have.property('id', 'lot_Z1LPW8OQMY23L6QM3KXJD45Y'); // Check the first element of the array
});

it('should throw an error if no lot is found', async () => {
nock(bundle.baseUrl)
.get(`/api/v1/wineries/${bundle.inputData.wineryId}/lots`)
.query(true)
.reply(200,
{results: [], pagination: {count: 0, next: null, previous: null}});

try {
await appTester(App.searches.getCaseGoodsLotId.operation.perform, bundle);
should.fail('No error', 'Error', 'No error was thrown', 'should.fail');
} catch (error) {
error.message.should.containEql(
'No lot found with the provided name, or the data structure is unexpected.');
}
});

it('should handle HTTP 400 Bad Request errors', async () => {
nock(bundle.baseUrl)
.get(`/api/v1/wineries/${bundle.inputData.wineryId}/lots`)
.query(true)
.reply(400, {
errors: [{details: 'Invalid input data'}],
});

try {
await appTester(App.searches.getCaseGoodsLotId.operation.perform, bundle);
should.fail('No error', 'Error', 'No error was thrown', 'should.fail');
} catch (error) {
try {
const errorContent = JSON.parse(error.message).content;
const errorObject = JSON.parse(errorContent);
should.exist(errorObject); // Ensure errorObject is not null or undefined
should(errorObject.errors[0].details).be.equal('Invalid input data');
} catch (parseError) {
should.fail('Error parsing JSON response', 'Error', parseError.message,
'should.fail');
}
}
});

it('should handle HTTP 500 Internal Server Error', async () => {
nock(bundle.baseUrl)
.get(`/api/v1/wineries/${bundle.inputData.wineryId}/lots`)
.query(true)
.reply(500, {
errors: [{details: 'Internal server error'}],
});

try {
await appTester(App.searches.getCaseGoodsLotId.operation.perform, bundle);
should.fail('No error', 'Error', 'No error was thrown', 'should.fail');
} catch (error) {
try {
const errorContent = JSON.parse(error.message).content;
const errorObject = JSON.parse(errorContent);
should.exist(errorObject); // Ensure errorObject is not null or undefined
should(errorObject.errors[0].details).be.equal('Internal server error');
} catch (parseError) {
should.fail('Error parsing JSON response', 'Error', parseError.message,
'should.fail');
}
}
});

it('should handle invalid JSON responses', async () => {
nock(bundle.baseUrl)
.get(`/api/v1/wineries/${bundle.inputData.wineryId}/lots`)
.query(true)
.reply(200, 'This is not JSON');

try {
await appTester(App.searches.getCaseGoodsLotId.operation.perform, bundle);
should.fail('No error', 'Error', 'Expected an invalid JSON error',
'should.fail');
} catch (error) {
should(error.message).containEql('Invalid JSON response');
}
});

it('should handle invalid input data', async function() {
// Modify the bundle to simulate invalid input
const invalidBundle = {
...bundle,
inputData: {
wineryId: 'invalid-id',
caseGoodsName: 'InvalidName',
},
};

try {
await appTester(App.searches.getCaseGoodsLotId.operation.perform,
invalidBundle);
should.fail('No error', 'Error', 'Expected an invalid input error',
'should.fail');
} catch (error) {
should(error.message).containEql('Innovint server error!');
}
});
});
Loading

0 comments on commit 0e7f8b6

Please sign in to comment.