Wikipedia para siempre
ShareCode
Permalink: http://www.treeweb.es/u/974/ 01/02/2011

ShareCode

1 <!DOCTYPE html>2 <html lang="es">3 <head>4  <meta charset="UTF-8">5  <title>Plataforma de Testing Automatizado de APIs</title>6  <!-- Enlaces a Bootstrap CSS y Bootstrap Icons -->7  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">8  <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" rel="stylesheet">9  <!-- Estilos personalizados -->10  <style>11  body {12  background-color: var(--bs-body-bg);13  color: var(--bs-body-color);14  transition: background-color 0.3s, color 0.3s;15  }16  .block {17  border: 1px solid #dee2e6;18  border-radius: 5px;19  margin-bottom: 10px;20  overflow: hidden;21  }22  .block-header {23  background-color: #f8f9fa;24  padding: 8px 12px;25  display: flex;26  align-items: center;27  justify-content: space-between;28  }29  .block-body {30  padding: 12px;31  }32  .block-controls button {33  background: none;34  border: none;35  margin-left: 5px;36  color: #6c757d;37  }38  .block-controls button:hover {39  color: #000;40  }41  .add-block {42  text-align: center;43  margin: 20px 0;44  }45  .theme-toggle {46  cursor: pointer;47  }48  .var-label {49  font-weight: bold;50  color: #0d6efd;51  margin-right: 10px;52  }53  .execute-btn {54  background: none;55  border: none;56  color: #198754;57  font-size: 1.2em;58  }59  .execute-btn:hover {60  color: #145c32;61  }62  </style>63 </head>64 <body>65  <!-- Barra de navegación -->66  <nav class="navbar navbar-expand-lg navbar-dark bg-primary">67  <div class="container-fluid">68  <a class="navbar-brand" href="#">69  <!-- Logo -->70  <img src="https://via.placeholder.com/150x40?text=Logo" alt="Logo">71  </a>72  <span class="navbar-text text-white">73  Plataforma de Testing Automatizado de APIs74  </span>75  <button class="btn btn-secondary ms-auto theme-toggle" id="themeToggle">76  <i class="bi bi-moon-fill"></i>77  </button>78  </div>79  </nav>80 81  <!-- Contenido principal -->82  <div id="app" class="container my-4">83  <!-- Lista de bloques -->84  <div v-for="(block, index) in blocks" :key="index" class="block">85  <div class="block-header">86  <div>87  <i :class="getBlockIcon(block.type)"></i>88  <span v-if="block.type === 'variable'" class="var-label">VAR</span>89  <strong v-html="getBlockTitle(block)"></strong>90  </div>91  <div class="block-controls">92  <button @click="moveUp(index)" :disabled="index === 0"><i class="bi bi-arrow-up"></i></button>93  <button @click="moveDown(index)" :disabled="index === blocks.length - 1"><i class="bi bi-arrow-down"></i></button>94  <button v-if="block.type === 'request'" @click="executeRequestBlock(index)" class="execute-btn"><i class="bi bi-play-circle"></i></button>95  <button @click="toggleBlock(index)"><i :class="block.expanded ? 'bi bi-chevron-up' : 'bi bi-chevron-down'"></i></button>96  <button @click="removeBlock(index)"><i class="bi bi-trash"></i></button>97  </div>98  </div>99  <div class="block-body" v-if="block.expanded">100  <!-- Contenido dinámico según el tipo de bloque -->101  <component :is="getBlockComponent(block.type)" v-model="block.data"></component>102  </div>103  </div>104 105  <!-- Botones para añadir nuevos bloques -->106  <div class="add-block">107  <button class="btn btn-outline-primary me-2" @click="addBlock('variable')">108  <i class="bi bi-sliders"></i> Variable109  </button>110  <button class="btn btn-outline-primary me-2" @click="addBlock('request')">111  <i class="bi bi-arrow-up-right-circle"></i> Solicitud HTTP112  </button>113  <button class="btn btn-outline-primary me-2" @click="addBlock('assertion')">114  <i class="bi bi-check-circle"></i> Aserción115  </button>116  <!-- Agrega más botones si es necesario -->117  </div>118 119  <!-- Botón de Ejecución -->120  <div class="text-center my-4">121  <button class="btn btn-lg btn-success" @click="executeTest" :disabled="!isExecutable">122  <i class="bi bi-play-fill"></i> Ejecutar Prueba Completa123  </button>124  </div>125 126  <!-- Resultados -->127  <div class="block" v-if="result">128  <div class="block-header" :class="{'bg-success text-white': result.success, 'bg-danger text-white': !result.success}">129  <strong>Resultado</strong>130  </div>131  <div class="block-body">132  <p><strong>STATUS:</strong> {{ result.status }}</p>133  <p><strong>Mensaje:</strong> {{ result.message }}</p>134  </div>135  </div>136  </div>137 138  <!-- Enlaces a Vue.js y Bootstrap JS -->139  <script src="https://cdn.jsdelivr.net/npm/vue@3.3.4/dist/vue.global.prod.js"></script>140  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>141 142  <!-- Componentes para los bloques -->143  <script>144  const VariableBlock = {145  template: `146  <div class="d-flex align-items-center">147  <span class="var-label">VAR</span>148  <input type="text" class="form-control me-2" v-model="data.name" placeholder="Nombre" style="max-width: 200px;">149  <input type="text" class="form-control" v-model="data.value" placeholder="Valor" style="max-width: 200px;">150  </div>151  `,152  props: ['modelValue'],153  computed: {154  data: {155  get() { return this.modelValue; },156  set(value) { this.$emit('update:modelValue', value); }157  }158  }159  };160 161  const RequestBlock = {162  template: `163  <div>164  <!-- Método y URL en una sola línea -->165  <div class="d-flex align-items-center">166  <select class="form-select me-2" v-model="data.method" style="max-width: 100px;">167  <option>GET</option>168  <option>POST</option>169  <option>PUT</option>170  <option>DELETE</option>171  </select>172  <input type="text" class="form-control" v-model="data.url" placeholder="URL">173  </div>174  <!-- Botones para Headers y Body -->175  <div class="mt-2">176  <button class="btn btn-sm btn-outline-secondary me-2" @click="toggleHeaders">177  <i class="bi" :class="showHeaders ? 'bi-dash' : 'bi-plus'"></i> Headers178  </button>179  <button class="btn btn-sm btn-outline-secondary" @click="toggleBody" v-if="data.method !== 'GET'">180  <i class="bi" :class="showBody ? 'bi-dash' : 'bi-plus'"></i> Body181  </button>182  </div>183  <!-- Headers -->184  <div v-if="showHeaders" class="mt-2">185  <div v-for="(header, index) in data.headers" :key="index" class="row g-2 mb-2 align-items-center">186  <div class="col-md-5">187  <input type="text" class="form-control" v-model="header.key" placeholder="Header Key">188  </div>189  <div class="col-md-5">190  <input type="text" class="form-control" v-model="header.value" placeholder="Header Value">191  </div>192  <div class="col-md-2">193  <button class="btn btn-outline-danger w-100" @click="removeHeader(index)">194  <i class="bi bi-trash"></i>195  </button>196  </div>197  </div>198  <button class="btn btn-outline-primary add-button" @click="addHeader">199  <i class="bi bi-plus-lg"></i> Agregar Header200  </button>201  </div>202  <!-- Body -->203  <div v-if="showBody" class="mt-2">204  <label class="form-label">Body</label>205  <textarea class="form-control" rows="3" v-model="data.body" placeholder="Cuerpo de la solicitud"></textarea>206  </div>207  </div>208  `,209  props: ['modelValue'],210  data() {211  return {212  showHeaders: false,213  showBody: false,214  }215  },216  computed: {217  data: {218  get() { return this.modelValue; },219  set(value) { this.$emit('update:modelValue', value); }220  }221  },222  methods: {223  toggleHeaders() {224  this.showHeaders = !this.showHeaders;225  },226  toggleBody() {227  this.showBody = !this.showBody;228  },229  addHeader() {230  this.data.headers.push({ key: '', value: '' });231  },232  removeHeader(index) {233  this.data.headers.splice(index, 1);234  }235  }236  };237 238  const AssertionBlock = {239  template: `240  <div class="d-flex align-items-center">241  <span class="me-2"><i class="bi bi-check2-circle"></i> Aserción:</span>242  <input type="text" class="form-control" v-model="data.condition" placeholder="Condición">243  </div>244  `,245  props: ['modelValue'],246  computed: {247  data: {248  get() { return this.modelValue; },249  set(value) { this.$emit('update:modelValue', value); }250  }251  }252  };253 254  // Instancia de Vue255  const { createApp } = Vue;256 257  createApp({258  components: {259  'variable-block': VariableBlock,260  'request-block': RequestBlock,261  'assertion-block': AssertionBlock,262  // Agrega más componentes según sea necesario263  },264  data() {265  return {266  blocks: [],267  result: null,268  darkTheme: false,269  }270  },271  computed: {272  isExecutable() {273  // Verifica si hay al menos un bloque para ejecutar274  return this.blocks.length > 0;275  }276  },277  methods: {278  getBlockTitle(block) {279  switch (block.type) {280  case 'variable':281  return `${block.data.name} = ${block.data.value}`;282  case 'request':283  return `${block.data.method} ${block.data.url}`;284  case 'assertion':285  return `${block.data.condition}`;286  // Otros casos...287  }288  },289  getBlockIcon(type) {290  switch (type) {291  case 'variable':292  return 'bi bi-sliders';293  case 'request':294  return 'bi bi-arrow-up-right-circle';295  case 'assertion':296  return 'bi bi-check-circle';297  // Otros casos...298  }299  },300  getBlockComponent(type) {301  switch (type) {302  case 'variable':303  return 'variable-block';304  case 'request':305  return 'request-block';306  case 'assertion':307  return 'assertion-block';308  // Otros casos...309  }310  },311  toggleBlock(index) {312  this.blocks[index].expanded = !this.blocks[index].expanded;313  },314  moveUp(index) {315  if (index > 0) {316  [this.blocks[index - 1], this.blocks[index]] = [this.blocks[index], this.blocks[index - 1]];317  }318  },319  moveDown(index) {320  if (index < this.blocks.length - 1) {321  [this.blocks[index], this.blocks[index + 1]] = [this.blocks[index + 1], this.blocks[index]];322  }323  },324  removeBlock(index) {325  this.blocks.splice(index, 1);326  },327  addBlock(type) {328  let newBlock = {329  type: type,330  expanded: true,331  data: {}332  };333  switch (type) {334  case 'variable':335  newBlock.data = { name: '', value: '' };336  break;337  case 'request':338  newBlock.data = { method: 'GET', url: '', headers: [], body: '' };339  break;340  case 'assertion':341  newBlock.data = { condition: '' };342  break;343  // Otros casos...344  }345  this.blocks.push(newBlock);346  },347  executeTest() {348  // Simulación de ejecución de prueba completa349  this.result = {350  success: true,351  status: 'COMPLETED',352  message: 'Prueba completa ejecutada exitosamente.'353  };354  // Animación de scroll al resultado355  this.$nextTick(() => {356  const resultBlock = document.querySelector('.block:last-child');357  resultBlock.scrollIntoView({ behavior: 'smooth' });358  });359  },360  executeRequestBlock(index) {361  // Simulación de ejecución individual del bloque Request362  alert(`Ejecutando solicitud: ${this.blocks[index].data.method} ${this.blocks[index].data.url}`);363  // Aquí podrías implementar la lógica para ejecutar solo este bloque y mostrar resultados364  }365  },366  mounted() {367  // Inicializar el tema según las preferencias del usuario368  const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;369  if (prefersDark) {370  this.toggleTheme();371  }372  }373  }).mount('#app');374 375  // Manejo del botón de cambio de tema fuera de Vue376  document.getElementById('themeToggle').addEventListener('click', () => {377  document.body.classList.toggle('bg-dark');378  document.body.classList.toggle('text-white');379  const icon = document.getElementById('themeToggle').querySelector('i');380  icon.classList.toggle('bi-moon-fill');381  icon.classList.toggle('bi-sun-fill');382  });383  </script>384 </body>385 </html>386 


Este ShareCode tiene versiones:
  1. Plataforma de Testing Automa... (28/09/2024)
Enlace
El enlace para compartir es: