diff --git a/cypress/e2e/basic.cy.js b/cypress/e2e/basic.cy.js index 5a0a767ed5..8dc07c1800 100644 --- a/cypress/e2e/basic.cy.js +++ b/cypress/e2e/basic.cy.js @@ -62,6 +62,10 @@ describe('After setup instance', () => { cy.get('[data-cy-signup-submit]').click(); cy.wait('@signup'); + }); + + it('signup with duplicated username', () => { + cy.registerUser('alice', 'alice1234'); cy.visitHome(); diff --git a/packages/frontend/src/components/MkSignup.vue b/packages/frontend/src/components/MkSignup.vue index fa69481394..22a8063809 100644 --- a/packages/frontend/src/components/MkSignup.vue +++ b/packages/frontend/src/components/MkSignup.vue @@ -110,6 +110,8 @@ let ToSAgreement: boolean = $ref(false); let hCaptchaResponse = $ref(null); let reCaptchaResponse = $ref(null); let turnstileResponse = $ref(null); +let usernameAbortController: null | AbortController = $ref(null); +let emailAbortController: null | AbortController = $ref(null); const shouldDisableSubmitting = $computed((): boolean => { return submitting || @@ -141,14 +143,20 @@ function onChangeUsername(): void { } } + if (usernameAbortController != null) { + usernameAbortController.abort(); + } usernameState = 'wait'; + usernameAbortController = new AbortController(); os.api('username/available', { username, - }).then(result => { + }, undefined, usernameAbortController.signal).then(result => { usernameState = result.available ? 'ok' : 'unavailable'; - }).catch(() => { - usernameState = 'error'; + }).catch((err) => { + if (err.name !== 'AbortError') { + usernameState = 'error'; + } }); } @@ -158,11 +166,15 @@ function onChangeEmail(): void { return; } + if (emailAbortController != null) { + emailAbortController.abort(); + } emailState = 'wait'; + emailAbortController = new AbortController(); os.api('email-address/available', { emailAddress: email, - }).then(result => { + }, undefined, emailAbortController.signal).then(result => { emailState = result.available ? 'ok' : result.reason === 'used' ? 'unavailable:used' : result.reason === 'format' ? 'unavailable:format' : @@ -170,8 +182,10 @@ function onChangeEmail(): void { result.reason === 'mx' ? 'unavailable:mx' : result.reason === 'smtp' ? 'unavailable:smtp' : 'unavailable'; - }).catch(() => { - emailState = 'error'; + }).catch((err) => { + if (err.name !== 'AbortError') { + emailState = 'error'; + } }); } diff --git a/packages/frontend/src/scripts/api.ts b/packages/frontend/src/scripts/api.ts index 5f34f5333e..97081d170f 100644 --- a/packages/frontend/src/scripts/api.ts +++ b/packages/frontend/src/scripts/api.ts @@ -5,7 +5,7 @@ import { $i } from '@/account'; export const pendingApiRequestsCount = ref(0); // Implements Misskey.api.ApiClient.request -export function api(endpoint: E, data: P = {} as any, token?: string | null | undefined): Promise { +export function api(endpoint: E, data: P = {} as any, token?: string | null | undefined, signal?: AbortSignal): Promise { pendingApiRequestsCount.value++; const onFinally = () => { @@ -26,6 +26,7 @@ export function api(en headers: { 'Content-Type': 'application/json', }, + signal, }).then(async (res) => { const body = res.status === 204 ? null : await res.json();