/* tslint:disable:no-non-null-assertion */ import { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants'; import { createErrorResultGuard, createTestEnvironment, E2E_DEFAULT_CHANNEL_TOKEN, ErrorResultGuard, } from '@vendure/testing'; import gql from 'graphql-tag'; import path from 'path'; import { initialData } from '../../../e2e-common/e2e-initial-data'; import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config'; import { AssignProductsToChannel, ChannelFragment, CreateAdministrator, CreateChannel, CreateRole, CurrencyCode, DeleteChannel, DeletionResult, ErrorCode, GetChannels, GetCustomerList, GetProductWithVariants, LanguageCode, Me, Permission, UpdateChannel, UpdateGlobalLanguages, } from './graphql/generated-e2e-admin-types'; import { ASSIGN_PRODUCT_TO_CHANNEL, CREATE_ADMINISTRATOR, CREATE_CHANNEL, CREATE_ROLE, GET_CHANNELS, GET_CUSTOMER_LIST, GET_PRODUCT_WITH_VARIANTS, ME, UPDATE_CHANNEL, } from './graphql/shared-definitions'; import { GET_ACTIVE_ORDER } from './graphql/shop-definitions'; import { assertThrowsWithMessage } from './utils/assert-throws-with-message'; describe('Channels', () => { const { server, adminClient, shopClient } = createTestEnvironment(testConfig()); const SECOND_CHANNEL_TOKEN = 'second_channel_token'; let secondChannelAdminRole: CreateRole.CreateRole; let customerUser: GetCustomerList.Items; const channelGuard: ErrorResultGuard = createErrorResultGuard( input => !!input.defaultLanguageCode, ); beforeAll(async () => { await server.init({ initialData, productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'), customerCount: 1, }); await adminClient.asSuperAdmin(); const { customers } = await adminClient.query( GET_CUSTOMER_LIST, { options: { take: 1 }, }, ); customerUser = customers.items[0]; }, TEST_SETUP_TIMEOUT_MS); afterAll(async () => { await server.destroy(); }); it('createChannel returns error result defaultLanguageCode not available', async () => { const { createChannel } = await adminClient.query( CREATE_CHANNEL, { input: { code: 'second-channel', token: SECOND_CHANNEL_TOKEN, defaultLanguageCode: LanguageCode.zh, currencyCode: CurrencyCode.GBP, pricesIncludeTax: true, defaultShippingZoneId: 'T_1', defaultTaxZoneId: 'T_1', }, }, ); channelGuard.assertErrorResult(createChannel); expect(createChannel.message).toBe( 'Language "zh" is not available. First enable it via GlobalSettings and try again', ); expect(createChannel.errorCode).toBe(ErrorCode.LANGUAGE_NOT_AVAILABLE_ERROR); expect(createChannel.languageCode).toBe('zh'); }); it('create a new Channel', async () => { const { createChannel } = await adminClient.query( 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); expect(createChannel).toEqual({ id: 'T_2', code: 'second-channel', token: SECOND_CHANNEL_TOKEN, currencyCode: 'GBP', defaultLanguageCode: 'en', defaultShippingZone: { id: 'T_1', }, defaultTaxZone: { id: 'T_1', }, pricesIncludeTax: true, }); }); it('superadmin has all permissions on new channel', async () => { const { me } = await adminClient.query(ME); expect(me!.channels.length).toBe(2); const secondChannelData = me!.channels.find(c => c.token === SECOND_CHANNEL_TOKEN); const nonOwnerPermissions = Object.values(Permission).filter( p => p !== Permission.Owner && p !== Permission.Public, ); expect(secondChannelData!.permissions).toEqual(nonOwnerPermissions); }); it('customer has Authenticated permission on new channel', async () => { await shopClient.asUserWithCredentials(customerUser.emailAddress, 'test'); const { me } = await shopClient.query(ME); expect(me!.channels.length).toBe(2); const secondChannelData = me!.channels.find(c => c.token === SECOND_CHANNEL_TOKEN); expect(me!.channels).toEqual([ { code: DEFAULT_CHANNEL_CODE, permissions: ['Authenticated'], token: E2E_DEFAULT_CHANNEL_TOKEN, }, { code: 'second-channel', permissions: ['Authenticated'], token: SECOND_CHANNEL_TOKEN, }, ]); }); it('createRole on second Channel', async () => { const { createRole } = await adminClient.query( CREATE_ROLE, { input: { description: 'second channel admin', code: 'second-channel-admin', channelIds: ['T_2'], permissions: [ Permission.ReadCatalog, Permission.ReadSettings, Permission.ReadAdministrator, Permission.CreateAdministrator, Permission.UpdateAdministrator, ], }, }, ); expect(createRole.channels).toEqual([ { id: 'T_2', code: 'second-channel', token: SECOND_CHANNEL_TOKEN, }, ]); secondChannelAdminRole = createRole; }); it('createAdministrator with second-channel-admin role', async () => { const { createAdministrator } = await adminClient.query< CreateAdministrator.Mutation, CreateAdministrator.Variables >(CREATE_ADMINISTRATOR, { input: { firstName: 'Admin', lastName: 'Two', emailAddress: 'admin2@test.com', password: 'test', roleIds: [secondChannelAdminRole.id], }, }); expect(createAdministrator.user.roles.map(r => r.description)).toEqual(['second channel admin']); }); it( 'cannot create role on channel for which admin does not have CreateAdministrator permission', assertThrowsWithMessage(async () => { await adminClient.asUserWithCredentials('admin2@test.com', 'test'); await adminClient.query(CREATE_ROLE, { input: { description: 'read default channel catalog', code: 'read default channel catalog', channelIds: ['T_1'], permissions: [Permission.ReadCatalog], }, }); }, 'You are not currently authorized to perform this action'), ); it('can create role on channel for which admin has CreateAdministrator permission', async () => { const { createRole } = await adminClient.query( CREATE_ROLE, { input: { description: 'read second channel catalog', code: 'read-second-channel-catalog', channelIds: ['T_2'], permissions: [Permission.ReadCatalog], }, }, ); expect(createRole.channels).toEqual([ { id: 'T_2', code: 'second-channel', token: SECOND_CHANNEL_TOKEN, }, ]); }); it('createRole with no channelId implicitly uses active channel', async () => { await adminClient.asSuperAdmin(); const { createRole } = await adminClient.query( CREATE_ROLE, { input: { description: 'update second channel catalog', code: 'update-second-channel-catalog', permissions: [Permission.UpdateCatalog], }, }, ); expect(createRole.channels).toEqual([ { id: 'T_2', code: 'second-channel', token: SECOND_CHANNEL_TOKEN, }, ]); }); describe('setting defaultLanguage', () => { it('returns error result if languageCode not in availableLanguages', async () => { await adminClient.asSuperAdmin(); await adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN); const { updateChannel } = await adminClient.query< UpdateChannel.Mutation, UpdateChannel.Variables >(UPDATE_CHANNEL, { input: { id: 'T_1', defaultLanguageCode: LanguageCode.zh, }, }); channelGuard.assertErrorResult(updateChannel); expect(updateChannel.message).toBe( 'Language "zh" is not available. First enable it via GlobalSettings and try again', ); expect(updateChannel.errorCode).toBe(ErrorCode.LANGUAGE_NOT_AVAILABLE_ERROR); expect(updateChannel.languageCode).toBe('zh'); }); it('allows setting to an available language', async () => { await adminClient.asSuperAdmin(); await adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN); await adminClient.query( UPDATE_GLOBAL_LANGUAGES, { input: { availableLanguages: [LanguageCode.en, LanguageCode.zh], }, }, ); const { updateChannel } = await adminClient.query< UpdateChannel.Mutation, UpdateChannel.Variables >(UPDATE_CHANNEL, { input: { id: 'T_1', defaultLanguageCode: LanguageCode.zh, }, }); expect(updateChannel.defaultLanguageCode).toBe(LanguageCode.zh); }); }); it('deleteChannel', async () => { const PROD_ID = 'T_1'; await adminClient.asSuperAdmin(); await adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN); const { assignProductsToChannel } = await adminClient.query< AssignProductsToChannel.Mutation, AssignProductsToChannel.Variables >(ASSIGN_PRODUCT_TO_CHANNEL, { input: { channelId: 'T_2', productIds: [PROD_ID], }, }); expect(assignProductsToChannel[0].channels.map(c => c.id).sort()).toEqual(['T_1', 'T_2']); // create a Session on the Channel to be deleted to ensure it gets cleaned up shopClient.setChannelToken(SECOND_CHANNEL_TOKEN); await shopClient.query(GET_ACTIVE_ORDER); const { deleteChannel } = await adminClient.query( DELETE_CHANNEL, { id: 'T_2', }, ); expect(deleteChannel.result).toBe(DeletionResult.DELETED); const { channels } = await adminClient.query(GET_CHANNELS); expect(channels.map(c => c.id).sort()).toEqual(['T_1']); const { product } = await adminClient.query< GetProductWithVariants.Query, GetProductWithVariants.Variables >(GET_PRODUCT_WITH_VARIANTS, { id: PROD_ID, }); expect(product!.channels.map(c => c.id)).toEqual(['T_1']); }); }); const DELETE_CHANNEL = gql` mutation DeleteChannel($id: ID!) { deleteChannel(id: $id) { message result } } `; const UPDATE_GLOBAL_LANGUAGES = gql` mutation UpdateGlobalLanguages($input: UpdateGlobalSettingsInput!) { updateGlobalSettings(input: $input) { ... on GlobalSettings { id availableLanguages } } } `;