CommonObjectAttributes.spec.ts 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. // Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
  2. vi.setSystemTime('2021-04-09T10:11:12Z')
  3. import { i18n } from '@shared/i18n'
  4. import { getByRole } from '@testing-library/vue'
  5. import { renderComponent } from '@tests/support/components'
  6. import { mockApplicationConfig } from '@tests/support/mock-applicationConfig'
  7. import { mockPermissions } from '@tests/support/mock-permissions'
  8. import { flushPromises } from '@vue/test-utils'
  9. import { keyBy } from 'lodash-es'
  10. import CommonObjectAttributes from '../CommonObjectAttributes.vue'
  11. import attributes from './attributes.json'
  12. const attributesByKey = keyBy(attributes, 'name')
  13. describe('common object attributes interface', () => {
  14. test('renders all available attributes', () => {
  15. mockPermissions(['admin.user', 'ticket.agent'])
  16. const object = {
  17. login: 'some_object',
  18. address: 'Berlin, Street, House',
  19. vip: true,
  20. note: 'note',
  21. active: true,
  22. invisible: 'invisible',
  23. objectAttributeValues: [
  24. {
  25. attribute: attributesByKey.date_attribute,
  26. value: '2022-08-19',
  27. __typename: 'ObjectAttributeValue',
  28. },
  29. {
  30. attribute: attributesByKey.textarea_field,
  31. value: 'textarea text',
  32. },
  33. {
  34. attribute: attributesByKey.integer_field,
  35. value: 600,
  36. },
  37. {
  38. attribute: attributesByKey.date_time_field,
  39. value: '2022-08-11T05:00:00.000Z',
  40. },
  41. {
  42. attribute: attributesByKey.single_select,
  43. value: 'key1',
  44. },
  45. {
  46. attribute: attributesByKey.multi_select_field,
  47. value: ['key1', 'key2'],
  48. },
  49. {
  50. attribute: attributesByKey.single_tree_select,
  51. value: 'key1::key1_child1',
  52. },
  53. {
  54. attribute: attributesByKey.multi_tree_select,
  55. value: ['key1', 'key2', 'key2::key2_child1'],
  56. },
  57. {
  58. attribute: attributesByKey.some_url,
  59. value: 'https://url.com',
  60. },
  61. {
  62. attribute: attributesByKey.some_email,
  63. value: 'email@email.com',
  64. },
  65. {
  66. attribute: attributesByKey.phone,
  67. value: '+49 123456789',
  68. },
  69. ],
  70. }
  71. i18n.setTranslationMap(
  72. new Map([
  73. ['FORMAT_DATE', 'dd/mm/yyyy'],
  74. ['FORMAT_DATETIME', 'dd/mm/yyyy HH:MM'],
  75. ]),
  76. )
  77. const view = renderComponent(CommonObjectAttributes, {
  78. props: {
  79. object,
  80. attributes,
  81. },
  82. router: true,
  83. store: true,
  84. })
  85. const getRegion = (name: string) => view.getByRole('region', { name })
  86. expect(getRegion('Login')).toHaveTextContent(object.login)
  87. expect(getRegion('Address')).toHaveTextContent(object.address)
  88. expect(getRegion('VIP')).toHaveTextContent('yes')
  89. expect(getRegion('Note')).toHaveTextContent(object.note)
  90. expect(getRegion('Active')).toHaveTextContent('yes')
  91. expect(getRegion('Date Attribute')).toHaveTextContent(/19\/08\/2022$/)
  92. expect(getRegion('Textarea Field')).toHaveTextContent('textarea text')
  93. expect(getRegion('Integer Field')).toHaveTextContent('600')
  94. expect(getRegion('DateTime Field')).toHaveTextContent('11/08/2022 05:00')
  95. expect(getRegion('Single Select Field')).toHaveTextContent('Display1')
  96. expect(getRegion('Multi Select Field')).toHaveTextContent(
  97. 'Display1, Display2',
  98. )
  99. expect(getRegion('Single Tree Select Field')).toHaveTextContent(
  100. 'key1::key1_child1',
  101. )
  102. expect(getRegion('Multi Tree Select Field')).toHaveTextContent(
  103. 'key1, key2, key2::key2_child1',
  104. )
  105. expect(
  106. getByRole(getRegion('Phone'), 'link', { name: '+49 123456789' }),
  107. ).toHaveAttribute('href', 'tel:+49123456789')
  108. expect(
  109. getByRole(getRegion('Email'), 'link', { name: 'email@email.com' }),
  110. ).toHaveAttribute('href', 'mailto:email@email.com')
  111. expect(
  112. getByRole(getRegion('Url'), 'link', { name: 'https://url.com' }),
  113. ).toHaveAttribute('href', 'https://url.com')
  114. expect(
  115. view.queryByRole('region', { name: 'Invisible' }),
  116. ).not.toBeInTheDocument()
  117. expect(
  118. view.queryByRole('region', { name: 'Hidden Boolean' }),
  119. ).not.toBeInTheDocument()
  120. })
  121. test('hides attributes without permission', () => {
  122. mockPermissions([])
  123. const object = {
  124. active: true,
  125. }
  126. const view = renderComponent(CommonObjectAttributes, {
  127. props: {
  128. object,
  129. attributes: [attributesByKey.active],
  130. },
  131. })
  132. expect(view.queryAllByRole('region')).toHaveLength(0)
  133. })
  134. test("don't show name", () => {
  135. const object = {
  136. name: 'some_object',
  137. }
  138. const view = renderComponent(CommonObjectAttributes, {
  139. props: {
  140. object,
  141. attributes: [{ ...attributesByKey.login, name: 'name' }],
  142. },
  143. })
  144. expect(view.queryAllByRole('region')).toHaveLength(0)
  145. })
  146. test("don't show empty fields", () => {
  147. const object = {
  148. login: '',
  149. objectAttributesValues: [
  150. {
  151. attribute: attributesByKey.integer_field,
  152. value: 0,
  153. },
  154. {
  155. attribute: attributesByKey.multi_select_field,
  156. value: [],
  157. },
  158. ],
  159. }
  160. const view = renderComponent(CommonObjectAttributes, {
  161. props: {
  162. object,
  163. attributes: [attributesByKey.login],
  164. },
  165. })
  166. expect(view.queryAllByRole('region')).toHaveLength(0)
  167. })
  168. test('show default, if not defined', () => {
  169. const object = {
  170. login: '',
  171. }
  172. const attribute = {
  173. ...attributesByKey.login,
  174. name: 'login',
  175. display: 'Login',
  176. }
  177. const view = renderComponent(CommonObjectAttributes, {
  178. props: {
  179. object,
  180. attributes: [
  181. {
  182. ...attribute,
  183. dataOption: { ...attribute.dataOption, default: 'default' },
  184. },
  185. ],
  186. },
  187. })
  188. expect(view.getByRole('region', { name: 'Login' })).toHaveTextContent(
  189. 'default',
  190. )
  191. })
  192. it('has linktemplate link, even for tel/email', () => {
  193. const object = {
  194. phone: '+49 123456789',
  195. }
  196. const view = renderComponent(CommonObjectAttributes, {
  197. props: {
  198. object,
  199. attributes: [
  200. {
  201. ...attributesByKey.phone,
  202. dataOption: {
  203. ...attributesByKey.phone.dataOption,
  204. linktemplate: 'https://link.com',
  205. },
  206. },
  207. ],
  208. },
  209. })
  210. const phoneRegion = view.getByRole('region', { name: 'Phone' })
  211. const phoneLink = getByRole(phoneRegion, 'link', {
  212. name: '+49 123456789',
  213. })
  214. expect(phoneLink).toHaveAttribute('href', 'https://link.com')
  215. })
  216. it('translates translatable', () => {
  217. mockPermissions(['admin.user', 'ticket.agent'])
  218. const object = {
  219. vip: true,
  220. single_select: 'key1',
  221. multi_select_field: ['key1', 'key2'],
  222. single_tree_select: 'key1::key1_child1',
  223. multi_tree_select: ['key1', 'key1::key1_child1'],
  224. }
  225. const translatable = (attr: any) => ({
  226. ...attr,
  227. dataOption: {
  228. ...attr.dataOption,
  229. translate: true,
  230. },
  231. })
  232. const attributes = [
  233. translatable(attributesByKey.vip),
  234. translatable(attributesByKey.single_select),
  235. translatable(attributesByKey.multi_select_field),
  236. translatable(attributesByKey.single_tree_select),
  237. translatable(attributesByKey.multi_tree_select),
  238. ]
  239. i18n.setTranslationMap(
  240. new Map([
  241. ['yes', 'sí'],
  242. ['Display1', 'Monitor1'],
  243. ['Display2', 'Monitor2'],
  244. ['key1', 'llave1'],
  245. ['key2', 'llave2'],
  246. ['key1_child1', 'llave1_niño1'],
  247. ]),
  248. )
  249. const view = renderComponent(CommonObjectAttributes, {
  250. props: {
  251. object,
  252. attributes,
  253. },
  254. router: true,
  255. })
  256. const getRegion = (name: string) => view.getByRole('region', { name })
  257. const vip = getRegion('VIP')
  258. const singleSelect = getRegion('Single Select Field')
  259. const multiSelect = getRegion('Multi Select Field')
  260. const singleTreeSelect = getRegion('Single Tree Select Field')
  261. const multiTreeSelect = getRegion('Multi Tree Select Field')
  262. expect(vip).toHaveTextContent('sí')
  263. expect(singleSelect).toHaveTextContent('Monitor1')
  264. expect(multiSelect).toHaveTextContent('Monitor1, Monitor2')
  265. expect(singleTreeSelect).toHaveTextContent('llave1::llave1_niño1')
  266. expect(multiTreeSelect).toHaveTextContent('llave1, llave1::llave1_niño1')
  267. })
  268. it('renders different dates', async () => {
  269. const object = {
  270. now: '2021-04-09T10:11:12Z',
  271. past: '2021-02-09T10:11:12Z',
  272. future: '2021-10-09T10:11:12Z',
  273. }
  274. const attributes = [
  275. { ...attributesByKey.date_time_field, name: 'now', display: 'now' },
  276. { ...attributesByKey.date_time_field, name: 'past', display: 'past' },
  277. { ...attributesByKey.date_time_field, name: 'future', display: 'future' },
  278. ]
  279. const view = renderComponent(CommonObjectAttributes, {
  280. props: {
  281. object,
  282. attributes,
  283. },
  284. router: true,
  285. })
  286. const getRegion = (time: string) => view.getByRole('region', { name: time })
  287. expect(getRegion('now')).toHaveTextContent('2021-04-09 10:11')
  288. expect(getRegion('past')).toHaveTextContent('2021-02-09 10:11')
  289. expect(getRegion('future')).toHaveTextContent('2021-10-09 10:11')
  290. mockApplicationConfig({
  291. pretty_date_format: 'relative',
  292. })
  293. await flushPromises()
  294. expect(getRegion('now')).toHaveTextContent('just now')
  295. expect(getRegion('past')).toHaveTextContent('1 month ago')
  296. expect(getRegion('future')).toHaveTextContent('in 6 months')
  297. })
  298. })