populate.e2e-spec.ts 9.0 KB

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