Skip to content

Commit

Permalink
Update/Fix form-data/x-www-form-urlencoded snippets (#4)
Browse files Browse the repository at this point in the history
* node-axios update application/form-data and x-www-form-urlencoded

* node axios minor touches,
node fetch placeholder path to file

* javascript axios multipart/form-data remove content-type header and handle file param as a file instead of base64

* case-insensitive removeProperty helper(currently used to remove "content-type" header)

* typo

* node-fetch - remove 'content-type' header and add spread formData headers on multipart/form-data

* update js-axios content-type header comment

* reusable params helper - construct params code,
checkIfRequestContainsFile general helper,
use URLSearchParams for x-www-form-urlencoded,
consistent code for node/js axios and fetch

* "encodedParams" also in js axios

* codeBuilder clone,
constructAppendedParamsCode same "append" method + options argument

* new helpers unit tests,
mocharc file(to take only spec files)

* insensitive case property remove test

* use lodash isObject,
check constructAppendedParamsCode test code result string

* constructAppendedParamsCode options argument tests
  • Loading branch information
saharbechor authored Mar 28, 2022
1 parent 6e4a67e commit fbaed97
Show file tree
Hide file tree
Showing 10 changed files with 378 additions and 140 deletions.
10 changes: 10 additions & 0 deletions .mocharc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"diff": true,
"extension": ["js", "cjs", "mjs"],
"package": "./package.json",
"reporter": "spec",
"slow": "75",
"timeout": "2000",
"ui": "bdd",
"spec": "**/*.spec.js"
}
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
},
"scripts": {
"quick": "mocha --no-timeouts --fgrep 'Request Validation' --invert",
"pretest": "standard && echint",
"test": "mocha --no-timeouts",
"posttest": "exit 0 && npm run coverage",
"coverage": "istanbul cover --dir coverage _mocha -- --fgrep 'Request Validation' --invert -R dot",
Expand Down Expand Up @@ -95,4 +94,4 @@
"pinkie-promise": "^2.0.0",
"stringify-object": "^3.3.0"
}
}
}
71 changes: 40 additions & 31 deletions src/helpers/code-builder.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'
"use strict";

const util = require('util')
const { cloneDeep } = require("lodash");
const util = require("util");

/**
* Helper object to format and aggragate lines of code.
Expand All @@ -12,10 +13,10 @@ const util = require('util')
* @param {string} join Desired character to join each line of code
*/
const CodeBuilder = function (indentation, join) {
this.code = []
this.indentation = indentation
this.lineJoin = join || '\n'
}
this.code = [];
this.indentation = indentation;
this.lineJoin = join || "\n";
};

/**
* Add given indentation level to given string and format the string (variadic)
Expand All @@ -37,26 +38,26 @@ const CodeBuilder = function (indentation, join) {
* // returns: 'console.log("\t\thello world")'
*/
CodeBuilder.prototype.buildLine = function (indentationLevel, line) {
let lineIndentation = ''
let slice = 2
if (Object.prototype.toString.call(indentationLevel) === '[object String]') {
slice = 1
line = indentationLevel
indentationLevel = 0
let lineIndentation = "";
let slice = 2;
if (Object.prototype.toString.call(indentationLevel) === "[object String]") {
slice = 1;
line = indentationLevel;
indentationLevel = 0;
} else if (indentationLevel === null) {
return null
return null;
}

while (indentationLevel) {
lineIndentation += this.indentation
indentationLevel--
lineIndentation += this.indentation;
indentationLevel--;
}

const format = Array.prototype.slice.call(arguments, slice, arguments.length)
format.unshift(lineIndentation + line)
const format = Array.prototype.slice.call(arguments, slice, arguments.length);
format.unshift(lineIndentation + line);

return util.format.apply(this, format)
}
return util.format.apply(this, format);
};

/**
* Invoke buildLine() and add the line at the top of current lines
Expand All @@ -65,10 +66,10 @@ CodeBuilder.prototype.buildLine = function (indentationLevel, line) {
* @return {this}
*/
CodeBuilder.prototype.unshift = function () {
this.code.unshift(this.buildLine.apply(this, arguments))
this.code.unshift(this.buildLine.apply(this, arguments));

return this
}
return this;
};

/**
* Invoke buildLine() and add the line at the bottom of current lines
Expand All @@ -77,27 +78,35 @@ CodeBuilder.prototype.unshift = function () {
* @return {this}
*/
CodeBuilder.prototype.push = function () {
this.code.push(this.buildLine.apply(this, arguments))
this.code.push(this.buildLine.apply(this, arguments));

return this
}
return this;
};

/**
* Add an empty line at the end of current lines
* @return {this}
*/
CodeBuilder.prototype.blank = function () {
this.code.push(null)
this.code.push(null);

return this
}
return this;
};

/**
* Concatenate all current lines using the given lineJoin
* @return {string}
*/
CodeBuilder.prototype.join = function () {
return this.code.join(this.lineJoin)
}
return this.code.join(this.lineJoin);
};

module.exports = CodeBuilder
CodeBuilder.prototype.clone = function () {
return cloneDeep(this);
};

CodeBuilder.prototype.getLength = function () {
return this.code.length;
};

module.exports = CodeBuilder;
30 changes: 30 additions & 0 deletions src/helpers/general.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const { omit, isObject } = require("lodash");

module.exports = {
/**
*
* @param {Object} originalObject - The object from which the property needs to be removed
* @param {string} propertyName - The name of the property to remove(case insensitive)
* @returns the object without the property that was asked to remove
*/
removeProperty: (originalObject, propertyName) => {
if (!isObject(originalObject)) {
throw new Error("originalObject must be an object.");
}
const key = Object.keys(originalObject).find(
(key) => key.toLowerCase() === propertyName.toLowerCase()
);
if (key) {
return omit(originalObject, key);
} else {
return originalObject;
}
},

checkIfRequestContainsFile: (request) => {
return (
request.postData.mimeType === "multipart/form-data" &&
request.postData.params.some((param) => param.fileName)
);
},
};
114 changes: 114 additions & 0 deletions src/helpers/helpers.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
const { omit } = require("lodash");
const should = require("should");
const CodeBuilder = require("./code-builder");

const { removeProperty } = require("./general");
const { constructAppendedParamsCode } = require("./params");

describe("Test helpers methods", () => {
describe("Test RemoveProperty helper", () => {
it("RemoveProperty called with invalid params", () => {
(function () {
removeProperty("str", "property");
}.should.throw(new Error("originalObject must be an object.")));
});

it("returned object stayed the same if a non existing property name sent", () => {
const obj = { a: 1, b: 2 };
const result = removeProperty(obj, "c");

result.should.equal(obj);
});

it("insensitive case property removed from object successfully", () => {
const obj = { a: 1, b: 2 };
const result = removeProperty(obj, "B");

result.should.deepEqual(omit(obj, "b"));
});
});

describe("Test constructAppendedParamsCode helper", () => {
const fakeParams = [
{ name: "a", value: "1" },
{ name: "b", value: "2" },
];

it("called with invalid code argument", () => {
(function () {
constructAppendedParamsCode({}, []);
}.should.throw(
new Error("code argument must be an instance of CodeBuilder")
));
});

it("called with invalid params argument", () => {
(function () {
constructAppendedParamsCode(new CodeBuilder(), {});
}.should.throw(new Error("params argument must be an array")));
});

describe("called with multiple options variations", () => {
const fakeParamsWithFile = [
...fakeParams,
{ name: "a", fileName: "fakeFileName" },
];
const lastIndex = params.length - 1;

it("called with file param and false isBrowser option", () => {
const result = constructAppendedParamsCode(
new CodeBuilder(),
fakeParamsWithFile,
{
isBrowser: false,
}
);

result.should.be.an.instanceof(CodeBuilder);
result
.join()
.should.containEql(
`fs.createReadStream("/PATH/TO/${fakeParamsWithFile[lastIndex].fileName}")`
);
});

it("called with file param and true isBrowser option", () => {
const result = constructAppendedParamsCode(
new CodeBuilder(),
fakeParamsWithFile,
{
isBrowser: true,
}
);

result.should.be.an.instanceof(CodeBuilder);
result
.join()
.should.containEql(
`yourAppInput.files[0], ${JSON.stringify(
params[lastIndex].fileName
)}`
);
});

it("called with dataVarName option", () => {
const result = constructAppendedParamsCode(new CodeBuilder(), params, {
dataVarName: "dataObject",
});

result.should.be.an.instanceof(CodeBuilder);
result.join().should.containEql("dataObject.append");
});
});

it("returned new code object with two params", () => {
const result = constructAppendedParamsCode(new CodeBuilder(), fakeParams);

result.should.be.an.instanceof(CodeBuilder);
result.getLength().should.equal(2);
result
.join()
.should.equal('data.append("a", "1");\ndata.append("b", "2");');
});
});
});
52 changes: 52 additions & 0 deletions src/helpers/params.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const { isArray } = require("lodash");

const CodeBuilder = require("./code-builder");

const defaultConstructParamsCodeOptions = {
isBrowser: false,
dataVarName: "data",
};

module.exports = {
/**
*
* @param {CodeBuilder} code - Original codeBuilder instance
* @param {[Object]} params - List of params objects
* * @param {Objects} options
* @param {boolean} options.isBrowser - Boolean indicating if browser or other environment(e.g. node)
* @param {string} options.dataVarName - The data object name
* @returns New code instance with params appended to the supplied data object
*/
constructAppendedParamsCode: (
code,
params = [],
options = defaultConstructParamsCodeOptions
) => {
if (!(code instanceof CodeBuilder)) {
throw new Error("code argument must be an instance of CodeBuilder");
} else if (!isArray(params)) {
throw new Error("params argument must be an array");
}

const { isBrowser = false, dataVarName = "data" } = options;
const newCode = code.clone();

params.forEach(function (param) {
let value =
param.value !== undefined ? JSON.stringify(param.value.toString()) : "";
if (param.fileName) {
value = isBrowser
? `yourAppInput.files[0], ${JSON.stringify(param.fileName)}`
: `fs.createReadStream("/PATH/TO/${param.fileName}")`;
}
newCode.push(
"%s.append(%s, %s);",
dataVarName,
JSON.stringify(param.name),
value
);
});

return newCode;
},
};
Loading

0 comments on commit fbaed97

Please sign in to comment.