import { CreateFacet, CreateFacetValues, DeletionResult, FacetWithValues, GetFacetList, GetFacetWithValues, GetProductList, GetProductWithVariants, LanguageCode, UpdateFacet, UpdateFacetValues, UpdateProduct, UpdateProductVariants, } from '@vendure/common/lib/generated-types'; import gql from 'graphql-tag'; import path from 'path'; import { CREATE_FACET, CREATE_FACET_VALUES, GET_FACET_LIST, GET_FACET_WITH_VALUES, UPDATE_FACET, UPDATE_FACET_VALUES, } from '../../../admin-ui/src/app/data/definitions/facet-definitions'; import { GET_PRODUCT_LIST, GET_PRODUCT_WITH_VARIANTS, UPDATE_PRODUCT, UPDATE_PRODUCT_VARIANTS, } from '../../../admin-ui/src/app/data/definitions/product-definitions'; import { TEST_SETUP_TIMEOUT_MS } from './config/test-config'; import { TestAdminClient } from './test-client'; import { TestServer } from './test-server'; // tslint:disable:no-non-null-assertion describe('Facet resolver', () => { const client = new TestAdminClient(); const server = new TestServer(); let brandFacet: FacetWithValues.Fragment; let speakerTypeFacet: FacetWithValues.Fragment; beforeAll(async () => { await server.init({ productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'), customerCount: 1, }); await client.init(); }, TEST_SETUP_TIMEOUT_MS); afterAll(async () => { await server.destroy(); }); it('createFacet', async () => { const result = await client.query(CREATE_FACET, { input: { code: 'speaker-type', translations: [{ languageCode: LanguageCode.en, name: 'Speaker Type' }], values: [ { code: 'portable', translations: [{ languageCode: LanguageCode.en, name: 'Portable' }], }, ], }, }); speakerTypeFacet = result.createFacet; expect(speakerTypeFacet).toMatchSnapshot(); }); it('updateFacet', async () => { const result = await client.query(UPDATE_FACET, { input: { id: speakerTypeFacet.id, translations: [{ languageCode: LanguageCode.en, name: 'Speaker Category' }], }, }); expect(result.updateFacet.name).toBe('Speaker Category'); }); it('createFacetValues', async () => { const result = await client.query( CREATE_FACET_VALUES, { input: [ { facetId: speakerTypeFacet.id, code: 'pc', translations: [{ languageCode: LanguageCode.en, name: 'PC Speakers' }], }, { facetId: speakerTypeFacet.id, code: 'hi-fi', translations: [{ languageCode: LanguageCode.en, name: 'Hi Fi Speakers' }], }, ], }, ); expect(result.createFacetValues).toMatchSnapshot(); }); it('updateFacetValues', async () => { const result = await client.query( UPDATE_FACET_VALUES, { input: [ { id: speakerTypeFacet.values[0].id, code: 'compact', }, ], }, ); expect(result.updateFacetValues[0].code).toBe('compact'); }); it('facets', async () => { const result = await client.query(GET_FACET_LIST); const { items } = result.facets; expect(items.length).toBe(2); expect(items[0].name).toBe('category'); expect(items[1].name).toBe('Speaker Category'); brandFacet = items[0]; speakerTypeFacet = items[1]; }); it('facet', async () => { const result = await client.query( GET_FACET_WITH_VALUES, { id: speakerTypeFacet.id, }, ); expect(result.facet!.name).toBe('Speaker Category'); }); describe('deletion', () => { let products: Array }>; beforeAll(async () => { // add the FacetValues to products and variants const result1 = await client.query(GET_PRODUCTS_LIST_WITH_VARIANTS); products = result1.products.items; await client.query(UPDATE_PRODUCT, { input: { id: products[0].id, facetValueIds: [speakerTypeFacet.values[0].id], }, }); await client.query( UPDATE_PRODUCT_VARIANTS, { input: [ { id: products[0].variants[0].id, facetValueIds: [speakerTypeFacet.values[0].id], }, ], }, ); await client.query(UPDATE_PRODUCT, { input: { id: products[1].id, facetValueIds: [speakerTypeFacet.values[1].id], }, }); }); it('deleteFacetValues deletes unused facetValue', async () => { const facetValueToDelete = speakerTypeFacet.values[2]; const result1 = await client.query(DELETE_FACET_VALUES, { ids: [facetValueToDelete.id], force: false, }); const result2 = await client.query( GET_FACET_WITH_VALUES, { id: speakerTypeFacet.id, }, ); expect(result1.deleteFacetValues).toEqual([ { result: DeletionResult.DELETED, message: ``, }, ]); expect(result2.facet!.values[0]).not.toEqual(facetValueToDelete); }); it('deleteFacetValues for FacetValue in use returns NOT_DELETED', async () => { const facetValueToDelete = speakerTypeFacet.values[0]; const result1 = await client.query(DELETE_FACET_VALUES, { ids: [facetValueToDelete.id], force: false, }); const result2 = await client.query( GET_FACET_WITH_VALUES, { id: speakerTypeFacet.id, }, ); expect(result1.deleteFacetValues).toEqual([ { result: DeletionResult.NOT_DELETED, message: `The selected FacetValue is assigned to 1 Product, 1 ProductVariant`, }, ]); expect(result2.facet!.values[0]).toEqual(facetValueToDelete); }); it('deleteFacetValues for FacetValue in use can be force deleted', async () => { const facetValueToDelete = speakerTypeFacet.values[0]; const result1 = await client.query(DELETE_FACET_VALUES, { ids: [facetValueToDelete.id], force: true, }); expect(result1.deleteFacetValues).toEqual([ { result: DeletionResult.DELETED, message: `The selected FacetValue was removed from 1 Product, 1 ProductVariant and deleted`, }, ]); // FacetValue no longer in the Facet.values array const result2 = await client.query( GET_FACET_WITH_VALUES, { id: speakerTypeFacet.id, }, ); expect(result2.facet!.values[0]).not.toEqual(facetValueToDelete); // FacetValue no longer in the Product.facetValues array const result3 = await client.query< GetProductWithVariants.Query, GetProductWithVariants.Variables >(GET_PRODUCT_WITH_VARIANTS, { id: products[0].id, }); expect(result3.product!.facetValues).toEqual([]); }); it('deleteFacet that is in use returns NOT_DELETED', async () => { const result1 = await client.query(DELETE_FACET, { id: speakerTypeFacet.id, force: false }); const result2 = await client.query( GET_FACET_WITH_VALUES, { id: speakerTypeFacet.id, }, ); expect(result1.deleteFacet).toEqual({ result: DeletionResult.NOT_DELETED, message: `The selected Facet includes FacetValues which are assigned to 1 Product`, }); expect(result2.facet).not.toBe(null); }); it('deleteFacet that is in use can be force deleted', async () => { const result1 = await client.query(DELETE_FACET, { id: speakerTypeFacet.id, force: true }); expect(result1.deleteFacet).toEqual({ result: DeletionResult.DELETED, message: `The Facet was deleted and its FacetValues were removed from 1 Product`, }); // FacetValue no longer in the Facet.values array const result2 = await client.query( GET_FACET_WITH_VALUES, { id: speakerTypeFacet.id, }, ); expect(result2.facet).toBe(null); // FacetValue no longer in the Product.facetValues array const result3 = await client.query< GetProductWithVariants.Query, GetProductWithVariants.Variables >(GET_PRODUCT_WITH_VARIANTS, { id: products[1].id, }); expect(result3.product!.facetValues).toEqual([]); }); }); }); const DELETE_FACET_VALUES = gql` mutation DeleteFacetValue($ids: [ID!]!, $force: Boolean) { deleteFacetValues(ids: $ids, force: $force) { result message } } `; const DELETE_FACET = gql` mutation DeleteFacet($id: ID!, $force: Boolean) { deleteFacet(id: $id, force: $force) { result message } } `; const GET_PRODUCTS_LIST_WITH_VARIANTS = gql` query GetProductListWithVariants { products { items { id name variants { id name } } totalItems } } `;