list-query-builder.e2e-spec.ts 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. import { mergeConfig } from '@vendure/core';
  2. import { createTestEnvironment } from '@vendure/testing';
  3. import gql from 'graphql-tag';
  4. import path from 'path';
  5. import { initialData } from '../../../e2e-common/e2e-initial-data';
  6. import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
  7. import { ListQueryPlugin } from './fixtures/test-plugins/list-query-plugin';
  8. import { LanguageCode, SortOrder } from './graphql/generated-e2e-admin-types';
  9. import { fixPostgresTimezone } from './utils/fix-pg-timezone';
  10. fixPostgresTimezone();
  11. describe('ListQueryBuilder', () => {
  12. const { server, adminClient } = createTestEnvironment(
  13. mergeConfig(testConfig, {
  14. plugins: [ListQueryPlugin],
  15. }),
  16. );
  17. beforeAll(async () => {
  18. await server.init({
  19. initialData,
  20. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
  21. customerCount: 1,
  22. });
  23. await adminClient.asSuperAdmin();
  24. }, TEST_SETUP_TIMEOUT_MS);
  25. afterAll(async () => {
  26. await server.destroy();
  27. });
  28. function getItemLabels(items: any[]): string[] {
  29. return items.map((x: any) => x.label).sort();
  30. }
  31. describe('pagination', () => {
  32. it('all en', async () => {
  33. const { testEntities } = await adminClient.query(
  34. GET_LIST,
  35. {
  36. options: {},
  37. },
  38. { languageCode: LanguageCode.en },
  39. );
  40. expect(testEntities.totalItems).toBe(5);
  41. expect(getItemLabels(testEntities.items)).toEqual(['A', 'B', 'C', 'D', 'E']);
  42. expect(testEntities.items.map((i: any) => i.name)).toEqual([
  43. 'apple',
  44. 'bike',
  45. 'cake',
  46. 'dog',
  47. 'egg',
  48. ]);
  49. });
  50. it('all de', async () => {
  51. const { testEntities } = await adminClient.query(
  52. GET_LIST,
  53. {
  54. options: {},
  55. },
  56. { languageCode: LanguageCode.de },
  57. );
  58. expect(testEntities.totalItems).toBe(5);
  59. expect(getItemLabels(testEntities.items)).toEqual(['A', 'B', 'C', 'D', 'E']);
  60. expect(testEntities.items.map((i: any) => i.name)).toEqual([
  61. 'apfel',
  62. 'fahrrad',
  63. 'kuchen',
  64. 'hund',
  65. 'egg', // falls back to en translation when de doesn't exist
  66. ]);
  67. });
  68. it('take', async () => {
  69. const { testEntities } = await adminClient.query(GET_LIST, {
  70. options: {
  71. take: 2,
  72. },
  73. });
  74. expect(testEntities.totalItems).toBe(5);
  75. expect(getItemLabels(testEntities.items)).toEqual(['A', 'B']);
  76. });
  77. it('skip', async () => {
  78. const { testEntities } = await adminClient.query(GET_LIST, {
  79. options: {
  80. skip: 2,
  81. },
  82. });
  83. expect(testEntities.totalItems).toBe(5);
  84. expect(getItemLabels(testEntities.items)).toEqual(['C', 'D', 'E']);
  85. });
  86. it('skip negative is ignored', async () => {
  87. const { testEntities } = await adminClient.query(GET_LIST, {
  88. options: {
  89. skip: -1,
  90. },
  91. });
  92. expect(testEntities.totalItems).toBe(5);
  93. expect(testEntities.items.length).toBe(5);
  94. });
  95. it('take zero is ignored', async () => {
  96. const { testEntities } = await adminClient.query(GET_LIST, {
  97. options: {
  98. take: 0,
  99. },
  100. });
  101. expect(testEntities.totalItems).toBe(5);
  102. expect(testEntities.items.length).toBe(5);
  103. });
  104. it('take negative is ignored', async () => {
  105. const { testEntities } = await adminClient.query(GET_LIST, {
  106. options: {
  107. take: -1,
  108. },
  109. });
  110. expect(testEntities.totalItems).toBe(5);
  111. expect(testEntities.items.length).toBe(5);
  112. });
  113. });
  114. describe('string filtering', () => {
  115. it('eq', async () => {
  116. const { testEntities } = await adminClient.query(GET_LIST, {
  117. options: {
  118. filter: {
  119. label: {
  120. eq: 'B',
  121. },
  122. },
  123. },
  124. });
  125. expect(getItemLabels(testEntities.items)).toEqual(['B']);
  126. });
  127. it('notEq', async () => {
  128. const { testEntities } = await adminClient.query(GET_LIST, {
  129. options: {
  130. filter: {
  131. label: {
  132. notEq: 'B',
  133. },
  134. },
  135. },
  136. });
  137. expect(getItemLabels(testEntities.items)).toEqual(['A', 'C', 'D', 'E']);
  138. });
  139. it('contains', async () => {
  140. const { testEntities } = await adminClient.query(GET_LIST, {
  141. options: {
  142. filter: {
  143. description: {
  144. contains: 'adip',
  145. },
  146. },
  147. },
  148. });
  149. expect(getItemLabels(testEntities.items)).toEqual(['C']);
  150. });
  151. it('notContains', async () => {
  152. const { testEntities } = await adminClient.query(GET_LIST, {
  153. options: {
  154. filter: {
  155. description: {
  156. notContains: 'te',
  157. },
  158. },
  159. },
  160. });
  161. expect(getItemLabels(testEntities.items)).toEqual(['A', 'B', 'E']);
  162. });
  163. it('in', async () => {
  164. const { testEntities } = await adminClient.query(GET_LIST, {
  165. options: {
  166. filter: {
  167. label: {
  168. in: ['A', 'C'],
  169. },
  170. },
  171. },
  172. });
  173. expect(getItemLabels(testEntities.items)).toEqual(['A', 'C']);
  174. });
  175. it('notIn', async () => {
  176. const { testEntities } = await adminClient.query(GET_LIST, {
  177. options: {
  178. filter: {
  179. label: {
  180. notIn: ['A', 'C'],
  181. },
  182. },
  183. },
  184. });
  185. expect(getItemLabels(testEntities.items)).toEqual(['B', 'D', 'E']);
  186. });
  187. describe('regex', () => {
  188. it('simple substring', async () => {
  189. const { testEntities } = await adminClient.query(GET_LIST, {
  190. options: {
  191. filter: {
  192. description: {
  193. regex: 'or',
  194. },
  195. },
  196. },
  197. });
  198. expect(getItemLabels(testEntities.items)).toEqual(['A', 'B', 'D']);
  199. });
  200. it('start of string', async () => {
  201. const { testEntities } = await adminClient.query(GET_LIST, {
  202. options: {
  203. filter: {
  204. description: {
  205. regex: '^in',
  206. },
  207. },
  208. },
  209. });
  210. expect(getItemLabels(testEntities.items)).toEqual(['E']);
  211. });
  212. it('end of string', async () => {
  213. const { testEntities } = await adminClient.query(GET_LIST, {
  214. options: {
  215. filter: {
  216. description: {
  217. regex: 'or$',
  218. },
  219. },
  220. },
  221. });
  222. expect(getItemLabels(testEntities.items)).toEqual(['D']);
  223. });
  224. it('alternation', async () => {
  225. const { testEntities } = await adminClient.query(GET_LIST, {
  226. options: {
  227. filter: {
  228. description: {
  229. regex: 'dolor|tempor',
  230. },
  231. },
  232. },
  233. });
  234. expect(getItemLabels(testEntities.items)).toEqual(['B', 'D']);
  235. });
  236. it('complex', async () => {
  237. const { testEntities } = await adminClient.query(GET_LIST, {
  238. options: {
  239. filter: {
  240. description: {
  241. regex: '(dolor|tempor)|inc[i]?d[^a]d.*nt',
  242. },
  243. },
  244. },
  245. });
  246. expect(getItemLabels(testEntities.items)).toEqual(['B', 'D', 'E']);
  247. });
  248. });
  249. });
  250. describe('boolean filtering', () => {
  251. it('eq', async () => {
  252. const { testEntities } = await adminClient.query(GET_LIST, {
  253. options: {
  254. filter: {
  255. active: {
  256. eq: false,
  257. },
  258. },
  259. },
  260. });
  261. expect(getItemLabels(testEntities.items)).toEqual(['C', 'E']);
  262. });
  263. });
  264. describe('number filtering', () => {
  265. it('eq', async () => {
  266. const { testEntities } = await adminClient.query(GET_LIST, {
  267. options: {
  268. filter: {
  269. order: {
  270. eq: 1,
  271. },
  272. },
  273. },
  274. });
  275. expect(getItemLabels(testEntities.items)).toEqual(['B']);
  276. });
  277. it('lt', async () => {
  278. const { testEntities } = await adminClient.query(GET_LIST, {
  279. options: {
  280. filter: {
  281. order: {
  282. lt: 1,
  283. },
  284. },
  285. },
  286. });
  287. expect(getItemLabels(testEntities.items)).toEqual(['A']);
  288. });
  289. it('lte', async () => {
  290. const { testEntities } = await adminClient.query(GET_LIST, {
  291. options: {
  292. filter: {
  293. order: {
  294. lte: 1,
  295. },
  296. },
  297. },
  298. });
  299. expect(getItemLabels(testEntities.items)).toEqual(['A', 'B']);
  300. });
  301. it('gt', async () => {
  302. const { testEntities } = await adminClient.query(GET_LIST, {
  303. options: {
  304. filter: {
  305. order: {
  306. gt: 1,
  307. },
  308. },
  309. },
  310. });
  311. expect(getItemLabels(testEntities.items)).toEqual(['C', 'D', 'E']);
  312. });
  313. it('gte', async () => {
  314. const { testEntities } = await adminClient.query(GET_LIST, {
  315. options: {
  316. filter: {
  317. order: {
  318. gte: 1,
  319. },
  320. },
  321. },
  322. });
  323. expect(getItemLabels(testEntities.items)).toEqual(['B', 'C', 'D', 'E']);
  324. });
  325. it('between', async () => {
  326. const { testEntities } = await adminClient.query(GET_LIST, {
  327. options: {
  328. filter: {
  329. order: {
  330. between: {
  331. start: 2,
  332. end: 4,
  333. },
  334. },
  335. },
  336. },
  337. });
  338. expect(getItemLabels(testEntities.items)).toEqual(['C', 'D', 'E']);
  339. });
  340. });
  341. describe('date filtering', () => {
  342. it('before', async () => {
  343. const { testEntities } = await adminClient.query(GET_LIST, {
  344. options: {
  345. filter: {
  346. date: {
  347. before: '2020-01-20T10:00:00.000Z',
  348. },
  349. },
  350. },
  351. });
  352. expect(getItemLabels(testEntities.items)).toEqual(['A', 'B']);
  353. });
  354. it('before on same date', async () => {
  355. const { testEntities } = await adminClient.query(GET_LIST, {
  356. options: {
  357. filter: {
  358. date: {
  359. before: '2020-01-15T17:00:00.000Z',
  360. },
  361. },
  362. },
  363. });
  364. expect(getItemLabels(testEntities.items)).toEqual(['A', 'B']);
  365. });
  366. it('after', async () => {
  367. const { testEntities } = await adminClient.query(GET_LIST, {
  368. options: {
  369. filter: {
  370. date: {
  371. after: '2020-01-20T10:00:00.000Z',
  372. },
  373. },
  374. },
  375. });
  376. expect(getItemLabels(testEntities.items)).toEqual(['C', 'D', 'E']);
  377. });
  378. it('after on same date', async () => {
  379. const { testEntities } = await adminClient.query(GET_LIST, {
  380. options: {
  381. filter: {
  382. date: {
  383. after: '2020-01-25T09:00:00.000Z',
  384. },
  385. },
  386. },
  387. });
  388. expect(getItemLabels(testEntities.items)).toEqual(['C', 'D', 'E']);
  389. });
  390. it('between', async () => {
  391. const { testEntities } = await adminClient.query(GET_LIST, {
  392. options: {
  393. filter: {
  394. date: {
  395. between: {
  396. start: '2020-01-10T10:00:00.000Z',
  397. end: '2020-01-20T10:00:00.000Z',
  398. },
  399. },
  400. },
  401. },
  402. });
  403. expect(getItemLabels(testEntities.items)).toEqual(['B']);
  404. });
  405. });
  406. describe('sorting', () => {
  407. it('sort by string', async () => {
  408. const { testEntities } = await adminClient.query(GET_LIST, {
  409. options: {
  410. sort: {
  411. label: SortOrder.DESC,
  412. },
  413. },
  414. });
  415. expect(testEntities.items.map((x: any) => x.label)).toEqual(['E', 'D', 'C', 'B', 'A']);
  416. });
  417. it('sort by number', async () => {
  418. const { testEntities } = await adminClient.query(GET_LIST, {
  419. options: {
  420. sort: {
  421. order: SortOrder.DESC,
  422. },
  423. },
  424. });
  425. expect(testEntities.items.map((x: any) => x.label)).toEqual(['E', 'D', 'C', 'B', 'A']);
  426. });
  427. it('sort by date', async () => {
  428. const { testEntities } = await adminClient.query(GET_LIST, {
  429. options: {
  430. sort: {
  431. date: SortOrder.DESC,
  432. },
  433. },
  434. });
  435. expect(testEntities.items.map((x: any) => x.label)).toEqual(['E', 'D', 'C', 'B', 'A']);
  436. });
  437. it('sort by ID', async () => {
  438. const { testEntities } = await adminClient.query(GET_LIST, {
  439. options: {
  440. sort: {
  441. id: SortOrder.DESC,
  442. },
  443. },
  444. });
  445. expect(testEntities.items.map((x: any) => x.label)).toEqual(['E', 'D', 'C', 'B', 'A']);
  446. });
  447. it('sort by translated field en', async () => {
  448. const { testEntities } = await adminClient.query(GET_LIST, {
  449. options: {
  450. sort: {
  451. name: SortOrder.ASC,
  452. },
  453. },
  454. });
  455. expect(testEntities.items.map((x: any) => x.name)).toEqual([
  456. 'apple',
  457. 'bike',
  458. 'cake',
  459. 'dog',
  460. 'egg',
  461. ]);
  462. });
  463. it('sort by translated field de', async () => {
  464. const { testEntities } = await adminClient.query(
  465. GET_LIST,
  466. {
  467. options: {
  468. sort: {
  469. name: SortOrder.ASC,
  470. },
  471. },
  472. },
  473. { languageCode: LanguageCode.de },
  474. );
  475. expect(testEntities.items.map((x: any) => x.name)).toEqual([
  476. 'apfel',
  477. 'egg',
  478. 'fahrrad',
  479. 'hund',
  480. 'kuchen',
  481. ]);
  482. });
  483. it('sort by translated field en with take', async () => {
  484. const { testEntities } = await adminClient.query(GET_LIST, {
  485. options: {
  486. sort: {
  487. name: SortOrder.ASC,
  488. },
  489. take: 3,
  490. },
  491. });
  492. expect(testEntities.items.map((x: any) => x.name)).toEqual(['apple', 'bike', 'cake']);
  493. });
  494. it('sort by translated field de with take', async () => {
  495. const { testEntities } = await adminClient.query(
  496. GET_LIST,
  497. {
  498. options: {
  499. sort: {
  500. name: SortOrder.ASC,
  501. },
  502. take: 3,
  503. },
  504. },
  505. { languageCode: LanguageCode.de },
  506. );
  507. expect(testEntities.items.map((x: any) => x.name)).toEqual(['apfel', 'egg', 'fahrrad']);
  508. });
  509. });
  510. describe('calculated fields', () => {
  511. it('filter by simple calculated property', async () => {
  512. const { testEntities } = await adminClient.query(GET_LIST, {
  513. options: {
  514. filter: {
  515. descriptionLength: {
  516. lt: 12,
  517. },
  518. },
  519. },
  520. });
  521. expect(getItemLabels(testEntities.items)).toEqual(['A', 'B']);
  522. });
  523. it('filter by calculated property with join', async () => {
  524. const { testEntities } = await adminClient.query(GET_LIST, {
  525. options: {
  526. filter: {
  527. price: {
  528. lt: 14,
  529. },
  530. },
  531. },
  532. });
  533. expect(getItemLabels(testEntities.items)).toEqual(['A', 'B', 'E']);
  534. });
  535. it('sort by simple calculated property', async () => {
  536. const { testEntities } = await adminClient.query(GET_LIST, {
  537. options: {
  538. sort: {
  539. descriptionLength: SortOrder.ASC,
  540. },
  541. },
  542. });
  543. expect(testEntities.items.map((x: any) => x.label)).toEqual(['B', 'A', 'E', 'D', 'C']);
  544. });
  545. it('sort by calculated property with join', async () => {
  546. const { testEntities } = await adminClient.query(GET_LIST, {
  547. options: {
  548. sort: {
  549. price: SortOrder.ASC,
  550. },
  551. },
  552. });
  553. expect(testEntities.items.map((x: any) => x.label)).toEqual(['B', 'A', 'E', 'D', 'C']);
  554. });
  555. });
  556. });
  557. const GET_LIST = gql`
  558. query GetTestEntities($options: TestEntityListOptions) {
  559. testEntities(options: $options) {
  560. totalItems
  561. items {
  562. id
  563. label
  564. name
  565. date
  566. }
  567. }
  568. }
  569. `;