diff --git a/.changeset/shared-sign-in-factor-helpers.md b/.changeset/shared-sign-in-factor-helpers.md new file mode 100644 index 00000000000..e6fe16c582d --- /dev/null +++ b/.changeset/shared-sign-in-factor-helpers.md @@ -0,0 +1,5 @@ +--- +'@clerk/shared': patch +--- + +Add an internal module with the starting sign-in factor helper used by `@clerk/ui`. diff --git a/packages/mosaic/docs/internals/sign-in-sign-up-flow.md b/packages/mosaic/docs/internals/sign-in-sign-up-flow.md index 6b4c55f02cf..e7663adcd27 100644 --- a/packages/mosaic/docs/internals/sign-in-sign-up-flow.md +++ b/packages/mosaic/docs/internals/sign-in-sign-up-flow.md @@ -70,7 +70,7 @@ Sign-up: `identifier` and `start` are what Mosaic shows before the resource exists; a sign-in with no status and a sign-up not yet created both return them. `sent` means a code or link is out, so a reload on the same `:factor` doesn't send another. Picking a different factor always sends, because `sent` can't tell two targets with the same strategy apart (see [Bridge](#bridge)). -With no `:factor`, `factorOne` starts on the factor `ui`'s `determineStartingSignInFactor` picks (`ui/src/components/SignIn/utils.ts:76`). That rule moves to `shared` so both use one copy. +With no `:factor`, `factorOne` starts on the factor `determineStartingSignInFactor` picks (`shared/src/internal/clerk-js/signInFactors.ts`), the same copy `ui` uses. ## Back, forward and reload diff --git a/packages/shared/src/internal/clerk-js/__tests__/signInFactors.test.ts b/packages/shared/src/internal/clerk-js/__tests__/signInFactors.test.ts new file mode 100644 index 00000000000..b52e8df6250 --- /dev/null +++ b/packages/shared/src/internal/clerk-js/__tests__/signInFactors.test.ts @@ -0,0 +1,102 @@ +import { describe, expect, it } from 'vitest'; + +import type { SignInFactor } from '@/types'; + +import { determineStartingSignInFactor } from '../signInFactors'; + +describe('determineStartingSignInFactor', () => { + describe('with password as the preferred sign in strategy', () => { + it('selects password if available', () => { + const factors: SignInFactor[] = [{ strategy: 'password' }]; + expect(determineStartingSignInFactor(factors, null, 'password', false)).toEqual({ strategy: 'password' }); + }); + + it('selects based on user input in the previous step if password is not available', () => { + const factors: SignInFactor[] = [ + { strategy: 'email_code', emailAddressId: 'idn_1', safeIdentifier: 'ccoe@example.com' }, + { strategy: 'phone_code', phoneNumberId: 'idn_2', safeIdentifier: 'jdoe@example.com' }, + ]; + expect(determineStartingSignInFactor(factors, 'jdoe@example.com', 'password', false)).toEqual({ + strategy: 'phone_code', + phoneNumberId: 'idn_2', + safeIdentifier: 'jdoe@example.com', + }); + }); + + it('selects by prioritizing email_code if all the above fail', () => { + const factors: SignInFactor[] = [ + { strategy: 'phone_code', phoneNumberId: 'idn_2', safeIdentifier: 'jdoe@example.com' }, + { strategy: 'email_code', emailAddressId: 'idn_1', safeIdentifier: 'ccoe@example.com' }, + ]; + expect(determineStartingSignInFactor(factors, null, 'password', false)).toEqual({ + strategy: 'email_code', + emailAddressId: 'idn_1', + safeIdentifier: 'ccoe@example.com', + }); + }); + + it('selects phone_code if all the above fail', () => { + const factors: SignInFactor[] = [ + { strategy: 'phone_code', phoneNumberId: 'idn_2', safeIdentifier: 'jdoe@example.com' }, + ]; + expect(determineStartingSignInFactor(factors, null, 'password', false)).toEqual({ + strategy: 'phone_code', + phoneNumberId: 'idn_2', + safeIdentifier: 'jdoe@example.com', + }); + }); + + it('returns null if every other scenario', () => { + expect(determineStartingSignInFactor([], null, 'password', false)).toBeNull(); + }); + }); + + describe('with OTP as the preferred sign in strategy', () => { + it('selects based on user input in the previous step', () => { + const factors: SignInFactor[] = [ + { strategy: 'password' }, + { strategy: 'email_code', emailAddressId: 'idn_1', safeIdentifier: 'ccoe@example.com' }, + { strategy: 'phone_code', phoneNumberId: 'idn_2', safeIdentifier: 'jdoe@example.com' }, + ]; + expect(determineStartingSignInFactor(factors, 'jdoe@example.com', 'otp', false)).toEqual({ + strategy: 'phone_code', + phoneNumberId: 'idn_2', + safeIdentifier: 'jdoe@example.com', + }); + }); + + it('selects by prioritizing email_code if the above fails', () => { + const factors: SignInFactor[] = [ + { strategy: 'password' }, + { strategy: 'phone_code', phoneNumberId: 'idn_2', safeIdentifier: 'jdoe@example.com' }, + { strategy: 'email_code', emailAddressId: 'idn_1', safeIdentifier: 'ccoe@example.com' }, + ]; + expect(determineStartingSignInFactor(factors, null, 'otp', false)).toEqual({ + strategy: 'email_code', + emailAddressId: 'idn_1', + safeIdentifier: 'ccoe@example.com', + }); + }); + + it('selects phone_code if all the above fail', () => { + const factors: SignInFactor[] = [ + { strategy: 'password' }, + { strategy: 'phone_code', phoneNumberId: 'idn_2', safeIdentifier: 'jdoe@example.com' }, + ]; + expect(determineStartingSignInFactor(factors, null, 'otp', false)).toEqual({ + strategy: 'phone_code', + phoneNumberId: 'idn_2', + safeIdentifier: 'jdoe@example.com', + }); + }); + + it('selects password as a last resort if available', () => { + const factors: SignInFactor[] = [{ strategy: 'password' }]; + expect(determineStartingSignInFactor(factors, null, 'otp', false)).toEqual({ strategy: 'password' }); + }); + + it('returns null if every other scenario', () => { + expect(determineStartingSignInFactor([], null, 'otp', false)).toBeNull(); + }); + }); +}); diff --git a/packages/shared/src/internal/clerk-js/signInFactors.ts b/packages/shared/src/internal/clerk-js/signInFactors.ts new file mode 100644 index 00000000000..117212df143 --- /dev/null +++ b/packages/shared/src/internal/clerk-js/signInFactors.ts @@ -0,0 +1,95 @@ +import type { PreferredSignInStrategy, SignInFactor, SignInStrategy } from '../../types'; + +/** + * Picks the first factor a sign-in starts on, following the algorithm at + * https://www.notion.so/clerkdev/Implement-sign-in-alt-methods-e6e60ffb644645b3a0553b50556468ce + * + * @internal + */ +export function determineStartingSignInFactor( + firstFactors: SignInFactor[] | null, + identifier: string | null, + preferredSignInStrategy: PreferredSignInStrategy, + webAuthnSupported: boolean, +): SignInFactor | null | undefined { + if (!firstFactors || firstFactors.length === 0) { + return null; + } + + return preferredSignInStrategy === 'password' + ? determineStrategyWhenPasswordIsPreferred(firstFactors, identifier, webAuthnSupported) + : determineStrategyWhenOTPIsPreferred(firstFactors, identifier, webAuthnSupported); +} + +function determineStrategyWhenPasswordIsPreferred( + factors: SignInFactor[], + identifier: string | null, + webAuthnSupported: boolean, +): SignInFactor | null { + const passkeyFactor = findPasskeyStrategy(factors, webAuthnSupported); + if (passkeyFactor) { + return passkeyFactor; + } + const selected = factors.sort(passwordPrefFactorComparator)[0]; + if (selected.strategy === 'password') { + return selected; + } + return factors.find(factorForIdentifier(identifier)) || selected || null; +} + +function determineStrategyWhenOTPIsPreferred( + factors: SignInFactor[], + identifier: string | null, + webAuthnSupported: boolean, +): SignInFactor | null { + const passkeyFactor = findPasskeyStrategy(factors, webAuthnSupported); + if (passkeyFactor) { + return passkeyFactor; + } + const sortedBasedOnPrefFactor = factors.sort(otpPrefFactorComparator); + const forIdentifier = sortedBasedOnPrefFactor.find(factorForIdentifier(identifier)); + if (forIdentifier) { + return forIdentifier; + } + const firstBasedOnPref = sortedBasedOnPrefFactor[0]; + if (firstBasedOnPref.strategy === 'email_link') { + return firstBasedOnPref; + } + return factors.find(factorForIdentifier(identifier)) || firstBasedOnPref || null; +} + +function findPasskeyStrategy(factors: SignInFactor[], webAuthnSupported: boolean): SignInFactor | null { + if (webAuthnSupported) { + const passkeyFactor = factors.find(({ strategy }) => strategy === 'passkey'); + + if (passkeyFactor) { + return passkeyFactor; + } + } + return null; +} + +const factorForIdentifier = (i: string | null) => (f: SignInFactor) => { + return 'safeIdentifier' in f && f.safeIdentifier === i; +}; + +const passwordPrefFactorComparator = makeSortingFunction([ + 'passkey', + 'password', + 'email_link', + 'email_code', + 'phone_code', +]); + +const otpPrefFactorComparator = makeSortingFunction(['email_link', 'email_code', 'phone_code', 'passkey', 'password']); + +function makeSortingFunction(order: SignInStrategy[]) { + return (a: SignInFactor, b: SignInFactor): number => { + const orderA = order.indexOf(a.strategy); + const orderB = order.indexOf(b.strategy); + if (orderA === -1 || orderB === -1) { + return 0; + } + return orderA - orderB; + }; +} diff --git a/packages/ui/src/components/SignIn/SignInFactorOne.tsx b/packages/ui/src/components/SignIn/SignInFactorOne.tsx index a6d25b6f7d3..425b9b24787 100644 --- a/packages/ui/src/components/SignIn/SignInFactorOne.tsx +++ b/packages/ui/src/components/SignIn/SignInFactorOne.tsx @@ -1,3 +1,4 @@ +import { determineStartingSignInFactor } from '@clerk/shared/internal/clerk-js/signInFactors'; import { useClerk } from '@clerk/shared/react'; import type { SignInFactor } from '@clerk/shared/types'; import React from 'react'; @@ -26,7 +27,7 @@ import { SignInFactorOnePasswordCard } from './SignInFactorOnePasswordCard'; import { SignInFactorOnePhoneCodeCard } from './SignInFactorOnePhoneCodeCard'; import { SignInFactorOneSSOBypass } from './SignInFactorOneSSOBypass'; import { useResetPasswordFactor } from './useResetPasswordFactor'; -import { determineStartingSignInFactor, factorHasLocalStrategy } from './utils'; +import { factorHasLocalStrategy } from './utils'; const factorKey = (factor: SignInFactor | null | undefined) => { if (!factor) { diff --git a/packages/ui/src/components/SignIn/__tests__/utils.test.ts b/packages/ui/src/components/SignIn/__tests__/utils.test.ts index eb227c249be..67ca011f483 100644 --- a/packages/ui/src/components/SignIn/__tests__/utils.test.ts +++ b/packages/ui/src/components/SignIn/__tests__/utils.test.ts @@ -5,215 +5,35 @@ import type { FormControlState } from '@/ui/utils/useFormControl'; import { determineSalutation, - determineStartingSignInFactor, determineStartingSignInSecondFactor, getPreferredAlternativePhoneChannel, getPreferredAlternativePhoneChannelForCombinedFlow, isOfferableSecondFactor, } from '../utils'; -describe('determineStrategy(signIn, displayConfig)', () => { - describe('with password as the preferred sign in strategy', () => { - it('selects password if available', () => { - const signIn = { - supportedFirstFactors: [ - { - strategy: 'password', - }, - ], - } as unknown as SignInResource; - expect(determineStartingSignInFactor(signIn.supportedFirstFactors, signIn.identifier, 'password', false)).toEqual( - { - strategy: 'password', - }, - ); - }); - - it('selects based on user input in the previous step if password is not available', () => { - const signIn = { - identifier: 'jdoe@example.com', - supportedFirstFactors: [ - { - strategy: 'email_code', - safeIdentifier: 'ccoe@example.com', - }, - { - strategy: 'phone_code', - safeIdentifier: 'jdoe@example.com', - }, - ], - } as unknown as SignInResource; - expect(determineStartingSignInFactor(signIn.supportedFirstFactors, signIn.identifier, 'password', false)).toEqual( - { - strategy: 'phone_code', - safeIdentifier: 'jdoe@example.com', - }, - ); - }); - - it('selects by prioritizing email_code if all the above fail', () => { - const signIn = { - identifier: undefined, - supportedFirstFactors: [ - { - strategy: 'phone_code', - safeIdentifier: 'jdoe@example.com', - }, - { - strategy: 'email_code', - safeIdentifier: 'ccoe@example.com', - }, - ], - } as unknown as SignInResource; - expect(determineStartingSignInFactor(signIn.supportedFirstFactors, signIn.identifier, 'password', false)).toEqual( - { - strategy: 'email_code', - safeIdentifier: 'ccoe@example.com', - }, - ); - }); - - it('selects phone_code if all the above fail', () => { - const signIn = { - identifier: undefined, - supportedFirstFactors: [ - { - strategy: 'phone_code', - safeIdentifier: 'jdoe@example.com', - }, - ], - } as unknown as SignInResource; - expect(determineStartingSignInFactor(signIn.supportedFirstFactors, signIn.identifier, 'password', false)).toEqual( - { - strategy: 'phone_code', - safeIdentifier: 'jdoe@example.com', - }, - ); - }); - - it('returns null if every other scenario', () => { - const signIn = { - identifier: undefined, - supportedFirstFactors: [], - } as unknown as SignInResource; - expect( - determineStartingSignInFactor(signIn.supportedFirstFactors, signIn.identifier, 'password', false), - ).toBeNull(); - }); - }); - - describe('with OTP as the preferred sign in strategy', () => { - it('selects based on user input in the previous step', () => { - const signIn = { - identifier: 'jdoe@example.com', - supportedFirstFactors: [ - { - strategy: 'password', - }, - { - strategy: 'email_code', - safeIdentifier: 'ccoe@example.com', - }, - { - strategy: 'phone_code', - safeIdentifier: 'jdoe@example.com', - }, - ], - } as unknown as SignInResource; - expect(determineStartingSignInFactor(signIn.supportedFirstFactors, signIn.identifier, 'otp', false)).toEqual({ - strategy: 'phone_code', - safeIdentifier: 'jdoe@example.com', - }); - }); - - it('selects by prioritizing email_code if the above fails', () => { - const signIn = { - identifier: undefined, - supportedFirstFactors: [ - { - strategy: 'password', - }, - { - strategy: 'phone_code', - safeIdentifier: 'jdoe@example.com', - }, - { - strategy: 'email_code', - safeIdentifier: 'ccoe@example.com', - }, - ], - } as unknown as SignInResource; - expect(determineStartingSignInFactor(signIn.supportedFirstFactors, signIn.identifier, 'otp', false)).toEqual({ - strategy: 'email_code', - safeIdentifier: 'ccoe@example.com', - }); - }); - - it('selects phone_code if all the above fail', () => { - const signIn = { - identifier: undefined, - supportedFirstFactors: [ - { - strategy: 'password', - }, - { - strategy: 'phone_code', - safeIdentifier: 'jdoe@example.com', - }, - ], - } as unknown as SignInResource; - expect(determineStartingSignInFactor(signIn.supportedFirstFactors, signIn.identifier, 'otp', false)).toEqual({ - strategy: 'phone_code', - safeIdentifier: 'jdoe@example.com', - }); - }); - - it('selects password as a last resort if available', () => { - const signIn = { - supportedFirstFactors: [ - { - strategy: 'password', - }, - ], - } as unknown as SignInResource; - expect(determineStartingSignInFactor(signIn.supportedFirstFactors, signIn.identifier, 'otp', false)).toEqual({ - strategy: 'password', - }); - }); - - it('returns null if every other scenario', () => { - const signIn = { - identifier: undefined, - supportedFirstFactors: [], - } as unknown as SignInResource; - expect(determineStartingSignInFactor(signIn.supportedFirstFactors, signIn.identifier, 'otp', false)).toBeNull(); - }); - }); - - describe('determineSalutation(signIn)', () => { - it('returns firstname, then lastname or the identifier', () => { - let signIn = { - identifier: 'jdoe@example.com', - userData: { - firstName: 'Joe', - lastName: 'Doe', - }, - } as unknown as SignInResource; - expect(determineSalutation(signIn)).toBe('Joe'); - - signIn = { - identifier: 'jdoe@example.com', - userData: { - lastName: 'Doe', - }, - } as unknown as SignInResource; - expect(determineSalutation(signIn)).toBe('Doe'); - - signIn = { - identifier: 'jdoe@example.com', - } as unknown as SignInResource; - expect(determineSalutation(signIn)).toBe('jdoe@example.com'); - }); +describe('determineSalutation(signIn)', () => { + it('returns firstname, then lastname or the identifier', () => { + let signIn = { + identifier: 'jdoe@example.com', + userData: { + firstName: 'Joe', + lastName: 'Doe', + }, + } as unknown as SignInResource; + expect(determineSalutation(signIn)).toBe('Joe'); + + signIn = { + identifier: 'jdoe@example.com', + userData: { + lastName: 'Doe', + }, + } as unknown as SignInResource; + expect(determineSalutation(signIn)).toBe('Doe'); + + signIn = { + identifier: 'jdoe@example.com', + } as unknown as SignInResource; + expect(determineSalutation(signIn)).toBe('jdoe@example.com'); }); }); diff --git a/packages/ui/src/components/SignIn/utils.ts b/packages/ui/src/components/SignIn/utils.ts index cb688762ccb..4515b08a9f1 100644 --- a/packages/ui/src/components/SignIn/utils.ts +++ b/packages/ui/src/components/SignIn/utils.ts @@ -1,23 +1,10 @@ -import type { - PhoneCodeChannel, - PreferredSignInStrategy, - SignInFactor, - SignInResource, - SignInStrategy, -} from '@clerk/shared/types'; +import type { PhoneCodeChannel, SignInFactor, SignInResource, SignInStrategy } from '@clerk/shared/types'; import { titleize } from '@clerk/shared/underscore'; import { isEmail } from '@/ui/utils/emailUtils'; import { getPreferredPhoneCodeChannelByCountry } from '@/ui/utils/phoneUtils'; import type { FormControlState } from '@/ui/utils/useFormControl'; -import { PREFERRED_SIGN_IN_STRATEGIES } from '../../common/constants'; -import { otpPrefFactorComparator, passwordPrefFactorComparator } from '../../utils/factorSorting'; - -const factorForIdentifier = (i: string | null) => (f: SignInFactor) => { - return 'safeIdentifier' in f && f.safeIdentifier === i; -}; - export function isOfferableSecondFactor(factor: { strategy: SignInStrategy }, webAuthnSupported: boolean): boolean { return factor.strategy !== 'passkey' || webAuthnSupported; } @@ -34,60 +21,6 @@ function findPasskeyStrategy(factors: SignInFactor[], webAuthnSupported: boolean return null; } -function determineStrategyWhenPasswordIsPreferred( - factors: SignInFactor[], - identifier: string | null, - webAuthnSupported: boolean, -): SignInFactor | null { - const passkeyFactor = findPasskeyStrategy(factors, webAuthnSupported); - if (passkeyFactor) { - return passkeyFactor; - } - const selected = factors.sort(passwordPrefFactorComparator)[0]; - if (selected.strategy === 'password') { - return selected; - } - return factors.find(factorForIdentifier(identifier)) || selected || null; -} - -function determineStrategyWhenOTPIsPreferred( - factors: SignInFactor[], - identifier: string | null, - webAuthnSupported: boolean, -): SignInFactor | null { - const passkeyFactor = findPasskeyStrategy(factors, webAuthnSupported); - if (passkeyFactor) { - return passkeyFactor; - } - const sortedBasedOnPrefFactor = factors.sort(otpPrefFactorComparator); - const forIdentifier = sortedBasedOnPrefFactor.find(factorForIdentifier(identifier)); - if (forIdentifier) { - return forIdentifier; - } - const firstBasedOnPref = sortedBasedOnPrefFactor[0]; - if (firstBasedOnPref.strategy === 'email_link') { - return firstBasedOnPref; - } - return factors.find(factorForIdentifier(identifier)) || firstBasedOnPref || null; -} - -// The algorithm can be found at -// https://www.notion.so/clerkdev/Implement-sign-in-alt-methods-e6e60ffb644645b3a0553b50556468ce -export function determineStartingSignInFactor( - firstFactors: SignInFactor[] | null, - identifier: string | null, - preferredSignInStrategy: PreferredSignInStrategy, - webAuthnSupported: boolean, -): SignInFactor | null | undefined { - if (!firstFactors || firstFactors.length === 0) { - return null; - } - - return preferredSignInStrategy === PREFERRED_SIGN_IN_STRATEGIES.Password - ? determineStrategyWhenPasswordIsPreferred(firstFactors, identifier, webAuthnSupported) - : determineStrategyWhenOTPIsPreferred(firstFactors, identifier, webAuthnSupported); -} - export function determineSalutation(signIn: Partial): string { if (!signIn) { return ''; diff --git a/packages/ui/src/components/UserVerification/UserVerificationFactorOne.tsx b/packages/ui/src/components/UserVerification/UserVerificationFactorOne.tsx index 73d73e5fbf5..943d560175d 100644 --- a/packages/ui/src/components/UserVerification/UserVerificationFactorOne.tsx +++ b/packages/ui/src/components/UserVerification/UserVerificationFactorOne.tsx @@ -1,3 +1,4 @@ +import { determineStartingSignInFactor } from '@clerk/shared/internal/clerk-js/signInFactors'; import type { SessionVerificationFirstFactor, SignInFactor } from '@clerk/shared/types'; import React, { useEffect, useMemo } from 'react'; @@ -9,7 +10,7 @@ import { useEnvironment } from '../../contexts'; import { useIsWebAuthnSupported } from '../../hooks'; import { localizationKeys } from '../../localization'; import { useRouter } from '../../router'; -import { determineStartingSignInFactor, factorHasLocalStrategy } from '../SignIn/utils'; +import { factorHasLocalStrategy } from '../SignIn/utils'; import { AlternativeMethods } from './AlternativeMethods'; import { useReverificationAlternativeStrategies } from './useReverificationAlternativeStrategies'; import { UserVerificationFactorOnePasswordCard } from './UserVerificationFactorOnePassword'; diff --git a/packages/ui/src/utils/__tests__/factorSorting.test.ts b/packages/ui/src/utils/__tests__/factorSorting.test.ts index 15d260b4ad0..fd175c417fd 100644 --- a/packages/ui/src/utils/__tests__/factorSorting.test.ts +++ b/packages/ui/src/utils/__tests__/factorSorting.test.ts @@ -1,59 +1,7 @@ import type { SignInFactor, SignInStrategy } from '@clerk/shared/types'; import { describe, expect, it } from 'vitest'; -import { - allStrategiesButtonsComparator, - otpPrefFactorComparator, - passwordPrefFactorComparator, -} from '../factorSorting'; - -describe('otpPrefFactorComparator(a,b)', function () { - it('sorts an array of factors based on the otp pref sorter', function () { - const factors: SignInFactor[] = [ - { strategy: 'password' }, - { strategy: 'password' }, - { strategy: 'email_code', emailAddressId: '', safeIdentifier: '' }, - { strategy: 'phone_code', phoneNumberId: '', safeIdentifier: '' }, - { strategy: 'email_link', emailAddressId: '', safeIdentifier: '' }, - { strategy: 'email_link', emailAddressId: '', safeIdentifier: '' }, - ]; - - const expectedOrder: SignInStrategy[] = [ - 'email_link', - 'email_link', - 'email_code', - 'phone_code', - 'password', - 'password', - ]; - - expect(factors.sort(otpPrefFactorComparator).map(f => f.strategy)).toEqual(expectedOrder); - }); -}); - -describe('passwordPrefFactorComparator(a,b)', function () { - it('sorts an array of factors based on the password pref sorter', function () { - const factors: SignInFactor[] = [ - { strategy: 'email_code', emailAddressId: '', safeIdentifier: '' }, - { strategy: 'password' }, - { strategy: 'phone_code', phoneNumberId: '', safeIdentifier: '' }, - { strategy: 'email_link', emailAddressId: '', safeIdentifier: '' }, - { strategy: 'password' }, - { strategy: 'email_link', emailAddressId: '', safeIdentifier: '' }, - ]; - - const expectedOrder: SignInStrategy[] = [ - 'password', - 'password', - 'email_link', - 'email_link', - 'email_code', - 'phone_code', - ]; - - expect(factors.sort(passwordPrefFactorComparator).map(f => f.strategy)).toEqual(expectedOrder); - }); -}); +import { allStrategiesButtonsComparator } from '../factorSorting'; describe('allStrategiesButtonsComparator(a,b)', function () { it('sorts an array of factors based on the password pref sorter', function () { diff --git a/packages/ui/src/utils/factorSorting.ts b/packages/ui/src/utils/factorSorting.ts index 5a6296e4ce4..c226e772472 100644 --- a/packages/ui/src/utils/factorSorting.ts +++ b/packages/ui/src/utils/factorSorting.ts @@ -9,22 +9,6 @@ const makeSortingOrderMap = (arr: T[]): Record => {} as Record, ); -const STRATEGY_SORT_ORDER_PASSWORD_PREF = makeSortingOrderMap([ - 'passkey', - 'password', - 'email_link', - 'email_code', - 'phone_code', -] as SignInStrategy[]); - -const STRATEGY_SORT_ORDER_OTP_PREF = makeSortingOrderMap([ - 'email_link', - 'email_code', - 'phone_code', - 'passkey', - 'password', -] as SignInStrategy[]); - const STRATEGY_SORT_ORDER_ALL_STRATEGIES_BUTTONS = makeSortingOrderMap([ 'email_link', 'email_code', @@ -51,7 +35,5 @@ const makeSortingFunction = return orderA - orderB; }; -export const passwordPrefFactorComparator = makeSortingFunction(STRATEGY_SORT_ORDER_PASSWORD_PREF); -export const otpPrefFactorComparator = makeSortingFunction(STRATEGY_SORT_ORDER_OTP_PREF); export const backupCodePrefFactorComparator = makeSortingFunction(STRATEGY_SORT_ORDER_BACKUP_CODE_PREF); export const allStrategiesButtonsComparator = makeSortingFunction(STRATEGY_SORT_ORDER_ALL_STRATEGIES_BUTTONS);