1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const webserver_1 = require("../webserver");
|
4 | const cli_1 = require("./cli");
|
5 | const config_1 = require("./config");
|
6 | const url_1 = require("url");
|
7 | const flagpoleexecutionoptions_1 = require("../flagpoleexecutionoptions");
|
8 | const suiteexecution_1 = require("./suiteexecution");
|
9 | const flagpoleexecutionoptions_2 = require("../flagpoleexecutionoptions");
|
10 | const open = require("open");
|
11 | const qs = require("querystring");
|
12 | const possibleEnvironments = [
|
13 | "dev",
|
14 | "stag",
|
15 | "prod",
|
16 | "qa",
|
17 | "rc",
|
18 | "preprod",
|
19 | "alpha",
|
20 | "beta"
|
21 | ];
|
22 | const routes = {
|
23 | "GET /api/suites": (url, response) => {
|
24 | sendJson(response, { suites: cli_1.Cli.config.suites });
|
25 | },
|
26 | "GET /import/suite": (url, response) => {
|
27 | sendGetImport(response);
|
28 | },
|
29 | "POST /import/suite": (url, response, postData) => {
|
30 | const name = postData.name;
|
31 | if (name) {
|
32 | cli_1.Cli.config.addSuite({
|
33 | name: name
|
34 | });
|
35 | cli_1.Cli.config.save();
|
36 | return sendOutput(response, `<p>Imported new suite ${name} from file ${name}.js</p><p><a href="/">Back</a>`);
|
37 | }
|
38 | fileNotFound(response);
|
39 | },
|
40 | "GET /init": (url, response) => {
|
41 | sendGetInit(response);
|
42 | },
|
43 | "POST /init": (url, response, postData) => {
|
44 | initProject(response, postData);
|
45 | },
|
46 | "GET /add/scenario": (url, response) => {
|
47 | const suiteName = url.searchParams.get("suite");
|
48 | const suite = getSuite(response, suiteName);
|
49 | if (suite) {
|
50 | return sendGetAddScenario(response, suite);
|
51 | }
|
52 | fileNotFound(response);
|
53 | },
|
54 | "POST /add/scenario": (url, response, postData) => {
|
55 | if (!postData.suite ||
|
56 | !postData.description ||
|
57 | !postData.path ||
|
58 | !postData.type) {
|
59 | return sendOutput(response, `<p>All fields are required.</p>`);
|
60 | }
|
61 | const suite = getSuite(response, postData.suite);
|
62 | if (!suite) {
|
63 | return fileNotFound(response);
|
64 | }
|
65 | cli_1.Cli.addScenario(suite, {
|
66 | description: postData.description,
|
67 | path: postData.path,
|
68 | type: postData.type
|
69 | })
|
70 | .then(() => {
|
71 | return sendOutput(response, `
|
72 | <p>Added scenario to <em>${suite.name}</em></p>
|
73 | <p><a href="/">Back</a></p>
|
74 | `);
|
75 | })
|
76 | .catch(err => {
|
77 | return sendOutput(response, `<p>${err}</p>`);
|
78 | });
|
79 | },
|
80 | "GET /add/suite": (url, response) => {
|
81 | sendGetAddSuite(response);
|
82 | },
|
83 | "POST /add/suite": (url, response, postData) => {
|
84 | if (!postData.suiteName ||
|
85 | !postData.suiteDescription ||
|
86 | !postData.scenarioDescription ||
|
87 | !postData.scenarioPath ||
|
88 | !postData.scenarioType) {
|
89 | return sendOutput(response, `<p>All fields are required. <a href="/add/suite">Try again</a></p>`);
|
90 | }
|
91 | let domains = {};
|
92 | Object.keys(postData).forEach((key) => {
|
93 | if (key.startsWith("baseDomain[") && key.endsWith("]")) {
|
94 | let envName = key.split("[")[1].slice(0, -1);
|
95 | domains[envName] = postData[key];
|
96 | }
|
97 | });
|
98 | if (Object.keys(domains).length == 0) {
|
99 | domains.dev = "http://localhost";
|
100 | }
|
101 | addSuite(response, {
|
102 | name: postData.suiteName,
|
103 | description: postData.suiteDescription
|
104 | }, {
|
105 | description: postData.scenarioDescription,
|
106 | path: postData.scenarioPath,
|
107 | type: postData.scenarioType
|
108 | });
|
109 | },
|
110 | "GET /suite": (url, response) => {
|
111 | const suite = getSuite(response, url.searchParams.get("name"));
|
112 | if (suite) {
|
113 | return sendGetEditSuite(response, suite);
|
114 | }
|
115 | fileNotFound(response);
|
116 | },
|
117 | "POST /suite": (url, response, postData) => {
|
118 | const suite = getSuite(response, postData.name);
|
119 | if (suite) {
|
120 | cli_1.Cli.config.suites[suite.name].clearTags();
|
121 | String(postData.tags)
|
122 | .split(",")
|
123 | .forEach(tag => {
|
124 | cli_1.Cli.config.suites[suite.name].addTag(tag);
|
125 | });
|
126 | cli_1.Cli.config
|
127 | .save()
|
128 | .then(() => {
|
129 | sendOutput(response, `<p>Saved changes to suite.</p><p><a href="/">Back</a>`);
|
130 | })
|
131 | .catch(err => {
|
132 | sendOutput(response, `<p>Error adding tag. ${err}</p><p><a href="/suite?name=${suite.name}">Back</a>`);
|
133 | });
|
134 | }
|
135 | },
|
136 | "POST /rm": (url, response) => {
|
137 | const env = url.searchParams.get("env");
|
138 | const suite = url.searchParams.get("suite");
|
139 | if (suite) {
|
140 | return removeSuite(response, suite);
|
141 | }
|
142 | else if (env) {
|
143 | return removeEnv(response, env);
|
144 | }
|
145 | fileNotFound(response);
|
146 | },
|
147 | "GET /add/env": (url, response) => {
|
148 | sendGetAddEnv(response);
|
149 | },
|
150 | "POST /add/env": (url, response, postData) => {
|
151 | const envName = postData.name;
|
152 | const defaultDomain = postData.domain;
|
153 | if (!envName || !defaultDomain) {
|
154 | return sendOutput(response, `<p>Imported new suite ${name} from file ${name}.js</p><p><a href="/">Back</a>`);
|
155 | }
|
156 | if (envName) {
|
157 | addEnv(response, new config_1.EnvConfig(cli_1.Cli.config, {
|
158 | name: envName,
|
159 | defaultDomain: defaultDomain
|
160 | }));
|
161 | }
|
162 | },
|
163 | "POST /run": (url, response, postData) => {
|
164 | const suiteName = postData.suite;
|
165 | const envName = postData.env;
|
166 | if (suiteName && cli_1.Cli.config.suites[suiteName]) {
|
167 | return runSuite(response, suiteName, envName || flagpoleexecutionoptions_2.FlagpoleExecution.opts.environment);
|
168 | }
|
169 | fileNotFound(response);
|
170 | }
|
171 | };
|
172 | const getSuite = (response, suiteName) => {
|
173 | if (!suiteName) {
|
174 | return sendOutput(response, `<p>No suite name. <a href="/">Back</a></p>`);
|
175 | }
|
176 | const suite = cli_1.Cli.config.suites[suiteName];
|
177 | if (!suite) {
|
178 | return sendOutput(response, `<p>That suite does not exist. <a href="/">Back</a></p>`);
|
179 | }
|
180 | return suite;
|
181 | };
|
182 | const getTemplate = (httpResponse) => {
|
183 | const response = webserver_1.WebResponse.createFromTemplate(httpResponse, `${__dirname}/report.html`);
|
184 | response.replace("nav", '<a href="/">Project Home</a>');
|
185 | return response;
|
186 | };
|
187 | const sendOutput = (response, output) => {
|
188 | getTemplate(response).send({
|
189 | output: output
|
190 | });
|
191 | };
|
192 | const sendJson = (response, json) => {
|
193 | webserver_1.WebResponse.createFromInput(response, JSON.stringify(json)).send();
|
194 | };
|
195 | const fileNotFound = (response) => {
|
196 | sendOutput(response, "File not found.");
|
197 | };
|
198 | const sendGetInit = (response) => {
|
199 | let output = `
|
200 | <h2>Initialize Flagpole</h2>
|
201 | <p>
|
202 | Flagpole has not yet been set up in this project. Complete the form below to configure.
|
203 | </p>
|
204 | <form method="POST" action="/init" id="frm">
|
205 | <div class="field">
|
206 | <label for="name">Project Name</label>
|
207 | <input type="text" name="projectName" id="name" value="${process
|
208 | .cwd()
|
209 | .split("/")
|
210 | .pop()}">
|
211 | </div>
|
212 | <div class="field">
|
213 | <label for="folder">Tests Folder</label>
|
214 | <input type="text" name="testsPath" id="folder" value="tests">
|
215 | </div>
|
216 | <div class="field">
|
217 | Environments (check all that you want to use)
|
218 | </div>`;
|
219 | possibleEnvironments.forEach((envName) => {
|
220 | output += `
|
221 | <div class="field">
|
222 | <input type="checkbox" name="envName[${envName}]" id="env_${envName}" value="${envName}">
|
223 | <label for="env_${envName}">${envName}</label>
|
224 | <input type="text" name="envDomain[${envName}]" id="domain_${envName}" placeholder="https://www.flagpolejs.com">
|
225 | </div>
|
226 | `;
|
227 | });
|
228 | output += `
|
229 | <div class="field button">
|
230 | <button type="submit">Initialize Project</button>
|
231 | </div>
|
232 | </form>`;
|
233 | sendOutput(response, output);
|
234 | };
|
235 | const sendGetAddEnv = (response) => {
|
236 | let output = `
|
237 | <h2>Add Environment</h2>
|
238 | <form method="POST" action="/add/env" id="frm">
|
239 | <div class="field">
|
240 | <label for="name">Environment Name</label>
|
241 | <input type="text" name="name" id="name" placeholder="dev">
|
242 | </div>
|
243 | <div class="field">
|
244 | <label for="domain">Base Path</label>
|
245 | <input type="url" name="domain" id="domain" placeholder="http://www.google.com/">
|
246 | </div>
|
247 | <div class="field button">
|
248 | <button type="submit">Add Environment</button>
|
249 | <button type="button" onclick="window.location.href='/'">Cancel</button>
|
250 | </div>
|
251 | </form>`;
|
252 | sendOutput(response, output);
|
253 | };
|
254 | const sendGetEditSuite = (response, suite) => {
|
255 | let output = `
|
256 | <h2>Edit Suite</h2>
|
257 | <form method="POST" action="/suite" id="frm">
|
258 | <div class="field">
|
259 | <label for="name">Suite Name</label>
|
260 | <input type="text" name="name" id="name" value="${suite.name}" readonly>
|
261 | </div>
|
262 | <div class="field">
|
263 | <label for="tags">Tags (comma-separated)</label>
|
264 | <input type="text" name="tags" id="tags" placeholder="tag1, tag2" value="${suite.tags.join(", ")}">
|
265 | </div>
|
266 | <div class="field button">
|
267 | <button type="submit">Save Changes</button>
|
268 | <button type="button" onclick="window.location.href='/'">Cancel</button>
|
269 | </div>
|
270 | </form>`;
|
271 | sendOutput(response, output);
|
272 | };
|
273 | const sendGetAddScenario = (response, suite) => {
|
274 | let output = `
|
275 | <h2>Add Scenario</h2>
|
276 | <p>Appending a new scenario to suite ${suite.name}.</p>
|
277 | <form method="POST" action="/add/scenario" id="frm">
|
278 | <div class="field">
|
279 | <label for="suite">Suite</label>
|
280 | <input type="text" readonly name="suite" id="suite" value="${suite.name}">
|
281 | </div>
|
282 | <div class="field">
|
283 | <label for="description">Description</label>
|
284 | <input type="text" name="description" id="description" placeholder="Make sure homepage loads">
|
285 | </div>
|
286 | <div class="field">
|
287 | <label for="path">Path</label>
|
288 | <input type="text" name="path" id="path" value="/" placeholder="/">
|
289 | </div>
|
290 | <div class="field">
|
291 | <label for="type">Type</label>
|
292 | <select name="type" id="type">
|
293 | <option value="html">HTML/DOM (Cheerio)</option>
|
294 | <option value="browser">Browser (Puppeteer)</option>
|
295 | <option value="json">JSON/REST API</option>
|
296 | </select>
|
297 | </div>
|
298 | <div class="field button">
|
299 | <button type="submit">Add Scenario</button>
|
300 | <button type="button" onclick="window.location.href = '/'">Cancel</button>
|
301 | </div>
|
302 | </form>
|
303 | `;
|
304 | return sendOutput(response, output);
|
305 | };
|
306 | const sendGetAddSuite = (response) => {
|
307 | let output = `
|
308 | <h2>New Suite</h2>
|
309 | <form method="POST" action="/add/suite" id="frm">
|
310 | <div class="field">
|
311 | <label for="suiteName">Suite Name</label>
|
312 | <input type="text" name="suiteName" id="suiteName" placeholder="smoke">
|
313 | </div>
|
314 | <div class="field">
|
315 | <label for="suiteDescription">Suite Description</label>
|
316 | <input type="text" name="suiteDescription" id="suiteDescription" placeholder="Basic smoke test of the site">
|
317 | </div>
|
318 | <fieldset>
|
319 | <legend>Base Domain</legend>`;
|
320 | cli_1.Cli.config.getEnvironments().forEach((env) => {
|
321 | output += `
|
322 | <div class="field">
|
323 | <label for="env_${env.name}">${env.name}</label>
|
324 | <input type="text" name="baseDomain[${env.name}]" id="env_${env.name}" value="${env.defaultDomain}">
|
325 | </div>`;
|
326 | });
|
327 | output += `</fieldset>
|
328 | <fieldset>
|
329 | <legend>First Scenario</legend>
|
330 | <div class="field">
|
331 | <label for="scenarioDescription">Title</label>
|
332 | <input type="text" name="scenarioDescription" id="scenarioDescription" placeholder="Make sure homepage loads">
|
333 | </div>
|
334 | <div class="field">
|
335 | <label for="scenarioPath">Path</label>
|
336 | <input type="text" name="scenarioPath" id="scenarioPath" value="/" placeholder="/">
|
337 | </div>
|
338 | <div class="field">
|
339 | <label for="scenarioType">Type</label>
|
340 | <select name="scenarioType" id="scenarioType">
|
341 | <option value="html">HTML/DOM (Cheerio)</option>
|
342 | <option value="browser">Browser (Puppeteer)</option>
|
343 | <option value="json">JSON/REST API</option>
|
344 | </select>
|
345 | </div>
|
346 | </fieldset>
|
347 | <div class="field button">
|
348 | <button type="submit">Add Suite</button>
|
349 | <button type="button" onclick="document.location.href='/'">Cancel</button>
|
350 | </div>
|
351 | </form>
|
352 | `;
|
353 | sendOutput(response, output);
|
354 | };
|
355 | const sendGetImport = (response) => {
|
356 | let output = `
|
357 | <h2>Import Suite</h2>
|
358 | `;
|
359 | const detachedSuites = cli_1.Cli.findDetachedSuites();
|
360 | if (detachedSuites.length == 0) {
|
361 | output += "<p>There are no unattached *.js files in test folder.</p>";
|
362 | }
|
363 | else {
|
364 | output += `
|
365 | <script>
|
366 | function importSuite() {
|
367 | var form = document.getElementById("frmImport");
|
368 | var e = document.getElementById("ddFile");
|
369 | var file = e.options[e.selectedIndex].value;
|
370 | if (file) {
|
371 | if (confirm('Import this file ' + file + '.js?')) {
|
372 | form.submit();
|
373 | }
|
374 | }
|
375 | else {
|
376 | alert('No file selected.');
|
377 | }
|
378 | }
|
379 | </script>
|
380 | <form method="POST" id="frmImport" action="/import/suite">
|
381 | <div class="field">
|
382 | <label for="ddFile">File to Import</label>
|
383 | <select name="suite" id="ddFile">
|
384 | `;
|
385 | detachedSuites.forEach((file) => {
|
386 | output += `
|
387 | <option value="${file}">${file}</option>
|
388 | `;
|
389 | });
|
390 | output += `
|
391 | </select>
|
392 | </div>
|
393 | <div class="field button">
|
394 | <button type="button" onclick="importSuite()">Import</button>
|
395 | <button type="button" onclick="window.location.href = '/'">Cancel</button>
|
396 | </div>
|
397 | </form>
|
398 | `;
|
399 | }
|
400 | sendOutput(response, output);
|
401 | };
|
402 | const removeSuite = (response, suiteName) => {
|
403 | cli_1.Cli.config.removeSuite(suiteName);
|
404 | cli_1.Cli.config
|
405 | .save()
|
406 | .then(() => {
|
407 | sendOutput(response, `Removed suite <em>${suiteName}</em>, but did not delete the file. <a href="/">Back</a>`);
|
408 | })
|
409 | .catch(ex => {
|
410 | sendOutput(response, `Error: ${ex}`);
|
411 | });
|
412 | };
|
413 | const removeEnv = (response, envName) => {
|
414 | cli_1.Cli.config.removeEnvironment(envName);
|
415 | cli_1.Cli.config
|
416 | .save()
|
417 | .then(() => {
|
418 | sendOutput(response, `Removed environment <em>${envName}</em>, no test scenarios were altered. <a href="/">Back</a>`);
|
419 | })
|
420 | .catch(ex => {
|
421 | sendOutput(response, `Error: ${ex}`);
|
422 | });
|
423 | };
|
424 | const initProject = (response, postData) => {
|
425 | if (!postData.projectName || !postData.testsPath) {
|
426 | return sendOutput(response, `<p>Project name and test path are required. <a href="/init">Try again</a></p>`);
|
427 | }
|
428 | cli_1.Cli.init({
|
429 | project: {
|
430 | name: postData.projectName,
|
431 | path: postData.testsPath
|
432 | },
|
433 | environments: []
|
434 | })
|
435 | .then(() => {
|
436 | let countEnvs = 0;
|
437 | possibleEnvironments.forEach(env => {
|
438 | if (postData[`envName[${env}]`]) {
|
439 | const domain = postData[`envDomain[${env}]`];
|
440 | cli_1.Cli.config.addEnvironment({
|
441 | name: env,
|
442 | defaultDomain: domain
|
443 | });
|
444 | countEnvs++;
|
445 | }
|
446 | });
|
447 | if (countEnvs == 0) {
|
448 | cli_1.Cli.config.addEnvironment({
|
449 | name: "dev"
|
450 | });
|
451 | countEnvs++;
|
452 | }
|
453 | cli_1.Cli.config
|
454 | .save()
|
455 | .then(() => {
|
456 | sendOutput(response, `
|
457 | <p><em>Awesome!</em> You're ready to get going. Flagpole has been initialized in this project.</p>
|
458 | <p>Next, we recommend you <strong><a href="/add/suite">add your first test suite</a></strong>.</p>
|
459 | <p>Or you can <a href="/">skip this step</a>.</p>
|
460 | `);
|
461 | })
|
462 | .catch(err => {
|
463 | sendOutput(response, `
|
464 | <p>Flagpole was initialized, but there was a problem saving environments: ${err}</p>
|
465 | <p><a href="/">Continue</a></p>
|
466 | `);
|
467 | });
|
468 | })
|
469 | .catch(err => {
|
470 | sendOutput(response, `<p>Error initializing: ${err}</p>p><a href="/init">Try again</a></p>`);
|
471 | });
|
472 | };
|
473 | const addSuite = (response, suite, scenario) => {
|
474 | cli_1.Cli.addSuite(suite, scenario)
|
475 | .then(() => {
|
476 | sendOutput(response, `Added new suite <em>${suite.name}</em>. <a href="/">Back</a>`);
|
477 | })
|
478 | .catch(err => {
|
479 | sendOutput(response, `Error: ${err}`);
|
480 | });
|
481 | };
|
482 | const addEnv = (response, env) => {
|
483 | if (cli_1.Cli.config.environments[env.name]) {
|
484 | sendOutput(response, "Error: Environment name is already taken.");
|
485 | }
|
486 | else {
|
487 | cli_1.Cli.config.addEnvironment({
|
488 | name: env.name,
|
489 | defaultDomain: env.defaultDomain
|
490 | });
|
491 | cli_1.Cli.config
|
492 | .save()
|
493 | .then(() => {
|
494 | sendOutput(response, `Added new environment <em>${env.name}</em>. <a href="/">Back</a>`);
|
495 | })
|
496 | .catch(ex => {
|
497 | sendOutput(response, `Error: ${ex}`);
|
498 | });
|
499 | }
|
500 | };
|
501 | const runSuite = (response, suiteName, envName) => {
|
502 | let opts = flagpoleexecutionoptions_1.FlagpoleExecutionOptions.createFromString(`-h -o json -e ${envName} -x`);
|
503 | const execution = suiteexecution_1.SuiteExecution.executePath(cli_1.Cli.config.suites[suiteName].getTestPath(), opts);
|
504 | execution.result
|
505 | .then((result) => {
|
506 | const json = JSON.parse(result.output.join(" "));
|
507 | let output = `<h2>${json.title}</h2>`;
|
508 | json.scenarios.forEach((scenario) => {
|
509 | output += `<article><h3>${scenario.title}</h3>`;
|
510 | output += "<ul>";
|
511 | scenario.log.forEach((logLine) => {
|
512 | output += `<li class="${logLine.type.toLowerCase()}">${logLine.message}</li>`;
|
513 | });
|
514 | output += "</ul></article>";
|
515 | });
|
516 | output += `<p><a href="/">Back</a></p>`;
|
517 | sendOutput(response, output);
|
518 | })
|
519 | .catch(err => {
|
520 | sendOutput(response, err);
|
521 | });
|
522 | };
|
523 | const sendIndex = (response) => {
|
524 | const suites = cli_1.Cli.config.getSuites();
|
525 | let output = `
|
526 | <ul>
|
527 | <li>Project Name: ${cli_1.Cli.config.project.name}</li>
|
528 | <li>Config Path: ${cli_1.Cli.configPath}</li>
|
529 | <li>Project Path: ${cli_1.Cli.projectPath}</li>
|
530 | <li>Environment: ${flagpoleexecutionoptions_2.FlagpoleExecution.opts.environment}</li>
|
531 | </ul>
|
532 | <h2>List of Suites</h2>
|
533 | <table>
|
534 | <thead>
|
535 | <tr>
|
536 | <th>Name</th>
|
537 | <th>Tags</th>
|
538 | <th>Actions</th>
|
539 | </tr>
|
540 | </thead>
|
541 | <tbody>
|
542 | `;
|
543 | suites.forEach((suite) => {
|
544 | output += `
|
545 | <tr>
|
546 | <td>${suite.name}</td>
|
547 | <td>
|
548 | ${suite.tags.length
|
549 | ? suite.tags.join(", ")
|
550 | : "<em>no tags</em>"}
|
551 | </td>
|
552 | <td>
|
553 | <form method="POST" action="/run">
|
554 | <button type="submit" name="suite" value="${suite.name}">Run</button>
|
555 | </form>
|
556 | <form method="GET" action="/suite">
|
557 | <button type="submit" name="name" value="${suite.name}">Edit</button>
|
558 | </form>
|
559 | <form method="GET" action="/add/scenario">
|
560 | <button type="submit" name="suite" value="${suite.name}">Add Scenario</button>
|
561 | </form>
|
562 | <form method="POST" id="rm_suite_${suite.name}">
|
563 | <button type="button" onclick="removeSuite('${suite.name}')">Remove</button>
|
564 | </form>
|
565 | </td>
|
566 | </tr>
|
567 | `;
|
568 | });
|
569 | output += `
|
570 | </tbody>
|
571 | </table>
|
572 | <div class="field button">
|
573 | <form method="GET" action="/add/suite">
|
574 | <button type="subit">New Suite</button>
|
575 | </form>
|
576 | <form method="GET" action="/import/suite">
|
577 | <button type="submit">Import Suite</button>
|
578 | </form>
|
579 | </div>
|
580 | `;
|
581 | output += `
|
582 | <h2>List of Environments</h2>
|
583 | <table>
|
584 | <thead>
|
585 | <tr>
|
586 | <th>Name</th>
|
587 | <th>Base Path</th>
|
588 | <th>Actions</th>
|
589 | </tr>
|
590 | </thead>
|
591 | <tbody>
|
592 | `;
|
593 | cli_1.Cli.config.getEnvironments().forEach((env) => {
|
594 | output += `
|
595 | <tr>
|
596 | <td>${env.name}</td>
|
597 | <td>
|
598 | <a href="${env.defaultDomain}" target="_new">${env.defaultDomain}</a>
|
599 | </td>
|
600 | <td>
|
601 | <form method="POST" action="/rm?env=${env.name}" id="rm_env_${env.name}">
|
602 | <button type="button" onclick="removeEnv('${env.name}')">Remove</button>
|
603 | </form>
|
604 | </td>
|
605 | </tr>
|
606 | `;
|
607 | });
|
608 | output += `
|
609 | </tbody>
|
610 | </table>
|
611 | <div class="field button">
|
612 | <form method="GET" id="addEnv" action="/add/env">
|
613 | <button type="submit">Add Environment</button>
|
614 | </form>
|
615 | </aside>
|
616 | <script>
|
617 | function removeEnv(envName) {
|
618 | const yes = confirm('Remove this environment ' + envName + '?')
|
619 | if (yes) {
|
620 | const form = document.querySelector('#rm_env_' + envName);
|
621 | form.setAttribute('action', '/rm?env=' + envName);
|
622 | form.submit();
|
623 | }
|
624 | }
|
625 | function removeSuite(suiteName) {
|
626 | const yes = confirm('Remove this suite ' + suiteName + '?')
|
627 | if (yes) {
|
628 | const form = document.querySelector('#rm_suite_' + suiteName);
|
629 | form.setAttribute('action', '/rm?suite=' + suiteName);
|
630 | form.submit();
|
631 | }
|
632 | }
|
633 | </script>
|
634 | `;
|
635 | sendOutput(response, output);
|
636 | };
|
637 | function serve(port = 3000) {
|
638 | const handler = (request, response) => {
|
639 | const requestPath = request.url || "/";
|
640 | const method = (request.method || "GET").toUpperCase();
|
641 | const url = new url_1.URL(requestPath, `http://localhost:${server.httpPort}`);
|
642 | const route = `${method} ${url.pathname}`;
|
643 | function respond(postData) {
|
644 | return routes[route]
|
645 | ? routes[route](url, response, postData)
|
646 | : sendIndex(response);
|
647 | }
|
648 | if (!cli_1.Cli.isInitialized() && requestPath != "/init") {
|
649 | return sendGetInit(response);
|
650 | }
|
651 | else if (method == "POST") {
|
652 | let body = "";
|
653 | request.on("data", function (data) {
|
654 | body += String(data);
|
655 | if (body.length > 1e6) {
|
656 | request.connection.destroy();
|
657 | }
|
658 | });
|
659 | request.on("end", function () {
|
660 | respond(qs.parse(body));
|
661 | });
|
662 | }
|
663 | else {
|
664 | respond();
|
665 | }
|
666 | };
|
667 | const server = new webserver_1.WebServer(handler);
|
668 | server.listen(port).then(() => {
|
669 | const url = `http://localhost:${server.httpPort}/`;
|
670 | console.log(`Flagpole Web Server running at: ${url}`);
|
671 | open(url);
|
672 | });
|
673 | }
|
674 | exports.serve = serve;
|
675 |
|
\ | No newline at end of file |