default-search-plugin.e2e-spec.ts 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. import { pick } from '@vendure/common/lib/pick';
  2. import { DefaultSearchPlugin, mergeConfig } from '@vendure/core';
  3. import { facetValueCollectionFilter } from '@vendure/core/dist/config/collection/default-collection-filters';
  4. import { createTestEnvironment, E2E_DEFAULT_CHANNEL_TOKEN, SimpleGraphQLClient } from '@vendure/testing';
  5. import gql from 'graphql-tag';
  6. import path from 'path';
  7. import { initialData } from '../../../e2e-common/e2e-initial-data';
  8. import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
  9. import {
  10. AssignProductsToChannel,
  11. CreateChannel,
  12. CreateCollection,
  13. CreateFacet,
  14. CurrencyCode,
  15. DeleteProduct,
  16. DeleteProductVariant,
  17. LanguageCode,
  18. RemoveProductsFromChannel,
  19. SearchFacetValues,
  20. SearchGetPrices,
  21. SearchInput,
  22. SortOrder,
  23. UpdateCollection,
  24. UpdateProduct,
  25. UpdateProductVariants,
  26. UpdateTaxRate,
  27. } from './graphql/generated-e2e-admin-types';
  28. import { SearchProductsShop } from './graphql/generated-e2e-shop-types';
  29. import {
  30. ASSIGN_PRODUCT_TO_CHANNEL,
  31. CREATE_CHANNEL,
  32. CREATE_COLLECTION,
  33. CREATE_FACET,
  34. DELETE_PRODUCT,
  35. DELETE_PRODUCT_VARIANT,
  36. REMOVE_PRODUCT_FROM_CHANNEL,
  37. UPDATE_COLLECTION,
  38. UPDATE_PRODUCT,
  39. UPDATE_PRODUCT_VARIANTS,
  40. UPDATE_TAX_RATE,
  41. } from './graphql/shared-definitions';
  42. import { SEARCH_PRODUCTS_SHOP } from './graphql/shop-definitions';
  43. import { awaitRunningJobs } from './utils/await-running-jobs';
  44. describe('Default search plugin', () => {
  45. const { server, adminClient, shopClient } = createTestEnvironment(
  46. mergeConfig(testConfig, { plugins: [DefaultSearchPlugin] }),
  47. );
  48. beforeAll(async () => {
  49. await server.init({
  50. initialData,
  51. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
  52. customerCount: 1,
  53. });
  54. await adminClient.asSuperAdmin();
  55. }, TEST_SETUP_TIMEOUT_MS);
  56. afterAll(async () => {
  57. await server.destroy();
  58. });
  59. function doAdminSearchQuery(input: SearchInput) {
  60. return adminClient.query<SearchProductsShop.Query, SearchProductsShop.Variables>(SEARCH_PRODUCTS, {
  61. input,
  62. });
  63. }
  64. async function testGroupByProduct(client: SimpleGraphQLClient) {
  65. const result = await client.query<SearchProductsShop.Query, SearchProductsShop.Variables>(
  66. SEARCH_PRODUCTS_SHOP,
  67. {
  68. input: {
  69. groupByProduct: true,
  70. },
  71. },
  72. );
  73. expect(result.search.totalItems).toBe(20);
  74. }
  75. async function testNoGrouping(client: SimpleGraphQLClient) {
  76. const result = await client.query<SearchProductsShop.Query, SearchProductsShop.Variables>(
  77. SEARCH_PRODUCTS_SHOP,
  78. {
  79. input: {
  80. groupByProduct: false,
  81. },
  82. },
  83. );
  84. expect(result.search.totalItems).toBe(34);
  85. }
  86. async function testMatchSearchTerm(client: SimpleGraphQLClient) {
  87. const result = await client.query<SearchProductsShop.Query, SearchProductsShop.Variables>(
  88. SEARCH_PRODUCTS_SHOP,
  89. {
  90. input: {
  91. term: 'camera',
  92. groupByProduct: true,
  93. sort: {
  94. name: SortOrder.ASC,
  95. },
  96. },
  97. },
  98. );
  99. expect(result.search.items.map(i => i.productName)).toEqual([
  100. 'Camera Lens',
  101. 'Instant Camera',
  102. 'Slr Camera',
  103. ]);
  104. }
  105. async function testMatchFacetIds(client: SimpleGraphQLClient) {
  106. const result = await client.query<SearchProductsShop.Query, SearchProductsShop.Variables>(
  107. SEARCH_PRODUCTS_SHOP,
  108. {
  109. input: {
  110. facetValueIds: ['T_1', 'T_2'],
  111. groupByProduct: true,
  112. },
  113. },
  114. );
  115. expect(result.search.items.map(i => i.productName)).toEqual([
  116. 'Laptop',
  117. 'Curvy Monitor',
  118. 'Gaming PC',
  119. 'Hard Drive',
  120. 'Clacky Keyboard',
  121. 'USB Cable',
  122. ]);
  123. }
  124. async function testMatchCollectionId(client: SimpleGraphQLClient) {
  125. const result = await client.query<SearchProductsShop.Query, SearchProductsShop.Variables>(
  126. SEARCH_PRODUCTS_SHOP,
  127. {
  128. input: {
  129. collectionId: 'T_2',
  130. groupByProduct: true,
  131. },
  132. },
  133. );
  134. expect(result.search.items.map(i => i.productName)).toEqual([
  135. 'Spiky Cactus',
  136. 'Orchid',
  137. 'Bonsai Tree',
  138. ]);
  139. }
  140. async function testSinglePrices(client: SimpleGraphQLClient) {
  141. const result = await client.query<SearchGetPrices.Query, SearchGetPrices.Variables>(
  142. SEARCH_GET_PRICES,
  143. {
  144. input: {
  145. groupByProduct: false,
  146. take: 3,
  147. } as SearchInput,
  148. },
  149. );
  150. expect(result.search.items).toEqual([
  151. {
  152. price: { value: 129900 },
  153. priceWithTax: { value: 155880 },
  154. },
  155. {
  156. price: { value: 139900 },
  157. priceWithTax: { value: 167880 },
  158. },
  159. {
  160. price: { value: 219900 },
  161. priceWithTax: { value: 263880 },
  162. },
  163. ]);
  164. }
  165. async function testPriceRanges(client: SimpleGraphQLClient) {
  166. const result = await client.query<SearchGetPrices.Query, SearchGetPrices.Variables>(
  167. SEARCH_GET_PRICES,
  168. {
  169. input: {
  170. groupByProduct: true,
  171. take: 3,
  172. } as SearchInput,
  173. },
  174. );
  175. expect(result.search.items).toEqual([
  176. {
  177. price: { min: 129900, max: 229900 },
  178. priceWithTax: { min: 155880, max: 275880 },
  179. },
  180. {
  181. price: { min: 14374, max: 16994 },
  182. priceWithTax: { min: 17249, max: 20393 },
  183. },
  184. {
  185. price: { min: 93120, max: 109995 },
  186. priceWithTax: { min: 111744, max: 131994 },
  187. },
  188. ]);
  189. }
  190. describe('shop api', () => {
  191. it('group by product', () => testGroupByProduct(shopClient));
  192. it('no grouping', () => testNoGrouping(shopClient));
  193. it('matches search term', () => testMatchSearchTerm(shopClient));
  194. it('matches by facetId', () => testMatchFacetIds(shopClient));
  195. it('matches by collectionId', () => testMatchCollectionId(shopClient));
  196. it('single prices', () => testSinglePrices(shopClient));
  197. it('price ranges', () => testPriceRanges(shopClient));
  198. it('returns correct facetValues when not grouped by product', async () => {
  199. const result = await shopClient.query<SearchFacetValues.Query, SearchFacetValues.Variables>(
  200. SEARCH_GET_FACET_VALUES,
  201. {
  202. input: {
  203. groupByProduct: false,
  204. },
  205. },
  206. );
  207. expect(result.search.facetValues).toEqual([
  208. { count: 21, facetValue: { id: 'T_1', name: 'electronics' } },
  209. { count: 17, facetValue: { id: 'T_2', name: 'computers' } },
  210. { count: 4, facetValue: { id: 'T_3', name: 'photo' } },
  211. { count: 10, facetValue: { id: 'T_4', name: 'sports equipment' } },
  212. { count: 3, facetValue: { id: 'T_5', name: 'home & garden' } },
  213. { count: 3, facetValue: { id: 'T_6', name: 'plants' } },
  214. ]);
  215. });
  216. it('returns correct facetValues when grouped by product', async () => {
  217. const result = await shopClient.query<SearchFacetValues.Query, SearchFacetValues.Variables>(
  218. SEARCH_GET_FACET_VALUES,
  219. {
  220. input: {
  221. groupByProduct: true,
  222. },
  223. },
  224. );
  225. expect(result.search.facetValues).toEqual([
  226. { count: 10, facetValue: { id: 'T_1', name: 'electronics' } },
  227. { count: 6, facetValue: { id: 'T_2', name: 'computers' } },
  228. { count: 4, facetValue: { id: 'T_3', name: 'photo' } },
  229. { count: 7, facetValue: { id: 'T_4', name: 'sports equipment' } },
  230. { count: 3, facetValue: { id: 'T_5', name: 'home & garden' } },
  231. { count: 3, facetValue: { id: 'T_6', name: 'plants' } },
  232. ]);
  233. });
  234. it('omits facetValues of private facets', async () => {
  235. const { createFacet } = await adminClient.query<CreateFacet.Mutation, CreateFacet.Variables>(
  236. CREATE_FACET,
  237. {
  238. input: {
  239. code: 'profit-margin',
  240. isPrivate: true,
  241. translations: [{ languageCode: LanguageCode.en, name: 'Profit Margin' }],
  242. values: [
  243. {
  244. code: 'massive',
  245. translations: [{ languageCode: LanguageCode.en, name: 'massive' }],
  246. },
  247. ],
  248. },
  249. },
  250. );
  251. await adminClient.query<UpdateProduct.Mutation, UpdateProduct.Variables>(UPDATE_PRODUCT, {
  252. input: {
  253. id: 'T_2',
  254. // T_1 & T_2 are the existing facetValues (electronics & photo)
  255. facetValueIds: ['T_1', 'T_2', createFacet.values[0].id],
  256. },
  257. });
  258. const result = await shopClient.query<SearchFacetValues.Query, SearchFacetValues.Variables>(
  259. SEARCH_GET_FACET_VALUES,
  260. {
  261. input: {
  262. groupByProduct: true,
  263. },
  264. },
  265. );
  266. expect(result.search.facetValues).toEqual([
  267. { count: 10, facetValue: { id: 'T_1', name: 'electronics' } },
  268. { count: 6, facetValue: { id: 'T_2', name: 'computers' } },
  269. { count: 4, facetValue: { id: 'T_3', name: 'photo' } },
  270. { count: 7, facetValue: { id: 'T_4', name: 'sports equipment' } },
  271. { count: 3, facetValue: { id: 'T_5', name: 'home & garden' } },
  272. { count: 3, facetValue: { id: 'T_6', name: 'plants' } },
  273. ]);
  274. });
  275. it('encodes the productId and productVariantId', async () => {
  276. const result = await shopClient.query<SearchProductsShop.Query, SearchProductsShop.Variables>(
  277. SEARCH_PRODUCTS_SHOP,
  278. {
  279. input: {
  280. groupByProduct: false,
  281. take: 1,
  282. },
  283. },
  284. );
  285. expect(pick(result.search.items[0], ['productId', 'productVariantId'])).toEqual({
  286. productId: 'T_1',
  287. productVariantId: 'T_1',
  288. });
  289. });
  290. it('omits results for disabled ProductVariants', async () => {
  291. await adminClient.query<UpdateProductVariants.Mutation, UpdateProductVariants.Variables>(
  292. UPDATE_PRODUCT_VARIANTS,
  293. {
  294. input: [{ id: 'T_3', enabled: false }],
  295. },
  296. );
  297. await awaitRunningJobs(adminClient);
  298. const result = await shopClient.query<SearchProductsShop.Query, SearchProductsShop.Variables>(
  299. SEARCH_PRODUCTS_SHOP,
  300. {
  301. input: {
  302. groupByProduct: false,
  303. take: 3,
  304. },
  305. },
  306. );
  307. expect(result.search.items.map(i => i.productVariantId)).toEqual(['T_1', 'T_2', 'T_4']);
  308. });
  309. it('encodes collectionIds', async () => {
  310. const result = await shopClient.query<SearchProductsShop.Query, SearchProductsShop.Variables>(
  311. SEARCH_PRODUCTS_SHOP,
  312. {
  313. input: {
  314. groupByProduct: false,
  315. term: 'cactus',
  316. take: 1,
  317. },
  318. },
  319. );
  320. expect(result.search.items[0].collectionIds).toEqual(['T_2']);
  321. });
  322. });
  323. describe('admin api', () => {
  324. it('group by product', () => testGroupByProduct(adminClient));
  325. it('no grouping', () => testNoGrouping(adminClient));
  326. it('matches search term', () => testMatchSearchTerm(adminClient));
  327. it('matches by facetId', () => testMatchFacetIds(adminClient));
  328. it('matches by collectionId', () => testMatchCollectionId(adminClient));
  329. it('single prices', () => testSinglePrices(adminClient));
  330. it('price ranges', () => testPriceRanges(adminClient));
  331. describe('updating the index', () => {
  332. it('updates index when ProductVariants are changed', async () => {
  333. await awaitRunningJobs(adminClient);
  334. const { search } = await doAdminSearchQuery({ term: 'drive', groupByProduct: false });
  335. expect(search.items.map(i => i.sku)).toEqual([
  336. 'IHD455T1',
  337. 'IHD455T2',
  338. 'IHD455T3',
  339. 'IHD455T4',
  340. 'IHD455T6',
  341. ]);
  342. await adminClient.query<UpdateProductVariants.Mutation, UpdateProductVariants.Variables>(
  343. UPDATE_PRODUCT_VARIANTS,
  344. {
  345. input: search.items.map(i => ({
  346. id: i.productVariantId,
  347. sku: i.sku + '_updated',
  348. })),
  349. },
  350. );
  351. await awaitRunningJobs(adminClient);
  352. const { search: search2 } = await doAdminSearchQuery({
  353. term: 'drive',
  354. groupByProduct: false,
  355. });
  356. expect(search2.items.map(i => i.sku)).toEqual([
  357. 'IHD455T1_updated',
  358. 'IHD455T2_updated',
  359. 'IHD455T3_updated',
  360. 'IHD455T4_updated',
  361. 'IHD455T6_updated',
  362. ]);
  363. });
  364. it('updates index when ProductVariants are deleted', async () => {
  365. await awaitRunningJobs(adminClient);
  366. const { search } = await doAdminSearchQuery({ term: 'drive', groupByProduct: false });
  367. await adminClient.query<DeleteProductVariant.Mutation, DeleteProductVariant.Variables>(
  368. DELETE_PRODUCT_VARIANT,
  369. {
  370. id: search.items[0].productVariantId,
  371. },
  372. );
  373. await awaitRunningJobs(adminClient);
  374. const { search: search2 } = await doAdminSearchQuery({
  375. term: 'drive',
  376. groupByProduct: false,
  377. });
  378. expect(search2.items.map(i => i.sku)).toEqual([
  379. 'IHD455T2_updated',
  380. 'IHD455T3_updated',
  381. 'IHD455T4_updated',
  382. 'IHD455T6_updated',
  383. ]);
  384. });
  385. it('updates index when a Product is changed', async () => {
  386. await adminClient.query<UpdateProduct.Mutation, UpdateProduct.Variables>(UPDATE_PRODUCT, {
  387. input: {
  388. id: 'T_1',
  389. facetValueIds: [],
  390. },
  391. });
  392. await awaitRunningJobs(adminClient);
  393. const result = await doAdminSearchQuery({ facetValueIds: ['T_2'], groupByProduct: true });
  394. expect(result.search.items.map(i => i.productName)).toEqual([
  395. 'Curvy Monitor',
  396. 'Gaming PC',
  397. 'Hard Drive',
  398. 'Clacky Keyboard',
  399. 'USB Cable',
  400. ]);
  401. });
  402. it('updates index when a Product is deleted', async () => {
  403. const { search } = await doAdminSearchQuery({ facetValueIds: ['T_2'], groupByProduct: true });
  404. expect(search.items.map(i => i.productId)).toEqual(['T_2', 'T_3', 'T_4', 'T_5', 'T_6']);
  405. await adminClient.query<DeleteProduct.Mutation, DeleteProduct.Variables>(DELETE_PRODUCT, {
  406. id: 'T_5',
  407. });
  408. await awaitRunningJobs(adminClient);
  409. const { search: search2 } = await doAdminSearchQuery({
  410. facetValueIds: ['T_2'],
  411. groupByProduct: true,
  412. });
  413. expect(search2.items.map(i => i.productId)).toEqual(['T_2', 'T_3', 'T_4', 'T_6']);
  414. });
  415. it('updates index when a Collection is changed', async () => {
  416. await adminClient.query<UpdateCollection.Mutation, UpdateCollection.Variables>(
  417. UPDATE_COLLECTION,
  418. {
  419. input: {
  420. id: 'T_2',
  421. filters: [
  422. {
  423. code: facetValueCollectionFilter.code,
  424. arguments: [
  425. {
  426. name: 'facetValueIds',
  427. value: `["T_4"]`,
  428. type: 'facetValueIds',
  429. },
  430. {
  431. name: 'containsAny',
  432. value: `false`,
  433. type: 'boolean',
  434. },
  435. ],
  436. },
  437. ],
  438. },
  439. },
  440. );
  441. await awaitRunningJobs(adminClient);
  442. const result = await doAdminSearchQuery({ collectionId: 'T_2', groupByProduct: true });
  443. expect(result.search.items.map(i => i.productName)).toEqual([
  444. 'Road Bike',
  445. 'Skipping Rope',
  446. 'Boxing Gloves',
  447. 'Tent',
  448. 'Cruiser Skateboard',
  449. 'Football',
  450. 'Running Shoe',
  451. ]);
  452. });
  453. it('updates index when a Collection created', async () => {
  454. const { createCollection } = await adminClient.query<
  455. CreateCollection.Mutation,
  456. CreateCollection.Variables
  457. >(CREATE_COLLECTION, {
  458. input: {
  459. translations: [
  460. {
  461. languageCode: LanguageCode.en,
  462. name: 'Photo',
  463. description: '',
  464. },
  465. ],
  466. filters: [
  467. {
  468. code: facetValueCollectionFilter.code,
  469. arguments: [
  470. {
  471. name: 'facetValueIds',
  472. value: `["T_3"]`,
  473. type: 'facetValueIds',
  474. },
  475. {
  476. name: 'containsAny',
  477. value: `false`,
  478. type: 'boolean',
  479. },
  480. ],
  481. },
  482. ],
  483. },
  484. });
  485. await awaitRunningJobs(adminClient);
  486. const result = await doAdminSearchQuery({
  487. collectionId: createCollection.id,
  488. groupByProduct: true,
  489. });
  490. expect(result.search.items.map(i => i.productName)).toEqual([
  491. 'Instant Camera',
  492. 'Camera Lens',
  493. 'Tripod',
  494. 'Slr Camera',
  495. ]);
  496. });
  497. it('updates index when a taxRate is changed', async () => {
  498. await adminClient.query<UpdateTaxRate.Mutation, UpdateTaxRate.Variables>(UPDATE_TAX_RATE, {
  499. input: {
  500. // Default Channel's defaultTaxZone is Europe (id 2) and the id of the standard TaxRate
  501. // to Europe is 2.
  502. id: 'T_2',
  503. value: 50,
  504. },
  505. });
  506. await awaitRunningJobs(adminClient);
  507. const result = await adminClient.query<SearchGetPrices.Query, SearchGetPrices.Variables>(
  508. SEARCH_GET_PRICES,
  509. {
  510. input: {
  511. groupByProduct: true,
  512. term: 'laptop',
  513. } as SearchInput,
  514. },
  515. );
  516. expect(result.search.items).toEqual([
  517. {
  518. price: { min: 129900, max: 229900 },
  519. priceWithTax: { min: 194850, max: 344850 },
  520. },
  521. ]);
  522. });
  523. it('returns enabled field when not grouped', async () => {
  524. const result = await doAdminSearchQuery({ groupByProduct: false, take: 3 });
  525. expect(result.search.items.map(pick(['productVariantId', 'enabled']))).toEqual([
  526. { productVariantId: 'T_1', enabled: true },
  527. { productVariantId: 'T_2', enabled: true },
  528. { productVariantId: 'T_3', enabled: false },
  529. ]);
  530. });
  531. it('when grouped, enabled is true if at least one variant is enabled', async () => {
  532. await adminClient.query<UpdateProductVariants.Mutation, UpdateProductVariants.Variables>(
  533. UPDATE_PRODUCT_VARIANTS,
  534. {
  535. input: [{ id: 'T_1', enabled: false }, { id: 'T_2', enabled: false }],
  536. },
  537. );
  538. await awaitRunningJobs(adminClient);
  539. const result = await doAdminSearchQuery({ groupByProduct: true, take: 3 });
  540. expect(result.search.items.map(pick(['productId', 'enabled']))).toEqual([
  541. { productId: 'T_1', enabled: true },
  542. { productId: 'T_2', enabled: true },
  543. { productId: 'T_3', enabled: true },
  544. ]);
  545. });
  546. it('when grouped, enabled is false if all variants are disabled', async () => {
  547. await adminClient.query<UpdateProductVariants.Mutation, UpdateProductVariants.Variables>(
  548. UPDATE_PRODUCT_VARIANTS,
  549. {
  550. input: [{ id: 'T_4', enabled: false }],
  551. },
  552. );
  553. await awaitRunningJobs(adminClient);
  554. const result = await doAdminSearchQuery({ groupByProduct: true, take: 3 });
  555. expect(result.search.items.map(pick(['productId', 'enabled']))).toEqual([
  556. { productId: 'T_1', enabled: false },
  557. { productId: 'T_2', enabled: true },
  558. { productId: 'T_3', enabled: true },
  559. ]);
  560. });
  561. it('when grouped, enabled is false if product is disabled', async () => {
  562. await adminClient.query<UpdateProduct.Mutation, UpdateProduct.Variables>(UPDATE_PRODUCT, {
  563. input: {
  564. id: 'T_3',
  565. enabled: false,
  566. },
  567. });
  568. await awaitRunningJobs(adminClient);
  569. const result = await doAdminSearchQuery({ groupByProduct: true, take: 3 });
  570. expect(result.search.items.map(pick(['productId', 'enabled']))).toEqual([
  571. { productId: 'T_1', enabled: false },
  572. { productId: 'T_2', enabled: true },
  573. { productId: 'T_3', enabled: false },
  574. ]);
  575. });
  576. });
  577. describe('channel handling', () => {
  578. const SECOND_CHANNEL_TOKEN = 'second-channel-token';
  579. let secondChannel: CreateChannel.CreateChannel;
  580. beforeAll(async () => {
  581. const { createChannel } = await adminClient.query<
  582. CreateChannel.Mutation,
  583. CreateChannel.Variables
  584. >(CREATE_CHANNEL, {
  585. input: {
  586. code: 'second-channel',
  587. token: SECOND_CHANNEL_TOKEN,
  588. defaultLanguageCode: LanguageCode.en,
  589. currencyCode: CurrencyCode.GBP,
  590. pricesIncludeTax: true,
  591. defaultTaxZoneId: 'T_1',
  592. defaultShippingZoneId: 'T_1',
  593. },
  594. });
  595. secondChannel = createChannel;
  596. });
  597. it('adding product to channel', async () => {
  598. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  599. await adminClient.query<AssignProductsToChannel.Mutation, AssignProductsToChannel.Variables>(
  600. ASSIGN_PRODUCT_TO_CHANNEL,
  601. {
  602. input: { channelId: secondChannel.id, productIds: ['T_1', 'T_2'] },
  603. },
  604. );
  605. await awaitRunningJobs(adminClient);
  606. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  607. const { search } = await doAdminSearchQuery({ groupByProduct: true });
  608. expect(search.items.map(i => i.productId)).toEqual(['T_1', 'T_2']);
  609. }, 10000);
  610. it('removing product from channel', async () => {
  611. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  612. const { removeProductsFromChannel } = await adminClient.query<
  613. RemoveProductsFromChannel.Mutation,
  614. RemoveProductsFromChannel.Variables
  615. >(REMOVE_PRODUCT_FROM_CHANNEL, {
  616. input: {
  617. productIds: ['T_2'],
  618. channelId: secondChannel.id,
  619. },
  620. });
  621. await awaitRunningJobs(adminClient);
  622. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  623. const { search } = await doAdminSearchQuery({ groupByProduct: true });
  624. expect(search.items.map(i => i.productId)).toEqual(['T_1']);
  625. }, 10000);
  626. });
  627. });
  628. });
  629. export const SEARCH_PRODUCTS = gql`
  630. query SearchProductsAdmin($input: SearchInput!) {
  631. search(input: $input) {
  632. totalItems
  633. items {
  634. enabled
  635. productId
  636. productName
  637. productPreview
  638. productVariantId
  639. productVariantName
  640. productVariantPreview
  641. sku
  642. }
  643. }
  644. }
  645. `;
  646. export const SEARCH_GET_FACET_VALUES = gql`
  647. query SearchFacetValues($input: SearchInput!) {
  648. search(input: $input) {
  649. totalItems
  650. facetValues {
  651. count
  652. facetValue {
  653. id
  654. name
  655. }
  656. }
  657. }
  658. }
  659. `;
  660. export const SEARCH_GET_PRICES = gql`
  661. query SearchGetPrices($input: SearchInput!) {
  662. search(input: $input) {
  663. items {
  664. price {
  665. ... on PriceRange {
  666. min
  667. max
  668. }
  669. ... on SinglePrice {
  670. value
  671. }
  672. }
  673. priceWithTax {
  674. ... on PriceRange {
  675. min
  676. max
  677. }
  678. ... on SinglePrice {
  679. value
  680. }
  681. }
  682. }
  683. }
  684. }
  685. `;