Skip to content

Commit add3166

Browse files
authored
Merge pull request ember-learn#594 from muziejus/octane-testing
Reading/Editing/Octaning “Testing” section
2 parents ded29db + 993f32f commit add3166

File tree

5 files changed

+102
-137
lines changed

5 files changed

+102
-137
lines changed

guides/release/testing/acceptance.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -83,22 +83,22 @@ your application, making it much easier to write deterministic tests.
8383

8484
Some of these handy helpers are:
8585

86-
* [`click(selector)`][1]
87-
- Clicks an element and triggers any actions triggered by the element's `click`
88-
event and returns a promise that fulfills when all resulting async behavior
89-
is complete.
90-
* [`fillIn(selector, value)`][2]
91-
- Fills in the selected input with the given value and returns a promise that
92-
fulfills when all resulting async behavior is complete. Works with `<select>` elements as well as `<input>` elements. Keep in mind that with `<select>` elements, `value` must be set to the _value_ of the `<option>` tag, rather than its _content_ (for example, `true` rather than `"Yes"`).
93-
* [`triggerKeyEvent(selector, type, keyCode)`][3]
94-
- Simulates a key event type, e.g. `keypress`, `keydown`, `keyup` with the
95-
desired keyCode on element found by the selector.
96-
* [`triggerEvent(selector, type, options)`][4]
97-
- Triggers the given event, e.g. `blur`, `dblclick` on the element identified
98-
by the provided selector.
99-
* [`visit(url)`][5]
100-
- Visits the given route and returns a promise that fulfills when all resulting
101-
async behavior is complete.
86+
* [`click(selector)`][1]: clicks an element and triggers any actions triggered
87+
by the element's `click` event and returns a promise that fulfills when all
88+
resulting async behavior is complete.
89+
* [`fillIn(selector, value)`][2]: fills in the selected input with the given
90+
value and returns a promise that fulfills when all resulting async behavior is
91+
complete. Works with `<select>` elements as well as `<input>` elements. Keep
92+
in mind that with `<select>` elements, `value` must be set to the _value_ of
93+
the `<option>` tag, rather than its _content_ (for example, `true` rather than
94+
`"Yes"`).
95+
* [`triggerKeyEvent(selector, type, keyCode)`][3]: simulates a key event type,
96+
e.g. `keypress`, `keydown`, `keyup` with the desired keyCode on element found
97+
by the selector.
98+
* [`triggerEvent(selector, type, options)`][4]: triggers the given event, e.g.
99+
`blur`, `dblclick` on the element identified by the provided selector.
100+
* [`visit(url)`][5]: visits the given route and returns a promise that
101+
fulfills when all resulting async behavior is complete.
102102

103103
You can find the full list of helpers in the [API Documentation of ember-test-helpers](https://github.com/emberjs/ember-test-helpers/blob/master/API.md).
104104

guides/release/testing/testing-components.md

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,19 @@ The `style` attribute of the component is bound to its `style` property.
88
> component pretty-color`.
99
1010
```javascript {data-filename="app/components/pretty-color.js"}
11-
import Component from '@ember/component';
12-
import { computed } from '@ember/object';
11+
import Component from '@glimmer/component';
1312

14-
export default Component.extend({
15-
attributeBindings: ['style'],
16-
17-
style: computed('name', function() {
18-
return `color: ${this.name}`;
19-
})
20-
});
13+
export default class PrettyColorComponent extends Component {
14+
get style() {
15+
return `color: ${this.args.name}`;
16+
}
17+
}
2118
```
2219

2320
```handlebars {data-filename="app/templates/components/pretty-color.hbs"}
24-
Pretty Color: {{this.name}}
21+
<div style={{this.style}}>
22+
Pretty Color: {{@name}}
23+
</div>
2524
```
2625

2726
The `module` from QUnit will scope your tests into groups of tests which can be configured and run independently.
@@ -156,23 +155,23 @@ Imagine you have the following component that changes its title when a button is
156155
> component magic-title`.
157156
158157
```javascript {data-filename="app/components/magic-title.js"}
159-
import Component from '@ember/component';
158+
import Component from '@glimmer/component';
159+
import { action } from '@ember/object';
160160

161-
export default Component.extend({
162-
title: 'Hello World',
161+
export default class MagicTitleComponent extends Component {
162+
title = 'Hello World';
163163

164-
actions: {
165-
updateTitle() {
166-
this.set('title', 'This is Magic');
167-
}
164+
@action
165+
updateTitle() {
166+
this.set('title', 'This is Magic');
168167
}
169-
});
168+
}
170169
```
171170

172171
```handlebars {data-filename="app/templates/components/magic-title.hbs"}
173172
<h2>{{this.title}}</h2>
174173
175-
<button class="title-button" {{action "updateTitle"}}>
174+
<button class="title-button" {{action this.updateTitle}}>
176175
Update Title
177176
</button>
178177
```
@@ -218,21 +217,21 @@ passing along the form's data:
218217
> component comment-form`.
219218
220219
```javascript {data-filename="app/components/comment-form.js"}
221-
import Component from '@ember/component';
220+
import Component from '@glimmer/component';
221+
import { action } from '@ember/object';
222222

223-
export default Component.extend({
224-
comment: '',
223+
export default class CommentFormComponent extends Component {
224+
comment = '';
225225

226-
actions: {
227-
submitComment() {
228-
this.submitComment({ comment: this.comment });;
229-
}
226+
@action
227+
submitComment() {
228+
this.args.submitComment({ comment: this.comment });;
230229
}
231-
});
230+
}
232231
```
233232

234233
```handlebars {data-filename="app/templates/components/comment-form.hbs"}
235-
<form {{action "submitComment" on="submit"}}>
234+
<form {{action this.submitComment on="submit"}}>
236235
<label>Comment:</label>
237236
{{textarea value=this.comment}}
238237
@@ -285,22 +284,21 @@ Imagine you have the following component that uses a location service to display
285284
> component location-indicator`.
286285
287286
```javascript {data-filename="app/components/location-indicator.js"}
288-
import Component from '@ember/component';
289-
import { computed } from '@ember/object';
287+
import Component from '@glimmer/component';
290288
import { inject as service } from '@ember/service';
291289

292-
export default Component.extend({
293-
locationService: service('location-service'),
290+
export default class LocationIndicatorComponent extends Component {
291+
@service location;
294292

295293
// when the coordinates change, call the location service to get the current city and country
296-
city: computed('locationService.currentLocation', function () {
297-
return this.locationService.getCurrentCity();
298-
}),
294+
get city() {
295+
return this.location.getCurrentCity();
296+
}
299297

300-
country: computed('locationService.currentLocation', function () {
301-
return this.locationService.getCurrentCountry();
302-
})
303-
});
298+
get country() {
299+
return this.location.getCurrentCountry();
300+
}
301+
};
304302
```
305303

306304
```handlebars {data-filename="app/templates/components/location-indicator.hbs"}
@@ -465,17 +463,17 @@ Imagine you have a typeahead component that uses [`Ember.run.debounce`](https://
465463
> component delayed-typeahead`.
466464
467465
```javascript {data-filename="app/components/delayed-typeahead.js"}
468-
import Component from '@ember/component';
466+
import Component from '@glimmer/component';
467+
import { action } from '@ember/object';
469468
import { debounce } from '@ember/runloop';
470469

471-
export default Component.extend({
472-
actions: {
473-
handleTyping() {
474-
//the fetchResults function is passed into the component from its parent
475-
debounce(this, this.fetchResults, this.searchValue, 250);
476-
}
470+
export default class DelayedTypeaheadComponent extends Component {
471+
@action
472+
handleTyping() {
473+
//the fetchResults function is passed into the component from its parent
474+
debounce(this, this.fetchResults, this.searchValue, 250);
477475
}
478-
});
476+
};
479477
```
480478

481479
```handlebars {data-filename="app/templates/components/delayed-typeahead.hbs"}

guides/release/testing/testing-controllers.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,22 @@ sets one of those properties, and an action named `setProps`.
1515
1616
```javascript {data-filename=app/controllers/posts.js}
1717
import Controller from '@ember/controller';
18+
import { action } from '@ember/object';
1819

19-
export default Controller.extend({
20-
propA: 'You need to write tests',
21-
propB: 'And write one for me too',
20+
export default class PostsController extends Controller {
21+
propA = 'You need to write tests';
22+
propB = 'And write one for me too';
2223

2324
setPropB(str) {
2425
this.set('propB', str);
25-
},
26+
}
2627

27-
actions: {
28-
setProps(str) {
29-
this.set('propA', 'Testing is cool');
30-
this.setPropB(str);
31-
}
28+
@action
29+
setProps(str) {
30+
this.set('propA', 'Testing is cool');
31+
this.setPropB(str);
3232
}
33-
});
33+
};
3434
```
3535

3636
The `setProps` action directly sets one property, and calls the method to set the other.

guides/release/testing/testing-models.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ new `levelName` when the player reaches level 5.
1111
> model player`.
1212
1313
```javascript {data-filename=app/models/player.js}
14-
import Model from 'ember-data/model';
15-
import attr from 'ember-data/attr';
14+
import DS from 'ember-data';
15+
const { Model, attr } = DS;
1616

17-
export default Model.extend({
18-
level: attr('number', { defaultValue: 0 }),
19-
levelName: attr('string', { defaultValue: 'Noob' }),
17+
export default class Player extends Model {
18+
@attr('number', { defaultValue: 0 }) level;
19+
@attr('string', { defaultValue: 'Noob' }) levelName;
2020

2121
levelUp() {
2222
let newLevel = this.incrementProperty('level');
2323
if (newLevel === 5) {
2424
this.set('levelName', 'Professional');
2525
}
2626
}
27-
});
27+
};
2828
```
2929

3030
Now let's create a test which will call `levelUp` on the player when they are
@@ -65,19 +65,20 @@ Assume that a `User` can own a `Profile`.
6565
> generate model user` and `ember generate model profile`.
6666
6767
```javascript {data-filename=app/models/profile.js}
68-
import Model from 'ember-data/model';
68+
import DS from 'ember-data';
69+
const { Model } = DS;
6970

70-
export default Model.extend({
71-
});
71+
export default class Profile extends Model {
72+
};
7273
```
7374

7475
```javascript {data-filename=app/models/user.js}
75-
import Model from 'ember-data/model';
76-
import { belongsTo } from 'ember-data/relationships';
76+
import DS from 'ember-data';
77+
const { Model, belongsTo } = DS;
7778

78-
export default Model.extend({
79-
profile: belongsTo('profile')
80-
});
79+
export default class User extends Model {
80+
@belongsTo('profile') profile;
81+
};
8182
```
8283

8384
Then you could test that the relationship by looking it up on the `user` model which it is part of.

guides/release/testing/unit-testing-basics.md

Lines changed: 16 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ based on a `foo` property.
1616
```javascript {data-filename=app/services/some-thing.js}
1717
import Service from '@ember/service';
1818
import { computed } from '@ember/object';
19+
import { tracked } from '@glimmer/tracking';
1920

20-
export default Service.extend({
21-
foo: 'bar',
21+
export default class SomeThingService extends Service {
22+
@tracked foo = 'bar';
2223

23-
computedFoo: computed('foo', function() {
24+
get computedFoo() {
2425
return `computed ${this.foo}`;
25-
})
26-
});
26+
}
27+
};
2728
```
2829

2930
Within the test for this object, we'll lookup the service instance, update the `foo` property (which
@@ -64,14 +65,15 @@ the `foo` property).
6465

6566
```javascript {data-filename=app/services/some-thing.js}
6667
import Service from '@ember/service';
68+
import { tracked } from '@glimmer/tracking';
6769

68-
export default Service.extend({
69-
foo: 'bar',
70+
export default class SomeThingService extends Service {
71+
@tracked foo = 'bar';
7072

7173
testMethod() {
72-
this.set('foo', 'baz');
74+
this.foo = 'baz';
7375
}
74-
});
76+
}
7577
```
7678

7779
To test it, we create an instance of our class `SomeThing` as defined above,
@@ -101,15 +103,16 @@ that returns a value based on some internal state.
101103

102104
```javascript {data-filename=app/services/some-thing.js}
103105
import Service from '@ember/service';
106+
import { tracked } from '@glimmer/tracking';
104107

105-
export default Service.extend({
106-
count: 0,
108+
export default class SomeThingService extends Service {
109+
@tracked count = 0;
107110

108111
calc() {
109-
this.incrementProperty('count');
112+
this.count += 1;
110113
return `count: ${this.count}`;
111114
}
112-
});
115+
};
113116
```
114117

115118
The test would call the `calc` method and assert it gets back the correct value.
@@ -130,43 +133,6 @@ module('Unit | Service | some thing', function(hooks) {
130133
});
131134
```
132135

133-
### Testing Observers
134-
135-
Suppose we have an object that has a property and a method observing that property.
136-
137-
```javascript {data-filename=app/services/some-thing.js}
138-
import Service from '@ember/service';
139-
import { observer } from "@ember/object";
140-
141-
export default Service.extend({
142-
foo: 'bar',
143-
other: 'no',
144-
145-
doSomething: observer('foo', function() {
146-
this.set('other', 'yes');
147-
})
148-
});
149-
```
150-
151-
In order to test the `doSomething` method we create an instance of `SomeThing`,
152-
update the observed property (`foo`), and assert that the expected effects are present.
153-
154-
```javascript {data-filename=tests/unit/services/some-thing-test.js}
155-
import { module, test } from 'qunit';
156-
import { setupTest } from 'ember-qunit';
157-
158-
module('Unit | Service | some thing', function(hooks) {
159-
setupTest(hooks);
160-
161-
test('should set other prop to yes when foo changes', function(assert) {
162-
const someThing = this.owner.lookup('service:some-thing');
163-
164-
someThing.set('foo', 'baz');
165-
assert.equal(someThing.get('other'), 'yes');
166-
});
167-
});
168-
```
169-
170136
### Skipping tests
171137

172138
Some times you might be working on a feature, but know that a certain test will fail so you might want to skip it.

0 commit comments

Comments
 (0)