/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { mergeConfig, OrderService } from '@vendure/core'; import { createErrorResultGuard, createTestEnvironment, ErrorResultGuard } from '@vendure/testing'; import { multivendorPaymentMethodHandler } from 'dev-server/example-plugins/multivendor-plugin/config/mv-payment-handler'; import { CONNECTED_PAYMENT_METHOD_CODE } from 'dev-server/example-plugins/multivendor-plugin/constants'; import { MultivendorPlugin } from 'dev-server/example-plugins/multivendor-plugin/multivendor.plugin'; import gql from 'graphql-tag'; import path from 'path'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { initialData } from '../../../e2e-common/e2e-initial-data'; import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config'; import { AssignProductsToChannelDocument, GetOrderWithSellerOrdersDocument, } from './graphql/generated-e2e-admin-types'; import * as CodegenShop from './graphql/generated-e2e-shop-types'; import { SetShippingMethodDocument } from './graphql/generated-e2e-shop-types'; import { ADD_ITEM_TO_ORDER, ADD_PAYMENT, GET_ELIGIBLE_SHIPPING_METHODS, SET_SHIPPING_ADDRESS, TRANSITION_TO_STATE, } from './graphql/shop-definitions'; declare module '@vendure/core/dist/entity/custom-entity-fields' { interface CustomShippingMethodFields { minPrice: number; maxPrice: number; } } describe('Multi-vendor orders', () => { const { server, adminClient, shopClient } = createTestEnvironment( mergeConfig(testConfig(), { plugins: [ MultivendorPlugin.init({ platformFeePercent: 10, platformFeeSKU: 'FEE', }), ], }), ); let bobsPartsChannel: { id: string; token: string; variantIds: string[] }; let alicesWaresChannel: { id: string; token: string; variantIds: string[] }; let orderId: string; type OrderSuccessResult = | CodegenShop.UpdatedOrderFragment | CodegenShop.TestOrderFragmentFragment | CodegenShop.TestOrderWithPaymentsFragment | CodegenShop.ActiveOrderCustomerFragment; const orderResultGuard: ErrorResultGuard = createErrorResultGuard( input => !!input.lines, ); beforeAll(async () => { await server.init({ initialData, productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'), customerCount: 3, }); await adminClient.asSuperAdmin(); }, TEST_SETUP_TIMEOUT_MS); afterAll(async () => { await server.destroy(); }); it('setup sellers', async () => { const result1 = await shopClient.query(REGISTER_SELLER, { input: { shopName: "Bob's Parts", seller: { firstName: 'Bob', lastName: 'Dobalina', emailAddress: 'bob@bobs-parts.com', password: 'test', }, }, }); bobsPartsChannel = result1.registerNewSeller; expect(bobsPartsChannel.token).toBe('bobs-parts-token'); const result2 = await shopClient.query(REGISTER_SELLER, { input: { shopName: "Alice's Wares", seller: { firstName: 'Alice', lastName: 'Smith', emailAddress: 'alice@alices-wares.com', password: 'test', }, }, }); alicesWaresChannel = result2.registerNewSeller; expect(alicesWaresChannel.token).toBe('alices-wares-token'); }); it('assign products to sellers', async () => { const { assignProductsToChannel } = await adminClient.query(AssignProductsToChannelDocument, { input: { channelId: bobsPartsChannel.id, productIds: ['T_1'], priceFactor: 1, }, }); expect(assignProductsToChannel[0].channels.map(c => c.code)).toEqual([ '__default_channel__', 'bobs-parts', ]); bobsPartsChannel.variantIds = assignProductsToChannel[0].variants.map(v => v.id); expect(bobsPartsChannel.variantIds).toEqual(['T_1', 'T_2', 'T_3', 'T_4']); const { assignProductsToChannel: result2 } = await adminClient.query( AssignProductsToChannelDocument, { input: { channelId: alicesWaresChannel.id, productIds: ['T_11'], priceFactor: 1, }, }, ); expect(result2[0].channels.map(c => c.code)).toEqual(['__default_channel__', 'alices-wares']); alicesWaresChannel.variantIds = result2[0].variants.map(v => v.id); expect(alicesWaresChannel.variantIds).toEqual(['T_22']); }); it('adds items and sets shipping methods', async () => { await shopClient.asUserWithCredentials('hayden.zieme12@hotmail.com', 'test'); await shopClient.query< CodegenShop.AddItemToOrderMutation, CodegenShop.AddItemToOrderMutationVariables >(ADD_ITEM_TO_ORDER, { productVariantId: bobsPartsChannel.variantIds[0], quantity: 1, }); await shopClient.query< CodegenShop.AddItemToOrderMutation, CodegenShop.AddItemToOrderMutationVariables >(ADD_ITEM_TO_ORDER, { productVariantId: alicesWaresChannel.variantIds[0], quantity: 1, }); await shopClient.query< CodegenShop.SetShippingAddressMutation, CodegenShop.SetShippingAddressMutationVariables >(SET_SHIPPING_ADDRESS, { input: { streetLine1: '12 the street', postalCode: '123456', countryCode: 'US', }, }); const { eligibleShippingMethods } = await shopClient.query( GET_ELIGIBLE_SHIPPING_METHODS, ); expect(eligibleShippingMethods.map(m => m.code).sort()).toEqual([ 'alices-wares-shipping', 'bobs-parts-shipping', 'express-shipping', 'standard-shipping', ]); const { setOrderShippingMethod } = await shopClient.query(SetShippingMethodDocument, { id: [ eligibleShippingMethods.find(m => m.code === 'bobs-parts-shipping')!.id, eligibleShippingMethods.find(m => m.code === 'alices-wares-shipping')!.id, ], }); orderResultGuard.assertSuccess(setOrderShippingMethod); expect(setOrderShippingMethod.shippingLines.map(l => l.shippingMethod.code).sort()).toEqual([ 'alices-wares-shipping', 'bobs-parts-shipping', ]); }); it('completing checkout splits order', async () => { const { transitionOrderToState } = await shopClient.query< CodegenShop.TransitionToStateMutation, CodegenShop.TransitionToStateMutationVariables >(TRANSITION_TO_STATE, { state: 'ArrangingPayment' }); orderResultGuard.assertSuccess(transitionOrderToState); const { addPaymentToOrder } = await shopClient.query< CodegenShop.AddPaymentToOrderMutation, CodegenShop.AddPaymentToOrderMutationVariables >(ADD_PAYMENT, { input: { method: CONNECTED_PAYMENT_METHOD_CODE, metadata: {}, }, }); orderResultGuard.assertSuccess(addPaymentToOrder); expect(addPaymentToOrder.state).toBe('PaymentSettled'); const { order } = await adminClient.query(GetOrderWithSellerOrdersDocument, { id: addPaymentToOrder.id, }); orderId = order!.id; expect(order?.sellerOrders?.length).toBe(2); }); it('order lines get split', async () => { const { order } = await adminClient.query(GetOrderWithSellerOrdersDocument, { id: orderId, }); expect(order?.sellerOrders?.[0].lines.map(l => l.productVariant.name)).toEqual([ 'Laptop 13 inch 8GB', ]); expect(order?.sellerOrders?.[1].lines.map(l => l.productVariant.name)).toEqual(['Road Bike']); }); it('shippingLines get split', async () => { const { order } = await adminClient.query(GetOrderWithSellerOrdersDocument, { id: orderId, }); expect(order?.sellerOrders?.[0]?.shippingLines.length).toBe(1); expect(order?.sellerOrders?.[1]?.shippingLines.length).toBe(1); expect(order?.sellerOrders?.[0]?.shippingLines[0].shippingMethod.code).toBe('bobs-parts-shipping'); expect(order?.sellerOrders?.[1]?.shippingLines[0].shippingMethod.code).toBe('alices-wares-shipping'); }); }); export const REGISTER_SELLER = gql` mutation RegisterSeller($input: RegisterSellerInput!) { registerNewSeller(input: $input) { id code token } } `;