diff options
Diffstat (limited to 'testing/web-platform/tests/tools/wave/www/configuration.html')
-rw-r--r-- | testing/web-platform/tests/tools/wave/www/configuration.html | 1586 |
1 files changed, 1586 insertions, 0 deletions
diff --git a/testing/web-platform/tests/tools/wave/www/configuration.html b/testing/web-platform/tests/tools/wave/www/configuration.html new file mode 100644 index 0000000000..327a155154 --- /dev/null +++ b/testing/web-platform/tests/tools/wave/www/configuration.html @@ -0,0 +1,1586 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <title>Session Configuration - Web Platform Test</title> + <link rel="stylesheet" href="css/bulma-0.7.5/bulma.min.css" /> + <link rel="stylesheet" href="css/fontawesome-5.7.2.min.css" /> + <script src="lib/utils.js"></script> + <script src="lib/wave-service.js"></script> + <script src="lib/ui.js"></script> + <style> + .site-logo { + max-width: 300px; + margin: 0 0 30px -15px; + } + </style> + </head> + <body> + <script> + // var apis = [ + // { title: "2D Context", path: "/2dcontext" }, + // { title: "Content Security Policy", path: "/content-security-policy" }, + // { title: "CSS", path: "/css" }, + // { title: "DOM", path: "/dom" }, + // { title: "ECMAScript", path: "/ecmascript" }, + // { title: "Encrypted media", path: "/encrypted-media" }, + // { title: "Fetch", path: "/fetch" }, + // { title: "FileAPI", path: "/FileAPI" }, + // { title: "Fullscreen", path: "/fullscreen" }, + // { title: "WebGL", path: "/webgl" }, + // { title: "HTML", path: "/html" }, + // { title: "IndexedDB", path: "/IndexedDB" }, + // { title: "Media Source", path: "/media-source" }, + // { title: "Notifications", path: "/notifications" }, + // { title: "Page Visibility", path: "/page-visibility" }, + // { title: "Service Workers", path: "/service-workers" }, + // { title: "UI Events", path: "/uievents" }, + // { title: "WAVE Extra", path: "/wave-extra" }, + // { title: "Webaudio", path: "/webaudio" }, + // { title: "WebCryptoAPI", path: "/WebCryptoAPI" }, + // { title: "Webmessaging", path: "/webmessaging" }, + // { title: "Websockets", path: "/websockets" }, + // { title: "Webstorage", path: "/webstorage" }, + // { title: "Workers", path: "/workers" }, + // { title: "XHR", path: "/xhr" } + // ]; + + // var referenceSessions = [ + // { + // title: "Edge 44.17763", + // engine: "", + // token: "b2924d20-6a93-11e9-98b4-a11fb92a6d1c", + // icon: "fab fa-edge" + // }, + // { + // title: "Firefox 64.0", + // engine: "Gecko 64.0", + // token: "bb7aafa0-6a92-11e9-8ec2-04f58dad2e4f", + // icon: "fab fa-firefox" + // }, + // { + // title: "WebKit 605.1.15", + // engine: "Revision 239158", + // token: "caf823e0-6a92-11e9-b732-3188d0065ebc", + // icon: "fab fa-safari" + // }, + // { + // title: "Chromium 73.0.3640.0", + // engine: "Blink 537.36", + // token: "a50c6db0-6a94-11e9-8d1b-e23fc4555885", + // icon: "fab fa-chrome" + // } + // ]; + + var testFileSelectionEnabled = true; + + window.onload = function () { + new ConfigurationView(); + }; + + function ConfigurationView() { + const query = utils.parseQuery(location.search); + var token = query.token; + if (token) WaveService.addRecentSession(token); + var referenceSessions = []; + var apis = []; + var testTypeSelectionEnabled = true; + var testFileSelectionEnabled = false; + + var types = [ + { title: "Automatic", value: "automatic" }, + { title: "Manual", value: "manual" }, + ]; + var state = {}; + loadServerStatus(); + loadSessionData(token, function () { + loadPublicSessionData(function () { + renderReferencesField(); + }); + }); + render(); + + function loadServerStatus() { + WaveService.readStatus(function (status) { + testTypeSelectionEnabled = status.testTypeSelectionEnabled; + testFileSelectionEnabled = status.testFileSelectionEnabled; + renderSessionConfiguration(); + }); + } + + function loadSessionData(token, callback) { + if (!token) { + state.expired = true; + return; + } + WaveService.readSessionStatus( + token, + function (status) { + if (status.status !== "pending") { + openResultsPage(token); + return; + } + state.status = status; + + WaveService.readSession(token, function (configuration) { + if ( + configuration.tests.include.findIndex( + (test) => test === "/" + ) !== -1 + ) { + configuration.tests.include = apis.map((api) => api.path); + } + state.configurationBackup = utils.copyObject(configuration); + state.configuration = configuration; + setTimeout( + handleExpiration, + status.expirationDate.getTime() - Date.now() + ); + renderSessionConfiguration(); + callback(); + WaveService.readAvailableApis(function (available_apis) { + available_apis = available_apis.sort((apiA, apiB) => + apiA.title.toLowerCase() > apiB.title.toLowerCase() ? 1 : -1 + ); + apis = available_apis; + selectAllTests(); + renderSessionConfiguration(); + }); + }); + }, + function () { + state.expired = true; + renderSessionConfiguration(); + renderExcludedTests(); + renderResumeView(); + } + ); + } + + function loadPublicSessionData(callback) { + WaveService.readPublicSessions(function (tokens) { + WaveService.readMultipleSessions(tokens, function (configurations) { + console.log(configurations); + referenceSessions = configurations + .sort((confA, confB) => + confA.browser.name.toLowerCase() > + confB.browser.name.toLowerCase() + ? 1 + : -1 + ) + .map((configuration) => { + var icon = ""; + switch (configuration.browser.name.toLowerCase()) { + case "firefox": + icon = "fab fa-firefox"; + break; + case "webkit": + case "safari": + icon = "fab fa-safari"; + break; + case "edge": + icon = "fab fa-edge"; + break; + case "chrome": + case "chromium": + icon = "fab fa-chrome"; + break; + } + return { + title: + configuration.browser.name + + " " + + configuration.browser.version, + token: configuration.token, + icon, + engine: configuration.browser.engine || "", + }; + }); + callback(referenceSessions); + }); + }); + } + + function handleConfigureSession() { + const tokenFragmentInput = UI.getElement("token-fragment"); + const fragment = tokenFragmentInput.value; + findSession(fragment, function (session) { + if (!session) { + const errorBox = UI.getElement("find-error"); + errorBox.setAttribute("style", "display: block"); + return; + } + tokenFragmentInput.value = ""; + const errorBox = UI.getElement("find-error"); + errorBox.setAttribute("style", "display: none"); + const path = location.pathname + "?token=" + session.token; + location.href = path; + }); + } + + function findSession(fragment, callback) { + if (!fragment || fragment.length < 8) { + callback(null); + return; + } + WaveService.findToken( + fragment, + function (token) { + WaveService.readSession(token, function (session) { + WaveService.readSessionStatus(token, function (status) { + session.status = status.status; + session.dateStarted = status.dateStarted; + session.dateFinished = status.dateFinished; + callback(session); + }); + }); + }, + function () { + callback(null); + } + ); + } + + function hasIncludedTest(path) { + var tests = state.configuration.tests; + //var index = tests.include.findIndex(function (test) { + // return test.match(new RegExp("^" + path)); + //}); + var index = tests.include.indexOf(path); + return index !== -1; + } + + function handleIncludedTestToggle(path) { + var configuration = state.configuration; + if (hasIncludedTest(path)) { + handleRemoveIncludedTest(path); + } else { + handleAddIncludedTest(path); + } + } + + function handleAddIncludedTest(path) { + var tests = state.configuration.tests; + if (state.tests && state.tests[path.substr(1)]) { + tests.include = tests.include.filter(function (test) { + return !test.match(new RegExp("^" + path + "/")); + }); + tests.include = tests.include.concat(state.tests[path.substr(1)]); + } else { + tests.include.push(path); + } + } + + function handleRemoveIncludedTest(path) { + var tests = state.configuration.tests; + + if (state.tests && state.tests[path.substr(1)]) { + tests.include = tests.include.filter(function (test) { + return !test.match(new RegExp("^" + path + "/")); + }); + } else { + var index = tests.include.findIndex((test) => test === path); + tests.include.splice(index, 1); + } + } + + function getIncludedRatio(path) { + var includedTests = state.configuration.tests.include; + if (!state.tests) { + return includedTests.indexOf(path) !== -1 ? 1 : 0; + } + var count = 0; + for (var test of includedTests) { + if (!test.match(new RegExp("^" + path))) continue; + count++; + } + return count / state.tests[path.substr(1)].length; + } + + function selectAllTests() { + var tests = state.configuration.tests; + if (state.tests) { + tests.include = []; + for (var api in state.tests) { + tests.include = tests.include.concat(state.tests[api]); + } + } else { + tests.include = apis.map((api) => api.path); + } + } + + function deselectAllTests() { + var configuration = state.configuration; + configuration.tests.include = []; + } + + function hasTestType(value) { + var configuration = state.configuration; + var index = configuration.types.findIndex((type) => type === value); + return index !== -1; + } + + function handleTestTypeToggle(value) { + var configuration = state.configuration; + if (hasTestType(value)) { + var index = configuration.types.findIndex((type) => type === value); + configuration.types.splice(index, 1); + } else { + configuration.types.push(value); + } + } + + function selectAllTestTypes() { + var configuration = state.configuration; + configuration.types = types.map((type) => type.value); + } + + function deselectAllTestTypes() { + var configuration = state.configuration; + configuration.types = []; + } + + function hasRefSession(session) { + var configuration = state.configuration; + var index = configuration.referenceTokens.findIndex( + (token) => token === session.token + ); + return index !== -1; + } + + function handleRefSessionToggle(session) { + var configuration = state.configuration; + if (hasRefSession(session)) { + var index = configuration.referenceTokens.findIndex( + (token) => token === session.token + ); + configuration.referenceTokens.splice(index, 1); + } else { + configuration.referenceTokens.push(session.token); + } + } + + function selectAllRefSessions() { + var configuration = state.configuration; + configuration.referenceTokens = referenceSessions.map( + (session) => session.token + ); + } + + function deselectAllRefSessions() { + var configuration = state.configuration; + configuration.referenceTokens = []; + } + + function isTestListValid() { + var configuration = state.configuration; + return configuration.tests.include.length > 0; + } + + function isTestTypeListValid() { + var configuration = state.configuration; + return configuration.types.length > 0; + } + + function isConfigurationValid() { + if (!isTestListValid()) return false; + if (!isTestTypeListValid()) return false; + return true; + } + + function isSessionStarting() { + return state.isStarting; + } + + function checkApiList() { + var apiErrorElement = UI.getElement("api-error"); + apiErrorElement.innerHTML = ""; + if (!isTestListValid()) { + apiErrorElement.appendChild( + UI.createElement( + createErrorMessage( + "Select at least one API or at least one test within an API" + ) + ) + ); + } + renderButtonsField(); + } + + function handleStart() { + if (isSessionStarting()) return; + var configuration = state.configuration; + var token = configuration.token; + WaveService.updateSession(token, configuration, function () { + WaveService.updateLabels(token, configuration.labels, function () { + WaveService.startSession(token, function () { + openResultsPage(token); + }); + }); + }); + state.isStarting = true; + } + + function handleDiscardChanges() { + state.configuration = utils.copyObject(state.configurationBackup); + } + + function handleExpiration() { + state.expired = true; + renderSessionConfiguration(); + renderResumeView(); + } + + function openResultsPage(token) { + location.href = WEB_ROOT + "results.html?token=" + token; + } + + function handleAddExludedTestsRaw() { + var excludedTestsTextArea = UI.getElement("excluded-tests-text"); + var tests = excludedTestsTextArea.value.split("\n"); + var configuration = state.configuration; + var excludedTests = configuration.tests.exclude; + for (var test of tests) { + if (!test) continue; + if (test.startsWith("#")) continue; + if (excludedTests.indexOf(test) !== -1) continue; + excludedTests.push(test); + } + + excludedTestsTextArea.value = ""; + renderExcludedTests(); + } + + function handleAddExludedTestsMalfunctioning() { + var excludedTestsTextArea = UI.getElement("excluded-tests-text"); + var token = excludedTestsTextArea.value; + var tokenRegExp = new RegExp( + "^[a-f0-9]{8}(-[a-f0-9]{0,4}|$)(-[a-f0-9]{0,4}|$)(-[a-f0-9]{0,4}|$)(-[a-f0-9]{0,12}|$)" + ); + var configuration = state.configuration; + var excludedTests = configuration.tests.exclude; + if (tokenRegExp.test(token)) { + WaveService.findToken( + token, + function (token) { + WaveService.readMalfunctioningTests(token, function ( + malfunctioningTests + ) { + for (var test of malfunctioningTests) { + if (!test) continue; + if (excludedTests.indexOf(test) !== -1) continue; + excludedTests.push(test); + } + renderExcludedTests(); + }); + }, + function () { + state.excludedTestError = "Session not found"; + renderExcludedTests(); + } + ); + } else { + state.excludedTestError = "Invalid session token"; + renderExcludedTests(); + } + } + + function handleAddExludedTestsExcluded() { + var excludedTestsTextArea = UI.getElement("excluded-tests-text"); + var token = excludedTestsTextArea.value; + var tokenRegExp = new RegExp( + "^[a-f0-9]{8}(-[a-f0-9]{0,4}|$)(-[a-f0-9]{0,4}|$)(-[a-f0-9]{0,4}|$)(-[a-f0-9]{0,12}|$)" + ); + var configuration = state.configuration; + var excludedTests = configuration.tests.exclude; + if (tokenRegExp.test(token)) { + WaveService.findToken( + token, + function (token) { + WaveService.readSession(token, function (sessionConfig) { + var prevExcludedTests = sessionConfig.tests.exclude; + for (var test of prevExcludedTests) { + if (!test) continue; + if (excludedTests.indexOf(test) !== -1) continue; + excludedTests.push(test); + } + renderExcludedTests(); + }); + }, + function () { + state.excludedTestError = "Session not found"; + renderExcludedTests(); + } + ); + } else { + state.excludedTestError = "Invalid session token"; + renderExcludedTests(); + } + } + + function handleRemoveExcludedTest(test) { + var configuration = state.configuration; + var excludedTests = configuration.tests.exclude; + var index = excludedTests.indexOf(test); + excludedTests.splice(index, 1); + renderExcludedTests(); + } + + function handleExcludeInputChange(type) { + if (state.activeExcludeInput === type) { + state.activeExcludeInput = null; + } else { + state.activeExcludeInput = type; + } + renderExcludedTests(); + } + + function showAddLabel() { + state.addLabelVisible = true; + renderLabelsField(); + UI.getElement("session-label-input").focus(); + } + + function hideAddLabel() { + state.addLabelVisible = false; + renderLabelsField(); + } + + function addLabel() { + var label = UI.getElement("session-label-input").value; + if (!label) return; + state.configuration.labels.push(label); + renderLabelsField(); + UI.getElement("session-label-input").focus(); + } + + function removeLabel(index) { + const { configuration } = state; + configuration.labels.splice(index, 1); + renderLabelsField(); + } + + function resumeSession() { + var resumeToken = UI.getElement("resume-token").value; + if (!resumeToken) return; + + WaveService.resumeSession( + state.configuration.token, + resumeToken, + function () { + openResultsPage(resumeToken); + } + ); + } + + function render() { + const configurationView = UI.createElement({ + element: "section", + className: "section", + children: [ + { + className: "container", + style: "margin-bottom: 2em", + children: [ + { + element: "img", + src: "res/wavelogo_2016.jpg", + className: "site-logo", + }, + { className: "title", text: "Session Configuration" }, + ], + }, + { + id: "session-configuration", + }, + { + id: "resume-view", + className: "container", + style: "margin-bottom: 2em", + }, + ], + }); + const root = UI.getRoot(); + root.innerHTML = ""; + root.appendChild(configurationView); + renderSessionConfiguration(); + renderResumeView(); + } + + function renderSessionConfiguration() { + var configuration = state.configuration; + var status = state.status; + var sessionConfigurationView = UI.createElement({}); + var sessionConfiguration = UI.getElement("session-configuration"); + sessionConfiguration.innerHTML = ""; + + if (state.expired) { + var expiredIndicator = UI.createElement({ + className: "level container", + style: "max-width: 500px", + children: { + element: "span", + className: "level-item field column", + children: [ + { + element: "article", + className: "message is-danger", + id: "find-error", + children: [ + { + text: + "Could not find any sessions! Try adding more characters of the token.", + className: "message-body", + }, + ], + style: "display: none", + }, + { + className: "label has-text-weight-normal", + text: "Session token:", + }, + { + className: "field-body", + children: { + className: "field", + children: { + className: "control", + children: { + style: "display: flex; margin-bottom: 10px;", + children: [ + { + element: "input", + inputType: "text", + className: "input is-family-monospace", + id: "token-fragment", + placeholder: + "First 8 characters or more of session token", + onKeyDown: function (event) { + if (event.key === "Enter") { + handleConfigureSession(); + } + }, + }, + ], + }, + }, + }, + }, + { + className: "field is-grouped is-grouped-right", + children: { + className: "control", + children: { + className: "button is-dark is-outlined", + children: [ + { + element: "span", + className: "icon", + children: [ + { + element: "i", + className: "fas fa-cog", + }, + ], + }, + { text: "Configure Session", element: "span" }, + ], + onclick: function () { + handleConfigureSession(); + }, + }, + }, + }, + ], + }, + }); + sessionConfigurationView.appendChild(expiredIndicator); + sessionConfiguration.appendChild(sessionConfigurationView); + return; + } + + if (!configuration) { + var loadingIndicator = createLoadingIndicator( + "Loading configuration ..." + ); + sessionConfigurationView.appendChild(loadingIndicator); + sessionConfiguration.appendChild(sessionConfigurationView); + return; + } + + sessionConfiguration.parentNode.replaceChild( + UI.createElement({ + id: "session-configuration", + className: "container", + style: "margin-bottom: 2em", + children: [ + { + id: "token-field", + }, + { + id: "expiration-field", + }, + { + id: "labels-field", + }, + { + id: "apis-field", + }, + { + id: "exclude-field", + }, + { + id: "types-field", + }, + { + id: "references-field", + }, + { + id: "buttons-field", + }, + ], + }), + sessionConfiguration + ); + + renderTokenField(); + renderExpirationField(); + renderLabelsField(); + renderApisField(); + renderExcludeField(); + renderTypesField(); + renderReferencesField(); + renderButtonsField(); + } + + function renderTokenField() { + var configuration = state.configuration; + var tokenField = UI.getElement("token-field"); + tokenField.parentNode.replaceChild( + UI.createElement({ + id: "token-field", + className: "field is-horizontal", + children: [ + { + className: "field-label", + children: { className: "label", text: "Token" }, + }, + { + className: "field-body", + children: { + className: "field", + children: { + className: "control", + text: configuration.token, + }, + }, + }, + ], + }), + tokenField + ); + } + + function renderExpirationField() { + var status = state.status; + var expirationField = UI.getElement("expiration-field"); + expirationField.parentNode.replaceChild( + UI.createElement({ + id: "expiration-field", + className: "field is-horizontal", + children: [ + { + className: "field-label", + children: { className: "label", text: "Expires" }, + }, + { + className: "field-body", + children: { + className: "field", + children: { + className: "control", + text: status.expirationDate.toLocaleString(), + }, + }, + }, + ], + }), + expirationField + ); + } + + function renderLabelsField() { + var addLabelVisible = state.addLabelVisible; + var configuration = state.configuration; + var labelsField = UI.getElement("labels-field"); + + labelsField.parentNode.replaceChild( + UI.createElement({ + id: "labels-field", + className: "field is-horizontal", + children: [ + { + className: "field-label", + children: { className: "label", text: "Labels" }, + }, + { + className: "field-body", + children: { + className: "field is-grouped is-grouped-multiline", + children: configuration.labels + .map((label, index) => ({ + className: "control", + children: { + className: "tags has-addons", + children: [ + { + element: "span", + className: "tag is-info", + text: label, + }, + { + element: "a", + className: "tag is-delete", + onClick: () => removeLabel(index), + }, + ], + }, + })) + .concat( + addLabelVisible + ? [ + { + className: "control field is-grouped", + children: [ + { + element: "input", + className: "input is-small control", + style: "width: 10rem", + id: "session-label-input", + type: "text", + onKeyUp: (event) => + event.keyCode === 13 ? addLabel() : null, + }, + { + className: + "button is-dark is-outlined is-small is-rounded control", + text: "save", + onClick: addLabel, + }, + { + className: + "button is-dark is-outlined is-small is-rounded control", + text: "cancel", + onClick: hideAddLabel, + }, + ], + }, + ] + : [ + { + className: "button is-rounded is-small", + text: "Add", + onClick: showAddLabel, + }, + ] + ), + }, + }, + ], + }), + labelsField + ); + } + + function renderApisField() { + var apisField = UI.getElement("apis-field"); + apisField.parentNode.replaceChild( + UI.createElement({ + id: "apis-field", + className: "field is-horizontal", + children: [ + { + className: "field-label", + children: [ + { className: "label", text: "APIs" }, + createSelectDeselectButtons( + function () { + selectAllTests(); + renderApisField(); + }, + function () { + deselectAllTests(); + renderApisField(); + } + ), + ], + }, + { + className: "field-body", + children: { + className: "field", + children: { + className: "control", + children: [ + { + id: "api-error", + }, + { + element: "ul", + className: "menu-list", + children: apis.map(function (api) { + return UI.createElement({ + element: "li", + id: api.title, + }); + }), + }, + ], + }, + }, + }, + ], + }), + apisField + ); + renderApisList(apis); + checkApiList(); + } + + function renderApisList(apis) { + for (var api of apis) { + renderApiList(api); + } + } + + function renderApiList(api) { + var listItem = UI.getElement(api.title); + var includedRatio = getIncludedRatio(api.path); + var apiListItem = { + element: "a", + onClick: function (event) { + if (!testFileSelectionEnabled) return; + if (!state.expandedApis) state.expandedApis = {}; + state.expandedApis[api.path] = !state.expandedApis[api.path]; + renderApiList(api); + }, + children: [ + { + element: "input", + type: "checkbox", + style: "width: 1.3em; height: 1.3em;vertical-align: middle;", + checked: includedRatio > 0, + indeterminate: includedRatio > 0 && includedRatio < 1, + onclick: function (event) { + event.stopPropagation(); + if (includedRatio > 0) { + handleRemoveIncludedTest(api.path); + } else { + handleAddIncludedTest(api.path); + } + renderApiList(api); + }, + }, + testFileSelectionEnabled + ? { + element: "span", + style: + "display: inline-block;vertical-align: middle;margin-left:0.3em;width: 0.7em", + children: { + element: "i", + className: + state.expandedApis && state.expandedApis[api.path] + ? "fas fa-angle-down" + : "fas fa-angle-right", + }, + } + : null, + { + style: + "display: inline-block;vertical-align: middle;margin-left:0.3em;width: 90%", + text: api.title, + }, + ], + }; + listItem.innerHTML = ""; + listItem.appendChild(UI.createElement(apiListItem)); + if (state.expandedApis && state.expandedApis[api.path]) { + listItem.appendChild(createApiTestsList(api)); + } + checkApiList(); + } + + function createApiTestsList(api) { + if (!state.tests) { + WaveService.readTestList( + function (readTests) { + state.tests = readTests; + for (var api in state.tests) { + if (hasIncludedTest("/" + api)) { + handleRemoveIncludedTest("/" + api); + handleAddIncludedTest("/" + api); + } + } + renderApiList(this.api); + }.bind({ api: api }) + ); + return createLoadingIndicator("Loading tests ..."); + } else { + var tests = state.tests[api.path.substr(1)]; + var testListView = { + element: "ul", + children: [], + }; + + testListView.children = testListView.children.concat( + tests + .sort() + .map(function (test) { + return { + element: "li", + onclick: function (event) { + handleIncludedTestToggle(test); + renderApiList(api); + }, + children: [ + { + element: "a", + children: [ + { + element: "input", + type: "checkbox", + style: + "width: 1.3em; height: 1.3em;vertical-align: middle;", + checked: hasIncludedTest(test), + }, + { + style: + "display: inline-block;vertical-align: middle;margin-left:0.3em;max-width: 90%", + text: test, + }, + ], + }, + ], + }; + }) + ); + return UI.createElement(testListView); + } + } + + function renderExcludeField() { + var excludeField = UI.getElement("exclude-field"); + excludeField.parentNode.replaceChild( + UI.createElement({ + id: "exclude-field", + className: "field is-horizontal", + children: [ + { + className: "field-label", + children: { className: "label", text: "Excluded Tests" }, + }, + { + className: "field-body", + children: { + className: "field", + children: { + className: "control", + children: { id: "excluded-tests-view" }, + }, + }, + }, + ], + }), + excludeField + ); + renderExcludedTests(); + } + + function renderTypesField() { + if (!testTypeSelectionEnabled) return; + var typesField = UI.getElement("types-field"); + typesField.parentNode.replaceChild( + UI.createElement({ + id: "types-field", + className: "field is-horizontal", + children: [ + { + className: "field-label", + children: { className: "label", text: "Test Types" }, + }, + { + className: "field-body", + children: { + className: "field", + children: { + className: "control", + children: [ + isTestTypeListValid() + ? null + : createErrorMessage("Select at least one test type"), + ].concat(createTestTypeList(types)), + }, + }, + }, + ], + }), + typesField + ); + } + + function renderReferencesField() { + if (referenceSessions.length === 0) { + return; + } + var referencesField = UI.getElement("references-field"); + referencesField.parentNode.replaceChild( + UI.createElement({ + id: "references-field", + className: "field is-horizontal", + children: [ + { + className: "field-label", + children: [ + { className: "label", text: "Reference Browsers" }, + createSelectDeselectButtons( + function () { + selectAllRefSessions(); + renderReferencesField(); + }, + function () { + deselectAllRefSessions(); + renderReferencesField(); + } + ), + ], + }, + { + className: "field-body", + children: { + className: "field", + children: { + className: "control", + children: createRefSessionsList(referenceSessions), + }, + }, + }, + ], + }), + referencesField + ); + } + + function renderButtonsField() { + var buttonsField = UI.getElement("buttons-field"); + buttonsField.parentNode.replaceChild( + UI.createElement({ + id: "buttons-field", + className: "level level-right", + children: [ + { + element: "button", + className: "button is-success", + style: "margin-right: 0.3em", + disabled: !isConfigurationValid(), + onClick: function () { + handleStart(); + renderButtonsField(); + }, + children: [ + { + element: "span", + className: "icon", + children: [ + { + element: "i", + className: isSessionStarting() + ? "fas fa-spinner fa-pulse" + : "fas fa-play", + }, + ], + }, + { + element: "span", + text: isSessionStarting() + ? "Starting Session ..." + : "Start Session", + }, + ], + }, + { + element: "button", + className: "button", + onClick: function () { + handleDiscardChanges(); + renderSessionConfiguration(); + }, + disabled: isSessionStarting(), + children: [ + { + element: "span", + className: "icon", + children: [ + { + element: "i", + className: "fas fa-times", + }, + ], + }, + { + element: "span", + text: "Discard Changes", + }, + ], + }, + ], + }), + buttonsField + ); + } + + function renderExcludedTests() { + var excludedTestsView = UI.getElement("excluded-tests-view"); + if (!excludedTestsView) return; + excludedTestsView.innerHTML = ""; + + var errorMessage = state.excludedTestError; + if (errorMessage) { + var error = createErrorMessage(errorMessage); + excludedTestsView.appendChild(UI.createElement(error)); + } + + var excludeInputs = [ + { title: "Add Raw", type: "raw" }, + { title: "Add Malfunctioning", type: "malfunc" }, + { title: "Add Previous Excluded", type: "excluded" }, + ]; + + var activeExcludeInput = state.activeExcludeInput; + + var excludedTestInputSwitch = UI.createElement({ + className: "tabs is-centered is-toggle is-small", + children: { + element: "ul", + children: excludeInputs.map(function (input) { + return { + element: "li", + onClick: function () { + handleExcludeInputChange(input.type); + }, + className: (function () { + if (activeExcludeInput === input.type) return "is-active"; + return ""; + })(), + children: { element: "a", text: input.title }, + }; + }), + }, + }); + excludedTestsView.appendChild(excludedTestInputSwitch); + + if (activeExcludeInput === "raw") { + var rawInput = UI.createElement({ + children: [ + { + className: "is-size-7", + style: "margin-bottom: 20px", + text: + "Provide paths to test files or directories to exclude them from the session. One path per line, lines starting with # are omitted.", + }, + { + element: "textarea", + className: "textarea", + id: "excluded-tests-text", + }, + { + style: "margin-top: 10px", + onClick: function () { + handleAddExludedTestsRaw(); + }, + children: [ + { + element: "button", + className: "button", + style: "margin-bottom: 20px", + text: "Add", + }, + ], + }, + ], + }); + excludedTestsView.appendChild(rawInput); + } else if ( + activeExcludeInput === "malfunc" || + activeExcludeInput === "excluded" + ) { + var malfuncInput = UI.createElement({ + style: "margin-bottom: 1em", + children: [ + { + className: "is-size-7", + style: "margin-bottom: 1em", + text: + activeExcludeInput === "malfunc" + ? "Add malfunctioning tests from past sessions by providing at least the first eight characters of the session's token." + : "Add excluded tests from past sessions by providing at least the first eight characters of the session's token.", + }, + { + className: "field is-horizontal", + children: [ + { + className: "field-label", + children: { className: "label", text: "Session Token" }, + }, + { + className: "field-body", + children: { + className: "field is-grouped is-multiline", + children: [ + { + id: "excluded-tests-text", + className: "input", + element: "input", + type: "text", + }, + { + className: "button", + style: "margin-left: 1em", + text: "Add", + onClick: function () { + if (activeExcludeInput === "malfunc") { + handleAddExludedTestsMalfunctioning(); + } else { + handleAddExludedTestsExcluded(); + } + }, + }, + ], + }, + }, + ], + }, + ], + }); + excludedTestsView.appendChild(malfuncInput); + } + + var excludedTestsTable = createExcludedTestsTable(); + var tableWrapper = UI.createElement({ + style: "max-height: 250px; overflow: auto; margin-bottom: 10px", + }); + tableWrapper.appendChild(excludedTestsTable); + excludedTestsView.appendChild(tableWrapper); + } + + function renderResumeView() { + var query = utils.parseQuery(location.search); + var resumeToken = query.resume; + if (!resumeToken) resumeToken = ""; + + var renderResumeElement = UI.getElement("resume-view"); + renderResumeElement.innerHTML = ""; + if (state.expired) return; + + var heading = UI.createElement({ + element: "h2", + className: "title is-5", + text: "Resume session", + }); + renderResumeElement.appendChild(heading); + + var resumeControls = UI.createElement({ + className: "columns", + children: [ + { + className: "column", + children: { + className: "field", + children: [ + { + element: "label", + className: "label", + text: "Token (first 8 characters or more)", + }, + { + className: "control", + children: { + element: "input", + id: "resume-token", + className: "input is-family-monospace tabbable", + type: "text", + style: "max-width: 30em", + value: resumeToken, + }, + }, + ], + }, + }, + { + className: "column", + style: + "display: flex; align-items: flex-end; justify-content: flex-end", + children: { + className: "button", + onClick: function () { + resumeSession(); + }, + children: [ + { + element: "span", + className: "icon", + children: { element: "i", className: "fas fa-redo-alt" }, + }, + { + element: "span", + text: "Resume", + }, + ], + }, + }, + ], + }); + renderResumeElement.appendChild(resumeControls); + } + + function createExcludedTestsTable() { + var excludedTests = state.configuration.tests.exclude; + if (excludedTests.length === 0) { + return UI.createElement({ + style: "text-align: center", + text: "- No Excluded Tests -", + }); + } + var table = UI.createElement({ + element: "table", + className: "table", + style: "width: 100%", + children: excludedTests.map(function (test) { + return { + element: "tr", + children: [ + { element: "td", style: "width: 100%;", text: test }, + { + element: "td", + children: { + element: "button", + className: "button is-small", + onClick: function () { + handleRemoveExcludedTest(test); + }, + children: { + element: "span", + className: "icon", + children: { + element: "i", + className: "fas fa-trash-alt", + }, + }, + }, + }, + ], + }; + }), + }); + return table; + } + + function createTestTypeList(types) { + return types.map((type) => ({ + element: "button", + style: "margin-right: 0.3em; margin-bottom: 0.3em", + className: "button" + (hasTestType(type.value) ? " is-info" : ""), + text: type.title, + onClick: function (event) { + handleTestTypeToggle(type.value); + renderTypesField(); + }, + })); + } + + function createRefSessionsList(referenceSessions) { + return referenceSessions.map((session) => ({ + element: "button", + className: "button" + (hasRefSession(session) ? " is-info" : ""), + style: "margin-right: 0.3em; margin-bottom: 0.3em; height: auto", + onClick: function () { + handleRefSessionToggle(session); + renderReferencesField(); + }, + children: [ + { + element: "span", + className: "icon", + children: [{ element: "i", className: session.icon }], + }, + { + element: "span", + children: [ + { text: session.title }, + { + text: session.engine, + style: "font-size: 0.8em", + }, + ], + }, + ], + })); + } + + function createSelectDeselectButtons(onSelect, onDeselect) { + return { + style: "margin-top: 0.3em", + children: [ + { + element: "button", + style: "margin-right: 0.3em", + className: "button is-rounded is-small", + text: "All", + onClick: onSelect, + }, + { + element: "button", + className: "button is-rounded is-small", + text: "None", + onClick: onDeselect, + }, + ], + }; + } + + function createErrorMessage(message) { + return { + element: "article", + className: "message is-danger", + children: [ + { + className: "message-body", + text: message, + }, + ], + }; + } + + function createLoadingIndicator(text) { + return UI.createElement({ + className: "level", + children: { + element: "span", + className: "level-item", + children: [ + { + element: "i", + className: "fas fa-spinner fa-pulse", + }, + { + style: "margin-left: 0.4em;", + text: text, + }, + ], + }, + }); + } + } + </script> + </body> +</html> |