custom-fields.e2e-spec.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. // Force the timezone to avoid tests failing in other locales
  2. process.env.TZ = 'UTC';
  3. import gql from 'graphql-tag';
  4. import path from 'path';
  5. import { LanguageCode } from '../../common/lib/generated-types';
  6. import { TEST_SETUP_TIMEOUT_MS } from './config/test-config';
  7. import { TestAdminClient, TestShopClient } from './test-client';
  8. import { TestServer } from './test-server';
  9. import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
  10. // tslint:disable:no-non-null-assertion
  11. describe('Custom fields', () => {
  12. const adminClient = new TestAdminClient();
  13. const shopClient = new TestShopClient();
  14. const server = new TestServer();
  15. beforeAll(async () => {
  16. await server.init(
  17. {
  18. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
  19. customerCount: 1,
  20. },
  21. {
  22. customFields: {
  23. Product: [
  24. { name: 'nullable', type: 'string' },
  25. { name: 'notNullable', type: 'string', nullable: false, defaultValue: '' },
  26. { name: 'stringWithDefault', type: 'string', defaultValue: 'hello' },
  27. { name: 'localeStringWithDefault', type: 'localeString', defaultValue: 'hola' },
  28. { name: 'intWithDefault', type: 'int', defaultValue: 5 },
  29. { name: 'floatWithDefault', type: 'float', defaultValue: 5.5 },
  30. { name: 'booleanWithDefault', type: 'boolean', defaultValue: true },
  31. {
  32. name: 'dateTimeWithDefault',
  33. type: 'datetime',
  34. defaultValue: new Date('2019-04-30T12:59:16.4158386Z'),
  35. },
  36. { name: 'validateString', type: 'string', pattern: '^[0-9][a-z]+$' },
  37. { name: 'validateLocaleString', type: 'localeString', pattern: '^[0-9][a-z]+$' },
  38. { name: 'validateInt', type: 'int', min: 0, max: 10 },
  39. { name: 'validateFloat', type: 'float', min: 0.5, max: 10.5 },
  40. {
  41. name: 'validateDateTime',
  42. type: 'datetime',
  43. min: '2019-01-01T08:30',
  44. max: '2019-06-01T08:30',
  45. },
  46. { name: 'validateFn1', type: 'string', validate: value => {
  47. if (value !== 'valid') {
  48. return `The value ['${value}'] is not valid`;
  49. }
  50. },
  51. },
  52. { name: 'validateFn2', type: 'string', validate: value => {
  53. if (value !== 'valid') {
  54. return [{ languageCode: LanguageCode.en, value: `The value ['${value}'] is not valid` }];
  55. }
  56. },
  57. },
  58. ],
  59. },
  60. },
  61. );
  62. await adminClient.init();
  63. await shopClient.init();
  64. }, TEST_SETUP_TIMEOUT_MS);
  65. afterAll(async () => {
  66. await server.destroy();
  67. });
  68. it('globalSettings.serverConfig.customFieldConfig', async () => {
  69. const { globalSettings } = await adminClient.query(gql`
  70. query {
  71. globalSettings {
  72. serverConfig {
  73. customFieldConfig {
  74. Product {
  75. ... on CustomField {
  76. name
  77. type
  78. }
  79. }
  80. }
  81. }
  82. }
  83. }
  84. `);
  85. expect(globalSettings.serverConfig.customFieldConfig).toEqual({
  86. Product: [
  87. { name: 'nullable', type: 'string' },
  88. { name: 'notNullable', type: 'string' },
  89. { name: 'stringWithDefault', type: 'string' },
  90. { name: 'localeStringWithDefault', type: 'localeString' },
  91. { name: 'intWithDefault', type: 'int' },
  92. { name: 'floatWithDefault', type: 'float' },
  93. { name: 'booleanWithDefault', type: 'boolean' },
  94. { name: 'dateTimeWithDefault', type: 'datetime' },
  95. { name: 'validateString', type: 'string' },
  96. { name: 'validateLocaleString', type: 'localeString' },
  97. { name: 'validateInt', type: 'int' },
  98. { name: 'validateFloat', type: 'float' },
  99. { name: 'validateDateTime', type: 'datetime' },
  100. { name: 'validateFn1', type: 'string' },
  101. { name: 'validateFn2', type: 'string' },
  102. ],
  103. });
  104. });
  105. it('get nullable with no default', async () => {
  106. const { product } = await adminClient.query(gql`
  107. query {
  108. product(id: "T_1") {
  109. id
  110. name
  111. customFields {
  112. nullable
  113. }
  114. }
  115. }
  116. `);
  117. expect(product).toEqual({
  118. id: 'T_1',
  119. name: 'Laptop',
  120. customFields: {
  121. nullable: null,
  122. },
  123. });
  124. });
  125. it('get fields with default values', async () => {
  126. const { product } = await adminClient.query(gql`
  127. query {
  128. product(id: "T_1") {
  129. id
  130. name
  131. customFields {
  132. stringWithDefault
  133. localeStringWithDefault
  134. intWithDefault
  135. floatWithDefault
  136. booleanWithDefault
  137. dateTimeWithDefault
  138. }
  139. }
  140. }
  141. `);
  142. expect(product).toEqual({
  143. id: 'T_1',
  144. name: 'Laptop',
  145. customFields: {
  146. stringWithDefault: 'hello',
  147. localeStringWithDefault: 'hola',
  148. intWithDefault: 5,
  149. floatWithDefault: 5.5,
  150. booleanWithDefault: true,
  151. dateTimeWithDefault: '2019-04-30T12:59:16.415Z',
  152. },
  153. });
  154. });
  155. it(
  156. 'update non-nullable field',
  157. assertThrowsWithMessage(async () => {
  158. await adminClient.query(gql`
  159. mutation {
  160. updateProduct(input: { id: "T_1", customFields: { notNullable: null } }) {
  161. id
  162. }
  163. }
  164. `);
  165. }, 'NOT NULL constraint failed: product.customFieldsNotnullable'),
  166. );
  167. describe('validation', () => {
  168. it(
  169. 'invalid string',
  170. assertThrowsWithMessage(async () => {
  171. await adminClient.query(gql`
  172. mutation {
  173. updateProduct(input: { id: "T_1", customFields: { validateString: "hello" } }) {
  174. id
  175. }
  176. }
  177. `);
  178. }, `The custom field value ['hello'] does not match the pattern [^[0-9][a-z]+$]`),
  179. );
  180. it(
  181. 'invalid localeString',
  182. assertThrowsWithMessage(async () => {
  183. await adminClient.query(gql`
  184. mutation {
  185. updateProduct(input: {
  186. id: "T_1"
  187. translations: [{
  188. id: "T_1"
  189. languageCode: en,
  190. customFields: { validateLocaleString: "servus" }
  191. }]
  192. }) {
  193. id
  194. }
  195. }
  196. `);
  197. }, `The custom field value ['servus'] does not match the pattern [^[0-9][a-z]+$]`),
  198. );
  199. it(
  200. 'invalid int',
  201. assertThrowsWithMessage(async () => {
  202. await adminClient.query(gql`
  203. mutation {
  204. updateProduct(input: {
  205. id: "T_1"
  206. customFields: { validateInt: 12 }
  207. }) {
  208. id
  209. }
  210. }
  211. `);
  212. }, `The custom field value [12] is greater than the maximum [10]`),
  213. );
  214. it(
  215. 'invalid float',
  216. assertThrowsWithMessage(async () => {
  217. await adminClient.query(gql`
  218. mutation {
  219. updateProduct(input: {
  220. id: "T_1"
  221. customFields: { validateFloat: 10.6 }
  222. }) {
  223. id
  224. }
  225. }
  226. `);
  227. }, `The custom field value [10.6] is greater than the maximum [10.5]`),
  228. );
  229. it(
  230. 'invalid datetime',
  231. assertThrowsWithMessage(async () => {
  232. await adminClient.query(gql`
  233. mutation {
  234. updateProduct(input: {
  235. id: "T_1"
  236. customFields: { validateDateTime: "2019-01-01T05:25:00.000Z" }
  237. }) {
  238. id
  239. }
  240. }
  241. `);
  242. }, `The custom field value [2019-01-01T05:25:00.000Z] is less than the minimum [2019-01-01T08:30]`),
  243. );
  244. it(
  245. 'invalid validate function with string',
  246. assertThrowsWithMessage(async () => {
  247. await adminClient.query(gql`
  248. mutation {
  249. updateProduct(input: {
  250. id: "T_1"
  251. customFields: { validateFn1: "invalid" }
  252. }) {
  253. id
  254. }
  255. }
  256. `);
  257. }, `The value ['invalid'] is not valid`),
  258. );
  259. it(
  260. 'invalid validate function with localized string',
  261. assertThrowsWithMessage(async () => {
  262. await adminClient.query(gql`
  263. mutation {
  264. updateProduct(input: {
  265. id: "T_1"
  266. customFields: { validateFn2: "invalid" }
  267. }) {
  268. id
  269. }
  270. }
  271. `);
  272. }, `The value ['invalid'] is not valid`),
  273. );
  274. });
  275. });