Refactor common test function into testHelpers.js
diff --git a/bundles/org.eclipse.orion.client.core/web/js-tests/xhr/testcase.js b/bundles/org.eclipse.orion.client.core/web/js-tests/xhr/testcase.js
index 7dc0cba..2389a49 100644
--- a/bundles/org.eclipse.orion.client.core/web/js-tests/xhr/testcase.js
+++ b/bundles/org.eclipse.orion.client.core/web/js-tests/xhr/testcase.js
@@ -10,9 +10,10 @@
  ******************************************************************************/
 
 /*global define setTimeout*/
-define(["orion/assert", "orion/test", "orion/Deferred", "orion/xhr", "orion/textview/eventTarget"],
-		function(assert, mTest, Deferred, xhr, mEventTarget) {
+define(["orion/assert", "orion/test", "orion/testHelpers", "orion/Deferred", "orion/xhr", "orion/textview/eventTarget"],
+		function(assert, mTest, testHelpers, Deferred, xhr, mEventTarget) {
 	var EventTarget = mEventTarget.EventTarget;
+	var getTimeoutable = testHelpers.getTimeoutable;
 	/**
 	 * Fake version of XMLHttpRequest for testing without actual network accesses.
 	 */
@@ -105,48 +106,16 @@
 		return d;
 	}
 
-	/**
-	 * Wraps a test body to ensure a test failure if the promise doesn't resolve.
-	 * @param {Function} func The test body (must return a promise).
-	 * @returns {Deferred}
-	 */
-	function withTimeout(func) {
-		return function() {
-			var wrapper = new Deferred();
-			var inner;
-			var innerPromiseFired = false;
-			try {
-				inner = func();
-				setTimeout(function() {
-					if (!innerPromiseFired) {
-						wrapper.reject('Timed out');
-					}
-				}, 3000);
-				inner.then(
-					function(result) {
-						innerPromiseFired = true;
-						wrapper.resolve(result);
-					}, function(err) {
-						innerPromiseFired = true;
-						wrapper.reject(err);
-					});
-			} catch (e) {
-				wrapper.reject(e);
-			}
-			return wrapper;
-		};
-	}
-
 	var tests = {};
-	tests['test GET resolve'] = withTimeout(function() {
+	tests['test GET resolve'] = getTimeoutable(function() {
 		return xhr('GET', '/', null, new OkXhr()).then(succeed, fail);
 	});
 
-	tests['test GET reject'] = withTimeout(function() {
+	tests['test GET reject'] = getTimeoutable(function() {
 		return xhr('GET', '/bogus/url/that/doesnt/exist', null, new FailXhr()).then(fail, succeed);
 	});
 
-	tests['test \'X-Requested-With\' is set'] = withTimeout(function() {
+	tests['test \'X-Requested-With\' is set'] = getTimeoutable(function() {
 		var d = new Deferred();
 		var headerCheckerXhr = new MockXMLHttpRequest();
 		headerCheckerXhr.send = function() {
@@ -162,7 +131,7 @@
 		return d;
 	});
 
-	tests['test GET query params'] = withTimeout(function() {
+	tests['test GET query params'] = getTimeoutable(function() {
 		return xhr('GET', '/', {
 			query: {
 				'foo': 3,
@@ -174,7 +143,7 @@
 		}, fail);
 	});
 
-	tests['test GET query params encoding'] = withTimeout(function() {
+	tests['test GET query params encoding'] = getTimeoutable(function() {
 		return xhr('GET', '/', {
 			query: {
 				'foo!bar': 31337,
@@ -186,7 +155,7 @@
 		}, fail);
 	});
 
-	tests['test GET query params with fragment'] = withTimeout(function() {
+	tests['test GET query params with fragment'] = getTimeoutable(function() {
 		return xhr('GET', '/#some?junk&we?dont&care?about', {
 			query: {
 				'foo*bar': 'baz',
@@ -198,7 +167,7 @@
 		}, fail);
 	});
 
-	tests['test GET query params with existing params and fragment'] = withTimeout(function() {
+	tests['test GET query params with existing params and fragment'] = getTimeoutable(function() {
 		return xhr('GET', '/?a%20=b#some?junk&we?dont&care?about', {
 			query: {
 				'foo*bar': 'baz'
@@ -209,7 +178,7 @@
 		}, fail);
 	});
 
-	tests['test GET with headers'] = withTimeout(function() {
+	tests['test GET with headers'] = getTimeoutable(function() {
 		return xhr('GET', '/', {
 			headers: {
 				'X-Foo-Bar': 'baz'
@@ -218,7 +187,7 @@
 		.then(succeed, fail);
 	});
 
-	tests['test open() exception causes reject'] = withTimeout(function() {
+	tests['test open() exception causes reject'] = getTimeoutable(function() {
 		var alreadyOpenXhr = new OkXhr();
 		alreadyOpenXhr.open('GET', '/foo');
 		// Since request is already OPEN the next call to open() will throw, and xhr should catch & reject
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/testHelpers.js b/bundles/org.eclipse.orion.client.core/web/orion/testHelpers.js
new file mode 100644
index 0000000..a22a712
--- /dev/null
+++ b/bundles/org.eclipse.orion.client.core/web/orion/testHelpers.js
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * @license
+ * Copyright (c) 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials are made 
+ * available under the terms of the Eclipse Public License v1.0 
+ * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+ * 
+ * Contributors: IBM Corporation - initial API and implementation
+ ******************************************************************************/
+/*global define setTimeout*/
+define(['orion/Deferred'], function(Deferred) {
+	var DEFAULT_TIMEOUT = 3000;
+	/**
+	 * @name orion.test.makeTimeoutable
+	 * Wraps a function into a timeout-able function. This is convenient for constructing a testcase function that fails
+	 * if an an expected promise never calls back.
+	 * @param {Function} func The test body function to be executed (must return a promise).
+	 * @param {Number} [optTimeout=3000] How long to wait for a response before rejecting.
+	 * @returns {Function} A testcase function. When executed, it returns a promise that rejects if <code>func()</code>'s
+	 * promise does not call back within the specified amount of time.
+	 */
+	function getTimeoutable(func, optTimeout) {
+		var timeout = typeof optTimeout === 'number' ? optTimeout : DEFAULT_TIMEOUT;
+		return function() {
+			var wrapper = new Deferred();
+			var inner;
+			var innerPromiseFired = false;
+			try {
+				inner = func();
+				setTimeout(function() {
+					if (!innerPromiseFired) {
+						wrapper.reject('Timed out');
+					}
+				}, timeout);
+				inner.then(
+					function(result) {
+						innerPromiseFired = true;
+						wrapper.resolve(result);
+					}, function(err) {
+						innerPromiseFired = true;
+						wrapper.reject(err);
+					});
+			} catch (e) {
+				wrapper.reject(e);
+			}
+		};
+	}
+	return {
+		getTimeoutable: getTimeoutable
+	};
+});
\ No newline at end of file
diff --git a/bundles/org.eclipse.orion.client.editor/web/js-tests/editor/contentAssist/testcase.js b/bundles/org.eclipse.orion.client.editor/web/js-tests/editor/contentAssist/testcase.js
index a8b5616..16195a7 100644
--- a/bundles/org.eclipse.orion.client.editor/web/js-tests/editor/contentAssist/testcase.js
+++ b/bundles/org.eclipse.orion.client.editor/web/js-tests/editor/contentAssist/testcase.js
@@ -9,45 +9,14 @@
  * Contributors: IBM Corporation - initial API and implementation
  ******************************************************************************/
 /*global define setTimeout*/
-define(['dojo', 'dojo/DeferredList', 'orion/assert', 'orion/textview/textModel', 'js-tests/editor/mockTextView', 'orion/editor/contentAssist'],
-		function(dojo, DeferredList, assert, mTextModel, mMockTextView, mContentAssist) {
+define(['dojo', 'dojo/DeferredList', 'orion/assert', 'orion/testHelpers', 'orion/textview/textModel', 'js-tests/editor/mockTextView', 'orion/editor/contentAssist'],
+		function(dojo, DeferredList, assert, testHelpers, mTextModel, mMockTextView, mContentAssist) {
 	var Deferred = dojo.Deferred,
+		getTimeoutable = testHelpers.getTimeoutable,
 	    ContentAssist = mContentAssist.ContentAssist,
 	    TextModel = mTextModel.TextModel,
 	    MockTextView = mMockTextView.MockTextView;
 
-	/**
-	 * Wraps a test body to ensure a test failure if the promise doesn't resolve.
-	 * @param {Function} func The test body (must return a promise).
-	 * @returns {Deferred}
-	 */
-	function createTestWithTimeout(func) {
-		return function() {
-			var wrapper = new Deferred();
-			var inner;
-			var innerPromiseFired = false;
-			try {
-				inner = func();
-				setTimeout(function() {
-					if (!innerPromiseFired) {
-						wrapper.reject('Timed out');
-					}
-				}, 3000);
-				inner.then(
-					function(result) {
-						innerPromiseFired = true;
-						wrapper.resolve(result);
-					}, function(err) {
-						innerPromiseFired = true;
-						wrapper.reject(err);
-					});
-			} catch (e) {
-				wrapper.reject(e);
-			}
-			return wrapper;
-		};
-	}
-
 	function withData(func) {
 		var view = new MockTextView({});
 		var contentAssist = new ContentAssist(view);
@@ -119,7 +88,7 @@
 
 	var tests = {};
 	// Tests that ContentAssist calls a provider's computeProposals() method with the expected parameters.
-	tests.testComputeProposals = createTestWithTimeout(function() {
+	tests.testComputeProposals = getTimeoutable(function() {
 		var text = 'this is the first line\nthis is the second line@@@';
 		return assertProviderInvoked(text, function(getProposalsFunction) {
 			return {
@@ -129,7 +98,7 @@
 	});
 
 	// Tests that 'getProposals' works as an alias of 'computeProposals' (backwards compatibility)
-	tests.testGetProposals = createTestWithTimeout(function() {
+	tests.testGetProposals = getTimeoutable(function() {
 		var text = 'this is the first line\nthis is the second line@@@';
 		return assertProviderInvoked(text, function(getProposalsFunction) {
 			return {
@@ -139,7 +108,7 @@
 	});
 	
 	// Tests that active ContentAssist will call providers as we type.
-	tests.testFiltering = createTestWithTimeout(function() {
+	tests.testFiltering = getTimeoutable(function() {
 		var first = new Deferred(),
 		    second = new Deferred(),
 		    deferred = new DeferredList([first, second]);
@@ -190,7 +159,7 @@
 	});
 
 	// Tests that Activating, Deactivating events are fired as expected.
-	tests.testEvents1 = createTestWithTimeout(function() {
+	tests.testEvents1 = getTimeoutable(function() {
 		var d1 = new Deferred(),
 		    d2 = new Deferred(),
 		    deferred = new DeferredList([d1, d2]);
@@ -212,7 +181,7 @@
 	});
 
 	// Tests that ProposalsComputed, ProposalsApplied events are fired as expected.
-	tests.testEvents2 = createTestWithTimeout(function() {
+	tests.testEvents2 = getTimeoutable(function() {
 		var d1 = new Deferred(),
 		    d2 = new Deferred(),
 		    deferred = new DeferredList([d1, d2]);