Skip to content

Commit 916e2b6

Browse files
authored
Recovery phrase set-up e2e tests. (dfinity#3517)
Recovery phrase set-up e2e tests. # Changes - Make dialog close button accessible. - Make recovery phrase verification step buttons accessible (wrap in unordered list and aria-pressable attribute). - Add `readClipboard` to e2e utils that avoids CSP errors. # Tests Implemented e2e tests to cover all currently possible flows on the new recovery phrase setup page. <!-- SCREENSHOTS REPORT START --> <!-- SCREENSHOTS REPORT STOP -->
1 parent 25ef1f2 commit 916e2b6

4 files changed

Lines changed: 364 additions & 45 deletions

File tree

src/frontend/src/lib/components/ui/Dialog.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import { nonNullish } from "@dfinity/utils";
66
import Button from "$lib/components/ui/Button.svelte";
77
import { XIcon } from "@lucide/svelte";
8+
import { t } from "$lib/stores/locale.store";
89
910
type Props = HTMLAttributes<HTMLDialogElement> & {
1011
onClose?: () => void;
@@ -133,8 +134,9 @@
133134
type="button"
134135
class="absolute top-2 right-2 z-2 !rounded-full"
135136
onclick={onClose}
137+
aria-label={$t`Close`}
136138
>
137-
<XIcon class="size-5" />
139+
<XIcon class="size-5" aria-hidden="true" />
138140
</Button>
139141
{/if}
140142
</div>

src/frontend/src/lib/components/wizards/createRecoveryPhrase/views/Verify.svelte

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,29 @@
2020
.sort((a, b) => a.sort - b.sort)
2121
.map(({ index }) => index),
2222
);
23+
const selectedWords = $derived(
24+
selectedIndexes.map((index) => recoveryPhrase[index]),
25+
);
2326
const isCheckingOrder = $derived(
24-
selectedIndexes.length === recoveryPhrase.length,
27+
selectedWords.length === recoveryPhrase.length,
2528
);
2629
30+
const handleSelect = (index: number) => {
31+
selectedIndexes = [...selectedIndexes, index];
32+
};
33+
const handleUndo = () => {
34+
selectedIndexes = selectedIndexes.slice(0, -1);
35+
};
36+
const handleClear = () => {
37+
selectedIndexes = [];
38+
};
39+
2740
// Auto-submit after the last word has been selected
2841
$effect(() => {
29-
if (selectedIndexes.length !== recoveryPhrase.length) {
42+
if (!isCheckingOrder) {
3043
return;
3144
}
32-
onCompleted(selectedIndexes.map((index) => recoveryPhrase[index]));
45+
onCompleted(selectedWords);
3346
});
3447
</script>
3548

@@ -54,57 +67,58 @@
5467
<Trans>Select each word in the correct order</Trans>
5568
{/if}
5669
</p>
57-
<div class={["mb-8 grid grid-cols-3 gap-3"]}>
70+
<ul class={["mb-8 grid grid-cols-3 gap-3"]}>
5871
{#each shuffledIndexes as index}
5972
{@const word = recoveryPhrase[index]}
6073
{@const selectedPosition = selectedIndexes.indexOf(index)}
6174
{@const isSelected = selectedPosition !== -1 && !isCheckingOrder}
6275
{@const isLastSelected = selectedIndexes.slice(-1)[0] === index}
63-
<button
64-
onclick={() =>
65-
(selectedIndexes = isLastSelected
66-
? selectedIndexes.slice(0, -1)
67-
: [...selectedIndexes, index])}
68-
class={[
69-
"border-border-primary hover:not-disabled:bg-bg-primary_hover focus-visible:not-disabled:bg-bg-primary_hover flex h-7 flex-row items-center rounded-full border px-1.5 outline-none",
70-
isSelected && "!border-fg-primary",
71-
isCheckingOrder && "!bg-bg-disabled !border-border-disabled_subtle",
72-
]}
73-
disabled={(isSelected && !isLastSelected) || isCheckingOrder}
74-
>
75-
<span
76-
class={[
77-
"text-text-secondary w-4 text-center text-xs font-semibold tabular-nums select-none",
78-
isSelected ? "!text-text-primary" : "-translate-y-0.25",
79-
isCheckingOrder && "!text-text-disabled",
80-
]}
81-
>
82-
{isSelected || isCheckingOrder
83-
? `${selectedPosition + 1}`.padStart(2, "0")
84-
: "_"}
85-
</span>
86-
<span
76+
<li class="contents">
77+
<button
78+
onclick={isLastSelected ? handleUndo : () => handleSelect(index)}
8779
class={[
88-
"border-border-secondary mx-1 h-full border-r",
80+
"border-border-primary hover:not-disabled:bg-bg-primary_hover focus-visible:not-disabled:bg-bg-primary_hover flex h-7 flex-row items-center rounded-full border px-1.5 outline-none",
8981
isSelected && "!border-fg-primary",
90-
isCheckingOrder && "!border-border-disabled_subtle",
91-
]}
92-
></span>
93-
<span
94-
class={[
95-
"text-text-secondary -translate-y-0.25 text-base select-none",
96-
word.length > 7 && "tracking-tight",
97-
isSelected && "!text-text-primary font-semibold",
98-
isCheckingOrder && "!text-text-disabled",
82+
isCheckingOrder && "!bg-bg-disabled !border-border-disabled_subtle",
9983
]}
84+
disabled={(isSelected && !isLastSelected) || isCheckingOrder}
85+
aria-pressed={isSelected ? "true" : "false"}
10086
>
101-
{word}
102-
</span>
103-
</button>
87+
<span
88+
class={[
89+
"text-text-secondary w-4 text-center text-xs font-semibold tabular-nums select-none",
90+
isSelected ? "!text-text-primary" : "-translate-y-0.25",
91+
isCheckingOrder && "!text-text-disabled",
92+
]}
93+
aria-hidden="true"
94+
>
95+
{isSelected || isCheckingOrder
96+
? `${selectedPosition + 1}`.padStart(2, "0")
97+
: "_"}
98+
</span>
99+
<span
100+
class={[
101+
"border-border-secondary mx-1 h-full border-r",
102+
isSelected && "!border-fg-primary",
103+
isCheckingOrder && "!border-border-disabled_subtle",
104+
]}
105+
></span>
106+
<span
107+
class={[
108+
"text-text-secondary -translate-y-0.25 text-base select-none",
109+
word.length > 7 && "tracking-tight",
110+
isSelected && "!text-text-primary font-semibold",
111+
isCheckingOrder && "!text-text-disabled",
112+
]}
113+
>
114+
{word}
115+
</span>
116+
</button>
117+
</li>
104118
{/each}
105-
</div>
119+
</ul>
106120
<Button
107-
onclick={() => (selectedIndexes = [])}
121+
onclick={handleClear}
108122
variant="secondary"
109123
size="lg"
110124
disabled={selectedIndexes.length === 0 || isCheckingOrder}

0 commit comments

Comments
 (0)