channel.e2e-spec.ts 13 KB

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