We were using a placeholder, which is way less accessible than a label.
One issue here (which also happened before, but is now more obvious) is
that, when adding several options, there will be many fields with the
same label.
Another issue is that, for some languages, we're using texts like "Add a
closed answer", which might be confusing because we might be editing an
existing answer. The proper solution would probably be using the text
"Option 1", "Option 2", ... I'm not doing so right now because I'm not
sure that's a good option and because changing the text would mean
losing the existing translations.
This way the fields are easier to use, and we can get rid of the
placeholders.
Note we're simplifying the `answer_result_value` in order to make it
easier to return `0` instead of `nil` when the field is empty.
Also note there's a small change of behavior here; previously, these
fields were empty by default, and now their value is `0` by default, so
blindly clicking the "Save" button would send `0` instead of an empty
value. I don't think it's a big deal, though, but we need to keep that
in mind.
Back when we added all the missing labels (changes that we merged in
commit c34cab282), we forgot about fields which had placeholdes, since
Axe doesn't report an error when there are placeholders but there aren't
labels.
In this case, we were using an invalid <label> tag for the question
options, and <h3> tags as labels for the votes.
Using standard labels solves the issue.
Saying that we're supposed to introduce a descriptive title in a field
labelled as "Title" is redundant. Besides, the text of the placeholder
was barely distinguishable, making it harder to fill in the form.
We forgot to apply this change in commit f5f96ba86.
Note that, in this case, executing `proposal_notification.author.email`
in the middle of a test would also result in a database query. For some
reason (probably the same reason why the code that explicitly created
the author was added in this test but not in other moderation tests),
that doesn't seem to happen in other moderation tests, so for now we
aren't changing those ones.
The link to the comments page was an "expand" icon, which was confusing
because it wasn't really expanding the contents of the sidebar but going
to an entirely different page. Furthermore, it didn't have any text for
people using screen readers, which is why Axe was reporting the
following accessibility error:
```
link-name: Links must have discernible text (serious)
https://dequeuniversity.com/rules/axe/4.10/link-name?application=axeAPI
The following 1 node violate this rule:
Selector: #annotation-link > a
HTML: <a href="/legislation/processes/75/draft_versions/30/annotations/8?sub_annotation_ids=">
<span class="icon-expand" aria-hidden="true"></span>
</a>
Fix all of the following:
- Element is in tab order and does not have accessible text
Fix any of the following:
- Element does not have text that is visible to screen readers
- aria-label attribute does not exist or is empty
- aria-labelledby attribute does not exist, references elements that
do not exist or references elements that are empty
- Element has no title attribute
```
So we're removing the icon and turning the "N comments" text into a
link, so it's easier to guess that the link takes us to the page showing
all the comments for this annotation.
This expectations in this test were true both before and after clicking
on the `.icon-expand` link, so it was possible that the test finished
before the request generated by that click did.
So we're adding an extra expectation to make sure we're testing what we
want to test: the content of the page after the request has finished.
Just like we do with the rest of the phases.
The reason why we're making this change right now is that we were
getting an accessibility error with processes with no result publication
date:
```
link-name: Links must have discernible text (serious)
https://dequeuniversity.com/rules/axe/4.10/link-name?application=axeAPI
The following 1 node violate this rule:
Selector: p:nth-child(6) > a
HTML: <a href="/legislation/processes/39/result_publication">
<strong></strong>
</a>
Fix all of the following:
- Element is in tab order and does not have accessible text
Fix any of the following:
- Element does not have text that is visible to screen readers
- aria-label attribute does not exist or is empty
- aria-labelledby attribute does not exist, references elements that
do not exist or references elements that are empty
- Element has no title attribute
```
This way we simplify the CSS and, in the case of the "check" icon, using
an SVG icon instead of an icon font offers several advantages, as
mentioned in commit 925f04e3f.
People using screen readers had no idea what these links were about (not
that the icons are very usable for people seeing them either... but
that's a different topic). Axe was reporting this error:
```
link-name: Links must have discernible text (serious)
https://dequeuniversity.com/rules/axe/4.10/link-name?application=axeAPI
The following 1 node violate this rule:
Selector: #dashboard_action_2_execute
HTML: <a id="dashboard_action_2_execute" class="unchecked-link"
rel="nofollow" data-method="post"
href="/proposals/16-proposal-6-title/dashboard/actions/2/execute">
<span class="unchecked"></span>
</a>
Fix all of the following:
- Element is in tab order and does not have accessible text
Fix any of the following:
- Element does not have text that is visible to screen readers
- aria-label attribute does not exist or is empty
- aria-labelledby attribute does not exist, references elements that
do not exist or references elements that are empty
- Element has no title attribute
```
All these tests were basically checking the same things. Since system
tests are slow, we're grouping them together so executing them is
slightly faster.
When using a link, people using screen readers might think they're going
to a new page where the password is going to be shown. With a button,
they get a better idea about what to expect.
Furthermore, with a button, we can use the `aria-pressed` attribute to
indicate whether the password is currently being shown.
We were using an icon for this link, but people who can't see the icon
couldn't know what the link was about. Axe was reporting the following
accessibility error:
```
link-name: Links must have discernible text (serious)
https://dequeuniversity.com/rules/axe/4.10/link-name?application=axeAPI
The following 1 node violate this rule:
Selector: .show-password
HTML: <a href="#" class="show-password">
<span class="icon-eye"></span>
</a>
Fix all of the following:
- Element is in tab order and does not have accessible text
Fix any of the following:
- Element does not have text that is visible to screen readers
- aria-label attribute does not exist or is empty
- aria-labelledby attribute does not exist, references elements
that do not exist or references elements that are empty
- Element has no title attribute
```
This happened when previewing banners in the "new banner form", which
might cause accessibility issues when people access the list of links on
the page.
We were getting the following accessibility error:
```
link-name: Links must have discernible text (serious)
https://dequeuniversity.com/rules/axe/4.9/link-name?application=axeAPI
The following node violate this rule:
Selector: a[href$="new"]
HTML: <a href="/admin/banners/new"><h2></h2><h3></h3></a>
Fix all of the following:
- Element is in tab order and does not have accessible text
Fix any of the following:
- Element does not have text that is visible to screen readers
- aria-label attribute does not exist or is empty
- aria-labelledby attribute does not exist, references elements that
do not exist or references elements that
- Element has no title attribute
```
People using screen readers might have a hard time knowing what a
progressbar is about unless we provide a label for it. Axe was reporting
failures like:
```
aria-progressbar-name: ARIA progressbar nodes must have an accessible
name (serious)
https://dequeuniversity.com/rules/axe/4.10/aria-progressbar-name?application=axeAPI
The following 1 node violate this rule:
Selector: .progress
HTML: <div class="progress" role="progressbar" tabindex="0"
aria-valuenow="0.0" aria-valuemin="0" aria-valuemax="100">
<div class="progress-meter" style="width: 0.0%"></div>
</div>
Fix any of the following:
- aria-label attribute does not exist or is empty
- aria-labelledby attribute does not exist, references
elements that do not exist or references elements that are empty
- Element has no title attribute
```
Note that, in the case of the ballot progressbar, it's easier to use
`aria-labelledby`, while in other place it's easier to use `aria-label`,
so we using the easier solution in each scenario.
Just like we do everywhere else. We're also removing the wrong ARIA
attributes that we added in commit c18479e3a, which caused an
accessibility issue reported by Axe:
```
aria-required-children: Certain ARIA roles must contain particular
children (critical)
https://dequeuniversity.com/rules/axe/4.10/aria-required-children?application=axeAPI
The following 1 node violate this rule:
Selector: .tabs-content
HTML: <div class="tabs-content"
data-tabs-content="information-texts-tabs" role="tablist">
Fix any of the following:
- Element has children which are not allowed: ul[tabindex]
```
Although, in this case, it would probably be better to have different
pages instead of tabs, so loading the page doesn't take too long.
Using a `data-toggle` attribute, which we do since commit 07fd5084f,
made Foundation generate an `aria-expanded` attribute to a radio button,
but this attribute can't be present in radio buttons. This makes sense,
since the main purpose of a radio button in a form is to choose an
option, not to show/hide content.
This resulted in the following error when checking the page with Axe:
```
Found 1 accessibility violation:
aria-allowed-attr: Elements must only use supported ARIA attributes
(critical)
https://dequeuniversity.com/rules/axe/4.10/aria-allowed-attr?application=axeAPI
The following 2 nodes violate this rule:
Selector: #dashboard_action_action_type_proposed_action
HTML: <input data-toggle="request_to_administrators short_description"
type="radio" value="proposed_action" checked="checked"
name="dashboard_action[action_type]"
id="dashboard_action_action_type_proposed_action"
aria-expanded="true"
aria-controls="request_to_administrators">
Fix all of the following:
- ARIA attribute is not allowed: aria-expanded="true"
Selector: #dashboard_action_action_type_resource
HTML: <input data-toggle="request_to_administrators short_description"
type="radio" value="resource"
name="dashboard_action[action_type]"
id="dashboard_action_action_type_resource"
aria-expanded="true"
aria-controls="request_to_administrators">
Fix all of the following:
- ARIA attribute is not allowed: aria-expanded="true"
```
So we're using custom JavaScript instead. We're also making the
`short_description` field act as intended; since the changes in commit
07fd5084f it was never shown because it had the `hide` HTML class and it
didn't have a `data-toggler` attribute.
In the tests for the edit/update action, we were using field names, but
using labels is a better approach because it tests that the label is
correctly associated with the field.
We aren't changing the tests for the new/create action because we were
already using labels there.
This way we avoid possible database corruption in our CI, which has
happened in the past when the process running the test accesses the
database after the process running the browser has started.
We can extract a method to reduce the amount of ERB code and remove the
duplication in the link texts. We also make the list consistent; now we
always use a <strong> tag in the group name, no matter whether there are
many groups or only one.
The original implementation (which was never merged) had a `<select>`
field for the switch, which offered accessibility issues. So I came up
with a very bad idea, which was emulating the look and feel of a select
field while making it more accessible for keyboard users.
This approach is inconvenient because we were using a bunch of ARIA
roles to do the same thing that can be done with a list of links, going
against the first rule of ARIA, which is:
> "Don’t use ARIA if you can achieve the same semantics with a native
> HTML element or attribute
Not only that, but the control was confusing for people using mobile
phones (select fields don't behave the same way), and we were using
*invalid* ARIA roles in this situation, leading Axe to report a critical
accessibility error:
```
aria-required-children: Certain ARIA roles must contain particular
children (critical)
https://dequeuniversity.com/rules/axe/4.10/aria-required-children?application=axeAPI
The following 1 node violate this rule:
Selector: ul[data-dropdown-menu="edw1i2-dropdown-menu"]
HTML: <ul class="dropdown menu" wnenu="edw1i2-dropdown-menu"
data-disable-hover="true" op="true" role="menubar">
Fix any of the following:
- Element has children which are not allowed: button[tabindex]
```
So, at least for now, we're using a simple list of links. We might style
it in the future if we find ways to make usability improvements, but,
for now, it does the job, and it does it better than the custom control
we were using.
We were getting an exception in this case, which was OK I guess since
this shouldn't happen if the application is used in a normal way, but we
can simplify the code a little bit if we make the `recipients` code
return an empty list of users.
Note that the behavior of the `AdminNotification#list_of_recipients` and
`Newsletter#list_of_recipient_emails` methods is now slightly different;
previously they returned `nil` when given an invalid segment recipient,
while now they return an empty array. I haven't found a place where this
change is relevant. For example, in both of these models, the `deliver`
method used to raise an exception when given an invalid segment while
now it doesn't, but we always check the user segment is valid before
calling the `deliver` method anyway, so it doesn't really affect the
application.
While we've already got a system test for the same purpose, we're going
to add another controller test for this action, so we're now writing a
test for the "happy path" scenario.
We were getting a warning by CodeQL regarding a possible code injection
in the `send(segment)` code.
In practice, this wasn't a big deal because the `self.recipients` method
is only called in the admin section, meaning only admin users could try
to take advantage of the code injection, and because this code is rarely
called with an invalid segment due to several conditions in the code
checking that the user segment is valid, with the only exception being
the `generate_csv` action in the `Admin::EmailsDownloadController`.
In any case, now we're checking that the segment is valid before calling
the `send` method. Since now we're making sure that the segment is valid
in the `recipients` method itself, we can remove this check from methods
calling it.
This way we can move some system tests to component tests and stop
creating records after starting the browser with a `visit`.
We could also split the system test in two, but since these tests
aren't checking any user interactions, moving the to component tests we
check the same things while making the tests faster.
Since the partial was using an instance variable, we're passing it to
the component. We're naming it `voter_user` instead of `user` because
passing something named `user` could make us think that we're passing
the `current_user`. I wasn't sure about naming it `voter` because it's a
`User` record and not a `Poll::Voter` record, but naming it `voter`
would definitely be an option.