The page has a sign-in form with a password field and a button for showing the password. The button starts hidden, because it can't work without JavaScript:
<form id="sign-in">
<label for="password">Password</label>
<input id="password" name="password" type="password" autocomplete="current-password">
<button id="show-password" type="button" aria-controls="password" hidden>Show password</button>
<button>Sign in</button>
</form>
Write setupPasswordToggle(input, button). It shows the button by removing its hidden.
Clicking the button shows the password: it sets the input's type to "text" and the button's aria-pressed to "true". Clicking it again hides the password: type goes back to "password", and aria-pressed to "false".
On setup, set aria-pressed to match the input: "true" if its type is already "text", and "false" otherwise.
Keep the button's text as it is. aria-pressed makes the button a toggle button, and screen readers read its name followed by its state, pressed or not pressed. A name that also changed, say to Hide password, would contradict the state.
If the input is in a form, hide the password again when that form is submitted, without stopping the submission. Browsers can save what's typed in a text field as an autocomplete suggestion, and a password must never become one. An input outside any form works the same, with no form to listen to.
setupPasswordToggle(document.getElementById("password"), document.getElementById("show-password"));
// the button appears, with aria-pressed="false"
// click it: the password shows as text, and aria-pressed is "true"
// submit the form: the field is a password field again before the form is sent
const button = document.getElementById("show-password");
setupPasswordToggle(document.getElementById("password"), button);
expect(button.hidden).toBe(false);
const button = document.getElementById("show-password");
setupPasswordToggle(document.getElementById("password"), button);
expect(button.getAttribute("aria-pressed")).toBe("false");
const input = document.getElementById("password");
const button = document.getElementById("show-password");
input.type = "text";
setupPasswordToggle(input, button);
expect(button.getAttribute("aria-pressed")).toBe("true");
fire(button, "click");
expect(input.type).toBe("password");
expect(button.getAttribute("aria-pressed")).toBe("false");
const input = document.getElementById("password");
const button = document.getElementById("show-password");
setupPasswordToggle(input, button);
fire(button, "click");
expect(input.type).toBe("text");
expect(button.getAttribute("aria-pressed")).toBe("true");
const input = document.getElementById("password");
const button = document.getElementById("show-password");
setupPasswordToggle(input, button);
fire(button, "click");
fire(button, "click");
expect(input.type).toBe("password");
expect(button.getAttribute("aria-pressed")).toBe("false");
fire(button, "click");
expect(input.type).toBe("text");
const button = document.getElementById("show-password");
setupPasswordToggle(document.getElementById("password"), button);
fire(button, "click");
expect(button.textContent).toBe("Show password");
fire(button, "click");
expect(button.textContent).toBe("Show password");
const input = document.getElementById("password");
const button = document.getElementById("show-password");
setupPasswordToggle(input, button);
fire(button, "click");
const event = fire(document.getElementById("sign-in"), "submit");
expect(input.type).toBe("password");
expect(button.getAttribute("aria-pressed")).toBe("false");
expect(event.defaultPrevented).toBe(false);
const input = document.getElementById("password");
const button = document.getElementById("show-password");
document.body.append(input, button);
setupPasswordToggle(input, button);
fire(button, "click");
expect(input.type).toBe("text");
expect(button.getAttribute("aria-pressed")).toBe("true");
Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.
Ctrl + Enter runs the tests (⌘ + Enter on a Mac).
I'm here to help with Show password toggle. I give hints, never the solution, so you get to solve it yourself. Ask for a hint, select code to ask about it, or press Ask Tuto why on a failing test.
Your first 3 answers need no account. for free to keep asking.