Skip to content

Mark slow specs with :slow tag#2764

Draft
lfdebrux wants to merge 5 commits into
mainfrom
ldeb-slow-specs
Draft

Mark slow specs with :slow tag#2764
lfdebrux wants to merge 5 commits into
mainfrom
ldeb-slow-specs

Conversation

@lfdebrux
Copy link
Copy Markdown
Contributor

@lfdebrux lfdebrux commented May 12, 2026

What problem does this pull request solve?

On my machine (MacBook Pro, Apple M1 Pro, 16 GB RAM, macOS Tahoe 26.4.1), running the specs in this repo takes around 17 minutes.

This PR adds a :slow tag to examples that consistently take over 1 second to run on my machine.

This is partly for documentation purposes, but also allows developers to skip slow specs when running tests locally with

rspec --tag ~slow

See the RSpec docs on the --tag option for details on how this works.

The changes in this PR should not affect how the tests/PR checks run in CI.

On my machine, with the changes from this PR, running rspec --tag ~slow takes around 7 minutes.

Notes on slow tests

While trying to figure what to tag as slow, I found three different kinds of slow tests:

  1. Tests that rely on browser automation

Anything that uses headless Chrome for testing is automatically a resource hog; I didn't look too closely at these. Instead I just added a bit of configuration to make all feature specs be marked as slow.

In theory we could try and speed some feature specs up by seeing which ones require a real browser and which could use the RackTest simulator that comes with Capybara [1]. However, in practice, most of our feature specs require a real browser because they a) rely on JavaScript for the sign in journey, and b) test for WCAG failures with aXe tools, which requires Chrome. So it would be quite a lot of work to try and speed up our feature specs this way (although it might become worth it at some point).

  1. Tests that are consistently slow

There were a few specs that were consistently significantly slower than a second when run on their own. These mostly appear to be weird outliers, and there also aren't that many of them. I've fixed two (see commit messages for details), and left the rest marked with the :slow tag.

  1. Tests that are intermittently slow

This was the biggest category of issue I found. When repeatedly running tests with rspec --profile --tag ~slow, after having marked tests in the above two categories, I found there was little consistency between runs in which tests were in the top ten slowest list.

After doing some profiling with ruby-prof using a modified version of https://gist.github.com/palkan/73395cc201a565ecd3ff61aac44ad5ae, I found one issue related to ViteRuby and added a workaround for that (see commit messages for details), but adding that workaround did not fully resolve the intermittent slowness. I also found that some specs can be slow when run in isolation, but quick when run as part of a group, likely because there is some shared caching happening.

Basically, some of the slowness is likely caused by a combination of Factory Bot (a known issue generally), bootsnap caching, thread contention, and general operating system constraints, and these are all difficult to pin down and fix.

Things to consider when reviewing

  • Ensure that you consider the wider context.
  • Does it work when run on your machine?
  • Is it clear what the code is doing?
  • Do the commit messages explain why the changes were made?
  • Are there all the unit tests needed?
  • Do the end to end tests need updating before these changes will pass?
  • Has all relevant documentation been updated?

@lfdebrux lfdebrux force-pushed the ldeb-slow-specs branch 6 times, most recently from 51a6eef to 38b5f76 Compare May 15, 2026 05:27
lfdebrux added 5 commits May 15, 2026 09:11
To help with comparing the time to run tests in CI and locally, add the
`--profile` flag to the invocation of RSpec in the test workflow.

Note that this shouldn't affect the actual runtime of the tests, because
RSpec always records this information; the `--profile` flag just
determines whether it is printed at the end or not [[1]].

[1]: https://github.com/rspec/rspec/blob/6687661ab4267307f89053b097d91155bed5dcbd/rspec-core/lib/rspec/core/example.rb#L284
On my machine (macOS Tahoe 26.4.1) when running request specs there are
random delays that cause individual examples to sometimes take longer
than 5 seconds.

Profiling the specs showed that the `ViteRuby#dev_server_running?`
check which occurs whenever a request is made was being held up by
hostname resolution in the call to `Socket.tcp`.

By default the dev server host is `localhost`; it is not clear why
resolving localhost can sometimes be slow, it may be related to
macOS/Bonjour, or something about the system configuration. Other
developers have reported similar delays however.

This commit adds a workaround, by changing the Vite configuration for
the test profile to a hardcoded IP address, we remove the need for host
resolution and the delay.

This change doesn't make much of a difference to the total runtime of a
complete test run, as a percentage of the total wall time, but does
shave a little bit off, and also makes it easier to determine which
tests are actually slow.

Note: This delay occurs whether or not the dev server is running (it is
not, for tests, unless run by the developer) and is unaffected by the
configurable timeout delay in Vite. The delay was not present in CI
because Vite is configured to assume that the dev server is not running
in CI [1] without making a network call.

[1]: https://github.com/ElMassimo/vite_ruby/blob/c6cf52a17199c50e7a09e3eea40f9a3d42986c0a/vite_ruby/lib/vite_ruby.rb#L110
Currently all our feature specs take over 1 second to run on my machine
(MacBook Pro, Apple M1 Pro CPU, 16 GB RAM), as they rely on browser
automation via headless Chrome.

This commit adds a small bit of configuration to RSpec to add a `:slow`
tag to all feature specs.

This is partly for documentation purposes, but mainly it allows
developers to skip slow specs when running tests locally with

```
rspec --tag ~slow
```

This change should not affect how the tests/PR checks run in CI.
Mark examples/example groups that consistently take over a second to run
on my machine (MacBook Pro, Apple M1 Pro CPU, 16 GB RAM) with the
`:slow` tag.

This is partly for documentation purposes, but mainly it allows
developers to skip slow specs when running tests locally with

```
rspec --tag ~slow
```

This change should not affect how the tests/PR checks run in CI.

Feature specs are not marked in this commit, as they are already marked
as slow generally (see the previous commit).
The `button` selector in Capybara when a locator is provided is very
complicated [1], and for these examples it was taking around 5 seconds
each on my machine (MacBook Pro, Apple M1 Pro CPU, 16 GB RAM).

[1]: https://github.com/teamcapybara/capybara/blob/master/lib/capybara/selector/definition/button.rb
@github-actions
Copy link
Copy Markdown

🎉 A review copy of this PR has been deployed! You can reach it at: https://pr-2764.admin.review.forms.service.gov.uk/

It may take 5 minutes or so for the application to be fully deployed and working. If it still isn't ready
after 5 minutes, there may be something wrong with the ECS task. You will need to go to the integration AWS account
to debug, or otherwise ask an infrastructure person.

For the sign in details and more information, see the review apps wiki page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant