asset-channel.e2e-spec.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /* eslint-disable @typescript-eslint/no-non-null-assertion */
  2. import { createTestEnvironment, E2E_DEFAULT_CHANNEL_TOKEN } from '@vendure/testing';
  3. import gql from 'graphql-tag';
  4. import path from 'path';
  5. import { afterAll, beforeAll, describe, expect, it } from 'vitest';
  6. import { initialData } from '../../../e2e-common/e2e-initial-data';
  7. import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
  8. import { DefaultLogger, LogLevel } from '../src/config';
  9. import { ASSET_FRAGMENT } from './graphql/fragments';
  10. import { CurrencyCode, LanguageCode } from './graphql/generated-e2e-admin-types';
  11. import * as Codegen from './graphql/generated-e2e-admin-types';
  12. import { DeletionResult } from './graphql/generated-e2e-shop-types';
  13. import {
  14. ASSIGN_COLLECTIONS_TO_CHANNEL,
  15. ASSIGN_PRODUCT_TO_CHANNEL,
  16. CREATE_ASSETS,
  17. CREATE_CHANNEL,
  18. DELETE_ASSET,
  19. GET_ASSET,
  20. GET_PRODUCT_WITH_VARIANTS,
  21. UPDATE_COLLECTION,
  22. UPDATE_PRODUCT,
  23. } from './graphql/shared-definitions';
  24. import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
  25. const { server, adminClient } = createTestEnvironment(testConfig());
  26. const SECOND_CHANNEL_TOKEN = 'second_channel_token';
  27. let createdAssetId: string;
  28. let channel2Id: string;
  29. let featuredAssetId: string;
  30. beforeAll(async () => {
  31. await server.init({
  32. initialData,
  33. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
  34. customerCount: 1,
  35. });
  36. await adminClient.asSuperAdmin();
  37. const { createChannel } = await adminClient.query<
  38. Codegen.CreateChannelMutation,
  39. Codegen.CreateChannelMutationVariables
  40. >(CREATE_CHANNEL, {
  41. input: {
  42. code: 'second-channel',
  43. token: SECOND_CHANNEL_TOKEN,
  44. defaultLanguageCode: LanguageCode.en,
  45. currencyCode: CurrencyCode.GBP,
  46. pricesIncludeTax: true,
  47. defaultShippingZoneId: 'T_1',
  48. defaultTaxZoneId: 'T_1',
  49. },
  50. });
  51. channel2Id = createChannel.id;
  52. }, TEST_SETUP_TIMEOUT_MS);
  53. afterAll(async () => {
  54. await server.destroy();
  55. });
  56. describe('ChannelAware Assets', () => {
  57. it('Create asset in default channel', async () => {
  58. const filesToUpload = [path.join(__dirname, 'fixtures/assets/pps2.jpg')];
  59. const { createAssets }: Codegen.CreateAssetsMutation = await adminClient.fileUploadMutation({
  60. mutation: CREATE_ASSETS,
  61. filePaths: filesToUpload,
  62. mapVariables: filePaths => ({
  63. input: filePaths.map(p => ({ file: null })),
  64. }),
  65. });
  66. expect(createAssets.length).toBe(1);
  67. createdAssetId = createAssets[0].id;
  68. expect(createdAssetId).toBeDefined();
  69. });
  70. it('Get asset from default channel', async () => {
  71. const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
  72. GET_ASSET,
  73. {
  74. id: createdAssetId,
  75. },
  76. );
  77. expect(asset?.id).toEqual(createdAssetId);
  78. });
  79. it('Asset is not in channel2', async () => {
  80. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  81. const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
  82. GET_ASSET,
  83. {
  84. id: createdAssetId,
  85. },
  86. );
  87. expect(asset).toBe(null);
  88. });
  89. it('Add asset to channel2', async () => {
  90. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  91. const { assignAssetsToChannel: assets } = await adminClient.query<
  92. Codegen.AssignAssetsToChannelMutation,
  93. Codegen.AssignAssetsToChannelMutationVariables
  94. >(ASSIGN_ASSET_TO_CHANNEL, {
  95. input: {
  96. assetIds: [createdAssetId],
  97. channelId: channel2Id,
  98. },
  99. });
  100. expect(assets[0].id).toBe(createdAssetId);
  101. });
  102. it('Get asset from channel2', async () => {
  103. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  104. const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
  105. GET_ASSET,
  106. {
  107. id: createdAssetId,
  108. },
  109. );
  110. expect(asset?.id).toBe(createdAssetId);
  111. });
  112. it('Delete asset from channel2', async () => {
  113. const { deleteAsset } = await adminClient.query<
  114. Codegen.DeleteAssetMutation,
  115. Codegen.DeleteAssetMutationVariables
  116. >(DELETE_ASSET, {
  117. input: {
  118. assetId: createdAssetId,
  119. },
  120. });
  121. expect(deleteAsset.result).toBe(DeletionResult.DELETED);
  122. });
  123. it('Asset is available in default channel', async () => {
  124. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  125. const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
  126. GET_ASSET,
  127. {
  128. id: createdAssetId,
  129. },
  130. );
  131. expect(asset?.id).toEqual(createdAssetId);
  132. });
  133. it('Add asset to channel2', async () => {
  134. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  135. const { assignAssetsToChannel: assets } = await adminClient.query<
  136. Codegen.AssignAssetsToChannelMutation,
  137. Codegen.AssignAssetsToChannelMutationVariables
  138. >(ASSIGN_ASSET_TO_CHANNEL, {
  139. input: {
  140. assetIds: [createdAssetId],
  141. channelId: channel2Id,
  142. },
  143. });
  144. expect(assets[0].id).toBe(createdAssetId);
  145. });
  146. it(
  147. 'Delete asset from all channels with insufficient permission',
  148. assertThrowsWithMessage(async () => {
  149. await adminClient.asAnonymousUser();
  150. const { deleteAsset } = await adminClient.query<
  151. Codegen.DeleteAssetMutation,
  152. Codegen.DeleteAssetMutationVariables
  153. >(DELETE_ASSET, {
  154. input: {
  155. assetId: createdAssetId,
  156. deleteFromAllChannels: true,
  157. },
  158. });
  159. }, 'You are not currently authorized to perform this action'),
  160. );
  161. it('Delete asset from all channels as superadmin', async () => {
  162. await adminClient.asSuperAdmin();
  163. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  164. const { deleteAsset } = await adminClient.query<
  165. Codegen.DeleteAssetMutation,
  166. Codegen.DeleteAssetMutationVariables
  167. >(DELETE_ASSET, {
  168. input: {
  169. assetId: createdAssetId,
  170. deleteFromAllChannels: true,
  171. },
  172. });
  173. expect(deleteAsset.result).toEqual(DeletionResult.DELETED);
  174. });
  175. it('Asset is also deleted in default channel', async () => {
  176. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  177. const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
  178. GET_ASSET,
  179. {
  180. id: createdAssetId,
  181. },
  182. );
  183. expect(asset?.id).toBeUndefined();
  184. });
  185. });
  186. describe('Product related assets', () => {
  187. it('Featured asset is available in default channel', async () => {
  188. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  189. const { product } = await adminClient.query<
  190. Codegen.GetProductWithVariantsQuery,
  191. Codegen.GetProductWithVariantsQueryVariables
  192. >(GET_PRODUCT_WITH_VARIANTS, {
  193. id: 'T_1',
  194. });
  195. featuredAssetId = product!.featuredAsset!.id;
  196. expect(featuredAssetId).toBeDefined();
  197. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  198. const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
  199. GET_ASSET,
  200. {
  201. id: featuredAssetId,
  202. },
  203. );
  204. expect(asset?.id).toEqual(featuredAssetId);
  205. });
  206. it('Featured asset is not available in channel2', async () => {
  207. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  208. const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
  209. GET_ASSET,
  210. {
  211. id: featuredAssetId,
  212. },
  213. );
  214. expect(asset?.id).toBeUndefined();
  215. });
  216. it('Add Product to channel2', async () => {
  217. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  218. const { assignProductsToChannel } = await adminClient.query<
  219. Codegen.AssignProductsToChannelMutation,
  220. Codegen.AssignProductsToChannelMutationVariables
  221. >(ASSIGN_PRODUCT_TO_CHANNEL, {
  222. input: {
  223. channelId: channel2Id,
  224. productIds: ['T_1'],
  225. },
  226. });
  227. expect(assignProductsToChannel[0].id).toEqual('T_1');
  228. expect(assignProductsToChannel[0].channels.map(c => c.id)).toContain(channel2Id);
  229. });
  230. it('Get featured asset from channel2', async () => {
  231. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  232. const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
  233. GET_ASSET,
  234. {
  235. id: featuredAssetId,
  236. },
  237. );
  238. expect(asset?.id).toEqual(featuredAssetId);
  239. });
  240. it('Add Product 2 to channel2', async () => {
  241. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  242. const { assignProductsToChannel } = await adminClient.query<
  243. Codegen.AssignProductsToChannelMutation,
  244. Codegen.AssignProductsToChannelMutationVariables
  245. >(ASSIGN_PRODUCT_TO_CHANNEL, {
  246. input: {
  247. channelId: channel2Id,
  248. productIds: ['T_2'],
  249. },
  250. });
  251. expect(assignProductsToChannel[0].id).toEqual('T_2');
  252. expect(assignProductsToChannel[0].channels.map(c => c.id)).toContain(channel2Id);
  253. });
  254. it('Add asset A to Product 2 in default channel', async () => {
  255. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  256. const { updateProduct } = await adminClient.query<
  257. Codegen.UpdateProductMutation,
  258. Codegen.UpdateProductMutationVariables
  259. >(UPDATE_PRODUCT, {
  260. input: {
  261. id: 'T_2',
  262. assetIds: ['T_3'],
  263. },
  264. });
  265. expect(updateProduct.assets.map(a => a.id)).toContain('T_3');
  266. });
  267. it('Channel2 does not have asset A', async () => {
  268. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  269. const { product } = await adminClient.query<
  270. Codegen.GetProductWithVariantsQuery,
  271. Codegen.GetProductWithVariantsQueryVariables
  272. >(GET_PRODUCT_WITH_VARIANTS, {
  273. id: 'T_2',
  274. });
  275. expect(product!.assets.find(a => a.id === 'T_3')).toBeUndefined();
  276. });
  277. });
  278. describe('Collection related assets', () => {
  279. let collectionFeaturedAssetId: string;
  280. it('Featured asset is available in default channel', async () => {
  281. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  282. await adminClient.query<Codegen.UpdateCollectionMutation, Codegen.UpdateCollectionMutationVariables>(
  283. UPDATE_COLLECTION,
  284. {
  285. input: {
  286. id: 'T_2',
  287. featuredAssetId: 'T_3',
  288. assetIds: ['T_3'],
  289. },
  290. },
  291. );
  292. const { collection } = await adminClient.query<
  293. Codegen.GetCollectionWithAssetsQuery,
  294. Codegen.GetCollectionWithAssetsQueryVariables
  295. >(GET_COLLECTION_WITH_ASSETS, {
  296. id: 'T_2',
  297. });
  298. collectionFeaturedAssetId = collection!.featuredAsset!.id;
  299. expect(collectionFeaturedAssetId).toBeDefined();
  300. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  301. const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
  302. GET_ASSET,
  303. {
  304. id: collectionFeaturedAssetId,
  305. },
  306. );
  307. expect(asset?.id).toEqual(collectionFeaturedAssetId);
  308. });
  309. it('Featured asset is not available in channel2', async () => {
  310. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  311. const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
  312. GET_ASSET,
  313. {
  314. id: collectionFeaturedAssetId,
  315. },
  316. );
  317. expect(asset?.id).toBeUndefined();
  318. });
  319. it('Add Collection to channel2', async () => {
  320. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  321. const { assignCollectionsToChannel } = await adminClient.query<
  322. Codegen.AssignCollectionsToChannelMutation,
  323. Codegen.AssignCollectionsToChannelMutationVariables
  324. >(ASSIGN_COLLECTIONS_TO_CHANNEL, {
  325. input: {
  326. channelId: channel2Id,
  327. collectionIds: ['T_2'],
  328. },
  329. });
  330. expect(assignCollectionsToChannel[0].id).toEqual('T_2');
  331. });
  332. it('Get featured asset from channel2', async () => {
  333. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  334. const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
  335. GET_ASSET,
  336. {
  337. id: collectionFeaturedAssetId,
  338. },
  339. );
  340. expect(asset?.id).toEqual(collectionFeaturedAssetId);
  341. });
  342. });
  343. const GET_COLLECTION_WITH_ASSETS = gql`
  344. query GetCollectionWithAssets($id: ID!) {
  345. collection(id: $id) {
  346. id
  347. name
  348. featuredAsset {
  349. ...Asset
  350. }
  351. assets {
  352. ...Asset
  353. }
  354. }
  355. }
  356. ${ASSET_FRAGMENT}
  357. `;
  358. export const ASSIGN_ASSET_TO_CHANNEL = gql`
  359. mutation assignAssetsToChannel($input: AssignAssetsToChannelInput!) {
  360. assignAssetsToChannel(input: $input) {
  361. ...Asset
  362. }
  363. }
  364. ${ASSET_FRAGMENT}
  365. `;