populate.e2e-spec.ts 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. import { INestApplication } from '@nestjs/common';
  2. import { DefaultLogger, User } from '@vendure/core';
  3. import { populate } from '@vendure/core/cli';
  4. import { createTestEnvironment, E2E_DEFAULT_CHANNEL_TOKEN } from '@vendure/testing';
  5. import path from 'path';
  6. import { initialData } from '../../../e2e-common/e2e-initial-data';
  7. import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
  8. import { InitialData } from '../src/index';
  9. import {
  10. ChannelFragment,
  11. CreateChannelMutation,
  12. CreateChannelMutationVariables,
  13. CurrencyCode,
  14. GetAssetListQuery,
  15. GetCollectionsQuery,
  16. GetProductListQuery,
  17. GetProductListQueryVariables,
  18. GetProductWithVariantsQuery,
  19. GetProductWithVariantsQueryVariables,
  20. LanguageCode,
  21. } from './graphql/generated-e2e-admin-types';
  22. import {
  23. CREATE_CHANNEL,
  24. GET_ASSET_LIST,
  25. GET_COLLECTIONS,
  26. GET_PRODUCT_LIST,
  27. GET_PRODUCT_WITH_VARIANTS,
  28. } from './graphql/shared-definitions';
  29. describe('populate() function', () => {
  30. let channel2: ChannelFragment;
  31. const { server, adminClient } = createTestEnvironment({
  32. ...testConfig(),
  33. // logger: new DefaultLogger(),
  34. customFields: {
  35. Product: [
  36. { type: 'string', name: 'pageType' },
  37. {
  38. name: 'owner',
  39. public: true,
  40. nullable: true,
  41. type: 'relation',
  42. entity: User,
  43. eager: true,
  44. },
  45. {
  46. name: 'keywords',
  47. public: true,
  48. nullable: true,
  49. type: 'string',
  50. list: true,
  51. },
  52. {
  53. name: 'localName',
  54. type: 'localeString',
  55. },
  56. ],
  57. ProductVariant: [{ type: 'int', name: 'weight' }],
  58. },
  59. });
  60. beforeAll(async () => {
  61. await server.init({
  62. initialData: { ...initialData, collections: [] },
  63. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-empty.csv'),
  64. customerCount: 1,
  65. });
  66. await adminClient.asSuperAdmin();
  67. const { createChannel } = await adminClient.query<
  68. CreateChannelMutation,
  69. CreateChannelMutationVariables
  70. >(CREATE_CHANNEL, {
  71. input: {
  72. code: 'Channel 2',
  73. token: 'channel-2',
  74. currencyCode: CurrencyCode.EUR,
  75. defaultLanguageCode: LanguageCode.en,
  76. defaultShippingZoneId: 'T_1',
  77. defaultTaxZoneId: 'T_2',
  78. pricesIncludeTax: true,
  79. },
  80. });
  81. channel2 = createChannel as ChannelFragment;
  82. await server.destroy();
  83. }, TEST_SETUP_TIMEOUT_MS);
  84. describe('populating default channel', () => {
  85. let app: INestApplication;
  86. beforeAll(async () => {
  87. const initialDataForPopulate: InitialData = {
  88. defaultLanguage: initialData.defaultLanguage,
  89. defaultZone: initialData.defaultZone,
  90. taxRates: [],
  91. shippingMethods: [],
  92. paymentMethods: [],
  93. countries: [],
  94. collections: [{ name: 'Collection 1', filters: [] }],
  95. };
  96. const csvFile = path.join(__dirname, 'fixtures', 'product-import.csv');
  97. app = await populate(
  98. async () => {
  99. await server.bootstrap();
  100. return server.app;
  101. },
  102. initialDataForPopulate,
  103. csvFile,
  104. );
  105. }, TEST_SETUP_TIMEOUT_MS);
  106. afterAll(async () => {
  107. await app.close();
  108. });
  109. it('populates products', async () => {
  110. await adminClient.asSuperAdmin();
  111. const { products } = await adminClient.query<GetProductListQuery>(GET_PRODUCT_LIST);
  112. expect(products.totalItems).toBe(4);
  113. expect(products.items.map(i => i.name).sort()).toEqual([
  114. 'Artists Smock',
  115. 'Giotto Mega Pencils',
  116. 'Mabef M/02 Studio Easel',
  117. 'Perfect Paper Stretcher',
  118. ]);
  119. });
  120. it('populates assets', async () => {
  121. const { assets } = await adminClient.query<GetAssetListQuery>(GET_ASSET_LIST);
  122. expect(assets.items.map(i => i.name).sort()).toEqual([
  123. 'box-of-12.jpg',
  124. 'box-of-8.jpg',
  125. 'pps1.jpg',
  126. 'pps2.jpg',
  127. ]);
  128. });
  129. it('populates collections', async () => {
  130. const { collections } = await adminClient.query<GetCollectionsQuery>(GET_COLLECTIONS);
  131. expect(collections.items.map(i => i.name).sort()).toEqual(['Collection 1']);
  132. });
  133. });
  134. describe('populating a non-default channel', () => {
  135. let app: INestApplication;
  136. beforeAll(async () => {
  137. const initialDataForPopulate: InitialData = {
  138. defaultLanguage: initialData.defaultLanguage,
  139. defaultZone: initialData.defaultZone,
  140. taxRates: [],
  141. shippingMethods: [],
  142. paymentMethods: [],
  143. countries: [],
  144. collections: [{ name: 'Collection 2', filters: [] }],
  145. };
  146. const csvFile = path.join(__dirname, 'fixtures', 'product-import-channel.csv');
  147. app = await populate(
  148. async () => {
  149. await server.bootstrap();
  150. return server.app;
  151. },
  152. initialDataForPopulate,
  153. csvFile,
  154. channel2.token,
  155. );
  156. });
  157. afterAll(async () => {
  158. await app.close();
  159. });
  160. it('populates products', async () => {
  161. await adminClient.asSuperAdmin();
  162. await adminClient.setChannelToken(channel2.token);
  163. const { products } = await adminClient.query<GetProductListQuery>(GET_PRODUCT_LIST);
  164. expect(products.totalItems).toBe(1);
  165. expect(products.items.map(i => i.name).sort()).toEqual(['Model Hand']);
  166. });
  167. it('populates assets', async () => {
  168. const { assets } = await adminClient.query<GetAssetListQuery>(GET_ASSET_LIST);
  169. expect(assets.items.map(i => i.name).sort()).toEqual(['vincent-botta-736919-unsplash.jpg']);
  170. });
  171. it('populates collections', async () => {
  172. const { collections } = await adminClient.query<GetCollectionsQuery>(GET_COLLECTIONS);
  173. expect(collections.items.map(i => i.name).sort()).toEqual(['Collection 2']);
  174. });
  175. it('product also assigned to default channel', async () => {
  176. await adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  177. const { products } = await adminClient.query<GetProductListQuery>(GET_PRODUCT_LIST);
  178. expect(products.items.map(i => i.name).includes('Model Hand')).toBe(true);
  179. });
  180. });
  181. // https://github.com/vendure-ecommerce/vendure/issues/1445
  182. describe('clashing option names', () => {
  183. let app: INestApplication;
  184. beforeAll(async () => {
  185. const initialDataForPopulate: InitialData = {
  186. defaultLanguage: initialData.defaultLanguage,
  187. defaultZone: initialData.defaultZone,
  188. taxRates: [],
  189. shippingMethods: [],
  190. paymentMethods: [],
  191. countries: [],
  192. collections: [{ name: 'Collection 1', filters: [] }],
  193. };
  194. const csvFile = path.join(__dirname, 'fixtures', 'product-import-option-values.csv');
  195. app = await populate(
  196. async () => {
  197. await server.bootstrap();
  198. return server.app;
  199. },
  200. initialDataForPopulate,
  201. csvFile,
  202. );
  203. }, TEST_SETUP_TIMEOUT_MS);
  204. afterAll(async () => {
  205. await app.close();
  206. });
  207. it('populates variants & options', async () => {
  208. await adminClient.asSuperAdmin();
  209. await adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  210. const { products } = await adminClient.query<GetProductListQuery, GetProductListQueryVariables>(
  211. GET_PRODUCT_LIST,
  212. {
  213. options: {
  214. filter: {
  215. slug: { eq: 'foo' },
  216. },
  217. },
  218. },
  219. );
  220. expect(products.totalItems).toBe(1);
  221. const fooProduct = products.items[0];
  222. expect(fooProduct.name).toBe('Foo');
  223. const { product } = await adminClient.query<
  224. GetProductWithVariantsQuery,
  225. GetProductWithVariantsQueryVariables
  226. >(GET_PRODUCT_WITH_VARIANTS, {
  227. id: fooProduct.id,
  228. });
  229. expect(product?.variants.length).toBe(4);
  230. expect(product?.optionGroups.map(og => og.name).sort()).toEqual(['Bar', 'Foo']);
  231. expect(
  232. product?.variants
  233. .find(v => v.sku === 'foo-fiz-buz')
  234. ?.options.map(o => o.name)
  235. .sort(),
  236. ).toEqual(['buz', 'fiz']);
  237. });
  238. });
  239. });