Skip to content
Open
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 @@ -3,9 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import React from 'react';
import { screen } from '@testing-library/react';
import { screen, waitFor } from '@testing-library/react';
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
import AuthComplete, { viewName } from '.';
import AuthComplete, { PAIR_DEVICE_INFO_KEY, viewName } from '.';
import { MOCK_METADATA_UNKNOWN_LOCATION } from '../../../components/DeviceInfoBlock/mocks';
import { usePageViewEvent } from '../../../lib/metrics';
import { REACT_ENTRYPOINT } from '../../../constants';
Expand Down Expand Up @@ -86,6 +86,7 @@ describe('AuthComplete page', () => {
);
mockIntegration = new PAI();
mockIntegration.data = { entrypoint: undefined };
sessionStorage.clear();
});

it('calls complete() on mount and destroy() on unmount', () => {
Expand All @@ -96,6 +97,46 @@ describe('AuthComplete page', () => {
unmount();
expect(mockIntegration.destroy).toHaveBeenCalled();
});

it('restores device info from sessionStorage after refresh', () => {
const cachedInfo = {
deviceFamily: 'Firefox',
deviceOS: 'Windows',
ipAddress: '1.2.3.4',
};
sessionStorage.setItem(PAIR_DEVICE_INFO_KEY, JSON.stringify(cachedInfo));

renderWithLocalizationProvider(
<AuthComplete integration={mockIntegration as unknown as Integration} />
);

expect(screen.getByRole('heading', { level: 2 })).toHaveTextContent(
'You are now syncing with: Firefox on Windows'
);
expect(mockIntegration.getSupplicantMetadata).not.toHaveBeenCalled();
});

it('persists fetched device info to sessionStorage', async () => {
const fetchedInfo = {
deviceFamily: 'Firefox',
deviceOS: 'Android',
ipAddress: '1.2.3.4',
};
mockIntegration.getSupplicantMetadata.mockResolvedValue(fetchedInfo);

renderWithLocalizationProvider(
<AuthComplete integration={mockIntegration as unknown as Integration} />
);

await waitFor(() =>
expect(sessionStorage.getItem(PAIR_DEVICE_INFO_KEY)).toBe(
JSON.stringify(fetchedInfo)
)
);
expect(screen.getByRole('heading', { level: 2 })).toHaveTextContent(
'You are now syncing with: Firefox on Android'
);
});
});

describe('Send Tab variant', () => {
Expand Down
25 changes: 20 additions & 5 deletions packages/fxa-settings/src/pages/Pair/AuthComplete/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { isSendTabEntrypoint } from '../../../lib/utilities';

export const viewName = 'pair.auth.complete';

export const PAIR_DEVICE_INFO_KEY = 'pair.supp.device-info';

type AuthCompleteProps = {
suppDeviceInfo?: RemoteMetadata;
supportsFirefoxView?: boolean;
Comment on lines +22 to 26
Expand All @@ -37,7 +39,15 @@ const AuthComplete = ({
usePageViewEvent(viewName, REACT_ENTRYPOINT);
const ftlMsgResolver = useFtlMsgResolver();
const [deviceInfo, setDeviceInfo] = useState<RemoteMetadata | undefined>(
suppDeviceInfoProp
() => {
if (suppDeviceInfoProp) return suppDeviceInfoProp;
try {
const cached = sessionStorage.getItem(PAIR_DEVICE_INFO_KEY);
return cached ? (JSON.parse(cached) as RemoteMetadata) : undefined;
} catch {
return undefined;
}
}
);

const authorityIntegration =
Expand All @@ -49,16 +59,21 @@ const AuthComplete = ({
const deviceOS = deviceInfo?.deviceOS || 'Unknown';
const isSendTab = isSendTabEntrypoint(integration?.data.entrypoint);

// Fetch supplicant metadata if not provided via props
// Fetch supplicant metadata if not already available from props or sessionStorage
useEffect(() => {
if (suppDeviceInfoProp) {
if (suppDeviceInfoProp || deviceInfo) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may as well, add authorityIntegration to this list.

return;
}
authorityIntegration
?.getSupplicantMetadata()
.then(setDeviceInfo)
.then((info) => {
try {
sessionStorage.setItem(PAIR_DEVICE_INFO_KEY, JSON.stringify(info));
} catch {}
setDeviceInfo(info);
})
.catch(() => {});
}, [authorityIntegration, suppDeviceInfoProp]);
}, [authorityIntegration, suppDeviceInfoProp, deviceInfo]);

// Signal pairing complete to Firefox on mount
useEffect(() => {
Expand Down
Loading