Source code

Revision control

Copy as Markdown

Other Tools

function sendRequest(method, uri, headers, data, onSuccess, onError) {
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.status === 200) {
onSuccess(xhr.response);
} else {
if (onError) onError(xhr.status, xhr.response);
}
};
xhr.onerror = function () {
if (onError) onError();
};
xhr.open(method, WaveService.uriPrefix + uri, true);
for (var header in headers) {
xhr.setRequestHeader(header, headers[header]);
}
xhr.send(data);
return xhr;
}
var WEB_ROOT = "{{WEB_ROOT}}";
var HTTP_PORT = "{{HTTP_PORT}}";
var HTTPS_PORT = "{{HTTPS_PORT}}";
var OPEN = "open";
var CLOSED = "closed";
var WaveService = {
uriPrefix: WEB_ROOT,
socket: {
state: CLOSED,
onMessage: function () {},
onOpen: function () {},
onClose: function () {},
send: function () {},
close: function () {},
onStateChange: function () {},
},
// SESSIONS API
createSession: function (configuration, onSuccess, onError) {
var data = JSON.stringify({
tests: configuration.tests,
types: configuration.types,
timeouts: configuration.timeouts,
reference_tokens: configuration.referenceTokens,
expiration_date: configuration.expirationDate,
labels: configuration.labels,
});
sendRequest(
"POST",
"api/sessions",
{ "Content-Type": "application/json" },
data,
function (response) {
var jsonObject = JSON.parse(response);
onSuccess(jsonObject.token);
},
onError
);
},
readSession: function (token, onSuccess, onError) {
sendRequest(
"GET",
"api/sessions/" + token,
null,
null,
function (response) {
var jsonObject = JSON.parse(response);
onSuccess({
token: jsonObject.token,
tests: jsonObject.tests,
types: jsonObject.types,
userAgent: jsonObject.user_agent,
labels: jsonObject.labels,
timeouts: jsonObject.timeouts,
browser: jsonObject.browser,
isPublic: jsonObject.is_public,
referenceTokens: jsonObject.reference_tokens,
});
},
onError
);
},
readMultipleSessions: function (tokens, onSuccess, onError) {
var requestsLeft = tokens.length;
if (requestsLeft === 0) onSuccess([]);
var configurations = [];
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
WaveService.readSession(
token,
function (configuration) {
requestsLeft--;
configurations.push(configuration);
if (requestsLeft === 0) onSuccess(configurations);
},
function (status) {
if (status === 404) requestsLeft--;
if (status !== 404 && onError) onError();
if (requestsLeft === 0) onSuccess(configurations);
}
);
}
},
readSessionStatus: function (token, onSuccess, onError) {
sendRequest(
"GET",
"api/sessions/" + token + "/status",
null,
null,
function (response) {
var jsonObject = JSON.parse(response);
var dateStarted = null;
if (jsonObject.date_started) {
dateStarted = new Date(jsonObject.date_started);
}
var dateFinished = null;
if (jsonObject.date_finished) {
dateFinished = new Date(jsonObject.date_finished);
}
var expirationDate = null;
if (jsonObject.expiration_date) {
expirationDate = new Date(jsonObject.expiration_date);
}
onSuccess({
token: jsonObject.token,
dateStarted: dateStarted,
dateFinished: dateFinished,
testFilesCount: jsonObject.test_files_count,
testFilesCompleted: jsonObject.test_files_completed,
status: jsonObject.status,
expirationDate: expirationDate,
});
},
function () {
if (onError) onError();
}
);
},
readMultipleSessionStatuses: function (tokens, onSuccess, onError) {
var requestsLeft = tokens.length;
if (requestsLeft === 0) onSuccess([]);
var statuses = [];
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
WaveService.readSessionStatus(
token,
function (status) {
requestsLeft--;
statuses.push(status);
if (requestsLeft === 0) onSuccess(statuses);
},
function () {
requestsLeft--;
if (requestsLeft === 0) onSuccess(statuses);
}
);
}
},
readPublicSessions: function (onSuccess, onError) {
sendRequest(
"GET",
"api/sessions/public",
null,
null,
function (response) {
var jsonObject = JSON.parse(response);
onSuccess(jsonObject);
},
onError
);
},
updateSession: function (token, configuration, onSuccess, onError) {
var data = JSON.stringify({
tests: configuration.tests,
types: configuration.types,
timeouts: configuration.timeouts,
reference_tokens: configuration.referenceTokens,
expiration_date: configuration.expirationDate,
type: configuration.type,
});
sendRequest(
"PUT",
"api/sessions/" + token,
{ "Content-Type": "application/json" },
data,
function () {
onSuccess();
},
onError
);
},
updateLabels: function (token, labels, onSuccess, onError) {
var data = JSON.stringify({ labels: labels });
sendRequest(
"PUT",
"api/sessions/" + token + "/labels",
{ "Content-Type": "application/json" },
data,
function () {
if (onSuccess) onSuccess();
},
onError
);
},
findToken: function (fragment, onSuccess, onError) {
sendRequest(
"GET",
"api/sessions/" + fragment,
null,
null,
function (response) {
var jsonObject = JSON.parse(response);
onSuccess(jsonObject.token);
},
onError
);
},
startSession: function (token, onSuccess, onError) {
sendRequest(
"POST",
"api/sessions/" + token + "/start",
null,
null,
function () {
onSuccess();
},
onError
);
},
pauseSession: function (token, onSuccess, onError) {
sendRequest(
"POST",
"api/sessions/" + token + "/pause",
null,
null,
function () {
onSuccess();
},
onError
);
},
stopSession: function (token, onSuccess, onError) {
sendRequest(
"POST",
"api/sessions/" + token + "/stop",
null,
null,
function () {
onSuccess();
},
onError
);
},
resumeSession: function (token, resumeToken, onSuccess, onError) {
var data = JSON.stringify({ resume_token: resumeToken });
sendRequest(
"POST",
"api/sessions/" + token + "/resume",
{ "Content-Type": "application/json" },
data,
function () {
if (onSuccess) onSuccess();
},
function (response) {
if (onError) onError(response);
}
);
},
deleteSession: function (token, onSuccess, onError) {
sendRequest(
"DELETE",
"api/sessions/" + token,
null,
null,
function () {
onSuccess();
},
onError
);
},
// TESTS API
readTestList: function (onSuccess, onError) {
sendRequest(
"GET",
"api/tests",
null,
null,
function (response) {
var jsonObject = JSON.parse(response);
onSuccess(jsonObject);
},
onError
);
},
readNextTest: function (token, onSuccess, onError) {
sendRequest(
"GET",
"api/tests/" + token + "/next",
null,
null,
function (response) {
var jsonObject = JSON.parse(response);
onSuccess(jsonObject.next_test);
},
onError
);
},
readLastCompletedTests: function (token, resultTypes, onSuccess, onError) {
var status = "";
if (resultTypes) {
for (var i = 0; i < resultTypes.length; i++) {
var type = resultTypes[i];
status += type + ",";
}
}
sendRequest(
"GET",
"api/tests/" + token + "/last_completed?status=" + status,
null,
null,
function (response) {
var tests = JSON.parse(response);
var parsedTests = [];
for (var status in tests) {
for (var i = 0; i < tests[status].length; i++) {
var path = tests[status][i];
parsedTests.push({ path: path, status: status });
}
}
onSuccess(parsedTests);
},
onError
);
},
readMalfunctioningTests: function (token, onSuccess, onError) {
sendRequest(
"GET",
"api/tests/" + token + "/malfunctioning",
null,
null,
function (response) {
var tests = JSON.parse(response);
onSuccess(tests);
},
function (response) {
var errorMessage = JSON.parse(response).error;
onError(errorMessage);
}
);
},
updateMalfunctioningTests: function (
token,
malfunctioningTests,
onSuccess,
onError
) {
var data = JSON.stringify(malfunctioningTests);
sendRequest(
"PUT",
"api/tests/" + token + "/malfunctioning",
{ "Content-Type": "application/json" },
data,
function () {
onSuccess();
},
function (response) {
var errorMessage = JSON.parse(response).error;
onError(errorMessage);
}
);
},
readAvailableApis: function (onSuccess, onError) {
sendRequest(
"GET",
"api/tests/apis",
null,
null,
function (response) {
var apis = JSON.parse(response);
onSuccess(apis);
},
function (response) {
if (!onError) return;
var errorMessage = JSON.parse(response).error;
onError(errorMessage);
}
);
},
// RESULTS API
createResult: function (token, result, onSuccess, onError) {
sendRequest(
"POST",
"api/results/" + token,
{ "Content-Type": "application/json" },
JSON.stringify(result),
function () {
onSuccess();
},
onError
);
},
readResults: function (token, onSuccess, onError) {
sendRequest(
"GET",
"api/results/" + token,
null,
null,
function (response) {
onSuccess(JSON.parse(response));
},
onError
);
},
readResultsCompact: function (token, onSuccess, onError) {
sendRequest(
"GET",
"api/results/" + token + "/compact",
null,
null,
function (response) {
var jsonObject = JSON.parse(response);
onSuccess(jsonObject);
},
onError
);
},
readResultComparison: function (tokens, onSuccess, onError) {
var comparison = {};
var fetchComplete = function (results) {
comparison.total = {};
for (var i = 0; i < results.length; i++) {
var result = results[i];
var token = result.token;
comparison[token] = {};
for (var api in result) {
if (api === "token") continue;
comparison[token][api] = result[api].pass;
if (!comparison.total[api]) {
var total = 0;
for (var status in result[api]) {
total = total + result[api][status];
}
comparison.total[api] = total;
}
}
}
onSuccess(comparison);
};
var requestsLeft = tokens.length;
if (requestsLeft === 0) onSuccess([]);
var results = [];
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
(function (token) {
WaveService.readResultsCompact(
token,
function (result) {
requestsLeft--;
result.token = token;
results.push(result);
if (requestsLeft === 0) fetchComplete(results);
},
function (responseStatus) {
if (responseStatus === 404) requestsLeft--;
if (status !== 404 && onError) onError();
if (requestsLeft === 0) fetchComplete(results);
}
);
})(token);
}
},
downloadResults: function (token) {
location.href = "api/results/" + token + "/export";
},
downloadApiResult: function (token, api) {
location.href = "api/results/" + token + "/" + api + "/json";
},
downloadAllApiResults: function (token, api) {
location.href = "api/results/" + token + "/json";
},
downloadReport: function (token, api) {
location.href = "api/results/" + token + "/" + api + "/report";
},
importResults: function (data, onSuccess, onError) {
sendRequest(
"POST",
"api/results/import",
{ "Content-Type": "application/octet-stream" },
data,
function (response) {
var token = JSON.parse(response).token;
onSuccess(token);
},
function (status, response) {
var errorMessage;
if (status === 500) {
errorMessage = "Internal server error.";
} else {
errorMessage = JSON.parse(response).error;
}
onError(errorMessage);
}
);
},
readReportUri: function (token, api, onSuccess, onError) {
sendRequest(
"GET",
"api/results/" + token + "/" + api + "/reporturl",
null,
null,
function (response) {
var jsonObject = JSON.parse(response);
onSuccess(jsonObject.uri);
},
onError
);
},
downloadMultiReport: function (tokens, api) {
location.href = "api/results/" + api + "/report?tokens=" + tokens.join(",");
},
readMultiReportUri: function (tokens, api, onSuccess, onError) {
sendRequest(
"GET",
"api/results/" + api + "/reporturl?tokens=" + tokens.join(","),
null,
null,
function (response) {
var jsonObject = JSON.parse(response);
onSuccess(jsonObject.uri);
},
onError
);
},
downloadResultsOverview: function (token) {
location.href = "api/results/" + token + "/overview";
},
// DEVICES API
_device_token: null,
_deviceEventListeners: {},
_deviceEventNumbers: {},
registerDevice: function (onSuccess, onError) {
sendRequest(
"POST",
"api/devices",
null,
null,
function (response) {
var data = JSON.parse(response);
WaveService._device_token = data.token;
onSuccess(data.token);
},
onError
);
},
readDevice: function (token, onSuccess, onError) {
sendRequest(
"GET",
"api/devices/" + token,
null,
null,
function (response) {
if (!onSuccess) return;
var data = JSON.parse(response);
onSuccess(data);
},
function (error) {
if (!onError) return;
onError(error);
}
);
},
DEVICE_ADDED_EVENT: "device_added",
DEVICE_REMOVED_EVENT: "device_removed",
START_SESSION: "start_session",
addDeviceEventListener: function (token, callback) {
var listeners = WaveService._deviceEventListeners;
if (!listeners[token]) listeners[token] = [];
listeners[token].push(callback);
WaveService._deviceEventListeners = listeners;
WaveService.listenDeviceEvents(token);
},
removeDeviceEventListener: function (callback) {
var listeners = WaveService._deviceEventListeners;
for (var token of Object.keys(listeners)) {
var index = listeners[token].indexOf(callback);
if (index === -1) continue;
listeners[token].splice(index, 1);
break;
}
WaveService._deviceEventListeners = listeners;
},
listenDeviceEvents: function (token) {
var listeners = WaveService._deviceEventListeners;
if (!listeners[token] || listeners.length === 0) return;
var url = "api/devices/" + token + "/events";
var lastEventNumber = WaveService._deviceEventNumbers[token];
if (lastEventNumber) {
url += "?last_active=" + lastEventNumber;
}
WaveService.listenHttpPolling(
url,
function (response) {
if (!response) {
WaveService.listenDeviceEvents(token);
return;
}
for (var listener of listeners[token]) {
listener(response);
}
WaveService._deviceEventNumbers[token] = lastEventNumber;
WaveService.listenDeviceEvents(token);
},
function () {
setTimeout(function () {
WaveService.listenDeviceEvents();
}, 1000);
}
);
},
sendDeviceEvent: function (device_token, event, onSuccess, onError) {
var data = JSON.stringify({
type: event.type,
data: event.data,
});
sendRequest(
"POST",
"api/devices/" + device_token + "/events",
{ "Content-Type": "application/json" },
data,
onSuccess,
onError
);
},
addGlobalDeviceEventListener: function (callback) {
WaveService._globalDeviceEventListeners.push(callback);
WaveService.listenGlobalDeviceEvents();
},
removeGlobalDeviceEventListener: function (callback) {
var index = WaveService._globalDeviceEventListeners.indexOf(callback);
WaveService._globalDeviceEventListeners.splice(index, 1);
},
listenGlobalDeviceEvents: function () {
var listeners = WaveService._globalDeviceEventListeners;
if (listeners.length === 0) return;
var query = "";
if (WaveService._device_token) {
query = "?device_token=" + WaveService._device_token;
}
WaveService.listenHttpPolling(
"api/devices/events" + query,
function (response) {
if (!response) {
WaveService.listenGlobalDeviceEvents();
return;
}
for (var listener of listeners) {
listener(response);
}
WaveService.listenGlobalDeviceEvents();
},
function () {
setTimeout(function () {
WaveService.listenGlobalDeviceEvents();
}, 1000);
}
);
},
sendGlobalDeviceEvent: function (event, onSuccess, onError) {
var data = JSON.stringify({
type: event.type,
data: event.data,
});
sendRequest(
"POST",
"api/devices/events",
{ "Content-Type": "application/json" },
data,
onSuccess,
onError
);
},
// GENERAL API
readStatus: function (onSuccess, onError) {
sendRequest(
"GET",
"api/status",
null,
null,
function (response) {
var data = JSON.parse(response);
var configuration = {
readSessionsEnabled: data.read_sessions_enabled,
importResultsEnabled: data.import_results_enabled,
reportsEnabled: data.reports_enabled,
versionString: data.version_string,
testTypeSelectionEnabled: data.test_type_selection_enabled,
testFileSelectionEnabled: data.test_file_selection_enabled
};
onSuccess(configuration);
},
onError
);
},
// UTILITY
addRecentSession: function (token) {
if (!token) return;
var state = WaveService.getState();
if (!state.recent_sessions) state.recent_sessions = [];
if (state.recent_sessions.indexOf(token) !== -1) return;
state.recent_sessions.unshift(token);
WaveService.setState(state);
},
addRecentSessions: function (tokens) {
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
WaveService.addRecentSession(token);
}
},
getPinnedSessions: function () {
var state = WaveService.getState();
if (!state || !state.pinned_sessions) return [];
return state.pinned_sessions;
},
addPinnedSession: function (token) {
if (!token) return;
var state = WaveService.getState();
if (!state.pinned_sessions) state.pinned_sessions = [];
if (state.pinned_sessions.indexOf(token) !== -1) return;
state.pinned_sessions.unshift(token);
WaveService.setState(state);
},
getRecentSessions: function () {
var state = WaveService.getState();
if (!state || !state.recent_sessions) return [];
return state.recent_sessions;
},
setRecentSessions: function (sessionTokens) {
var state = WaveService.getState();
state.recent_sessions = sessionTokens;
WaveService.setState(state);
},
removePinnedSession: function (token) {
if (!token) return;
var state = WaveService.getState();
if (!state.pinned_sessions) return;
var index = state.pinned_sessions.indexOf(token);
if (index === -1) return;
state.pinned_sessions.splice(index, 1);
WaveService.setState(state);
},
removeRecentSession: function (token) {
var state = WaveService.getState();
if (!state.recent_sessions) return;
var index = state.recent_sessions.indexOf(token);
if (index === -1) return;
state.recent_sessions.splice(index, 1);
WaveService.setState(state);
},
getState: function () {
if (!window.localStorage) return null;
var storage = window.localStorage;
var state = JSON.parse(storage.getItem("wave"));
if (!state) return {};
return state;
},
setState: function (state) {
if (!window.localStorage) return null;
var storage = window.localStorage;
storage.setItem("wave", JSON.stringify(state));
},
_globalDeviceEventListeners: [],
_sessionEventListeners: {},
_sessionEventNumbers: {},
listenHttpPolling: function (url, onSuccess, onError) {
var uniqueId = new Date().getTime();
if (url.indexOf("?") === -1) {
url = url + "?id=" + uniqueId;
} else {
url = url + "&id=" + uniqueId;
}
sendRequest(
"GET",
url,
null,
null,
function (response) {
if (!response) {
onSuccess(null);
return;
}
onSuccess(JSON.parse(response));
},
onError
);
},
addSessionEventListener: function (token, callback) {
var listeners = WaveService._sessionEventListeners;
if (!listeners[token]) listeners[token] = [];
if (listeners[token].indexOf(callback) >= 0) return;
listeners[token].push(callback);
WaveService._sessionEventListeners = listeners;
WaveService.listenSessionEvents(token);
},
removeSessionEventListener: function (callback) {
var listeners = WaveService._sessionEventListeners;
for (var token of Object.keys(listeners)) {
var index = listeners[token].indexOf(callback);
if (index === -1) continue;
listeners[token].splice(index, 1);
break;
}
WaveService._sessionEventListeners = listeners;
},
listenSessionEvents: function (token) {
var listeners = WaveService._sessionEventListeners;
if (!listeners[token] || listeners.length === 0) return;
var url = "api/sessions/" + token + "/events";
var lastEventNumber = WaveService._sessionEventNumbers[token];
if (lastEventNumber) {
url += "?last_event=" + lastEventNumber;
}
WaveService.listenHttpPolling(
url,
function (response) {
if (!response) {
WaveService.listenSessionEvents(token);
return;
}
var lastEventNumber = 0;
for (var listener of listeners[token]) {
for (var event of response) {
if (event.number > lastEventNumber) {
lastEventNumber = event.number;
}
listener(event);
}
}
WaveService._sessionEventNumbers[token] = lastEventNumber;
WaveService.listenSessionEvents(token);
},
function () {
setTimeout(function () {
WaveService.listenSessionEvents();
}, 1000);
}
);
},
openSession: function (token) {
location.href = "/results.html?token=" + token;
},
};
if (!Object.keys)
Object.keys = function (o) {
if (o !== Object(o))
throw new TypeError("Object.keys called on a non-object");
var k = [],
p;
for (p in o) if (Object.prototype.hasOwnProperty.call(o, p)) k.push(p);
return k;
};