import { http, HttpResponse } from "msw"; import preview from "../../.storybook/preview.tsx"; import { sleep } from "../sleep.ts"; import type { CurrentUser, SessionInfo } from "../types.ts"; import { PasswordResetCard } from "./PasswordResetCard.tsx"; function createMocks(options?: { responseSpeed?: number }) { const simulateNetwork = () => sleep(options?.responseSpeed ?? 2000); const john: CurrentUser = { id: "john", email: "john@example.com", isVerified: true, }; const sessionInfo: SessionInfo = { createdTs: 123, expiresTs: 123, }; return { data: { john }, handlers: { requestPasswordReset: { success: () => { return http.post( "http://mock.api/v1/password-reset-tokens", async () => { await simulateNetwork(); return HttpResponse.json({ message: "OK", tokenId: "1" }); }, ); }, userNotFound: () => { return http.post( "http://mock.api/v1/password-reset-tokens", async () => { await simulateNetwork(); return HttpResponse.text("User not found", { status: 404 }); }, ); }, unknownFailure: () => { return http.post( "http://mock.api/v1/password-reset-tokens", async () => { await simulateNetwork(); return HttpResponse.text("Internal server error", { status: 500, }); }, ); }, }, checkPasswordResetCode: { success() { return http.get( "http://mock.api/v1/password-reset-tokens/:id", async () => { await simulateNetwork(); return HttpResponse.json({ message: "OK" }); }, ); }, notFoundOrExpired() { return http.get( "http://mock.api/v1/password-reset-tokens/:id", async () => { await simulateNetwork(); return HttpResponse.text("Not found", { status: 404 }); }, ); }, unknownFailure() { return http.get( "http://mock.api/v1/password-reset-tokens/:id", async () => { await simulateNetwork(); return HttpResponse.text("Internal server error", { status: 500, }); }, ); }, }, setNewPassword: { success() { return http.put( "http://mock.api/v1/password-reset-tokens/:id", async () => { await simulateNetwork(); return HttpResponse.json({ message: "OK" }); }, ); }, notFoundOrExpired() { return http.put( "http://mock.api/v1/password-reset-tokens/:id", async () => { await simulateNetwork(); return HttpResponse.text("Not found", { status: 404 }); }, ); }, unknownFailure() { return http.put( "http://mock.api/v1/password-reset-tokens/:id", async () => { await simulateNetwork(); return HttpResponse.text("Internal server error", { status: 500, }); }, ); }, }, createNewSession: { success: (currentUser: CurrentUser) => { return http.post("http://mock.api/v1/sessions", async () => { await simulateNetwork(); return HttpResponse.json({ currentUser, sessionInfo }); }); }, }, }, }; } const { data, handlers } = createMocks({ responseSpeed: 700 }); const meta = preview.meta({ title: "Account/Password Reset Page", component: PasswordResetCard, tags: ["autodocs"], args: {}, parameters: { msw: { handlers: { request: handlers.requestPasswordReset.success(), check: handlers.checkPasswordResetCode.success(), set: handlers.setNewPassword.success(), login: handlers.createNewSession.success(data.john), }, }, }, }); /** * The default case in which all steps of the flow succeed. */ export const Success = meta.story({}); /** * In this case, the initial step fails because the email address was not * found in our database. */ export const UserNotFoundOnRequestCode = meta.story({ parameters: { msw: { handlers: { request: handlers.requestPasswordReset.userNotFound(), }, }, }, }); /** * In this case, the initial step fails for a reason that doesn't have any * special handling in this location. E.g. network error, server error, etc. */ export const UnknownFailureOnRequestCode = meta.story({ parameters: { msw: { handlers: { request: handlers.requestPasswordReset.unknownFailure(), }, }, }, }); /** * In this case, the check code step fails because the token has expired, * or is incorrect. */ export const NotFoundOrExpiredOnCheckCode = meta.story({ parameters: { msw: { handlers: { check: handlers.checkPasswordResetCode.notFoundOrExpired(), }, }, }, }); /** * In this case, the check step fails for a reason that doesn't have any * special handling in this location. E.g. network error, server error, etc. */ export const UnknownFailureOnCheckCode = meta.story({ parameters: { msw: { handlers: { check: handlers.checkPasswordResetCode.unknownFailure(), }, }, }, }); /** * In this case, the final set password step fails because the token has * expired. * * Note that technically the token could also be incorrect/not found, but * because the user has gotten through the check step, that would require * some very strange set of circumstances. */ export const NotFoundOrExpiredOnSetPassword = meta.story({ parameters: { msw: { handlers: { set: handlers.setNewPassword.notFoundOrExpired(), }, }, }, }); /** * In this case, the set password step fails for a reason that doesn't have any * special handling in this location. E.g. network error, server error, etc. */ export const UnknownFailureOnSetPassword = meta.story({ parameters: { msw: { handlers: { set: handlers.setNewPassword.unknownFailure(), }, }, }, });