diff --git a/src/frontend/src/lib/components/core/Menu.svelte b/src/frontend/src/lib/components/core/Menu.svelte index 9a887e0815..683348024e 100644 --- a/src/frontend/src/lib/components/core/Menu.svelte +++ b/src/frontend/src/lib/components/core/Menu.svelte @@ -1,12 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/frontend/src/lib/constants/test-ids.constants.ts b/src/frontend/src/lib/constants/test-ids.constants.ts index 68497a3465..4867369c2c 100644 --- a/src/frontend/src/lib/constants/test-ids.constants.ts +++ b/src/frontend/src/lib/constants/test-ids.constants.ts @@ -1,5 +1,6 @@ export const NAVIGATION_MENU_BUTTON = 'navigation-menu-button'; export const NAVIGATION_MENU = 'navigation-menu'; +export const NAVIGATION_MENU_VIP_BUTTON = 'navigation-menu-vip-button'; export const LOGOUT_BUTTON = 'logout-button'; export const LOGIN_BUTTON = 'login-button'; diff --git a/src/frontend/src/lib/i18n/en.json b/src/frontend/src/lib/i18n/en.json index b37ccd0148..1705a51a5f 100644 --- a/src/frontend/src/lib/i18n/en.json +++ b/src/frontend/src/lib/i18n/en.json @@ -41,7 +41,8 @@ "source_code": "Source code", "changelog": "Changelog", "submit_ticket": "Submit a ticket", - "confirm_navigate": "Are you sure you want to navigate away?" + "confirm_navigate": "Are you sure you want to navigate away?", + "vip_qr_code": "VIP QR codes" }, "alt": { "tokens": "Go to the assets view", @@ -52,7 +53,8 @@ "menu": "Your wallet address, settings, sign-out and external links", "changelog": "Open the changelog of $oisy_name on GitHub to review the latest updates", "submit_ticket": "Report an issue or request a feature on GitHub", - "open_twitter": "Open the DFINITY X/Twitter feed" + "open_twitter": "Open the DFINITY X/Twitter feed", + "vip_qr_code": "Generate an invitation link" } }, "auth": { diff --git a/src/frontend/src/lib/types/i18n.d.ts b/src/frontend/src/lib/types/i18n.d.ts index 1c8bc7f441..73e96b9c2a 100644 --- a/src/frontend/src/lib/types/i18n.d.ts +++ b/src/frontend/src/lib/types/i18n.d.ts @@ -38,6 +38,7 @@ interface I18nNavigation { changelog: string; submit_ticket: string; confirm_navigate: string; + vip_qr_code: string; }; alt: { tokens: string; @@ -49,6 +50,7 @@ interface I18nNavigation { changelog: string; submit_ticket: string; open_twitter: string; + vip_qr_code: string; }; } diff --git a/src/frontend/src/tests/lib/components/core/Menu.spec.ts b/src/frontend/src/tests/lib/components/core/Menu.spec.ts new file mode 100644 index 0000000000..71235041bb --- /dev/null +++ b/src/frontend/src/tests/lib/components/core/Menu.spec.ts @@ -0,0 +1,80 @@ +import type { UserData } from '$declarations/rewards/rewards.did'; +import * as rewardApi from '$lib/api/reward.api'; +import Menu from '$lib/components/core/Menu.svelte'; +import { + NAVIGATION_MENU_BUTTON, + NAVIGATION_MENU_VIP_BUTTON +} from '$lib/constants/test-ids.constants'; +import * as authStore from '$lib/derived/auth.derived'; +import { userProfileStore } from '$lib/stores/user-profile.store'; +import { mockIdentity } from '$tests/mocks/identity.mock'; +import type { Identity } from '@dfinity/agent'; +import { render, waitFor } from '@testing-library/svelte'; +import { beforeEach } from 'node:test'; +import { readable } from 'svelte/store'; + +describe('Menu', () => { + const menuButtonSelector = `button[data-tid="${NAVIGATION_MENU_BUTTON}"]`; + const menuItemVipButtonSelector = `button[data-tid="${NAVIGATION_MENU_VIP_BUTTON}"]`; + + beforeEach(() => { + userProfileStore.reset(); + }); + + const mockAuthStore = (value: Identity | null = mockIdentity) => + vi.spyOn(authStore, 'authIdentity', 'get').mockImplementation(() => readable(value)); + + it('renders the vip menu item', async () => { + const mockedUserData: UserData = { + is_vip: [true], + airdrops: [], + sprinkles: [] + }; + vi.spyOn(rewardApi, 'getUserInfo').mockResolvedValue(mockedUserData); + mockAuthStore(); + + const { container } = render(Menu); + const menuButton: HTMLButtonElement | null = container.querySelector(menuButtonSelector); + + expect(menuButton).toBeInTheDocument(); + + menuButton?.click(); + + await waitFor(() => { + const menuItemVipButton: HTMLButtonElement | null = + container.querySelector(menuItemVipButtonSelector); + if (menuItemVipButton == null) { + throw new Error('menu item not yet loaded'); + } + + expect(menuItemVipButton).toBeInTheDocument(); + }); + }); + + it('does not render the vip menu item', async () => { + const mockedUserData: UserData = { + is_vip: [false], + airdrops: [], + sprinkles: [] + }; + vi.spyOn(rewardApi, 'getUserInfo').mockResolvedValue(mockedUserData); + mockAuthStore(); + + const { container } = render(Menu); + const menuButton: HTMLButtonElement | null = container.querySelector(menuButtonSelector); + + expect(menuButton).toBeInTheDocument(); + + menuButton?.click(); + + await waitFor(() => { + const menuItemVipButton: HTMLButtonElement | null = + container.querySelector(menuItemVipButtonSelector); + if (menuItemVipButton == null) { + expect(menuItemVipButton).toBeNull(); + } else { + throw new Error('menu item loaded'); + } + }); + }); +});