import.e2e-spec.ts 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. import { omit } from '@vendure/common/lib/omit';
  2. import { User } from '@vendure/core';
  3. import { createTestEnvironment } from '@vendure/testing';
  4. import gql from 'graphql-tag';
  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. describe('Import resolver', () => {
  9. const { server, adminClient } = createTestEnvironment({
  10. ...testConfig,
  11. customFields: {
  12. Product: [
  13. { type: 'string', name: 'pageType' },
  14. {
  15. name: 'owner',
  16. public: true,
  17. nullable: true,
  18. type: 'relation',
  19. entity: User,
  20. eager: true,
  21. },
  22. ],
  23. ProductVariant: [{ type: 'int', name: 'weight' }],
  24. },
  25. });
  26. beforeAll(async () => {
  27. await server.init({
  28. initialData,
  29. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-empty.csv'),
  30. customerCount: 0,
  31. });
  32. await adminClient.asSuperAdmin();
  33. }, TEST_SETUP_TIMEOUT_MS);
  34. afterAll(async () => {
  35. await server.destroy();
  36. });
  37. it('imports products', async () => {
  38. // TODO: waste a few more hours actually fixing this for real
  39. // Forgive me this abomination of a work-around.
  40. // On the inital run (as in CI), when the sqlite db has just been populated,
  41. // this test will fail due to an "out of memory" exception originating from
  42. // SqljsQueryRunner.ts:79:22, which is part of the findOne() operation on the
  43. // Session repository called from the AuthService.validateSession() method.
  44. // After several hours of fruitless hunting, I did what any desperate JavaScript
  45. // developer would do, and threw in a setTimeout. Which of course "works"...
  46. const timeout = process.env.CI ? 2000 : 1000;
  47. await new Promise(resolve => {
  48. setTimeout(resolve, timeout);
  49. });
  50. const csvFile = path.join(__dirname, 'fixtures', 'product-import.csv');
  51. const result = await adminClient.fileUploadMutation({
  52. mutation: gql`
  53. mutation ImportProducts($csvFile: Upload!) {
  54. importProducts(csvFile: $csvFile) {
  55. imported
  56. processed
  57. errors
  58. }
  59. }
  60. `,
  61. filePaths: [csvFile],
  62. mapVariables: () => ({ csvFile: null }),
  63. });
  64. expect(result.importProducts.errors).toEqual([
  65. 'Invalid Record Length: header length is 17, got 1 on line 8',
  66. ]);
  67. expect(result.importProducts.imported).toBe(4);
  68. expect(result.importProducts.processed).toBe(4);
  69. const productResult = await adminClient.query(
  70. gql`
  71. query GetProducts($options: ProductListOptions) {
  72. products(options: $options) {
  73. totalItems
  74. items {
  75. id
  76. name
  77. slug
  78. description
  79. featuredAsset {
  80. id
  81. name
  82. preview
  83. source
  84. }
  85. assets {
  86. id
  87. name
  88. preview
  89. source
  90. }
  91. optionGroups {
  92. id
  93. code
  94. name
  95. }
  96. facetValues {
  97. id
  98. name
  99. facet {
  100. id
  101. name
  102. }
  103. }
  104. customFields {
  105. pageType
  106. owner {
  107. id
  108. }
  109. }
  110. variants {
  111. id
  112. name
  113. sku
  114. price
  115. taxCategory {
  116. id
  117. name
  118. }
  119. options {
  120. id
  121. code
  122. }
  123. assets {
  124. id
  125. name
  126. preview
  127. source
  128. }
  129. featuredAsset {
  130. id
  131. name
  132. preview
  133. source
  134. }
  135. facetValues {
  136. id
  137. code
  138. name
  139. facet {
  140. id
  141. name
  142. }
  143. }
  144. stockOnHand
  145. trackInventory
  146. stockMovements {
  147. items {
  148. ... on StockMovement {
  149. id
  150. type
  151. quantity
  152. }
  153. }
  154. }
  155. customFields {
  156. weight
  157. }
  158. }
  159. }
  160. }
  161. }
  162. `,
  163. {
  164. options: {},
  165. },
  166. );
  167. expect(productResult.products.totalItems).toBe(4);
  168. const paperStretcher = productResult.products.items.find(
  169. (p: any) => p.name === 'Perfect Paper Stretcher',
  170. );
  171. const easel = productResult.products.items.find((p: any) => p.name === 'Mabef M/02 Studio Easel');
  172. const pencils = productResult.products.items.find((p: any) => p.name === 'Giotto Mega Pencils');
  173. const smock = productResult.products.items.find((p: any) => p.name === 'Artists Smock');
  174. // Omit FacetValues & options due to variations in the ordering between different DB engines
  175. expect(omit(paperStretcher, ['facetValues', 'options'], true)).toMatchSnapshot();
  176. expect(omit(easel, ['facetValues', 'options'], true)).toMatchSnapshot();
  177. expect(omit(pencils, ['facetValues', 'options'], true)).toMatchSnapshot();
  178. expect(omit(smock, ['facetValues', 'options'], true)).toMatchSnapshot();
  179. const byName = (e: { name: string }) => e.name;
  180. const byCode = (e: { code: string }) => e.code;
  181. expect(paperStretcher.facetValues).toEqual([]);
  182. expect(easel.facetValues).toEqual([]);
  183. expect(pencils.facetValues).toEqual([]);
  184. expect(smock.facetValues.map(byName).sort()).toEqual(['Denim', 'clothes']);
  185. expect(paperStretcher.variants[0].facetValues.map(byName).sort()).toEqual(['Accessory', 'KB']);
  186. expect(paperStretcher.variants[1].facetValues.map(byName).sort()).toEqual(['Accessory', 'KB']);
  187. expect(paperStretcher.variants[2].facetValues.map(byName).sort()).toEqual(['Accessory', 'KB']);
  188. expect(paperStretcher.variants[0].options.map(byCode).sort()).toEqual(['half-imperial']);
  189. expect(paperStretcher.variants[1].options.map(byCode).sort()).toEqual(['quarter-imperial']);
  190. expect(paperStretcher.variants[2].options.map(byCode).sort()).toEqual(['full-imperial']);
  191. expect(easel.variants[0].facetValues.map(byName).sort()).toEqual(['Easel', 'Mabef']);
  192. expect(pencils.variants[0].facetValues.map(byName).sort()).toEqual(['Xmas Sale']);
  193. expect(pencils.variants[1].facetValues.map(byName).sort()).toEqual(['Xmas Sale']);
  194. expect(pencils.variants[0].options.map(byCode).sort()).toEqual(['box-of-8']);
  195. expect(pencils.variants[1].options.map(byCode).sort()).toEqual(['box-of-12']);
  196. expect(smock.variants[0].facetValues.map(byName).sort()).toEqual([]);
  197. expect(smock.variants[1].facetValues.map(byName).sort()).toEqual([]);
  198. expect(smock.variants[2].facetValues.map(byName).sort()).toEqual([]);
  199. expect(smock.variants[3].facetValues.map(byName).sort()).toEqual([]);
  200. expect(smock.variants[0].options.map(byCode).sort()).toEqual(['beige', 'small']);
  201. expect(smock.variants[1].options.map(byCode).sort()).toEqual(['beige', 'large']);
  202. expect(smock.variants[2].options.map(byCode).sort()).toEqual(['navy', 'small']);
  203. expect(smock.variants[3].options.map(byCode).sort()).toEqual(['large', 'navy']);
  204. expect(paperStretcher.customFields.owner.id).toBe('T_1');
  205. expect(easel.customFields.owner.id).toBe('T_1');
  206. expect(pencils.customFields.owner.id).toBe('T_1');
  207. expect(smock.customFields.owner.id).toBe('T_1');
  208. }, 20000);
  209. });