nitro-v36-with-renderer-v36
/
src /
components /
catalog /
views /
page /
layout /
CatalogLayoutVipBuyView.test.tsx
CatalogLayoutVipBuyView.test.tsx 11.4 Ko
Télécharger le fichier
import { CreateLinkEvent } from '@octane/renderer';
import { cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { DispatchUiEvent, SendMessageComposer } from '../../../../../api';
import {
useCatalogActions,
useCatalogData,
useCatalogSkipPurchaseConfirmation,
useCatalogUiState,
useClubOffers,
useGiftConfiguration,
useNotification,
usePurse
} from '../../../../../hooks';
import { CatalogLayoutVipBuyView } from './CatalogLayoutVipBuyView';
const composerTypes = vi.hoisted(() => {
class PurchaseFromCatalogComposer {
public constructor(
public readonly pageId: number,
public readonly offerId: number,
public readonly extraData: string | null,
public readonly amount: number
) {}
}
class PurchaseFromCatalogAsGiftComposer {
public constructor(..._args: unknown[]) {}
}
return { PurchaseFromCatalogAsGiftComposer, PurchaseFromCatalogComposer };
});
vi.mock('@octane/renderer', () => ({
CreateLinkEvent: vi.fn(),
GiftReceiverNotFoundEvent: class {},
PurchaseFromCatalogAsGiftComposer: composerTypes.PurchaseFromCatalogAsGiftComposer,
PurchaseFromCatalogComposer: composerTypes.PurchaseFromCatalogComposer
}));
vi.mock('../../../../../api', () => ({
CatalogPurchaseState: { CONFIRM: 1, FAILED: 3, NONE: 0, PURCHASE: 2 },
DispatchUiEvent: vi.fn(),
GetConfigurationValue: vi.fn((_key: string, fallback: string) => fallback),
LocalizeText: (key: string, _names?: string[], values?: string[]) => `${key}${values?.length ? `:${values.join(',')}` : ''}`,
OpenUrl: vi.fn(),
SanitizeHtml: (value: string) => value,
SendMessageComposer: vi.fn(),
ShowVipBenefits: vi.fn()
}));
vi.mock('../../../../../common', () => ({
AutoGrid: ({ children, ...props }: any) => <div {...props}>{children}</div>,
Button: ({ children, classNames: _classNames, fullWidth: _fullWidth, variant: _variant, ...props }: any) => <button {...props}>{children}</button>,
Column: ({ children, ...props }: any) => <div {...props}>{children}</div>,
Flex: ({ alignItems: _alignItems, children, ...props }: any) => <div {...props}>{children}</div>,
Grid: ({ children, ...props }: any) => <div {...props}>{children}</div>,
LayoutCurrencyIcon: () => <span />,
LayoutLoadingSpinnerView: () => <span />,
OctaneCardContentView: ({ children, classNames = [], overflow: _overflow, ...props }: any) => (
<div className={classNames.join(' ')} {...props}>
{children}
</div>
),
OctaneCardHeaderView: ({ headerText, onCloseClick }: any) => (
<header>
<span>{headerText}</span>
<button aria-label="close" type="button" onClick={onCloseClick} />
</header>
),
OctaneCardView: ({ children, classNames = [], frameStyle, isResizable: _isResizable, theme: _theme, ...props }: any) => (
<div className={`${classNames.join(' ')} octane-card-frame-${frameStyle}`} {...props}>
{children}
</div>
),
Text: ({ children, ...props }: any) => <span {...props}>{children}</span>
}));
vi.mock('../../../../../events', () => ({
CatalogEvent: class {},
CatalogInitGiftEvent: class {
public constructor(
public pageId: number,
public offerId: number,
public extraData: string,
public receiverName: string
) {}
},
CatalogPurchasedEvent: { PURCHASE_SUCCESS: 'purchase-success' },
CatalogPurchaseFailureEvent: { PURCHASE_FAILED: 'purchase-failed' },
CatalogPurchaseNotAllowedEvent: { NOT_ALLOWED: 'purchase-not-allowed' },
CatalogPurchaseSoldOutEvent: { SOLD_OUT: 'purchase-sold-out' }
}));
vi.mock('../../../../../hooks', () => ({
useCatalogActions: vi.fn(),
useCatalogData: vi.fn(),
useCatalogSkipPurchaseConfirmation: vi.fn(),
useCatalogUiState: vi.fn(),
useClubOffers: vi.fn(),
useGiftConfiguration: vi.fn(),
useMessageEvent: vi.fn(),
useNotification: vi.fn(),
usePurse: vi.fn(),
useUiEvent: vi.fn(),
useUserDataSnapshot: () => ({ userName: 'Owner' })
}));
const makeOffer = (offerId: number, months: number, vip: boolean) => ({
day: 1,
extraDays: 0,
giftable: false,
month: 1,
months,
offerId,
priceActivityPoints: 0,
priceActivityPointsType: 0,
priceCredits: 10,
vip,
year: 2030
});
const renderLayout = (layoutCode: string) =>
render(
<CatalogLayoutVipBuyView
page={{ layoutCode, localization: { getImage: () => '', getText: () => '' }, offers: [], pageId: 50 } as any}
hideNavigation={() => undefined}
/>
);
afterEach(cleanup);
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(useCatalogData).mockImplementation(
() =>
({
currentPage: (screen.queryByTestId('unused') as any) ?? null
}) as any
);
vi.mocked(useClubOffers).mockReturnValue({ data: [makeOffer(1, 1, false), makeOffer(2, 2, true)] } as any);
vi.mocked(useCatalogActions).mockReturnValue({ resetPlacedOfferData: vi.fn() } as any);
vi.mocked(useGiftConfiguration).mockReturnValue({ data: { isEnabled: true } } as any);
vi.mocked(useCatalogSkipPurchaseConfirmation).mockReturnValue([false] as any);
vi.mocked(useCatalogUiState).mockReturnValue({ giftReceiver: 'Gift Friend' } as any);
vi.mocked(useNotification).mockReturnValue({ showConfirm: vi.fn(), simpleAlert: vi.fn() } as any);
vi.mocked(usePurse).mockReturnValue({
getCurrencyAmount: () => 1000,
purse: { clubDays: 0, clubPeriods: 0, isVip: false }
} as any);
});
const setCurrentPage = (layoutCode: string) => {
vi.mocked(useCatalogData).mockReturnValue({
currentPage: { layoutCode, localization: { getImage: () => '', getText: () => '' }, offers: [], pageId: 50 }
} as any);
};
describe('club purchase layout', () => {
it('asks each club page for its own offer window', () => {
for (const [layoutCode, windowId] of [['club_buy', 0], ['vip_buy', 1], ['loyalty_vip_buy', 6]] as const) {
setCurrentPage(layoutCode);
renderLayout(layoutCode);
expect(vi.mocked(useClubOffers)).toHaveBeenLastCalledWith(windowId);
cleanup();
}
});
it('renders only VIP offers on the VIP page', () => {
setCurrentPage('vip_buy');
renderLayout('vip_buy');
expect(screen.queryByText('catalog.vip.item.header.months:1')).not.toBeInTheDocument();
expect(screen.getByText('catalog.vip.item.header.months:2')).toBeInTheDocument();
expect(document.querySelector('.octane-club-vip-intro')).toBeInTheDocument();
expect(document.querySelector('.octane-club-vip-offers')).toBeInTheDocument();
expect(document.querySelector('.octane-club-columns')).not.toBeInTheDocument();
expect(document.querySelector('.is-vip-page .octane-club-vip-medium-mark')).toBeInTheDocument();
expect(document.querySelector('.is-vip-page .octane-club-compact-mark')).not.toBeInTheDocument();
});
it('renders the loyalty vip page as the VIP purchase page', () => {
setCurrentPage('loyalty_vip_buy');
renderLayout('loyalty_vip_buy');
expect(screen.queryByText('catalog.vip.item.header.months:1')).not.toBeInTheDocument();
expect(screen.getByText('catalog.vip.item.header.months:2')).toBeInTheDocument();
expect(document.querySelector('.is-vip-page .octane-club-vip-offers')).toBeInTheDocument();
expect(document.querySelector('.octane-club-columns')).not.toBeInTheDocument();
});
it('links the loyalty vip page to the VIP benefits window like AIR, and the vip page to the HC Center', async () => {
const { ShowVipBenefits } = await import('../../../../../api');
setCurrentPage('loyalty_vip_buy');
const view = renderLayout('loyalty_vip_buy');
fireEvent.click(screen.getByRole('button', { name: 'catalog.vip.buy.link' }));
expect(ShowVipBenefits).toHaveBeenCalledTimes(1);
expect(document.querySelector('.octane-club-center-link')).not.toBeInTheDocument();
view.unmount();
setCurrentPage('vip_buy');
renderLayout('vip_buy');
expect(screen.queryByRole('button', { name: 'catalog.vip.buy.link' })).not.toBeInTheDocument();
expect(document.querySelector('.octane-club-center-link')).toBeInTheDocument();
});
it('renders separate HC and VIP offer groups on the club page', () => {
setCurrentPage('club_buy');
renderLayout('club_buy');
expect(document.querySelector('.octane-club-columns')).toBeInTheDocument();
expect(document.querySelector('.octane-club-hc-column')).toBeInTheDocument();
expect(document.querySelector('.octane-club-vip-column')).toBeInTheDocument();
expect(screen.getByText('catalog.club.item.header:1')).toBeInTheDocument();
expect(screen.getByText('catalog.club.item.header:2')).toBeInTheDocument();
expect(screen.getAllByText('catalog.club.price:10')).toHaveLength(2);
expect(document.querySelector('.octane-club-offer.is-compact .octane-currency-icon')).not.toBeInTheDocument();
expect(document.querySelector('.octane-club-purchase-panel')).not.toBeInTheDocument();
});
it('renders safely while membership data is unavailable', () => {
setCurrentPage('club_buy');
vi.mocked(usePurse).mockReturnValue({ getCurrencyAmount: () => 0, purse: null } as any);
expect(() => renderLayout('club_buy')).not.toThrow();
expect(screen.getByText('catalog.club.buy.header.none')).toBeInTheDocument();
});
it('opens the club center through the existing plain-text link', () => {
setCurrentPage('club_buy');
renderLayout('club_buy');
fireEvent.click(screen.getByRole('button', { name: 'catalog.club.buy.link' }));
expect(CreateLinkEvent).toHaveBeenCalledWith('habboUI/open/hccenter');
});
it('submits an offer from its own buy button once', async () => {
setCurrentPage('club_buy');
vi.mocked(useCatalogSkipPurchaseConfirmation).mockReturnValue([true] as any);
renderLayout('club_buy');
const buyButton = (await screen.findAllByRole('button', { name: 'catalog.club.button.buy' }))[0];
fireEvent.click(buyButton);
fireEvent.click(buyButton);
await waitFor(() => expect(SendMessageComposer).toHaveBeenCalledTimes(1));
expect(vi.mocked(SendMessageComposer).mock.calls[0][0]).toBeInstanceOf(composerTypes.PurchaseFromCatalogComposer);
expect(vi.mocked(SendMessageComposer).mock.calls[0][0]).toMatchObject({ amount: 1, offerId: 1, pageId: 50 });
});
it('turns the purchase confirmation into gifting before opening the customizer', () => {
setCurrentPage('vip_buy');
vi.mocked(useClubOffers).mockReturnValue({ data: [{ ...makeOffer(2, 2, true), giftable: true }] } as any);
renderLayout('vip_buy');
fireEvent.click(screen.getByRole('button', { name: 'catalog.purchase_confirmation.gift' }));
expect(DispatchUiEvent).not.toHaveBeenCalled();
const dialog = screen.getByRole('dialog', { name: 'catalog.club.buy.confirm' });
fireEvent.click(within(dialog).getByRole('button', { name: 'catalog.club.buy.subscribe' }));
expect(DispatchUiEvent).toHaveBeenCalledWith(expect.objectContaining({ extraData: '', offerId: 2, pageId: 50, receiverName: 'Gift Friend' }));
});
});
