edx-ui-toolkit
Advanced tools
Comparing version 1.2.0 to 1.3.0
# Changelog | ||
## 1.3.0 (2016-06-21) | ||
* Extend AjaxHelpers with capabilities from edx-platform | ||
- - - | ||
## 1.2.0 (2016-06-14) | ||
@@ -4,0 +9,0 @@ * In dropdown menu component icons switched to Font Awesome for accessibility |
{ | ||
"name": "edx-ui-toolkit", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "A JavaScript toolkit for building edX user interfaces", | ||
@@ -5,0 +5,0 @@ "license": "Apache-2.0", |
@@ -18,20 +18,90 @@ /** | ||
var fakeRequests, expectRequest, expectJsonRequest, expectPostRequest, expectRequestURL, | ||
respondWithJson, respondWithError, respondWithTextError, respondWithNoContent; | ||
var XHR_READY_STATES, fakeServer, createFakeRequests, withFakeRequests, fakeRequests, currentRequest, | ||
expectRequest, expectNoRequests, expectJsonRequest, expectPostRequest, expectRequestURL, skipResetRequest, | ||
respond, respondWithJson, respondWithError, respondWithTextError, respondWithNoContent; | ||
/** | ||
* Keep track of all requests to a fake server, and call `spec` | ||
* with a reference to the server. Allows tests to respond to | ||
* individual requests. | ||
* An enumeration of valid XHR ready states. | ||
*/ | ||
fakeRequests = function (spec) { | ||
return function () { | ||
var requests = [], | ||
xhr = sinon.useFakeXMLHttpRequest(), | ||
XHR_READY_STATES = { | ||
UNSENT: 0, | ||
OPENED: 1, | ||
LOADING: 3, | ||
DONE: 4 | ||
}; | ||
/* These utility methods are used by Jasmine tests to create a mock server or | ||
* get reference to mock requests. In either case, the cleanup (restore) is done with | ||
* an after function. | ||
* | ||
* This pattern is being used instead of the more common beforeEach/afterEach pattern | ||
* because we were seeing sporadic failures in the afterEach restore call. The cause of the | ||
* errors were that one test suite was incorrectly being linked as the parent of an unrelated | ||
* test suite (causing both suites' afterEach methods to be called). No solution for the root | ||
* cause has been found, but initializing sinon and cleaning it up on a method-by-method | ||
* basis seems to work. For more details, see STUD-1264. | ||
*/ | ||
/** | ||
* Get a reference to the mocked server, and respond to all requests | ||
* with the specified response. | ||
* | ||
* @param {string} response the fake response. | ||
* @returns {*} The current request. | ||
*/ | ||
fakeServer = function(response) { | ||
var server = sinon.fakeServer.create(); | ||
afterEach(function() { | ||
if (server) { | ||
server.restore(); | ||
} | ||
}); | ||
server.respondWith(response); | ||
return server; | ||
}; | ||
createFakeRequests = function() { | ||
var requests = [], | ||
xhr = sinon.useFakeXMLHttpRequest(); | ||
requests.currentIndex = 0; | ||
requests.restore = function() { | ||
if (xhr && xhr.hasOwnProperty('restore')) { | ||
xhr.restore(); | ||
} | ||
}; | ||
xhr.onCreate = function(request) { | ||
requests.push(request); | ||
}; | ||
return requests; | ||
}; | ||
/** | ||
* Keep track of all requests to a fake server, and return a reference to the Array. | ||
* This allows tests to respond to individual requests. | ||
* | ||
* @returns {Array} An array tracking the fake requests. | ||
*/ | ||
fakeRequests = function() { | ||
var requests = createFakeRequests(); | ||
afterEach(function() { | ||
requests.restore(); | ||
}); | ||
return requests; | ||
}; | ||
/** | ||
* Wraps a test function so that it is invoked with an additional parameter | ||
* containing an array of fake HTTP requests. | ||
* | ||
* @param {function} test A function to be invoked with the fake requests. | ||
* @returns {function} A wrapped version of the input function. | ||
*/ | ||
withFakeRequests = function(test) { | ||
return function() { | ||
var requests = createFakeRequests(), | ||
args = Array.prototype.slice.call(arguments); | ||
xhr.onCreate = function(request) { | ||
requests.push(request); | ||
}; | ||
spec.apply(null, args.concat([requests])); | ||
xhr.restore(); | ||
test.apply(null, args.concat([requests])); | ||
requests.restore(); | ||
}; | ||
@@ -41,20 +111,31 @@ }; | ||
/** | ||
* Returns the request that has not yet been responded to. If no such request | ||
* is available then the current test will fail. | ||
* | ||
* @param {object} requests an array of fired sinon requests | ||
* @returns {*} The current request. | ||
*/ | ||
currentRequest = function(requests) { | ||
expect(requests.length).toBeGreaterThan(requests.currentIndex); | ||
return requests[requests.currentIndex]; | ||
}; | ||
/** | ||
* Expect that a request was made as expected. | ||
* | ||
* @param requests an array of fired sinon requests | ||
* @param method the expected method of the request | ||
* @param url the expected url of the request | ||
* @param body the expected request body | ||
* @param requestIndex the expected index of the request in the | ||
* array (higher indices occur later). Defaults to | ||
* requests.length - 1. | ||
* @param {object} requests an array of fired sinon requests | ||
* @param {string} method the expected method of the request | ||
* @param {string} url the expected url of the request | ||
* @param {string} body the expected request body | ||
*/ | ||
expectRequest = function(requests, method, url, body, requestIndex) { | ||
var request; | ||
if (_.isUndefined(requestIndex)) { | ||
requestIndex = requests.length - 1; | ||
} | ||
request = requests[requestIndex]; | ||
expectRequest = function(requests, method, url, body) { | ||
var request = currentRequest(requests); | ||
expect(request.readyState).toEqual(XHR_READY_STATES.OPENED); | ||
expect(request.url).toEqual(url); | ||
expect(request.method).toEqual(method); | ||
if (typeof body === 'undefined') { | ||
// The body of the request may not be germane to the current test, | ||
// such as a call by a library, so allow it to be ignored. | ||
return; | ||
} | ||
expect(request.requestBody).toEqual(body); | ||
@@ -64,21 +145,24 @@ }; | ||
/** | ||
* Verifies that there are no unconsumed requests. | ||
* | ||
* @param {object} requests an array of fired sinon requests | ||
*/ | ||
expectNoRequests = function(requests) { | ||
expect(requests.length).toEqual(requests.currentIndex); | ||
}; | ||
/** | ||
* Expect that a request with a JSON payload was made as expected. | ||
* | ||
* @param requests an array of fired sinon requests | ||
* @param method the expected method of the request | ||
* @param url the expected url of the request | ||
* @param jsonBody the expected request body as an object | ||
* @param requestIndex the expected index of the request in the | ||
* array (higher indices occur later). Defaults to | ||
* requests.length - 1. | ||
* @param {object} requests an array of fired sinon requests | ||
* @param {string} method the expected method of the request | ||
* @param {string} url the expected url of the request | ||
* @param {object} jsonRequest the expected request body as an object | ||
*/ | ||
expectJsonRequest = function(requests, method, url, jsonBody, requestIndex) { | ||
var request; | ||
if (_.isUndefined(requestIndex)) { | ||
requestIndex = requests.length - 1; | ||
} | ||
request = requests[requestIndex]; | ||
expectJsonRequest = function(requests, method, url, jsonRequest) { | ||
var request = currentRequest(requests); | ||
expect(request.readyState).toEqual(XHR_READY_STATES.OPENED); | ||
expect(request.url).toEqual(url); | ||
expect(request.method).toEqual(method); | ||
expect(JSON.parse(request.requestBody)).toEqual(jsonBody); | ||
expect(JSON.parse(request.requestBody)).toEqual(jsonRequest === undefined ? null : jsonRequest); | ||
}; | ||
@@ -89,13 +173,9 @@ | ||
* | ||
* @param requests The collected requests | ||
* @param expectedUrl The expected URL excluding the parameters | ||
* @param expectedParameters An object representing the URL parameters | ||
* @param requestIndex An optional index for the request (by default, the last request is used) | ||
* @param {object} requests The collected requests | ||
* @param {string} expectedUrl The expected URL excluding the parameters | ||
* @param {object} expectedParameters An object representing the URL parameters | ||
*/ | ||
expectRequestURL = function(requests, expectedUrl, expectedParameters, requestIndex) { | ||
var request, parameters; | ||
if (_.isUndefined(requestIndex)) { | ||
requestIndex = requests.length - 1; | ||
} | ||
request = requests[requestIndex]; | ||
expectRequestURL = function(requests, expectedUrl, expectedParameters) { | ||
var request = currentRequest(requests), | ||
parameters; | ||
expect(new URI(request.url).path()).toEqual(expectedUrl); | ||
@@ -108,18 +188,11 @@ parameters = new URI(request.url).query(true); | ||
/** | ||
* Intended for use with POST requests using | ||
* application/x-www-form-urlencoded. | ||
* Intended for use with POST requests using application/x-www-form-urlencoded. | ||
* | ||
* @param requests an array of fired sinon requests | ||
* @param url the expected url of the request | ||
* @param body the expected body of the request | ||
* @param requestIndex the expected index of the request in the | ||
* array (higher indices occur later). Defaults to | ||
* requests.length - 1. | ||
* @param {object} requests an array of fired sinon requests | ||
* @param {string} url the expected url of the request | ||
* @param {string} body the expected body of the request | ||
*/ | ||
expectPostRequest = function(requests, url, body, requestIndex) { | ||
var request; | ||
if (_.isUndefined(requestIndex)) { | ||
requestIndex = requests.length - 1; | ||
} | ||
request = requests[requestIndex]; | ||
expectPostRequest = function(requests, url, body) { | ||
var request = currentRequest(requests); | ||
expect(request.readyState).toEqual(XHR_READY_STATES.OPENED); | ||
expect(request.url).toEqual(url); | ||
@@ -131,17 +204,48 @@ expect(request.method).toEqual('POST'); | ||
/** | ||
* Verify that the HTTP request was marked as reset, and then skip it. | ||
* | ||
* Note: this is typically used when code has explicitly canceled a request | ||
* after it has been sent. A good example is when a user chooses to cancel | ||
* a slow running search. | ||
* @param {object} requests an array of fired sinon requests | ||
*/ | ||
skipResetRequest = function(requests) { | ||
var request = currentRequest(requests); | ||
expect(request.readyState).toEqual(XHR_READY_STATES.UNSENT); | ||
requests.currentIndex++; | ||
}; | ||
/** | ||
* Respond to a server request with a set of options: | ||
* | ||
* - `statusCode`: the status code to be returned (defaults to 200) | ||
* - `contentType`: the content type of the response (defaults to 'application/json') | ||
* - `body`: the body of the response (if JSON, it will be converted to a string) | ||
* | ||
* @param {object} requests an array of fired sinon requests | ||
* @param {object} options the options to provide to the response | ||
*/ | ||
respond = function(requests, options) { | ||
var request = currentRequest(requests), | ||
statusCode = options.statusCode || 200, | ||
contentType = options.contentType || 'application/json', | ||
body = options.body || ''; | ||
request.respond(statusCode, | ||
{'Content-Type': contentType}, | ||
contentType === 'application/json' ? JSON.stringify(body || {}) : body | ||
); | ||
requests.currentIndex++; | ||
}; | ||
/** | ||
* Respond to a request with JSON. | ||
* | ||
* @param requests an array of fired sinon requests | ||
* @param jsonResponse an object to be serialized to the response | ||
* @param requestIndex the expected index of the request in the | ||
* array (higher indices occur later). Defaults to | ||
* requests.length - 1. | ||
* @param {object} requests an array of fired sinon requests | ||
* @param {object} body an object to be serialized to the response | ||
*/ | ||
respondWithJson = function(requests, jsonResponse, requestIndex) { | ||
if (_.isUndefined(requestIndex)) { | ||
requestIndex = requests.length - 1; | ||
} | ||
requests[requestIndex].respond(200, | ||
{ 'Content-Type': 'application/json' }, | ||
JSON.stringify(jsonResponse)); | ||
respondWithJson = function(requests, body) { | ||
respond(requests, { | ||
body: body | ||
}); | ||
}; | ||
@@ -153,24 +257,12 @@ | ||
* | ||
* @param requests an array of fired sinon requests | ||
* @param statusCode the HTTP status code of the response | ||
* @param {object} requests an array of fired sinon requests | ||
* @param {int} statusCode the HTTP status code of the response | ||
* (defaults to 500) | ||
* @param jsonResponse an object to be serialized to the response | ||
* @param requestIndex the expected index of the request in the | ||
* array (higher indices occur later). Defaults to | ||
* requests.length - 1. | ||
* @param {object} body an object to be serialized to the response | ||
*/ | ||
respondWithError = function(requests, statusCode, jsonResponse, requestIndex) { | ||
if (_.isUndefined(requestIndex)) { | ||
requestIndex = requests.length - 1; | ||
} | ||
if (_.isUndefined(statusCode)) { | ||
statusCode = 500; | ||
} | ||
if (_.isUndefined(jsonResponse)) { | ||
jsonResponse = {}; | ||
} | ||
requests[requestIndex].respond(statusCode, | ||
{ 'Content-Type': 'application/json' }, | ||
JSON.stringify(jsonResponse) | ||
); | ||
respondWithError = function(requests, statusCode, body) { | ||
respond(requests, { | ||
statusCode: statusCode || 500, | ||
body: body | ||
}); | ||
}; | ||
@@ -181,24 +273,13 @@ | ||
* | ||
* @param requests an array of fired sinon requests | ||
* @param statusCode the HTTP status code of the response | ||
* @param {object} requests an array of fired sinon requests | ||
* @param {int} statusCode the HTTP status code of the response | ||
* (defaults to 500) | ||
* @param textResponse the response body as a string | ||
* @param requestIndex the expected index of the request in the | ||
* array (higher indices occur later). Defaults to | ||
* requests.length - 1. | ||
* @param {object} body the response body as a string | ||
*/ | ||
respondWithTextError = function(requests, statusCode, textResponse, requestIndex) { | ||
if (_.isUndefined(requestIndex)) { | ||
requestIndex = requests.length - 1; | ||
} | ||
if (_.isUndefined(statusCode)) { | ||
statusCode = 500; | ||
} | ||
if (_.isUndefined(textResponse)) { | ||
textResponse = ''; | ||
} | ||
requests[requestIndex].respond(statusCode, | ||
{ 'Content-Type': 'text/plain' }, | ||
textResponse | ||
); | ||
respondWithTextError = function(requests, statusCode, body) { | ||
respond(requests, { | ||
statusCode: statusCode || 500, | ||
contentType: 'text/plain', | ||
body: body | ||
}); | ||
}; | ||
@@ -209,21 +290,22 @@ | ||
* | ||
* @param requests an array of fired sinon requests | ||
* @param requestIndex the expected index of the request in the | ||
* array (higher indices occur later). Defaults to | ||
* requests.length - 1. | ||
* @param {object} requests an array of fired sinon requests | ||
*/ | ||
respondWithNoContent = function(requests, requestIndex) { | ||
if (_.isUndefined(requestIndex)) { | ||
requestIndex = requests.length - 1; | ||
} | ||
requests[requestIndex].respond(204, | ||
{ 'Content-Type': 'application/json' }); | ||
respondWithNoContent = function(requests) { | ||
respond(requests, { | ||
statusCode: 204 | ||
}); | ||
}; | ||
return { | ||
server: fakeServer, | ||
requests: fakeRequests, | ||
withFakeRequests: withFakeRequests, | ||
currentRequest: currentRequest, | ||
expectRequest: expectRequest, | ||
expectNoRequests: expectNoRequests, | ||
expectJsonRequest: expectJsonRequest, | ||
expectPostRequest: expectPostRequest, | ||
expectRequestURL: expectRequestURL, | ||
skipResetRequest: skipResetRequest, | ||
respond: respond, | ||
respondWithJson: respondWithJson, | ||
@@ -230,0 +312,0 @@ respondWithError: respondWithError, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 21 instances in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
4865654
173
51225
1
22