channel.e2e-spec.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /* tslint:disable:no-non-null-assertion */
  2. import { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants';
  3. import {
  4. createErrorResultGuard,
  5. createTestEnvironment,
  6. E2E_DEFAULT_CHANNEL_TOKEN,
  7. ErrorResultGuard,
  8. } from '@vendure/testing';
  9. import gql from 'graphql-tag';
  10. import path from 'path';
  11. import { initialData } from '../../../e2e-common/e2e-initial-data';
  12. import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
  13. import {
  14. ChannelFragment,
  15. CurrencyCode,
  16. DeletionResult,
  17. ErrorCode,
  18. LanguageCode,
  19. Permission,
  20. } from './graphql/generated-e2e-admin-types';
  21. import * as Codegen from './graphql/generated-e2e-admin-types';
  22. import {
  23. ASSIGN_PRODUCT_TO_CHANNEL,
  24. CREATE_ADMINISTRATOR,
  25. CREATE_CHANNEL,
  26. CREATE_ROLE,
  27. GET_CHANNELS,
  28. GET_CUSTOMER_LIST,
  29. GET_PRODUCT_WITH_VARIANTS,
  30. ME,
  31. UPDATE_CHANNEL,
  32. } from './graphql/shared-definitions';
  33. import { GET_ACTIVE_ORDER } from './graphql/shop-definitions';
  34. import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
  35. describe('Channels', () => {
  36. const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
  37. const SECOND_CHANNEL_TOKEN = 'second_channel_token';
  38. let secondChannelAdminRole: Codegen.CreateRoleMutation['createRole'];
  39. let customerUser: Codegen.GetCustomerListQuery['customers']['items'][number];
  40. const channelGuard: ErrorResultGuard<Codegen.ChannelFragment> =
  41. createErrorResultGuard<Codegen.ChannelFragment>(input => !!input.defaultLanguageCode);
  42. beforeAll(async () => {
  43. await server.init({
  44. initialData,
  45. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
  46. customerCount: 1,
  47. });
  48. await adminClient.asSuperAdmin();
  49. const { customers } = await adminClient.query<
  50. Codegen.GetCustomerListQuery,
  51. Codegen.GetCustomerListQueryVariables
  52. >(GET_CUSTOMER_LIST, {
  53. options: { take: 1 },
  54. });
  55. customerUser = customers.items[0];
  56. }, TEST_SETUP_TIMEOUT_MS);
  57. afterAll(async () => {
  58. await server.destroy();
  59. });
  60. it('createChannel returns error result defaultLanguageCode not available', async () => {
  61. const { createChannel } = await adminClient.query<
  62. Codegen.CreateChannelMutation,
  63. Codegen.CreateChannelMutationVariables
  64. >(CREATE_CHANNEL, {
  65. input: {
  66. code: 'second-channel',
  67. token: SECOND_CHANNEL_TOKEN,
  68. defaultLanguageCode: LanguageCode.zh,
  69. currencyCode: CurrencyCode.GBP,
  70. pricesIncludeTax: true,
  71. defaultShippingZoneId: 'T_1',
  72. defaultTaxZoneId: 'T_1',
  73. },
  74. });
  75. channelGuard.assertErrorResult(createChannel);
  76. expect(createChannel.message).toBe(
  77. 'Language "zh" is not available. First enable it via GlobalSettings and try again',
  78. );
  79. expect(createChannel.errorCode).toBe(ErrorCode.LANGUAGE_NOT_AVAILABLE_ERROR);
  80. expect(createChannel.languageCode).toBe('zh');
  81. });
  82. it('create a new Channel', async () => {
  83. const { createChannel } = await adminClient.query<
  84. Codegen.CreateChannelMutation,
  85. Codegen.CreateChannelMutationVariables
  86. >(CREATE_CHANNEL, {
  87. input: {
  88. code: 'second-channel',
  89. token: SECOND_CHANNEL_TOKEN,
  90. defaultLanguageCode: LanguageCode.en,
  91. currencyCode: CurrencyCode.GBP,
  92. pricesIncludeTax: true,
  93. defaultShippingZoneId: 'T_1',
  94. defaultTaxZoneId: 'T_1',
  95. },
  96. });
  97. channelGuard.assertSuccess(createChannel);
  98. expect(createChannel).toEqual({
  99. id: 'T_2',
  100. code: 'second-channel',
  101. token: SECOND_CHANNEL_TOKEN,
  102. currencyCode: 'GBP',
  103. defaultLanguageCode: 'en',
  104. defaultShippingZone: {
  105. id: 'T_1',
  106. },
  107. defaultTaxZone: {
  108. id: 'T_1',
  109. },
  110. pricesIncludeTax: true,
  111. });
  112. });
  113. it('superadmin has all permissions on new channel', async () => {
  114. const { me } = await adminClient.query<Codegen.MeQuery>(ME);
  115. expect(me!.channels.length).toBe(2);
  116. const secondChannelData = me!.channels.find(c => c.token === SECOND_CHANNEL_TOKEN);
  117. const nonOwnerPermissions = Object.values(Permission).filter(
  118. p => p !== Permission.Owner && p !== Permission.Public,
  119. );
  120. expect(secondChannelData!.permissions.sort()).toEqual(nonOwnerPermissions);
  121. });
  122. it('customer has Authenticated permission on new channel', async () => {
  123. await shopClient.asUserWithCredentials(customerUser.emailAddress, 'test');
  124. const { me } = await shopClient.query<Codegen.MeQuery>(ME);
  125. expect(me!.channels.length).toBe(2);
  126. const secondChannelData = me!.channels.find(c => c.token === SECOND_CHANNEL_TOKEN);
  127. expect(me!.channels).toEqual([
  128. {
  129. code: DEFAULT_CHANNEL_CODE,
  130. permissions: ['Authenticated'],
  131. token: E2E_DEFAULT_CHANNEL_TOKEN,
  132. },
  133. {
  134. code: 'second-channel',
  135. permissions: ['Authenticated'],
  136. token: SECOND_CHANNEL_TOKEN,
  137. },
  138. ]);
  139. });
  140. it('createRole on second Channel', async () => {
  141. const { createRole } = await adminClient.query<
  142. Codegen.CreateRoleMutation,
  143. Codegen.CreateRoleMutationVariables
  144. >(CREATE_ROLE, {
  145. input: {
  146. description: 'second channel admin',
  147. code: 'second-channel-admin',
  148. channelIds: ['T_2'],
  149. permissions: [
  150. Permission.ReadCatalog,
  151. Permission.ReadSettings,
  152. Permission.ReadAdministrator,
  153. Permission.CreateAdministrator,
  154. Permission.UpdateAdministrator,
  155. ],
  156. },
  157. });
  158. expect(createRole.channels).toEqual([
  159. {
  160. id: 'T_2',
  161. code: 'second-channel',
  162. token: SECOND_CHANNEL_TOKEN,
  163. },
  164. ]);
  165. secondChannelAdminRole = createRole;
  166. });
  167. it('createAdministrator with second-channel-admin role', async () => {
  168. const { createAdministrator } = await adminClient.query<
  169. Codegen.CreateAdministratorMutation,
  170. Codegen.CreateAdministratorMutationVariables
  171. >(CREATE_ADMINISTRATOR, {
  172. input: {
  173. firstName: 'Admin',
  174. lastName: 'Two',
  175. emailAddress: 'admin2@test.com',
  176. password: 'test',
  177. roleIds: [secondChannelAdminRole.id],
  178. },
  179. });
  180. expect(createAdministrator.user.roles.map(r => r.description)).toEqual(['second channel admin']);
  181. });
  182. it(
  183. 'cannot create role on channel for which admin does not have CreateAdministrator permission',
  184. assertThrowsWithMessage(async () => {
  185. await adminClient.asUserWithCredentials('admin2@test.com', 'test');
  186. await adminClient.query<Codegen.CreateRoleMutation, Codegen.CreateRoleMutationVariables>(
  187. CREATE_ROLE,
  188. {
  189. input: {
  190. description: 'read default channel catalog',
  191. code: 'read default channel catalog',
  192. channelIds: ['T_1'],
  193. permissions: [Permission.ReadCatalog],
  194. },
  195. },
  196. );
  197. }, 'You are not currently authorized to perform this action'),
  198. );
  199. it('can create role on channel for which admin has CreateAdministrator permission', async () => {
  200. const { createRole } = await adminClient.query<
  201. Codegen.CreateRoleMutation,
  202. Codegen.CreateRoleMutationVariables
  203. >(CREATE_ROLE, {
  204. input: {
  205. description: 'read second channel catalog',
  206. code: 'read-second-channel-catalog',
  207. channelIds: ['T_2'],
  208. permissions: [Permission.ReadCatalog],
  209. },
  210. });
  211. expect(createRole.channels).toEqual([
  212. {
  213. id: 'T_2',
  214. code: 'second-channel',
  215. token: SECOND_CHANNEL_TOKEN,
  216. },
  217. ]);
  218. });
  219. it('createRole with no channelId implicitly uses active channel', async () => {
  220. await adminClient.asSuperAdmin();
  221. const { createRole } = await adminClient.query<
  222. Codegen.CreateRoleMutation,
  223. Codegen.CreateRoleMutationVariables
  224. >(CREATE_ROLE, {
  225. input: {
  226. description: 'update second channel catalog',
  227. code: 'update-second-channel-catalog',
  228. permissions: [Permission.UpdateCatalog],
  229. },
  230. });
  231. expect(createRole.channels).toEqual([
  232. {
  233. id: 'T_2',
  234. code: 'second-channel',
  235. token: SECOND_CHANNEL_TOKEN,
  236. },
  237. ]);
  238. });
  239. describe('setting defaultLanguage', () => {
  240. it('returns error result if languageCode not in availableLanguages', async () => {
  241. await adminClient.asSuperAdmin();
  242. await adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  243. const { updateChannel } = await adminClient.query<
  244. Codegen.UpdateChannelMutation,
  245. Codegen.UpdateChannelMutationVariables
  246. >(UPDATE_CHANNEL, {
  247. input: {
  248. id: 'T_1',
  249. defaultLanguageCode: LanguageCode.zh,
  250. },
  251. });
  252. channelGuard.assertErrorResult(updateChannel);
  253. expect(updateChannel.message).toBe(
  254. 'Language "zh" is not available. First enable it via GlobalSettings and try again',
  255. );
  256. expect(updateChannel.errorCode).toBe(ErrorCode.LANGUAGE_NOT_AVAILABLE_ERROR);
  257. expect(updateChannel.languageCode).toBe('zh');
  258. });
  259. it('allows setting to an available language', async () => {
  260. await adminClient.asSuperAdmin();
  261. await adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  262. await adminClient.query<
  263. Codegen.UpdateGlobalLanguagesMutation,
  264. Codegen.UpdateGlobalLanguagesMutationVariables
  265. >(UPDATE_GLOBAL_LANGUAGES, {
  266. input: {
  267. availableLanguages: [LanguageCode.en, LanguageCode.zh],
  268. },
  269. });
  270. const { updateChannel } = await adminClient.query<
  271. Codegen.UpdateChannelMutation,
  272. Codegen.UpdateChannelMutationVariables
  273. >(UPDATE_CHANNEL, {
  274. input: {
  275. id: 'T_1',
  276. defaultLanguageCode: LanguageCode.zh,
  277. },
  278. });
  279. expect(updateChannel.defaultLanguageCode).toBe(LanguageCode.zh);
  280. });
  281. });
  282. it('deleteChannel', async () => {
  283. const PROD_ID = 'T_1';
  284. await adminClient.asSuperAdmin();
  285. await adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  286. const { assignProductsToChannel } = await adminClient.query<
  287. Codegen.AssignProductsToChannelMutation,
  288. Codegen.AssignProductsToChannelMutationVariables
  289. >(ASSIGN_PRODUCT_TO_CHANNEL, {
  290. input: {
  291. channelId: 'T_2',
  292. productIds: [PROD_ID],
  293. },
  294. });
  295. expect(assignProductsToChannel[0].channels.map(c => c.id).sort()).toEqual(['T_1', 'T_2']);
  296. // create a Session on the Channel to be deleted to ensure it gets cleaned up
  297. shopClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  298. await shopClient.query(GET_ACTIVE_ORDER);
  299. const { deleteChannel } = await adminClient.query<
  300. Codegen.DeleteChannelMutation,
  301. Codegen.DeleteChannelMutationVariables
  302. >(DELETE_CHANNEL, {
  303. id: 'T_2',
  304. });
  305. expect(deleteChannel.result).toBe(DeletionResult.DELETED);
  306. const { channels } = await adminClient.query<Codegen.GetChannelsQuery>(GET_CHANNELS);
  307. expect(channels.map(c => c.id).sort()).toEqual(['T_1']);
  308. const { product } = await adminClient.query<
  309. Codegen.GetProductWithVariantsQuery,
  310. Codegen.GetProductWithVariantsQueryVariables
  311. >(GET_PRODUCT_WITH_VARIANTS, {
  312. id: PROD_ID,
  313. });
  314. expect(product!.channels.map(c => c.id)).toEqual(['T_1']);
  315. });
  316. });
  317. const DELETE_CHANNEL = gql`
  318. mutation DeleteChannel($id: ID!) {
  319. deleteChannel(id: $id) {
  320. message
  321. result
  322. }
  323. }
  324. `;
  325. const UPDATE_GLOBAL_LANGUAGES = gql`
  326. mutation UpdateGlobalLanguages($input: UpdateGlobalSettingsInput!) {
  327. updateGlobalSettings(input: $input) {
  328. ... on GlobalSettings {
  329. id
  330. availableLanguages
  331. }
  332. }
  333. }
  334. `;