channel.e2e-spec.ts 13 KB

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