Note we're keeping this section's original design (which had one button
to add a new group which after being pressed was replaced by a button to
cancel) but we aren't using Foundation's `data-toggle` because there
were a couple of usability and accessibility issues.
First, using `data-toggle` multiple times and applying it to multiple
elements led to the "cancel" button not being available after submitting
a form with errors. Fixing it made the code more complicated.
Second, the "Add new group" button always had the `aria-expanded`
attribute set to "true", so my screen reader was announcing the button
as expanded even when it wasn't. I didn't manage to fix it using
`data-toggle`.
Finally, after pressing either the "Add new group" and "Cancel" buttons,
the keyboard focus was lost since the elements disappeared.
So we're simplifying the HTML and adding some custom JavaScript to be
able to handle the focus and manually setting the `aria-expanded`
attribute.
Co-Authored-By: Javi Martín <javim@elretirao.net>
Co-Authored-By: Julian Herrero <microweb10@gmail.com>
We don't allow deleting a budget with associated investments. However,
we allow deleting a budget with associated administrators and valuators.
This results in a foreign key violation error:
PG::ForeignKeyViolation: ERROR: update or delete on table "budgets"
violates foreign key constraint "fk_rails_c847a52b1d" on table
"budget_administrators"
Using the `dependent: :destroy` option when defining the relationship,
we remove the association records when removing the budget.
As a bonus, we reduce the number of Rubocop offenses regarding the
`Rails/HasManyOrHasOneDependent` rule. Only 72 to go! :)
When configuring phases in a process, we were validating the start date
or the end date is present, the other date is present too.
However, in other parts of the application we were checking whether a
phase is enabled and then assumed its dates were present if the phase
was enabled. However, we weren't validating this behavior, so it was
possible to enable a phase and leaving its dates blank, causing the
application to crash.
So, as suggested by Alberto, we're changing the validation rule so
phase dates are mandatory when a phase is enabled.
With this rule, the old validation rules are not necessary. I've
considered leaving them in order to avoid database inconsistencies.
However, I realized records having a disabled phase with its start and
end dates have always been valid. This means applications checking for
the presence of these dates instead of checking whether the phase is
enabled have never worked properly.
We don't have to change the logic anywhere else because as mentioned we
were already checking phases are enabled before using their dates.
Before commit 28caabecd, it was clear which budgets were in draft mode
because their phase was "drafting".
Now the phase isn't "drafting" anymore, so we have to make it clear
somehow that the budget is a draft.
I'm using styles similar to the ones we added in commit 2f636eaf7 for
completed budgets but at the same time making them slightly different so
it's easy to differenciate completed and drafting budgets.
Particularly the line with `within "tr", text: "Finished budget" do` is
now easier to read.
This way we avoid a potential pitfall. Imagine that the factory which
creates a finished budget generated a budget with the name "COMPLETED
Budget 1". Then the test:
```
within "#budget_#{finished_budget.id}" do
expect(page).to have_content("COMPLETED")
end
```
Would pass even if we didn't add the text "COMPLETED" anywhere else,
because it would be included in the name of the budget.
The link to edit the process is already present before clicking the
"All" link, which meant the test failed sometimes because Capybara might
try to click on the "Edit" link at the same time the page is changing
due to the click on the "All" link".
Due to this issue, this test has failed at least one in our CI [1].
[1] https://github.com/consul/consul/runs/2324773853
We were checking content which was already present/absent before making
a certain request, so the expectations were not checking the request had
already finished. Our intention here is to check the page contents after
the request has finished.
We want to make sure the request is finished after clicking a button and
before visiting a different page, so we need to check the page has
changed.
Usually this shouldn't be a problem because most of our forms are sent
with regular HTTP requests instead of AJAX ones, so the `visit` method
wouldn't be called before the request is finished.
However, we're experiencing problems with certain version of
Chromedriver, and in general it's a good practice because we might send
forms using AJAX/Turbolinks in the future.
When we create a record like a debate or an event and we check the page
content, we want to make sure that today's date is present, since it's
the date where the record is supposed to have been created.
This way we avoid querying the database after the browser has been
started.
It's strange to create records without assigning them to a variable and
then query the database to fetch the very same records. Assigning them
to a variable makes the tests easier to understand.
Besides, this way we avoid querying the database after the browser has
started.
Users don't care about database content; they care about what they see
on the screen.
Writing tests this way we also avoid potencial database inconsistencies
due to accessing the database after starting the browser.
Checking the database with methods like Activity.last does not test that
the record is present where it should be (first record of the table in
this case). In these tests there's only one record, though, so the order
doesn't matter that match.
However, calling methods like Activity.last generates a database query
after the process running the browser has been started, and this might
lead to inconsistent data.
System tests are about user experience, so instead of checking the slug
has been updated in the database, we check whether the page can be
accessed using the slug.
Note the budget group test is a bit different because the name of the
group isn't present in the budget group page.
We were checking the database, but users don't care about what's inside
the database; they care about what happens when they visit the page of a
record they've just restored.
This way we also avoid data inconsistency due to the process running the
test accessing the database after the process running the browser has
started.
These tests check what happens from the user's point of view. For
instance, we check that after disabling recommendations, they are not
shown. What happens in the database is not related to the user
experience.
Furthermore, checking the database after the browser has started is
proving to be a major source for inconsistent data in specs.
Changing the database after the process running the browser has started
is proving to be one of the reasons tests are failing sometimes, so
we're reducing the number of times were that happens. In this case, we
were changing a setting.
We were adding a `visit` in a `before` block but then we started the
search tests with another `visit`.
We also created records in the database in between, which increased the
risk of database inconsistency since the process running the browser had
already been started.
JavaScript is used by about 98% of web users, so by testing without it
enabled, we're only testing that the application works for a very
reduced number of users.
We proceeded this way in the past because CONSUL started using Rails 4.2
and truncating the database between JavaScript tests with database
cleaner, which made these tests terribly slow.
When we upgraded to Rails 5.1 and introduced system tests, we started
using database transactions in JavaScript tests, making these tests much
faster. So now we can use JavaScript tests everywhere without critically
slowing down our test suite.
Content like lowercase letters with `text-transform: uppercase` or
spaces after elements with `display: block` or "You're on page:" are not
seen that way by users with a browser supporting CSS.
So we're testing what most users actually experience.
This menu requires JavaScript to open/close subnavigation menus, so
we're now testing the way users with a browser supporting JavaScript
(98%-99% of the users) deal with the menu.
IMHO opening new windows is a usability issue which has been known for
twenty years since it takes control away from the user and breaks the
"back button", but for now we're keeping the same behavior as we already
had, while slightly increasing the complexity of the tests (which is a
good indicator of a usability issue).
Before clicking the "Edit phase" link, there's already a "Name" field
present in the page (the name of the budget).
With the rack driver, there's no problem since the `fill_in` action
waits until the page is loaded.
However, the test will be a flaky spec if we use a driver supporting
JavaScript, since clicking the "Edit phase" link will cause an AJAX
request and the `fill_in` action might be executed before the AJAX
request is finished.
The test was creating a new "upload.images" setting instead of using
"uploads.images". It passed because it wasn't using JavaScript but was
configuring the wrong setting.
IMHO testing the navigation once is enough. In the rest of the tests we
can access the page directly and make the tests faster by reducing the
number of requests.
We're improving the readability of the ones we're about to modify.
Using human texts makes tests easier to read and guarantees we're
testing from the user's point of view. For instance, if we write
`fill_in banner_target_url`, the test will pass even if the field has no
label associated to it. However, `fill_in "Link"` makes sure there's a
field with an associated label.
Using `have_selector` Capybara might detect `<a>` tags which are not
links because they don't have an `href` attribute. Besides, with
`have_selector` Capybara only detects visible text, which means it won't
detect links which are icons with tooltips.
Using `have_current_path`, Capybara waits until the condition is true,
while using `include` the expectation is evaluated immediately and so
tests might fail when using a driver supporting JavaScript.
Besides, using `have_current_path` the error message is more readable
when the test fails.
When using tests with a driver supporting JavaScript, there might be
concurrency issues if both the process running the test and the process
running the browser access the database once the browser has been
started.