Use the UI Toolkit's spec helpers.

This commit is contained in:
Andy Armstrong
2016-04-20 23:43:11 -04:00
parent cae69f9600
commit d462c73fd8
109 changed files with 678 additions and 892 deletions

View File

@@ -3,7 +3,7 @@ define([
'backbone',
'underscore',
'edx-ui-toolkit/js/pagination/paging-collection',
'common/js/spec_helpers/ajax_helpers',
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers',
'common/js/components/views/paginated_view'
], function ($, Backbone, _, PagingCollection, AjaxHelpers, PaginatedView) {
'use strict';

View File

@@ -3,7 +3,7 @@ define([
'URI',
'underscore',
'edx-ui-toolkit/js/pagination/paging-collection',
'common/js/spec_helpers/ajax_helpers',
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers',
'common/js/components/views/paging_footer'
], function ($, URI, _, PagingCollection, AjaxHelpers, PagingFooter) {
'use strict';

View File

@@ -1,17 +1,17 @@
define([
'underscore',
'URI',
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers',
'edx-ui-toolkit/js/pagination/paging-collection',
'common/js/components/views/search_field',
'common/js/spec_helpers/ajax_helpers'
], function (_, URI, PagingCollection, SearchFieldView, AjaxHelpers) {
'common/js/components/views/search_field'
], function(_, URI, AjaxHelpers, PagingCollection, SearchFieldView) {
'use strict';
describe('SearchFieldView', function () {
describe('SearchFieldView', function() {
var searchFieldView,
mockUrl = '/api/mock_collection';
var newCollection = function (size, perPage) {
var results = _.map(_.range(size), function (i) { return {foo: i}; });
var newCollection = function(size, perPage) {
var results = _.map(_.range(size), function(i) { return {foo: i}; });
var TestPagingCollection = PagingCollection.extend({
state: {
pageSize: 5
@@ -29,7 +29,7 @@ define([
return collection;
};
var createSearchFieldView = function (options) {
var createSearchFieldView = function(options) {
options = _.extend(
{
type: 'test',
@@ -41,14 +41,14 @@ define([
return new SearchFieldView(options);
};
var assertQueryParams = function (request, expectedParameters) {
var assertQueryParams = function(request, expectedParameters) {
var urlParams = new URI(request.url).query(true);
_.each(expectedParameters, function (value, key) {
_.each(expectedParameters, function(value, key) {
expect(urlParams[key]).toBe(value);
});
};
var assertNotInQueryParams = function (request, param) {
var assertNotInQueryParams = function(request, param) {
var urlParams = new URI(request.url).query(true);
return !urlParams.hasOwnProperty(param);
};
@@ -57,20 +57,20 @@ define([
setFixtures('<section class="test-search"></section>');
});
it('correctly displays itself', function () {
it('correctly displays itself', function() {
searchFieldView = createSearchFieldView().render();
expect(searchFieldView.$('.search-field').val(), '');
expect(searchFieldView.$('.action-clear')).toHaveClass('is-hidden');
});
it('can display with an initial search string', function () {
it('can display with an initial search string', function() {
searchFieldView = createSearchFieldView({
searchString: 'foo'
}).render();
expect(searchFieldView.$('.search-field').val(), 'foo');
});
it('refreshes the collection when performing a search', function () {
it('refreshes the collection when performing a search', function() {
var requests = AjaxHelpers.requests(this);
searchFieldView = createSearchFieldView().render();
searchFieldView.$('.search-field').val('foo');
@@ -80,7 +80,7 @@ define([
page_size: '5',
text_search: 'foo'
});
AjaxHelpers.respondWithJson(requests, {
count: 10,
page: 1,
@@ -90,7 +90,7 @@ define([
expect(searchFieldView.$('.search-field').val(), 'foo');
});
it('can clear the search', function () {
it('can clear the search', function() {
var requests = AjaxHelpers.requests(this);
searchFieldView = createSearchFieldView({
searchString: 'foo'

View File

@@ -1,207 +0,0 @@
define(['sinon', 'underscore', 'URI'], function(sinon, _, URI) {
'use strict';
var XML_HTTP_READY_STATES, fakeServer, fakeRequests, currentRequest, expectRequest, expectNoRequests,
expectJsonRequest, expectPostRequest, expectRequestURL, skipResetRequest,
respondWithJson, respondWithError, respondWithTextError, respondWithNoContent;
XML_HTTP_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 statusCode.
*/
fakeServer = function (response) {
var server = sinon.fakeServer.create();
afterEach(function() {
if (server) {
server.restore();
}
});
server.respondWith(response);
return server;
};
/**
* Keep track of all requests to a fake server, and
* return a reference to the Array. This allows tests
* to respond for individual requests.
*/
fakeRequests = function () {
var requests = [],
xhr = sinon.useFakeXMLHttpRequest();
requests.currentIndex = 0;
xhr.onCreate = function(request) {
requests.push(request);
};
afterEach(function() {
if (xhr && xhr.hasOwnProperty('restore')) {
xhr.restore();
}
});
return requests;
};
/**
* Returns the request that has not yet been responded to. If no such request
* is available then the current test will fail.
* @param requests The Sinon requests list.
* @returns {*} The current request.
*/
currentRequest = function(requests) {
expect(requests.length).toBeGreaterThan(requests.currentIndex);
return requests[requests.currentIndex];
};
expectRequest = function(requests, method, url, body) {
var request = currentRequest(requests);
expect(request.readyState).toEqual(XML_HTTP_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-- like some call by a library,
// so allow it to be ignored.
return;
}
expect(request.requestBody).toEqual(body);
};
/**
* Verifies the there are no unconsumed requests.
*/
expectNoRequests = function(requests) {
expect(requests.length).toEqual(requests.currentIndex);
};
expectJsonRequest = function(requests, method, url, jsonRequest) {
jsonRequest = jsonRequest || null;
var request = currentRequest(requests);
expect(request.readyState).toEqual(XML_HTTP_READY_STATES.OPENED);
expect(request.url).toEqual(url);
expect(request.method).toEqual(method);
expect(JSON.parse(request.requestBody)).toEqual(jsonRequest === undefined ? null : jsonRequest);
};
/**
* Expect that a JSON request be made with the given URL and parameters.
* @param requests The collected requests
* @param expectedUrl The expected URL excluding the parameters
* @param expectedParameters An object representing the URL parameters
*/
expectRequestURL = function(requests, expectedUrl, expectedParameters) {
var request = currentRequest(requests),
parameters;
expect(new URI(request.url).path()).toEqual(expectedUrl);
parameters = new URI(request.url).query(true);
delete parameters._; // Ignore the cache-busting argument
expect(parameters).toEqual(expectedParameters);
};
/**
* Intended for use with POST requests using application/x-www-form-urlencoded.
*/
expectPostRequest = function(requests, url, body) {
var request = currentRequest(requests);
expect(request.readyState).toEqual(XML_HTTP_READY_STATES.OPENED);
expect(request.url).toEqual(url);
expect(request.method).toEqual("POST");
expect(_.difference(request.requestBody.split('&'), body.split('&'))).toEqual([]);
};
/**
* 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.
*/
skipResetRequest = function(requests) {
var request = currentRequest(requests);
expect(request.readyState).toEqual(XML_HTTP_READY_STATES.UNSENT);
requests.currentIndex++;
};
respondWithJson = function(requests, jsonResponse) {
var request = currentRequest(requests);
request.respond(200,
{ 'Content-Type': 'application/json' },
JSON.stringify(jsonResponse));
requests.currentIndex++;
};
respondWithError = function(requests, statusCode, jsonResponse) {
var request = currentRequest(requests);
if (_.isUndefined(statusCode)) {
statusCode = 500;
}
if (_.isUndefined(jsonResponse)) {
jsonResponse = {};
}
request.respond(
statusCode,
{ 'Content-Type': 'application/json' },
JSON.stringify(jsonResponse)
);
requests.currentIndex++;
};
respondWithTextError = function(requests, statusCode, textResponse) {
var request = currentRequest(requests);
if (_.isUndefined(statusCode)) {
statusCode = 500;
}
if (_.isUndefined(textResponse)) {
textResponse = "";
}
request.respond(
statusCode,
{ 'Content-Type': 'text/plain' },
textResponse
);
requests.currentIndex++;
};
respondWithNoContent = function(requests) {
var request = currentRequest(requests);
request.respond(
204,
{ 'Content-Type': 'application/json' }
);
requests.currentIndex++;
};
return {
server: fakeServer,
requests: fakeRequests,
currentRequest: currentRequest,
expectRequest: expectRequest,
expectNoRequests: expectNoRequests,
expectJsonRequest: expectJsonRequest,
expectPostRequest: expectPostRequest,
expectRequestURL: expectRequestURL,
skipResetRequest: skipResetRequest,
respondWithJson: respondWithJson,
respondWithError: respondWithError,
respondWithTextError: respondWithTextError,
respondWithNoContent: respondWithNoContent
};
});

View File

@@ -1,52 +0,0 @@
/**
* Generally useful helper functions for writing Jasmine unit tests.
*/
define([], function () {
'use strict';
/**
* Runs func as a test case multiple times, using entries from data as arguments. Like Python's DDT.
* @param data An object mapping test names to arrays of function parameters. The name is passed to it() as the name
* of the test case, and the list of arguments is applied as arguments to func.
* @param func The function that actually expresses the logic of the test.
*/
var withData = function (data, func) {
for (var name in data) {
if (data.hasOwnProperty(name)) {
(function (name) {
it(name, function () {
func.apply(this, data[name]);
});
})(name);
}
}
};
/**
* Runs test multiple times, wrapping each call in a describe with beforeEach specified by setup and arguments and
* name coming from entries in config.
* @param config An object mapping configuration names to arrays of setup function parameters. The name is passed
* to describe as the name of the group of tests, and the list of arguments is applied as arguments to setup.
* @param setup The function to setup the given configuration before each test case. Runs in beforeEach.
* @param test The function that actually express the logic of the test. May include it() or more describe().
*/
var withConfiguration = function (config, setup, test) {
for (var name in config) {
if (config.hasOwnProperty(name)) {
(function (name) {
describe(name, function () {
beforeEach(function () {
setup.apply(this, config[name]);
});
test();
});
})(name);
}
}
};
return {
withData: withData,
withConfiguration: withConfiguration
};
});

View File

@@ -4,7 +4,7 @@
;(function (define) {
'use strict';
define(["jquery", "common/js/components/views/feedback_notification", "common/js/components/views/feedback_prompt",
'common/js/spec_helpers/ajax_helpers'],
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers'],
function($, NotificationView, Prompt, AjaxHelpers) {
var installViewTemplates, createFeedbackSpy, verifyFeedbackShowing,
verifyFeedbackHidden, createNotificationSpy, verifyNotificationShowing,