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');
+ }
+ });
+ });
+});