| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- import { mergeConfig } from '@vendure/core';
- import {
- createErrorResultGuard,
- createTestEnvironment,
- E2E_DEFAULT_CHANNEL_TOKEN,
- ErrorResultGuard,
- } from '@vendure/testing';
- 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 { testSuccessfulPaymentMethod } from './fixtures/test-payment-methods';
- import * as Codegen from './graphql/generated-e2e-admin-types';
- import {
- AssignProductsToChannelDocument,
- CurrencyCode,
- DeletionResult,
- LanguageCode,
- SortOrder,
- TestAssignStockLocationToChannelDocument,
- TestCreateStockLocationDocument,
- TestDeleteStockLocationDocument,
- TestGetStockLevelsForVariantDocument,
- TestGetStockLocationsListDocument,
- TestRemoveStockLocationsFromChannelDocument,
- TestSetStockLevelInLocationDocument,
- TestUpdateStockLocationDocument,
- } from './graphql/generated-e2e-admin-types';
- import * as CodegenShop from './graphql/generated-e2e-shop-types';
- import { CREATE_CHANNEL } from './graphql/shared-definitions';
- describe('Stock location', () => {
- const defaultStockLocationId = 'T_1';
- let secondStockLocationId: string;
- const { server, adminClient, shopClient } = createTestEnvironment(
- mergeConfig(testConfig(), {
- paymentOptions: {
- paymentMethodHandlers: [testSuccessfulPaymentMethod],
- },
- }),
- );
- const orderGuard: ErrorResultGuard<
- CodegenShop.TestOrderFragmentFragment | CodegenShop.UpdatedOrderFragment
- > = createErrorResultGuard(input => !!input.lines);
- beforeAll(async () => {
- await server.init({
- initialData,
- productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-stock-control-multi.csv'),
- customerCount: 3,
- });
- await adminClient.asSuperAdmin();
- }, TEST_SETUP_TIMEOUT_MS);
- afterAll(async () => {
- await server.destroy();
- });
- it('createStockLocation', async () => {
- const { createStockLocation } = await adminClient.query(TestCreateStockLocationDocument, {
- input: {
- name: 'Second location',
- description: 'Second location description',
- },
- });
- expect(createStockLocation.name).toBe('Second location');
- expect(createStockLocation.description).toBe('Second location description');
- secondStockLocationId = createStockLocation.id;
- });
- it('updateStockLocation', async () => {
- const { updateStockLocation } = await adminClient.query(TestUpdateStockLocationDocument, {
- input: {
- id: secondStockLocationId,
- name: 'Second location updated',
- description: 'Second location description updated',
- },
- });
- expect(updateStockLocation.name).toBe('Second location updated');
- expect(updateStockLocation.description).toBe('Second location description updated');
- });
- it('get stock locations list', async () => {
- const { stockLocations } = await adminClient.query(TestGetStockLocationsListDocument, {
- options: {
- sort: {
- id: SortOrder.ASC,
- },
- },
- });
- expect(stockLocations.items.length).toBe(2);
- expect(stockLocations.items[0].name).toBe('Default Stock Location');
- expect(stockLocations.items[1].name).toBe('Second location updated');
- });
- it('assign stock to second location', async () => {
- const { updateProductVariants } = await adminClient.query(TestSetStockLevelInLocationDocument, {
- input: {
- id: 'T_1',
- stockLevels: [
- {
- stockLocationId: secondStockLocationId,
- stockOnHand: 50,
- },
- ],
- },
- });
- expect(
- updateProductVariants[0]?.stockLevels.find(sl => sl.stockLocationId === defaultStockLocationId),
- ).toEqual({
- stockOnHand: 100,
- stockAllocated: 0,
- stockLocationId: defaultStockLocationId,
- });
- expect(
- updateProductVariants[0]?.stockLevels.find(sl => sl.stockLocationId === secondStockLocationId),
- ).toEqual({
- stockOnHand: 50,
- stockAllocated: 0,
- stockLocationId: secondStockLocationId,
- });
- });
- it('delete second stock location and assign stock to default location', async () => {
- const { deleteStockLocation } = await adminClient.query(TestDeleteStockLocationDocument, {
- input: {
- id: secondStockLocationId,
- transferToLocationId: defaultStockLocationId,
- },
- });
- expect(deleteStockLocation.result).toBe(DeletionResult.DELETED);
- const { productVariant } = await adminClient.query(TestGetStockLevelsForVariantDocument, {
- id: 'T_1',
- });
- expect(productVariant?.stockLevels.length).toBe(1);
- expect(productVariant?.stockLevels[0]).toEqual({
- stockOnHand: 150,
- stockAllocated: 0,
- stockLocationId: defaultStockLocationId,
- });
- });
- it('cannot delete last remaining stock location', async () => {
- const { deleteStockLocation } = await adminClient.query(TestDeleteStockLocationDocument, {
- input: {
- id: defaultStockLocationId,
- },
- });
- expect(deleteStockLocation.result).toBe(DeletionResult.NOT_DELETED);
- expect(deleteStockLocation.message).toBe('The last remaining StockLocation cannot be deleted');
- const { stockLocations } = await adminClient.query(TestGetStockLocationsListDocument);
- expect(stockLocations.items.length).toBe(1);
- });
- describe('multi channel', () => {
- const SECOND_CHANNEL_TOKEN = 'second_channel_token';
- let channelStockLocationId: string;
- let secondChannelId: string;
- const channelGuard: ErrorResultGuard<Codegen.ChannelFragment> =
- createErrorResultGuard<Codegen.ChannelFragment>(input => !!input.defaultLanguageCode);
- beforeAll(async () => {
- const { createStockLocation } = await adminClient.query(TestCreateStockLocationDocument, {
- input: {
- name: 'Channel location',
- },
- });
- channelStockLocationId = createStockLocation.id;
- const { createChannel } = await adminClient.query<
- Codegen.CreateChannelMutation,
- Codegen.CreateChannelMutationVariables
- >(CREATE_CHANNEL, {
- input: {
- code: 'second-channel',
- token: SECOND_CHANNEL_TOKEN,
- defaultLanguageCode: LanguageCode.en,
- currencyCode: CurrencyCode.GBP,
- pricesIncludeTax: true,
- defaultShippingZoneId: 'T_1',
- defaultTaxZoneId: 'T_1',
- },
- });
- channelGuard.assertSuccess(createChannel);
- secondChannelId = createChannel.id;
- await adminClient.query(AssignProductsToChannelDocument, {
- input: {
- channelId: secondChannelId,
- productIds: ['T_1'],
- },
- });
- });
- it('stock location not visible in channel before being assigned', async () => {
- adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
- const { stockLocations } = await adminClient.query(TestGetStockLocationsListDocument);
- expect(stockLocations.items.length).toBe(0);
- });
- it('assign stock location to channel', async () => {
- adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
- const { assignStockLocationsToChannel } = await adminClient.query(
- TestAssignStockLocationToChannelDocument,
- {
- input: {
- stockLocationIds: [channelStockLocationId],
- channelId: secondChannelId,
- },
- },
- );
- expect(assignStockLocationsToChannel.length).toBe(1);
- expect(assignStockLocationsToChannel[0].name).toBe('Channel location');
- });
- it('stock location visible in channel once assigned', async () => {
- adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
- const { stockLocations } = await adminClient.query(TestGetStockLocationsListDocument);
- expect(stockLocations.items.length).toBe(1);
- expect(stockLocations.items[0].name).toBe('Channel location');
- });
- it('assign stock to location in channel', async () => {
- adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
- const { updateProductVariants } = await adminClient.query(TestSetStockLevelInLocationDocument, {
- input: {
- id: 'T_1',
- stockLevels: [
- {
- stockLocationId: channelStockLocationId,
- stockOnHand: 10,
- },
- ],
- },
- });
- });
- it('assigned variant stock level visible in channel', async () => {
- adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
- const { productVariant } = await adminClient.query(TestGetStockLevelsForVariantDocument, {
- id: 'T_1',
- });
- expect(productVariant?.stockLevels.length).toBe(1);
- expect(productVariant?.stockLevels[0]).toEqual({
- stockOnHand: 10,
- stockAllocated: 0,
- stockLocationId: channelStockLocationId,
- });
- });
- it('remove stock location from channel', async () => {
- adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
- const { removeStockLocationsFromChannel } = await adminClient.query(
- TestRemoveStockLocationsFromChannelDocument,
- {
- input: {
- stockLocationIds: [channelStockLocationId],
- channelId: secondChannelId,
- },
- },
- );
- expect(removeStockLocationsFromChannel.length).toBe(1);
- expect(removeStockLocationsFromChannel[0].name).toBe('Channel location');
- });
- it('variant stock level no longer visible once removed from channel', async () => {
- adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
- const { productVariant } = await adminClient.query(TestGetStockLevelsForVariantDocument, {
- id: 'T_1',
- });
- expect(productVariant?.stockLevels.length).toBe(0);
- });
- });
- });
- const GET_STOCK_LOCATIONS_LIST = gql`
- query TestGetStockLocationsList($options: StockLocationListOptions) {
- stockLocations(options: $options) {
- items {
- id
- name
- description
- }
- totalItems
- }
- }
- `;
- const GET_STOCK_LOCATION = gql`
- query TestGetStockLocation($id: ID!) {
- stockLocation(id: $id) {
- id
- name
- description
- }
- }
- `;
- const CREATE_STOCK_LOCATION = gql`
- mutation TestCreateStockLocation($input: CreateStockLocationInput!) {
- createStockLocation(input: $input) {
- id
- name
- description
- }
- }
- `;
- const UPDATE_STOCK_LOCATION = gql`
- mutation TestUpdateStockLocation($input: UpdateStockLocationInput!) {
- updateStockLocation(input: $input) {
- id
- name
- description
- }
- }
- `;
- const DELETE_STOCK_LOCATION = gql`
- mutation TestDeleteStockLocation($input: DeleteStockLocationInput!) {
- deleteStockLocation(input: $input) {
- result
- message
- }
- }
- `;
- const GET_STOCK_LEVELS_FOR_VARIANT = gql`
- query TestGetStockLevelsForVariant($id: ID!) {
- productVariant(id: $id) {
- id
- stockLevels {
- stockOnHand
- stockAllocated
- stockLocationId
- }
- }
- }
- `;
- const SET_STOCK_LEVEL_IN_LOCATION = gql`
- mutation TestSetStockLevelInLocation($input: UpdateProductVariantInput!) {
- updateProductVariants(input: [$input]) {
- id
- stockLevels {
- stockOnHand
- stockAllocated
- stockLocationId
- }
- }
- }
- `;
- const ASSIGN_STOCK_LOCATION_TO_CHANNEL = gql`
- mutation TestAssignStockLocationToChannel($input: AssignStockLocationsToChannelInput!) {
- assignStockLocationsToChannel(input: $input) {
- id
- name
- }
- }
- `;
- const REMOVE_STOCK_LOCATIONS_FROM_CHANNEL = gql`
- mutation TestRemoveStockLocationsFromChannel($input: RemoveStockLocationsFromChannelInput!) {
- removeStockLocationsFromChannel(input: $input) {
- id
- name
- }
- }
- `;
|