Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(DIA-942): add tests for auth2 #11192

Merged
merged 3 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,14 @@ const ForgotPasswordStepForm: React.FC = () => {

{!!requestedPasswordReset ? (
<Text color="blue100" mt={1} variant="sm">
Password reset link set—check your email. Please note, you must wait 5 minutes to
Password reset link sent—check your email. Please note, you must wait 5 minutes to
receive another link.
</Text>
) : (
<>
<Spacer y={2} />
<Input
accessibilityHint="Enter your email address"
autoCapitalize="none"
autoComplete="email"
autoCorrect={false}
Expand Down
3 changes: 3 additions & 0 deletions src/app/Scenes/Onboarding/Auth2/scenes/LoginPasswordStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ const LoginPasswordStepForm: React.FC = () => {
<Text variant="sm-display">Welcome back to Artsy</Text>

<Input
accessibilityHint="Enter your password"
autoCapitalize="none"
autoComplete="password"
importantForAutofill="yes"
Expand Down Expand Up @@ -162,6 +163,7 @@ const LoginPasswordStepForm: React.FC = () => {
onPress={handleSubmit}
disabled={!isValid || !values.password}
loading={isSubmitting}
accessibilityHint="Continue to the next screen"
>
Continue
</Button>
Expand All @@ -181,6 +183,7 @@ const LoginPasswordStepForm: React.FC = () => {
})
resetForm()
}}
accessibilityHint="Go to the sign-up screen"
>
Sign up.
</LinkText>
Expand Down
3 changes: 3 additions & 0 deletions src/app/Scenes/Onboarding/Auth2/scenes/SignUpPasswordStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ const SignUpPasswordStepForm: React.FC = () => {
<Text variant="sm-display">Welcome to Artsy</Text>

<Input
accessibilityHint="Enter your password"
autoCapitalize="none"
autoComplete="password"
autoCorrect={false}
Expand Down Expand Up @@ -118,6 +119,7 @@ const SignUpPasswordStepForm: React.FC = () => {
onPress={handleSubmit}
loading={isSubmitting}
disabled={!isValid || !values.password}
accessibilityHint="Continue to the next screen"
>
Continue
</Button>
Expand All @@ -137,6 +139,7 @@ const SignUpPasswordStepForm: React.FC = () => {
})
resetForm()
}}
accessibilityHint="Go to the login screen"
>
Login.
</LinkText>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { fireEvent, screen, waitFor } from "@testing-library/react-native"
import {
useAuthNavigation,
useAuthScreen,
} from "app/Scenes/Onboarding/Auth2/hooks/useAuthNavigation"
import { ForgotPasswordStep } from "app/Scenes/Onboarding/Auth2/scenes/ForgotPasswordStep"
import { GlobalStore } from "app/store/GlobalStore"
import { renderWithWrappers } from "app/utils/tests/renderWithWrappers"

jest.mock("app/Scenes/Onboarding/Auth2/hooks/useAuthNavigation", () => ({
useAuthNavigation: jest.fn(),
useAuthScreen: jest.fn().mockReturnValue({
params: { email: "[email protected]" },
}),
}))

describe("ForgotPasswordStep", () => {
const mockUseAuthNavigation = useAuthNavigation as jest.Mock
const mockUseAuthScreen = useAuthScreen as jest.Mock

it("disables the 'send reset link' button when the email address is invalid", async () => {
renderWithWrappers(<ForgotPasswordStep />)
expect(screen.getByDisplayValue("[email protected]")).toBeOnTheScreen()
expect(screen.getByText("Send Reset Link")).toBeEnabled()
fireEvent.changeText(screen.getByA11yHint("Enter your email address"), "invalid-email")
await waitFor(() => expect(screen.getByText("Send Reset Link")).toBeDisabled())
})

describe("when a reset link is successfully requested", () => {
beforeEach(() => {
jest.spyOn(GlobalStore.actions.auth, "forgotPassword").mockResolvedValue(true)
mockUseAuthNavigation.mockReturnValue({
/**
* When the user successfully requests a password reset, we add a requestedPasswordReset param
* to the screen so that a confirmation message can be displayed on the next render. This
* simulates that by updating the useAuthScreen mock to return the new params.
*/
setParams: jest.fn().mockImplementation((params) => {
mockUseAuthScreen.mockReturnValue({
params: { ...mockUseAuthScreen().params, ...params },
})
}),
navigate: jest.fn(),
})
})

afterEach(() => {
/**
* Restore the useAuthScreen mock to its default state after each test so that subsequent
* tests don't start on the confirmation screen.
*/
mockUseAuthScreen.mockReturnValue({
params: { email: "[email protected]" },
})
})

it("shows a confirmation message", async () => {
renderWithWrappers(<ForgotPasswordStep />)
fireEvent.press(screen.getByText("Send Reset Link"))
await waitFor(() => expect(screen.queryByA11yHint("Enter your email address")).toBeNull())
expect(
screen.getByText(
"Password reset link sent—check your email. Please note, you must wait 5 minutes to receive another link."
)
).toBeOnTheScreen()
})

it("sends a reset link when the 'send again' button is pressed", async () => {
renderWithWrappers(<ForgotPasswordStep />)
fireEvent.press(screen.getByText("Send Reset Link"))
await waitFor(() => expect(screen.queryByA11yHint("Enter your email address")).toBeNull())
fireEvent.press(screen.getByText("Send Again"))
await waitFor(() => expect(GlobalStore.actions.auth.forgotPassword).toHaveBeenCalledTimes(2))
})

it("returns to the login screen when the 'return to login' button is pressed", async () => {
renderWithWrappers(<ForgotPasswordStep />)
fireEvent.press(screen.getByText("Send Reset Link"))
await waitFor(() => expect(screen.queryByA11yHint("Enter your email address")).toBeNull())
fireEvent.press(screen.getByText("Return to Login"))
await waitFor(() =>
expect(mockUseAuthNavigation().navigate).toHaveBeenCalledWith({
name: "LoginWelcomeStep",
})
)
})
})

it("displays an error message if the reset link could not be sent", async () => {
jest.spyOn(GlobalStore.actions.auth, "forgotPassword").mockResolvedValue(false)
renderWithWrappers(<ForgotPasswordStep />)
fireEvent.press(screen.getByText("Send Reset Link"))
await screen.findByText(
"Couldn't send reset password link. Please try again, or contact [email protected]"
)
})
})

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { fireEvent, screen, waitFor } from "@testing-library/react-native"
import {
useAuthNavigation,
useAuthScreen,
} from "app/Scenes/Onboarding/Auth2/hooks/useAuthNavigation"
import { LoginPasswordStep } from "app/Scenes/Onboarding/Auth2/scenes/LoginPasswordStep"
import { GlobalStore } from "app/store/GlobalStore"
import { renderWithWrappers } from "app/utils/tests/renderWithWrappers"
import { Alert } from "react-native"

jest.mock("app/Scenes/Onboarding/Auth2/hooks/useAuthNavigation")

describe("LoginPasswordStep", () => {
const mockUseAuthNavigation = useAuthNavigation as jest.Mock
const mockUseAuthScreen = useAuthScreen as jest.Mock

beforeEach(() => {
jest.clearAllMocks()
mockUseAuthNavigation.mockReturnValue({
navigate: jest.fn(),
})
mockUseAuthScreen.mockReturnValue({
name: "SignUpPasswordStep",
params: { email: "[email protected]" },
})
})

/**
* GlobalStore.actions.auth.signIn is responsible for taking the user to the home screen when
* login succeeds, so this test will only assert that it was called.
*/
it("calls the global login function", async () => {
jest.spyOn(GlobalStore.actions.auth, "signIn").mockResolvedValue("success")
renderWithWrappers(<LoginPasswordStep />)
fireEvent.changeText(screen.getByA11yHint("Enter your password"), "Password1")
fireEvent.press(screen.getByA11yHint("Continue to the next screen"))
await waitFor(() => expect(GlobalStore.actions.auth.signIn).toHaveBeenCalled())
})

it("shows an error when login fails", async () => {
jest.spyOn(GlobalStore.actions.auth, "signIn").mockResolvedValue("failure")
renderWithWrappers(<LoginPasswordStep />)
fireEvent.changeText(screen.getByA11yHint("Enter your password"), "Password2")
fireEvent.press(screen.getByA11yHint("Continue to the next screen"))
await screen.findByText("Incorrect email or password")
})

it("navigates to the standard OTP step with required", async () => {
jest.spyOn(GlobalStore.actions.auth, "signIn").mockResolvedValue("otp_missing")
renderWithWrappers(<LoginPasswordStep />)
fireEvent.changeText(screen.getByA11yHint("Enter your password"), "Password1")
fireEvent.press(screen.getByA11yHint("Continue to the next screen"))
await waitFor(() =>
expect(mockUseAuthNavigation().navigate).toHaveBeenCalledWith({
name: "LoginOTPStep",
params: { email: "[email protected]", password: "Password1", otpMode: "standard" }, // pragma: allowlist secret
})
)
})

it("navigates to the on-demand OTP step when required", async () => {
jest.spyOn(GlobalStore.actions.auth, "signIn").mockResolvedValue("on_demand_otp_missing")
renderWithWrappers(<LoginPasswordStep />)
fireEvent.changeText(screen.getByA11yHint("Enter your password"), "Password1")
fireEvent.press(screen.getByA11yHint("Continue to the next screen"))
await waitFor(() =>
expect(mockUseAuthNavigation().navigate).toHaveBeenCalledWith({
name: "LoginOTPStep",
params: { email: "[email protected]", password: "Password1", otpMode: "on_demand" }, // pragma: allowlist secret
})
)
})

it("shows an error when auth is blocked", async () => {
jest.spyOn(GlobalStore.actions.auth, "signIn").mockResolvedValue("auth_blocked")
jest.spyOn(Alert, "alert")
renderWithWrappers(<LoginPasswordStep />)
fireEvent.changeText(screen.getByA11yHint("Enter your password"), "Password1")
fireEvent.press(screen.getByA11yHint("Continue to the next screen"))
await waitFor(() =>
expect(Alert.alert).toHaveBeenCalledWith(
"Sign in attempt blocked",
"Please try signing in from a different internet connection or contact [email protected] for help.",
expect.any(Array)
)
)
})

describe("when showLoginLink param is true", () => {
beforeEach(() => {
mockUseAuthScreen.mockReturnValue({
name: "SignUpPasswordStep",
params: {
email: "[email protected]",
showSignUpLink: true,
},
})
})

it("navigates to the sign-up screen when the login link is pressed", () => {
renderWithWrappers(<LoginPasswordStep />)
fireEvent.press(screen.getByA11yHint("Go to the sign-up screen"))
expect(mockUseAuthNavigation().navigate).toHaveBeenCalledWith({
name: "SignUpPasswordStep",
params: { email: "[email protected]", showLoginLink: true },
})
})
})
})

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { fireEvent, screen, waitFor } from "@testing-library/react-native"
import {
useAuthNavigation,
useAuthScreen,
} from "app/Scenes/Onboarding/Auth2/hooks/useAuthNavigation"
import { SignUpPasswordStep } from "app/Scenes/Onboarding/Auth2/scenes/SignUpPasswordStep"
import { renderWithWrappers } from "app/utils/tests/renderWithWrappers"

jest.mock("app/Scenes/Onboarding/Auth2/hooks/useAuthNavigation", () => ({
useAuthNavigation: jest.fn().mockReturnValue({
navigate: jest.fn(),
goBack: jest.fn(),
}),
useAuthScreen: jest.fn().mockReturnValue({
name: "SignUpPasswordStep",
params: {
email: "[email protected]",
},
}),
}))

describe("SignUpPasswordStep", () => {
const mockUseAuthNavigation = useAuthNavigation as jest.Mock
const mockUseAuthScreen = useAuthScreen as jest.Mock

beforeEach(() => {
jest.clearAllMocks()
})

it("navigates to the next step when a valid password is entered", async () => {
renderWithWrappers(<SignUpPasswordStep />)

fireEvent.changeText(screen.getByA11yHint("Enter your password"), "Password1")
fireEvent.press(screen.getByA11yHint("Continue to the next screen"))

await waitFor(() => {
expect(mockUseAuthNavigation().navigate).toHaveBeenCalledWith({
name: "SignUpNameStep",
params: {
email: "[email protected]",
password: "Password1", // pragma: allowlist secret
},
})
})
})

it("navigates back when back button is pressed", () => {
renderWithWrappers(<SignUpPasswordStep />)
fireEvent.press(screen.getByA11yHint("Go back to the previous screen"))
expect(mockUseAuthNavigation().goBack).toHaveBeenCalled()
})

describe("when showLoginLink param is true", () => {
beforeEach(() => {
mockUseAuthScreen.mockReturnValue({
name: "SignUpPasswordStep",
params: {
email: "[email protected]",
showLoginLink: true,
},
})
})

it("displays a login link", () => {
renderWithWrappers(<SignUpPasswordStep />)
expect(screen.getByA11yHint("Go to the login screen")).toBeDefined()
})

it("navigates to the login screen when the login link is pressed", () => {
renderWithWrappers(<SignUpPasswordStep />)
fireEvent.press(screen.getByA11yHint("Go to the login screen"))
expect(mockUseAuthNavigation().navigate).toHaveBeenCalledWith({
name: "LoginPasswordStep",
params: { email: "[email protected]", showSignUpLink: true },
})
})
})
})