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
2 changes: 1 addition & 1 deletion packages/fxa-settings/src/components/App/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ jest.mock('../../lib/glean', () => ({
initialize: jest.fn(),
getEnabled: jest.fn(),
useGlean: jest.fn().mockReturnValue({ enabled: true }),
accountPref: { view: jest.fn(), promoMonitorView: jest.fn() },
accountPref: { view: jest.fn(), promoVpnView: jest.fn() },
emailFirst: { view: jest.fn(), engage: jest.fn() },
error: { view: jest.fn() },
pageLoad: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jest.mock('../../../lib/glean', () => ({
default: {
accountPref: {
view: jest.fn(),
promoMonitorView: jest.fn(),
promoVpnView: jest.fn(),
},
deleteAccount: {
settingsSubmit: jest.fn(),
Expand All @@ -53,7 +53,6 @@ jest.mock('../../../lib/glean', () => ({

const mockGetProductPromoData = jest.fn().mockReturnValue({
hidePromo: false,
gleanEvent: { event: { reason: 'default' } },
});
jest.mock('../ProductPromo', () => ({
__esModule: true,
Expand Down Expand Up @@ -155,10 +154,9 @@ describe('PageSettings', () => {
});

describe('product promo event', () => {
it('user does not have Monitor, promo is shown and glean metric is called', async () => {
it('user does not have VPN, promo is shown and glean metric is called', async () => {
mockGetProductPromoData.mockReturnValue({
hidePromo: false,
gleanEvent: { event: { reason: 'default' } },
});
renderWithRouter(
<AppContext.Provider
Expand All @@ -168,16 +166,11 @@ describe('PageSettings', () => {
</AppContext.Provider>
);
await waitFor(() =>
expect(
GleanMetrics.accountPref.promoMonitorView
).toHaveBeenCalledTimes(1)
expect(GleanMetrics.accountPref.promoVpnView).toHaveBeenCalledTimes(1)
);
expect(GleanMetrics.accountPref.promoMonitorView).toHaveBeenCalledWith({
event: { reason: 'default' },
});
});

it('user has Monitor, promo is not shown and glean metric is not called', async () => {
it('user has VPN, promo is not shown and glean metric is not called', async () => {
mockGetProductPromoData.mockReturnValue({
hidePromo: true,
});
Expand All @@ -189,9 +182,7 @@ describe('PageSettings', () => {
</AppContext.Provider>
);
await waitFor(() =>
expect(
GleanMetrics.accountPref.promoMonitorView
).not.toHaveBeenCalled()
expect(GleanMetrics.accountPref.promoVpnView).not.toHaveBeenCalled()
);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import DataCollection from '../DataCollection';
import GleanMetrics from '../../../lib/glean';
import ProductPromo, {
getProductPromoData,
MonitorPromoData,
VpnPromoData,
} from '../ProductPromo';
import SideBar from '../Sidebar';
import Head from 'fxa-react/components/Head';
Expand Down Expand Up @@ -59,9 +59,7 @@ export const PageSettings = ({
GleanMetrics.accountPref.view();
}, []);

const [monitorPromo, setMonitorPromo] = useState<MonitorPromoData | null>(
null
);
const [vpnPromo, setVpnPromo] = useState<VpnPromoData | null>(null);
const [productPromoGleanEventSent, setProductPromoGleanEventSent] =
useState(false);

Expand Down Expand Up @@ -98,32 +96,27 @@ export const PageSettings = ({

useEffect(() => {
(async () => {
if (monitorPromo !== null) {
if (vpnPromo !== null) {
return;
}

const promoData = getProductPromoData(account.attachedClients);

setMonitorPromo(promoData);
setVpnPromo(promoData);
})();
}, [account, monitorPromo]);
}, [account, vpnPromo]);

// -- Relying party promotion checks --
useEffect(() => {
if (!monitorPromo) return;
if (!vpnPromo) return;
// We want this view event to fire whenever the account settings page view
// event fires, if the user is shown the promo.
if (!monitorPromo.hidePromo && !productPromoGleanEventSent) {
GleanMetrics.accountPref.promoMonitorView(monitorPromo.gleanEvent);
if (!vpnPromo.hidePromo && !productPromoGleanEventSent) {
GleanMetrics.accountPref.promoVpnView();
// Keep track of this because `attachedClients` can change on disconnect
setProductPromoGleanEventSent(true);
}
}, [
attachedClients,
monitorPromo,
subscriptions,
productPromoGleanEventSent,
]);
}, [attachedClients, vpnPromo, subscriptions, productPromoGleanEventSent]);

useEffect(() => {
const targetEmail = (() => {
Expand Down Expand Up @@ -187,7 +180,7 @@ export const PageSettings = ({
connectedServicesRef,
linkedAccountsRef,
dataCollectionRef,
monitorPromo,
vpnPromo,
}}
/>
</div>
Expand All @@ -211,8 +204,8 @@ export const PageSettings = ({
</Link>
</Localized>
</div>
{monitorPromo && !monitorPromo.hidePromo && (
<ProductPromo type="settings" {...{ monitorPromo }} />
{vpnPromo && !vpnPromo.hidePromo && (
<ProductPromo type="settings" {...{ vpnPromo }} />
)}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@ product-promo-monitor =
product-promo-monitor-description-v2 = Find where your private info is exposed and take control
# Links out to the Monitor site
product-promo-monitor-cta = Get free scan

product-promo-vpn =
.alt = { -product-mozilla-vpn }
product-promo-vpn-description = Discover an added layer of anonymous browsing and protection.
# Links out to the VPN site
product-promo-vpn-cta = Get { -product-mozilla-vpn-short }

##
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ function storyWithProps(props: ProductPromoProps, storyName?: string) {
export const MobilePromo = storyWithProps(
{
type: 'settings',
monitorPromo: { hidePromo: false },
vpnPromo: { hidePromo: false },
},
'Monitor promo - Banner - mobile only'
'VPN promo - Banner - mobile only'
);
export const DesktopPromo = storyWithProps(
{
type: 'sidebar',
monitorPromo: { hidePromo: false },
vpnPromo: { hidePromo: false },
},
'Monitor promo - Sidebar - desktop'
'VPN promo - Sidebar - desktop'
);
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ jest.mock('../../../lib/glean', () => ({
__esModule: true,
default: {
accountPref: {
promoMonitorView: jest.fn(),
promoMonitorSubmit: jest.fn(),
promoVpnView: jest.fn(),
promoVpnSubmit: jest.fn(),
},
},
}));
Expand All @@ -28,32 +28,30 @@ describe('ProductPromo', () => {

it('can hide the promo', async () => {
renderWithLocalizationProvider(
<ProductPromo type="settings" monitorPromo={{ hidePromo: true }} />
<ProductPromo type="settings" vpnPromo={{ hidePromo: true }} />
);

// nothing should render
await waitFor(() =>
expect(screen.queryByAltText('Mozilla Monitor')).toBeNull()
expect(screen.queryByAltText('Mozilla VPN')).toBeNull()
);
});

it('can show promo', async () => {
renderWithLocalizationProvider(
<ProductPromo type="settings" monitorPromo={{ hidePromo: false }} />
<ProductPromo type="settings" vpnPromo={{ hidePromo: false }} />
);

await waitFor(() =>
expect(
screen.getByText(
'Find where your private info is exposed and take control'
'Discover an added layer of anonymous browsing and protection.'
)
).toBeVisible()
);
expect(
screen.getByRole('link', { name: /Get free scan/i })
).toHaveAttribute(
expect(screen.getByRole('link', { name: /Get VPN/i })).toHaveAttribute(
'href',
'https://monitor.mozilla.org/?utm_source=moz-account&utm_medium=referral&utm_term=settings&utm_content=get-free-scan-global&utm_campaign=settings-promo'
'https://vpn.mozilla.org/?utm_source=moz-account&utm_medium=mozilla-websites&utm_term=settings&utm_content=vpn&utm_campaign=promo'
);
});

Expand All @@ -62,59 +60,47 @@ describe('ProductPromo', () => {
renderWithLocalizationProvider(
<ProductPromo
type="settings"
monitorPromo={{
vpnPromo={{
hidePromo: false,
gleanEvent: { event: { reason: 'default' } },
}}
/>
);

await waitFor(() =>
expect(
screen.getByText(
'Find where your private info is exposed and take control'
'Discover an added layer of anonymous browsing and protection.'
)
).toBeVisible()
);
await user.click(
screen.getByRole('link', {
name: /Get free scan/i,
name: /Get VPN/i,
})
);
await waitFor(() => {
expect(GleanMetrics.accountPref.promoMonitorSubmit).toHaveBeenCalledWith({
event: { reason: 'default' },
});
expect(GleanMetrics.accountPref.promoVpnSubmit).toHaveBeenCalledWith();
});
});

describe('getProductPromoData', () => {
it('hides promo when Monitor is present', () => {
it('hides promo when VPN is present', () => {
const result = getProductPromoData([
{ name: MozServices.Monitor },
{ name: MozServices.MozillaVPN },
] as AttachedClient[]);
expect(result).toEqual({ hidePromo: true });
});

it('hides promo when Monitor Stage is present', () => {
const result = getProductPromoData([
{ name: MozServices.MonitorStage },
] as AttachedClient[]);
expect(result).toEqual({ hidePromo: true });
});

it('shows promo and provides gleanEvent when Monitor not present', () => {
it('shows promo when VPN not present', () => {
const result = getProductPromoData([
{ name: MozServices.Default },
] as AttachedClient[]);
expect(result.hidePromo).toBe(false);
expect(result.gleanEvent).toEqual({ event: { reason: 'default' } });
});

it('shows promo with gleanEvent when there are no attached clients', () => {
it('shows promo when there are no attached clients', () => {
const result = getProductPromoData([] as AttachedClient[]);
expect(result.hidePromo).toBe(false);
expect(result.gleanEvent).toEqual({ event: { reason: 'default' } });
});
});
});
Loading
Loading