@@ -90,7 +90,7 @@ Obviously we should reduce test dependencies, and avoiding
...
@@ -90,7 +90,7 @@ Obviously we should reduce test dependencies, and avoiding
capabilities also reduces the amount of set-up needed.
capabilities also reduces the amount of set-up needed.
`:js` is particularly important to avoid. This must only be used if the feature
`:js` is particularly important to avoid. This must only be used if the feature
test requires JavaScript reactivity in the browser, since using a headless
test requires JavaScript reactivity in the browser. Using a headless
browser is much slower than parsing the HTML response from the app.
browser is much slower than parsing the HTML response from the app.
#### Optimize factory usage
#### Optimize factory usage
...
@@ -108,8 +108,8 @@ To avoid creation, it is worth bearing in mind that:
...
@@ -108,8 +108,8 @@ To avoid creation, it is worth bearing in mind that:
-`instance_double` and `spy` are faster than `FactoryBot.build(...)`.
-`instance_double` and `spy` are faster than `FactoryBot.build(...)`.
-`FactoryBot.build(...)` and `.build_stubbed` are faster than `.create`.
-`FactoryBot.build(...)` and `.build_stubbed` are faster than `.create`.
- Don't `create` an object when `build`, `build_stubbed`, `attributes_for`,
- Don't `create` an object when you can use `build`, `build_stubbed`, `attributes_for`,
`spy`, or `instance_double` will do. Database persistence is slow!
`spy`, or `instance_double`. Database persistence is slow!
Use [Factory Doctor](https://test-prof.evilmartians.io/#/profilers/factory_doctor) to find cases where database persistence is not needed in a given test.
Use [Factory Doctor](https://test-prof.evilmartians.io/#/profilers/factory_doctor) to find cases where database persistence is not needed in a given test.
...
@@ -171,14 +171,14 @@ RSpec.describe API::Search, factory_default: :keep do
...
@@ -171,14 +171,14 @@ RSpec.describe API::Search, factory_default: :keep do
let_it_be(:namespace){create_default(:namespace)}
let_it_be(:namespace){create_default(:namespace)}
```
```
Then every project we create will use this `namespace`, without us having to pass
Then every project we create uses this `namespace`, without us having to pass
it as `namespace: namespace`. In order to make it work along with `let_it_be`, `factory_default: :keep`
it as `namespace: namespace`. In order to make it work along with `let_it_be`, `factory_default: :keep`
must be explicitly specified. That will keep the default factory for every example in a suite instead of
must be explicitly specified. That keeps the default factory for every example in a suite instead of
recreating it for each example.
recreating it for each example.
Maybe we don't need to create 208 different projects - we
Maybe we don't need to create 208 different projects - we
can create one and reuse it. In addition, we can see that only about 1/3 of the
can create one and reuse it. In addition, we can see that only about 1/3 of the
projects we create are ones we ask for (76/208), so there is benefit in setting
projects we create are ones we ask for (76/208). There is benefit in setting
a default value for projects as well:
a default value for projects as well:
```ruby
```ruby
...
@@ -233,8 +233,8 @@ Finished in 2 minutes 19 seconds (files took 1 minute 4.42 seconds to load)
...
@@ -233,8 +233,8 @@ Finished in 2 minutes 19 seconds (files took 1 minute 4.42 seconds to load)
```
```
From this result, we can see the most expensive examples in our spec, giving us
From this result, we can see the most expensive examples in our spec, giving us
a place to start. The fact that the most expensive examples here are in
a place to start. The most expensive examples here are in
shared examples means that any reductions are likely to have a larger impact as
shared examples; any reductions generally have a larger impact as
they are called in multiple places.
they are called in multiple places.
#### Avoid repeating expensive actions
#### Avoid repeating expensive actions
...
@@ -287,7 +287,7 @@ results are available, and not just the first failure.
...
@@ -287,7 +287,7 @@ results are available, and not just the first failure.
- Use `.method` to describe class methods and `#method` to describe instance
- Use `.method` to describe class methods and `#method` to describe instance
methods.
methods.
- Use `context` to test branching logic.
- Use `context` to test branching logic.
- Try to match the ordering of tests to the ordering within the class.
- Try to match the ordering of tests to the ordering in the class.
- Try to follow the [Four-Phase Test](https://thoughtbot.com/blog/four-phase-test) pattern, using newlines
- Try to follow the [Four-Phase Test](https://thoughtbot.com/blog/four-phase-test) pattern, using newlines
to separate phases.
to separate phases.
- Use `Gitlab.config.gitlab.host` rather than hard coding `'localhost'`
- Use `Gitlab.config.gitlab.host` rather than hard coding `'localhost'`
...
@@ -295,10 +295,10 @@ results are available, and not just the first failure.
...
@@ -295,10 +295,10 @@ results are available, and not just the first failure.
- Don't supply the `:each` argument to hooks since it's the default.
- Don't supply the `:each` argument to hooks because it's the default.
- On `before` and `after` hooks, prefer it scoped to `:context` over `:all`
- On `before` and `after` hooks, prefer it scoped to `:context` over `:all`
- When using `evaluate_script("$('.js-foo').testSomething()")` (or `execute_script`) which acts on a given element,
- When using `evaluate_script("$('.js-foo').testSomething()")` (or `execute_script`) which acts on a given element,
use a Capybara matcher beforehand (e.g.`find('.js-foo')`) to ensure the element actually exists.
use a Capybara matcher beforehand (such as`find('.js-foo')`) to ensure the element actually exists.
- Use `focus: true` to isolate parts of the specs you want to run.
- Use `focus: true` to isolate parts of the specs you want to run.
- Use [`:aggregate_failures`](https://relishapp.com/rspec/rspec-core/docs/expectation-framework-integration/aggregating-failures) when there is more than one expectation in a test.
- Use [`:aggregate_failures`](https://relishapp.com/rspec/rspec-core/docs/expectation-framework-integration/aggregating-failures) when there is more than one expectation in a test.
- For [empty test description blocks](https://github.com/rubocop-hq/rspec-style-guide#it-and-specify), use `specify` rather than `it do` if the test is self-explanatory.
- For [empty test description blocks](https://github.com/rubocop-hq/rspec-style-guide#it-and-specify), use `specify` rather than `it do` if the test is self-explanatory.