5180 fichiers 38.5 Mo 0 téléchargements 234 vues mis à jour il y a 5 heures ui
nitro-v36-with-renderer-v36 / src / hooks / catalog / useCatalogQueries.test.ts
useCatalogQueries.test.ts 7.9 Ko Télécharger le fichier
/* @vitest-environment jsdom */
import { QueryClient } from '@tanstack/react-query';
import { describe, expect, it } from 'vitest';
import { CatalogPage, CatalogType, Offer, PageLocalization } from '../../api';
import {
    bindCatalogQueryClient,
    buildPurchasableOffer,
    catalogIndexKey,
    catalogPageKey,
    cloneCachedCatalogPages,
    dropCatalogCache,
    invalidateAllCatalogIndexes,
    invalidateCatalogIndex,
    invalidateCatalogPage,
    isOfferAllowedInCatalogType,
    readCatalogIndex,
    selectCatalogIndex,
    selectCatalogPage
} from './useCatalogQueries';

const productData = { id: 1, name: 'chair' } as any;
const furnitureData = { className: 'chair', id: 10 } as any;
const lookups = {
    getProductData: () => productData,
    getFurnitureData: () => furnitureData
};

const parserProduct = (overrides: Partial<Record<string, unknown>> = {}) => ({
    productType: 's',
    furniClassId: 10,
    extraParam: '',
    productCount: 1,
    uniqueLimitedItem: false,
    uniqueLimitedSeriesSize: 0,
    uniqueLimitedItemsLeft: 0,
    ...overrides
});

const parserOffer = (offerId: number, products = [parserProduct()], overrides: Partial<Record<string, unknown>> = {}) => ({
    offerId,
    localizationId: `offer_${offerId}`,
    rent: false,
    priceCredits: 3,
    priceActivityPoints: 0,
    priceActivityPointsType: 0,
    giftable: true,
    clubLevel: 0,
    products,
    bundlePurchaseAllowed: false,
    itemIds: '',
    haveOffer: false,
    ...overrides
});

const parserNode = (pageId: number, children: any[] = [], offerIds: number[] = []) => ({
    visible: true,
    icon: 0,
    pageId,
    parentId: -1,
    pageName: `page_${pageId}`,
    localization: `Page ${pageId}`,
    children,
    offerIds
});

describe('catalog query keys', () => {
    it('scope the index and the pages under the same root', () => {
        expect(catalogIndexKey(CatalogType.NORMAL)).toEqual(['octane', 'catalog', 'index', 'NORMAL']);
        expect(catalogPageKey(CatalogType.BUILDER, 7)).toEqual(['octane', 'catalog', 'page', CatalogType.BUILDER, 7]);
    });
});

describe('buildPurchasableOffer', () => {
    it('builds an Offer with one Product per parser product', () => {
        const offer = buildPurchasableOffer(parserOffer(5, [parserProduct(), parserProduct({ furniClassId: 11 })]), lookups);

        expect(offer).toBeInstanceOf(Offer);
        expect(offer.offerId).toBe(5);
        expect(offer.products).toHaveLength(2);
        expect(offer.product.furnitureData).toBe(furnitureData);
    });

    it('returns null when the parser offer carries no products', () => {
        expect(buildPurchasableOffer(parserOffer(5, []), lookups)).toBeNull();
    });
});

describe('isOfferAllowedInCatalogType', () => {
    it('keeps every offer in the normal catalog and drops bundles in the builder catalog', () => {
        const bundle = buildPurchasableOffer(parserOffer(1, [parserProduct(), parserProduct({ furniClassId: 11 })]), lookups);
        const single = buildPurchasableOffer(parserOffer(2), lookups);

        expect(isOfferAllowedInCatalogType(bundle, CatalogType.NORMAL)).toBe(true);
        expect(isOfferAllowedInCatalogType(bundle, CatalogType.BUILDER)).toBe(false);
        expect(isOfferAllowedInCatalogType(single, CatalogType.BUILDER)).toBe(true);
    });
});

describe('selectCatalogIndex', () => {
    it('returns the built tree and the offer index', () => {
        const root = parserNode(-1, [parserNode(1, [], [100, 101]), parserNode(2, [], [101])]);
        const index = selectCatalogIndex({ root } as any);

        expect(index.rootNode.children).toHaveLength(2);
        expect(index.offersToNodes.get(101)).toHaveLength(2);
    });
});

describe('selectCatalogPage', () => {
    const parserPage = (overrides: Partial<Record<string, unknown>> = {}) => ({
        pageId: 3,
        catalogType: CatalogType.NORMAL,
        layoutCode: 'default_3x3',
        localization: { images: ['a.png'], texts: ['Hello'] },
        offers: [parserOffer(1), parserOffer(2, [])],
        offerId: 2,
        acceptSeasonCurrencyAsCredits: true,
        frontPageItems: [],
        ...overrides
    });

    it('builds the page, skipping parser offers without products', () => {
        const data = selectCatalogPage(parserPage() as any, CatalogType.NORMAL, lookups);

        expect(data.page).toBeInstanceOf(CatalogPage);
        expect(data.page.pageId).toBe(3);
        expect(data.page.layoutCode).toBe('default_3x3');
        expect(data.page.offers.map((offer) => offer.offerId)).toEqual([1]);
        expect(data.page.acceptSeasonCurrencyAsCredits).toBe(true);
        expect(data.page.localization.getText(0)).toBe('Hello');
        expect(data.offerId).toBe(2);
    });

    it('applies the builder pricing-model filter', () => {
        const bundle = parserOffer(9, [parserProduct(), parserProduct({ furniClassId: 11 })]);
        const data = selectCatalogPage(parserPage({ offers: [bundle, parserOffer(1)] }) as any, CatalogType.BUILDER, lookups);

        expect(data.page.offers.map((offer) => offer.offerId)).toEqual([1]);
    });

    it('passes the front page items through', () => {
        const items = [{ type: 1 }] as any;
        const data = selectCatalogPage(parserPage({ frontPageItems: items }) as any, CatalogType.NORMAL, lookups);

        expect(data.frontPageItems).toBe(items);
    });
});

describe('cache helpers', () => {
    it('read, invalidate and drop through the bound client', () => {
        const client = new QueryClient();
        bindCatalogQueryClient(client);

        const index = { rootNode: {} as any, offersToNodes: new Map() };
        client.setQueryData(catalogIndexKey(CatalogType.NORMAL), index);
        client.setQueryData(catalogPageKey(CatalogType.NORMAL, 3), { page: null, frontPageItems: [], offerId: -1 });

        expect(readCatalogIndex(CatalogType.NORMAL)).toBe(index);

        invalidateCatalogIndex(CatalogType.NORMAL);
        expect(client.getQueryState(catalogIndexKey(CatalogType.NORMAL)).isInvalidated).toBe(true);

        invalidateCatalogPage(CatalogType.NORMAL, 3);
        expect(client.getQueryState(catalogPageKey(CatalogType.NORMAL, 3)).isInvalidated).toBe(true);

        // A publish invalidates the index of every catalog type, not only the one open.
        client.setQueryData(catalogIndexKey(CatalogType.NORMAL), index);
        client.setQueryData(catalogIndexKey(CatalogType.BUILDER), index);
        invalidateAllCatalogIndexes();
        expect(client.getQueryState(catalogIndexKey(CatalogType.NORMAL)).isInvalidated).toBe(true);
        expect(client.getQueryState(catalogIndexKey(CatalogType.BUILDER)).isInvalidated).toBe(true);
        expect(client.getQueryState(catalogPageKey(CatalogType.NORMAL, 3)).isInvalidated).toBe(true);

        dropCatalogCache();
        expect(readCatalogIndex(CatalogType.NORMAL)).toBeUndefined();
        expect(client.getQueryData(catalogPageKey(CatalogType.NORMAL, 3))).toBeUndefined();

        bindCatalogQueryClient(null);
    });

    it('cloneCachedCatalogPages rebuilds every cached page with cloned offers', () => {
        const client = new QueryClient();
        bindCatalogQueryClient(client);

        const offer = buildPurchasableOffer(parserOffer(1), lookups);
        const page = new CatalogPage(3, 'default_3x3', new PageLocalization([], []), [offer], false);
        client.setQueryData(catalogPageKey(CatalogType.NORMAL, 3), { page, frontPageItems: [], offerId: -1 });

        cloneCachedCatalogPages();

        const after = client.getQueryData<{ page: CatalogPage }>(catalogPageKey(CatalogType.NORMAL, 3));
        expect(after.page).not.toBe(page);
        expect(after.page.offers[0]).not.toBe(offer);
        expect(after.page.offers[0].offerId).toBe(1);

        bindCatalogQueryClient(null);
    });

    it('helpers are no-ops when no client is bound', () => {
        bindCatalogQueryClient(null);
        expect(() => invalidateCatalogIndex(CatalogType.NORMAL)).not.toThrow();
        expect(readCatalogIndex(CatalogType.NORMAL)).toBeUndefined();
    });
});
15Sujets
1Dépôts
20Membres
2En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser