github.com/outbrain/consul@v1.4.5/ui-v2/tests/steps.js (about) 1 /* eslint no-console: "off" */ 2 import Inflector from 'ember-inflector'; 3 import yadda from './helpers/yadda'; 4 import { currentURL, click, triggerKeyEvent, fillIn, find } from '@ember/test-helpers'; 5 import getDictionary from '@hashicorp/ember-cli-api-double/dictionary'; 6 import pages from 'consul-ui/tests/pages'; 7 import api from 'consul-ui/tests/helpers/api'; 8 // const dont = `( don't| shouldn't| can't)?`; 9 const pluralize = function(str) { 10 return Inflector.inflector.pluralize(str); 11 }; 12 const create = function(number, name, value) { 13 // don't return a promise here as 14 // I don't need it to wait 15 api.server.createList(name, number, value); 16 }; 17 const lastRequest = function(method) { 18 return api.server.history 19 .slice(0) 20 .reverse() 21 .find(function(item) { 22 return item.method === method; 23 }); 24 }; 25 const fillInElement = function(page, name, value) { 26 const cm = document.querySelector(`textarea[name="${name}"] + .CodeMirror`); 27 if (cm) { 28 cm.CodeMirror.setValue(value); 29 return page; 30 } else { 31 return page.fillIn(name, value); 32 } 33 }; 34 var currentPage; 35 export default function(assert) { 36 return ( 37 yadda.localisation.English.library( 38 getDictionary(function(model, cb) { 39 switch (model) { 40 case 'datacenter': 41 case 'datacenters': 42 case 'dcs': 43 model = 'dc'; 44 break; 45 case 'services': 46 model = 'service'; 47 break; 48 case 'nodes': 49 model = 'node'; 50 break; 51 case 'kvs': 52 model = 'kv'; 53 break; 54 case 'acls': 55 model = 'acl'; 56 break; 57 case 'sessions': 58 model = 'session'; 59 break; 60 case 'intentions': 61 model = 'intention'; 62 break; 63 } 64 cb(null, model); 65 }, yadda) 66 ) 67 // doubles 68 .given(['$number $model model[s]?', '$number $model models'], function(number, model) { 69 return create(number, model); 70 }) 71 .given(['$number $model model[s]? with the value "$value"'], function(number, model, value) { 72 return create(number, model, value); 73 }) 74 .given( 75 ['$number $model model[s]? from yaml\n$yaml', '$number $model model[s]? from json\n$json'], 76 function(number, model, data) { 77 return create(number, model, data); 78 } 79 ) 80 .given(["I'm using a legacy token"], function(number, model, data) { 81 window.localStorage['consul:token'] = JSON.stringify({ AccessorID: null, SecretID: 'id' }); 82 }) 83 // TODO: Abstract this away from HTTP 84 .given(['the url "$url" responds with a $status status'], function(url, status) { 85 return api.server.respondWithStatus(url.split('?')[0], parseInt(status)); 86 }) 87 .given(['the url "$url" responds with from yaml\n$yaml'], function(url, data) { 88 api.server.respondWith(url.split('?')[0], data); 89 }) 90 // interactions 91 .when('I visit the $name page', function(name) { 92 currentPage = pages[name]; 93 return currentPage.visit(); 94 }) 95 .when('I visit the $name page for the "$id" $model', function(name, id, model) { 96 currentPage = pages[name]; 97 return currentPage.visit({ 98 [model]: id, 99 }); 100 }) 101 .when( 102 ['I visit the $name page for yaml\n$yaml', 'I visit the $name page for json\n$json'], 103 function(name, data) { 104 currentPage = pages[name]; 105 // TODO: Consider putting an assertion here for testing the current url 106 // do I absolutely definitely need that all the time? 107 return pages[name].visit(data); 108 } 109 ) 110 .when('I click "$selector"', function(selector) { 111 return click(selector); 112 }) 113 // TODO: Probably nicer to think of better vocab than having the 'without " rule' 114 .when('I click (?!")$property(?!")', function(property) { 115 try { 116 return currentPage[property](); 117 } catch (e) { 118 console.error(e); 119 throw new Error(`The '${property}' property on the page object doesn't exist`); 120 } 121 }) 122 .when('I click $prop on the $component', function(prop, component) { 123 // Collection 124 var obj; 125 if (typeof currentPage[component].objectAt === 'function') { 126 obj = currentPage[component].objectAt(0); 127 } else { 128 obj = currentPage[component]; 129 } 130 const func = obj[prop].bind(obj); 131 try { 132 return func(); 133 } catch (e) { 134 throw new Error( 135 `The '${prop}' property on the '${component}' page object doesn't exist.\n${e.message}` 136 ); 137 } 138 }) 139 .when('I submit', function(selector) { 140 return currentPage.submit(); 141 }) 142 .then('I fill in "$name" with "$value"', function(name, value) { 143 return currentPage.fillIn(name, value); 144 }) 145 .then(['I fill in with yaml\n$yaml', 'I fill in with json\n$json'], function(data) { 146 return Object.keys(data).reduce(function(prev, item, i, arr) { 147 return fillInElement(prev, item, data[item]); 148 }, currentPage); 149 }) 150 .then( 151 ['I fill in the $form form with yaml\n$yaml', 'I fill in the $form with json\n$json'], 152 function(form, data) { 153 return Object.keys(data).reduce(function(prev, item, i, arr) { 154 const name = `${form}[${item}]`; 155 return fillInElement(prev, name, data[item]); 156 }, currentPage); 157 } 158 ) 159 .then(['I type "$text" into "$selector"'], function(text, selector) { 160 return fillIn(selector, text); 161 }) 162 .then(['I type with yaml\n$yaml'], function(data) { 163 const keys = Object.keys(data); 164 return keys 165 .reduce(function(prev, item, i, arr) { 166 return prev.fillIn(item, data[item]); 167 }, currentPage) 168 .then(function() { 169 return Promise.all( 170 keys.map(function(item) { 171 return triggerKeyEvent(`[name="${item}"]`, 'keyup', 83); // TODO: This is 's', be more generic 172 }) 173 ); 174 }); 175 }) 176 // debugging helpers 177 .then('print the current url', function(url) { 178 console.log(currentURL()); 179 return Promise.resolve(); 180 }) 181 .then('log the "$text"', function(text) { 182 console.log(text); 183 return Promise.resolve(); 184 }) 185 .then('pause for $milliseconds', function(milliseconds) { 186 return new Promise(function(resolve) { 187 setTimeout(resolve, milliseconds); 188 }); 189 }) 190 // assertions 191 .then('a $method request is made to "$url" with the body from yaml\n$yaml', function( 192 method, 193 url, 194 data 195 ) { 196 const request = api.server.history[api.server.history.length - 2]; 197 assert.equal( 198 request.method, 199 method, 200 `Expected the request method to be ${method}, was ${request.method}` 201 ); 202 assert.equal(request.url, url, `Expected the request url to be ${url}, was ${request.url}`); 203 const body = JSON.parse(request.requestBody); 204 Object.keys(data).forEach(function(key, i, arr) { 205 assert.deepEqual( 206 body[key], 207 data[key], 208 `Expected the payload to contain ${key} equaling ${data[key]}, ${key} was ${body[key]}` 209 ); 210 }); 211 }) 212 // TODO: This one can replace the above one, it covers more use cases 213 // also DRY it out a bit 214 .then('a $method request is made to "$url" from yaml\n$yaml', function(method, url, yaml) { 215 const request = api.server.history[api.server.history.length - 2]; 216 assert.equal( 217 request.method, 218 method, 219 `Expected the request method to be ${method}, was ${request.method}` 220 ); 221 assert.equal(request.url, url, `Expected the request url to be ${url}, was ${request.url}`); 222 let data = yaml.body || {}; 223 const body = JSON.parse(request.requestBody); 224 Object.keys(data).forEach(function(key, i, arr) { 225 assert.equal( 226 body[key], 227 data[key], 228 `Expected the payload to contain ${key} to equal ${body[key]}, ${key} was ${data[key]}` 229 ); 230 }); 231 data = yaml.headers || {}; 232 const headers = request.requestHeaders; 233 Object.keys(data).forEach(function(key, i, arr) { 234 assert.equal( 235 headers[key], 236 data[key], 237 `Expected the payload to contain ${key} to equal ${headers[key]}, ${key} was ${ 238 data[key] 239 }` 240 ); 241 }); 242 }) 243 .then('a $method request is made to "$url" with the body "$body"', function( 244 method, 245 url, 246 data 247 ) { 248 const request = api.server.history[api.server.history.length - 2]; 249 assert.equal( 250 request.method, 251 method, 252 `Expected the request method to be ${method}, was ${request.method}` 253 ); 254 assert.equal(request.url, url, `Expected the request url to be ${url}, was ${request.url}`); 255 const body = request.requestBody; 256 assert.equal(body, data, `Expected the request body to be ${data}, was ${body}`); 257 }) 258 .then('a $method request is made to "$url" with no body', function(method, url) { 259 const request = api.server.history[api.server.history.length - 2]; 260 assert.equal( 261 request.method, 262 method, 263 `Expected the request method to be ${method}, was ${request.method}` 264 ); 265 assert.equal(request.url, url, `Expected the request url to be ${url}, was ${request.url}`); 266 const body = request.requestBody; 267 assert.equal(body, null, `Expected the request body to be null, was ${body}`); 268 }) 269 270 .then('a $method request is made to "$url"', function(method, url) { 271 const request = api.server.history[api.server.history.length - 2]; 272 assert.equal( 273 request.method, 274 method, 275 `Expected the request method to be ${method}, was ${request.method}` 276 ); 277 assert.equal(request.url, url, `Expected the request url to be ${url}, was ${request.url}`); 278 }) 279 .then('the last $method request was made to "$url"', function(method, url) { 280 const request = lastRequest(method); 281 assert.equal( 282 request.method, 283 method, 284 `Expected the request method to be ${method}, was ${request.method}` 285 ); 286 assert.equal(request.url, url, `Expected the request url to be ${url}, was ${request.url}`); 287 }) 288 .then('the last $method request was made to "$url" with the body from yaml\n$yaml', function( 289 method, 290 url, 291 data 292 ) { 293 const request = lastRequest(method); 294 assert.ok(request, `Expected a ${method} request`); 295 assert.equal( 296 request.method, 297 method, 298 `Expected the request method to be ${method}, was ${request.method}` 299 ); 300 assert.equal(request.url, url, `Expected the request url to be ${url}, was ${request.url}`); 301 const body = JSON.parse(request.requestBody); 302 Object.keys(data).forEach(function(key, i, arr) { 303 assert.deepEqual( 304 body[key], 305 data[key], 306 `Expected the payload to contain ${key} equaling ${data[key]}, ${key} was ${body[key]}` 307 ); 308 }); 309 }) 310 .then('the last $method requests were like yaml\n$yaml', function(method, data) { 311 const requests = api.server.history.reverse().filter(function(item) { 312 return item.method === method; 313 }); 314 data.reverse().forEach(function(item, i, arr) { 315 assert.equal( 316 requests[i].url, 317 item, 318 `Expected the request url to be ${item}, was ${requests[i].url}` 319 ); 320 }); 321 }) 322 .then('the url should be $url', function(url) { 323 // TODO: nice! $url should be wrapped in "" 324 if (url === "''") { 325 url = ''; 326 } 327 const current = currentURL() || ''; 328 assert.equal(current, url, `Expected the url to be ${url} was ${current}`); 329 }) 330 .then(['I see $num $model', 'I see $num $model model', 'I see $num $model models'], function( 331 num, 332 model 333 ) { 334 const len = currentPage[pluralize(model)].filter(function(item) { 335 return item.isVisible; 336 }).length; 337 338 assert.equal(len, num, `Expected ${num} ${pluralize(model)}, saw ${len}`); 339 }) 340 // TODO: I${ dont } see 341 .then([`I see $num $model model[s]? with the $property "$value"`], function( 342 // negate, 343 num, 344 model, 345 property, 346 value 347 ) { 348 const len = currentPage[pluralize(model)].filter(function(item) { 349 return item.isVisible && item[property] == value; 350 }).length; 351 assert.equal( 352 len, 353 num, 354 `Expected ${num} ${pluralize(model)} with ${property} set to "${value}", saw ${len}` 355 ); 356 }) 357 // TODO: Make this accept a 'contains' word so you can search for text containing also 358 .then('I have settings like yaml\n$yaml', function(data) { 359 // TODO: Inject this 360 const settings = window.localStorage; 361 Object.keys(data).forEach(function(prop) { 362 const actual = settings.getItem(prop); 363 const expected = data[prop]; 364 assert.strictEqual(actual, expected, `Expected settings to be ${expected} was ${actual}`); 365 }); 366 }) 367 .then('I see $property on the $component like yaml\n$yaml', function( 368 property, 369 component, 370 yaml 371 ) { 372 const _component = currentPage[component]; 373 const iterator = new Array(_component.length).fill(true); 374 // this will catch if we get aren't managing to select a component 375 assert.ok(iterator.length > 0); 376 iterator.forEach(function(item, i, arr) { 377 const actual = 378 typeof _component.objectAt(i)[property] === 'undefined' 379 ? null 380 : _component.objectAt(i)[property]; 381 382 // anything coming from the DOM is going to be text/strings 383 // if the yaml has numbers, cast them to strings 384 // TODO: This would get problematic for deeper objects 385 // will have to look to do this recursively 386 const expected = typeof yaml[i] === 'number' ? yaml[i].toString() : yaml[i]; 387 388 assert.deepEqual( 389 actual, 390 expected, 391 `Expected to see ${property} on ${component}[${i}] as ${JSON.stringify( 392 expected 393 )}, was ${JSON.stringify(actual)}` 394 ); 395 }); 396 }) 397 .then(['I see $property on the $component'], function(property, component) { 398 // TODO: Time to work on repetition 399 // Collection 400 var obj; 401 if (typeof currentPage[component].objectAt === 'function') { 402 obj = currentPage[component].objectAt(0); 403 } else { 404 obj = currentPage[component]; 405 } 406 let _component; 407 if (typeof obj === 'function') { 408 const func = obj[property].bind(obj); 409 try { 410 _component = func(); 411 } catch (e) { 412 console.error(e); 413 throw new Error( 414 `The '${property}' property on the '${component}' page object doesn't exist` 415 ); 416 } 417 } else { 418 _component = obj; 419 } 420 assert.ok(_component[property], `Expected to see ${property} on ${component}`); 421 }) 422 .then(["I don't see $property on the $component"], function(property, component) { 423 // Collection 424 var obj; 425 if (typeof currentPage[component].objectAt === 'function') { 426 obj = currentPage[component].objectAt(0); 427 } else { 428 obj = currentPage[component]; 429 } 430 const func = obj[property].bind(obj); 431 assert.throws( 432 function() { 433 func(); 434 }, 435 function(e) { 436 return e.toString().indexOf('Element not found') !== -1; 437 }, 438 `Expected to not see ${property} on ${component}` 439 ); 440 }) 441 .then(["I don't see $property"], function(property) { 442 assert.throws( 443 function() { 444 currentPage[property](); 445 }, 446 function(e) { 447 return e.toString().indexOf('Element not found') !== -1; 448 }, 449 `Expected to not see ${property}` 450 ); 451 }) 452 .then(['I see $property'], function(property) { 453 assert.ok(currentPage[property], `Expected to see ${property}`); 454 }) 455 .then(['I see $property like "$value"'], function(property, value) { 456 assert.equal( 457 currentPage[property], 458 value, 459 `Expected to see ${property}, was ${currentPage[property]}` 460 ); 461 }) 462 .then(['I see the text "$text" in "$selector"'], function(text, selector) { 463 assert.ok( 464 find(selector).textContent.indexOf(text) !== -1, 465 `Expected to see "${text}" in "${selector}"` 466 ); 467 }) 468 // TODO: Think of better language 469 // TODO: These should be mergeable 470 .then(['"$selector" has the "$class" class'], function(selector, cls) { 471 // because `find` doesn't work, guessing its sandboxed to ember's container 472 assert.ok( 473 document.querySelector(selector).classList.contains(cls), 474 `Expected [class] to contain ${cls} on ${selector}` 475 ); 476 }) 477 .then(['"$selector" doesn\'t have the "$class" class'], function(selector, cls) { 478 assert.ok( 479 !document.querySelector(selector).classList.contains(cls), 480 `Expected [class] not to contain ${cls} on ${selector}` 481 ); 482 }) 483 .then('ok', function() { 484 assert.ok(true); 485 }) 486 ); 487 }