Skip to content

Commit c6e16e2

Browse files
committed
cleanup(signin): Adjust signin stories for better documentation
Because: * Signin states are confusing This commit: * Adjusts Signin story names, consolidates some stories, accounts for others * Adds a comment above isPasswordNeeded * Changes an integration mock that had wantsKeys=true when that integration never wantsKeys and updates tests closes FXA-13204
1 parent b7f67a6 commit c6e16e2

8 files changed

Lines changed: 218 additions & 140 deletions

File tree

packages/fxa-settings/src/lib/hooks/useFxAStatus/index.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ export function useFxAStatus(integration: FxAStatusIntegration) {
4040
const [declinedSyncEngines, setDeclinedSyncEngines] = useState<string[]>([]);
4141
const [supportsKeysOptionalLogin, setSupportsKeysOptionalLogin] =
4242
useState<boolean>(false);
43-
const [supportsCanLinkAccountUid, setSupportsCanLinkAccountUid] =
44-
useState<boolean | undefined>(undefined);
43+
const [supportsCanLinkAccountUid, setSupportsCanLinkAccountUid] = useState<
44+
boolean | undefined
45+
>(undefined);
4546

4647
useEffect(() => {
4748
// This sends a web channel message to the browser to prompt a response
@@ -68,7 +69,8 @@ export function useFxAStatus(integration: FxAStatusIntegration) {
6869
setWebChannelEngines(status.capabilities.engines);
6970
}
7071
}
71-
// Check if third party auth (passwordless) log in to the browser is supported
72+
// Check if third party auth (passwordless) log in to the browser is supported,
73+
// currently only Firefox desktop 147+ as of Q1 2026
7274
if (
7375
status.capabilities.keys_optional &&
7476
isOAuthNative &&

packages/fxa-settings/src/lib/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export enum MozServices {
5858
Default = 'account settings',
5959
Monitor = 'Mozilla Monitor',
6060
FirefoxSync = 'Firefox Sync',
61+
SmartWindow = 'Smart Window',
6162
MozillaVPN = 'Mozilla VPN',
6263
Relay = 'Mozilla Relay',
6364
TestService = '123Done',

packages/fxa-settings/src/models/integrations/integration.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,20 @@ export class GenericIntegration<
150150
}
151151
}
152152

153+
/**
154+
* Currently only Sync _requires_ keys (entering a password). Other
155+
* services may see cached signin or choose to sign in with third party auth.
156+
* However, for non-Sync browser service signins, if the password is entered,
157+
* we go ahead and get Sync keys so users can turn Sync on in the browser
158+
* without being bounced back to FxA.
159+
*
160+
* Note, the Relay browser service login launched in Firefox desktop 135, and
161+
* the "keys optional" capability launched in Fx desktop 147, meaning all Relay
162+
* service users in those Fx versions require a password.
163+
*
164+
* Desktop OAuth launched with Fx 134. SyncDesktopV3 users don't have non-Sync
165+
* browser support.
166+
* */
153167
wantsKeys(): boolean {
154168
return false;
155169
}

packages/fxa-settings/src/models/integrations/oauth-native-integration.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ export class OAuthNativeIntegration extends OAuthWebIntegration {
143143
);
144144
}
145145

146+
// See JSDoc comment above the generic integration base class wantsKeys
146147
wantsKeys() {
147-
// TODO: this will not always be true when working on FXA-12374
148148
return true;
149149
}
150150

packages/fxa-settings/src/pages/Signin/index.stories.tsx

Lines changed: 185 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -26,147 +26,206 @@ export default {
2626
decorators: [withLocalization],
2727
} as Meta;
2828

29-
const storyWithProps = ({
30-
...props // overrides
31-
}: Partial<SigninProps> & { supportsKeysOptionalLogin?: boolean } = {}) => {
29+
const storyWithProps = (
30+
props: Partial<SigninProps> & { supportsKeysOptionalLogin?: boolean } = {},
31+
storyName?: string
32+
) => {
3233
const story = () => <Subject {...props} />;
34+
if (storyName) story.storyName = storyName;
3335
return story;
3436
};
3537

36-
export const SignInToSettingsWithPassword = storyWithProps();
37-
export const SignInToSettingsWithPasswordAccountLockedError = storyWithProps({
38-
beginSigninHandler: () => {
39-
return Promise.resolve({
40-
error: AuthUiErrors.ACCOUNT_RESET as BeginSigninError,
41-
});
42-
},
43-
});
44-
45-
export const SignInToRelyingPartyWithPassword = storyWithProps({
46-
serviceName: MOCK_SERVICE,
47-
});
48-
49-
export const SignInToSettingsWithCachedCredentials = storyWithProps({
50-
sessionToken: MOCK_SESSION_TOKEN,
51-
});
52-
export const SignInToRelyingPartyWithCachedCredentials = storyWithProps({
53-
sessionToken: MOCK_SESSION_TOKEN,
54-
serviceName: MOCK_SERVICE,
55-
});
56-
57-
export const SignInToSyncWithCachedCredentials = storyWithProps({
58-
sessionToken: MOCK_SESSION_TOKEN,
59-
integration: createMockSigninOAuthIntegration({ wantsKeys: true }),
60-
});
61-
62-
export const HasLinkedAccountAndNoPassword = storyWithProps({
63-
hasLinkedAccount: true,
64-
hasPassword: false,
65-
});
66-
67-
// UX could be improved, see FXA-8278
68-
export const NoLinkedAccountAndNoPassword = storyWithProps({
69-
hasPassword: false,
70-
});
71-
72-
export const SignInToSync = storyWithProps({
73-
serviceName: MozServices.FirefoxSync,
74-
hasLinkedAccount: true,
75-
hasPassword: true,
76-
integration: createMockSigninOAuthNativeSyncIntegration(),
77-
});
78-
79-
export const SignInToSyncNoPassword = storyWithProps({
80-
serviceName: MozServices.FirefoxSync,
81-
hasLinkedAccount: true,
82-
hasPassword: false,
83-
integration: createMockSigninOAuthNativeSyncIntegration(),
84-
});
85-
86-
export const SignInWithCms = storyWithProps({
87-
integration: createMockSigninOAuthIntegration({
88-
cmsInfo: MOCK_CMS_INFO,
89-
}),
90-
});
38+
export const NonCachedAccountHasPasswordSettingsOrRP = storyWithProps(
39+
{},
40+
'Non-Cached > Account has password > Settings or Relying Party'
41+
);
9142

92-
export const SignInWithCmsSplitLayout = storyWithProps({
93-
integration: createMockSigninOAuthIntegration({
94-
cmsInfo: {
95-
...MOCK_CMS_INFO,
96-
SigninPage: {
97-
...MOCK_CMS_INFO.SigninPage!,
98-
splitLayout: true,
43+
export const NonCachedAccountHasPasswordSettingsAccountLockedError =
44+
storyWithProps(
45+
{
46+
beginSigninHandler: () => {
47+
return Promise.resolve({
48+
error: AuthUiErrors.ACCOUNT_RESET as BeginSigninError,
49+
});
9950
},
10051
},
101-
}),
102-
});
52+
'Non-Cached > Account has password > Settings, account locked error (click sign in)'
53+
);
54+
55+
export const NonCachedPasswordlessAccountSettingsOrRelyingParty =
56+
storyWithProps(
57+
{
58+
hasLinkedAccount: true,
59+
hasPassword: false,
60+
},
61+
'Non-Cached > Passwordless account > Settings or Relying Party'
62+
);
63+
64+
export const NonCachedSyncBrowserServiceAccountHasPassword = storyWithProps(
65+
{
66+
serviceName: MozServices.FirefoxSync,
67+
hasLinkedAccount: true,
68+
hasPassword: true,
69+
integration: createMockSigninOAuthNativeSyncIntegration(),
70+
},
71+
'Non-Cached > Sync browser service > Account has password'
72+
);
10373

104-
export const SignInWithCmsCachedCredentials = storyWithProps({
105-
sessionToken: MOCK_SESSION_TOKEN,
106-
integration: createMockSigninOAuthIntegration({
107-
wantsKeys: false,
108-
cmsInfo: MOCK_CMS_INFO,
109-
}),
110-
});
74+
export const NonCachedSyncBrowserServicePasswordlessAccount = storyWithProps(
75+
{
76+
serviceName: MozServices.FirefoxSync,
77+
hasLinkedAccount: true,
78+
hasPassword: false,
79+
integration: createMockSigninOAuthNativeSyncIntegration(),
80+
},
81+
'Non-Cached > Sync browser service > Passwordless account (user will be taken to Set Password page)'
82+
);
11183

112-
export const SignInWithCmsCachedCredentialsSplitLayout = storyWithProps({
113-
sessionToken: MOCK_SESSION_TOKEN,
114-
integration: createMockSigninOAuthIntegration({
115-
wantsKeys: false,
116-
cmsInfo: {
117-
...MOCK_CMS_INFO,
118-
SigninPage: {
119-
...MOCK_CMS_INFO.SigninPage!,
120-
splitLayout: true,
121-
},
84+
export const NonCachedNonSyncBrowserServiceBrowserHasPasswordlessCapability =
85+
storyWithProps(
86+
{
87+
serviceName: MozServices.SmartWindow,
88+
integration: createMockSigninOAuthNativeIntegration({
89+
service: OAuthNativeServices.SmartWindow,
90+
isSync: false,
91+
}),
92+
supportsKeysOptionalLogin: true,
12293
},
123-
}),
124-
});
125-
126-
export const SignInWithCmsCachedPage = storyWithProps({
127-
sessionToken: MOCK_SESSION_TOKEN,
128-
integration: createMockSigninOAuthIntegration({
129-
wantsKeys: false,
130-
cmsInfo: {
131-
...MOCK_CMS_INFO,
132-
SigninCachedPage: {
133-
headline: 'Welcome back',
134-
description: 'Continue to your Mozilla account',
135-
primaryButtonText: 'Continue',
136-
pageTitle: 'Welcome back',
137-
},
94+
'Non-Cached > Non-Sync browser service > Browser has Sync keys optional capability'
95+
);
96+
97+
export const NonCachedNonSyncBrowserServiceBrowserDoesNotHavePasswordlessCapability =
98+
storyWithProps(
99+
{
100+
serviceName: MozServices.Relay,
101+
integration: createMockSigninOAuthNativeIntegration({
102+
service: OAuthNativeServices.Relay,
103+
isSync: false,
104+
}),
105+
supportsKeysOptionalLogin: false,
138106
},
139-
}),
140-
});
107+
'Non-Cached > Non-Sync browser service > Browser does not have Sync keys optional capability'
108+
);
141109

142-
export const SignInRelayNoPasswordlessSupport = storyWithProps({
143-
integration: createMockSigninOAuthNativeIntegration({
144-
service: OAuthNativeServices.Relay,
145-
isSync: false,
146-
}),
147-
supportsKeysOptionalLogin: false,
148-
});
149-
150-
export const SignInNonSyncWithBrowserPasswordlessSupport = storyWithProps({
151-
integration: createMockSigninOAuthNativeIntegration({
152-
service: OAuthNativeServices.SmartWindow,
153-
isSync: false,
154-
}),
155-
supportsKeysOptionalLogin: true,
156-
});
110+
export const CachedAccountHasPasswordSettings = storyWithProps(
111+
{
112+
sessionToken: MOCK_SESSION_TOKEN,
113+
},
114+
'Cached > Account has password > Settings'
115+
);
157116

158-
export const CachedSignInNonSyncWithBrowserPasswordlessSupport = storyWithProps(
117+
export const CachedAccountHasPasswordRelyingParty = storyWithProps(
159118
{
160119
sessionToken: MOCK_SESSION_TOKEN,
161-
integration: createMockSigninOAuthNativeIntegration({
162-
service: OAuthNativeServices.SmartWindow,
163-
isSync: false,
120+
serviceName: MOCK_SERVICE,
121+
hasPassword: false,
122+
integration: createMockSigninOAuthIntegration({
123+
service: MOCK_SERVICE,
164124
}),
165-
supportsKeysOptionalLogin: true,
166-
}
125+
},
126+
'Cached > Passwordless account > Relying Party'
167127
);
128+
export const CachedSyncBrowserService = storyWithProps(
129+
{
130+
sessionToken: MOCK_SESSION_TOKEN,
131+
integration: createMockSigninOAuthNativeSyncIntegration(),
132+
},
133+
'Cached > Sync browser service'
134+
);
135+
export const CachedNonSyncBrowserServiceWithoutPasswordlessCapability =
136+
storyWithProps(
137+
{
138+
sessionToken: MOCK_SESSION_TOKEN,
139+
serviceName: MozServices.SmartWindow,
140+
integration: createMockSigninOAuthNativeIntegration({
141+
service: OAuthNativeServices.SmartWindow,
142+
isSync: false,
143+
}),
144+
supportsKeysOptionalLogin: false,
145+
},
146+
'Cached > Non-Sync browser service > Browser does not have Sync keys optional capability'
147+
);
148+
export const CachedNonSyncBrowserServiceWithPasswordlessCapabilitySignedIntoDesktop =
149+
storyWithProps(
150+
{
151+
sessionToken: MOCK_SESSION_TOKEN,
152+
serviceName: MozServices.SmartWindow,
153+
integration: createMockSigninOAuthNativeIntegration({
154+
service: OAuthNativeServices.SmartWindow,
155+
isSync: false,
156+
}),
157+
supportsKeysOptionalLogin: true,
158+
isSignedIntoFirefoxDesktop: true,
159+
},
160+
'Cached > Non-Sync browser service > Browser has Sync keys optional capability > Account is signed into Firefox Desktop'
161+
);
162+
export const CachedNonSyncBrowserServiceWithPasswordlessCapabilityNotSignedIntoDesktop =
163+
storyWithProps(
164+
{
165+
sessionToken: MOCK_SESSION_TOKEN,
166+
serviceName: MozServices.SmartWindow,
167+
hasLinkedAccount: true,
168+
hasPassword: false,
169+
integration: createMockSigninOAuthNativeIntegration({
170+
service: OAuthNativeServices.SmartWindow,
171+
isSync: false,
172+
}),
173+
supportsKeysOptionalLogin: true,
174+
},
175+
'Cached > Non-Sync browser service > Browser has Sync keys optional capability > Account is not signed into Firefox Desktop'
176+
);
168177

169-
export const CachedSignInSignedIntoFirefoxDesktop = storyWithProps({
170-
sessionToken: MOCK_SESSION_TOKEN,
171-
isSignedIntoFirefoxDesktop: true,
172-
});
178+
export const CmsNonCachedDefault = storyWithProps(
179+
{
180+
integration: createMockSigninOAuthIntegration({
181+
cmsInfo: MOCK_CMS_INFO,
182+
}),
183+
},
184+
'CMS > Regular layout > Non-Cached'
185+
);
186+
export const CmsNonCachedSplitLayout = storyWithProps(
187+
{
188+
integration: createMockSigninOAuthIntegration({
189+
cmsInfo: {
190+
...MOCK_CMS_INFO,
191+
SigninPage: {
192+
...MOCK_CMS_INFO.SigninPage!,
193+
splitLayout: true,
194+
},
195+
},
196+
}),
197+
},
198+
'CMS > Split layout > Non-Cached'
199+
);
200+
export const CmsCachedSplitLayout = storyWithProps(
201+
{
202+
sessionToken: MOCK_SESSION_TOKEN,
203+
integration: createMockSigninOAuthIntegration({
204+
cmsInfo: {
205+
...MOCK_CMS_INFO,
206+
SigninPage: {
207+
...MOCK_CMS_INFO.SigninPage!,
208+
splitLayout: true,
209+
},
210+
},
211+
}),
212+
},
213+
'CMS > Split layout > Cached'
214+
);
215+
export const CmsCachedCachedPage = storyWithProps(
216+
{
217+
sessionToken: MOCK_SESSION_TOKEN,
218+
integration: createMockSigninOAuthIntegration({
219+
cmsInfo: {
220+
...MOCK_CMS_INFO,
221+
SigninCachedPage: {
222+
headline: 'Welcome back',
223+
description: 'Continue to your Mozilla account',
224+
primaryButtonText: 'Continue',
225+
pageTitle: 'Welcome back',
226+
},
227+
},
228+
}),
229+
},
230+
'CMS > Regular layout > Cached'
231+
);

0 commit comments

Comments
 (0)