ObjectAttribute.spec.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. // Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/
  2. import { keyBy } from 'lodash-es'
  3. import { renderComponent } from '#tests/support/components/index.ts'
  4. import { mockApplicationConfig } from '#tests/support/mock-applicationConfig.ts'
  5. import { i18n } from '#shared/i18n.ts'
  6. import ObjectAttribute from '../ObjectAttribute.vue'
  7. import attributes from './attributes.json'
  8. vi.hoisted(() => {
  9. vi.setSystemTime('2021-04-09T10:11:12Z')
  10. })
  11. const attributesByKey = keyBy(attributes, 'name')
  12. const object = {
  13. login: 'some_object',
  14. address: 'Berlin\nStreet\nHouse',
  15. vip: true,
  16. note: 'note',
  17. active: true,
  18. objectAttributeValues: [
  19. {
  20. attribute: attributesByKey.date_attribute,
  21. value: '2022-08-19',
  22. __typename: 'ObjectAttributeValue',
  23. },
  24. {
  25. attribute: attributesByKey.textarea_field,
  26. value: 'textarea text',
  27. },
  28. {
  29. attribute: {
  30. ...attributesByKey.integer_field,
  31. dataOption: {
  32. ...attributesByKey.integer_field.dataOption,
  33. linktemplate: 'https://integer.com/#{render}',
  34. },
  35. },
  36. value: 600,
  37. renderedLink: 'https://integer.com/rendered',
  38. },
  39. {
  40. attribute: attributesByKey.date_time_field,
  41. value: '2022-08-11T05:00:00.000Z',
  42. },
  43. {
  44. attribute: attributesByKey.single_select,
  45. value: 'key1',
  46. },
  47. {
  48. attribute: attributesByKey.multi_select_field,
  49. value: ['key1', 'key2'],
  50. },
  51. {
  52. attribute: attributesByKey.single_tree_select,
  53. value: 'key1::key1_child1',
  54. },
  55. {
  56. attribute: attributesByKey.multi_tree_select,
  57. value: ['key1', 'key2', 'key2::key2_child1'],
  58. },
  59. {
  60. attribute: attributesByKey.some_url,
  61. value: 'https://url.com',
  62. },
  63. {
  64. attribute: attributesByKey.some_email,
  65. value: 'email@email.com',
  66. },
  67. {
  68. attribute: attributesByKey.phone,
  69. value: '+49 123456789',
  70. },
  71. {
  72. attribute: attributesByKey.external_attribute,
  73. value: { value: 1, label: 'Display External' },
  74. },
  75. ],
  76. }
  77. describe('common object attributes interface', () => {
  78. beforeEach(() => {
  79. mockApplicationConfig({
  80. pretty_date_format: 'absolute',
  81. })
  82. })
  83. test('renders all available attributes', () => {
  84. i18n.setTranslationMap(
  85. new Map([
  86. ['FORMAT_DATE', 'dd/mm/yyyy'],
  87. ['FORMAT_DATETIME', 'dd/mm/yyyy HH:MM'],
  88. ]),
  89. )
  90. const view = renderComponent(ObjectAttribute, {
  91. props: {
  92. object,
  93. attribute: attributesByKey.login,
  94. },
  95. router: true,
  96. store: true,
  97. })
  98. expect(view.getByText(object.login)).toBeInTheDocument()
  99. })
  100. test('show dash for empty fields', () => {
  101. const view = renderComponent(ObjectAttribute, {
  102. props: {
  103. object: {
  104. login: '',
  105. },
  106. attribute: attributesByKey.login,
  107. },
  108. })
  109. expect(view.getByText('-')).toBeInTheDocument()
  110. })
  111. it('translates translatable', () => {
  112. const translatable = (attr: any) => ({
  113. ...attr,
  114. dataOption: {
  115. ...attr.dataOption,
  116. translate: true,
  117. },
  118. })
  119. i18n.setTranslationMap(new Map([['Display1', 'llave1']]))
  120. const view = renderComponent(ObjectAttribute, {
  121. props: {
  122. object,
  123. attribute: translatable(attributesByKey.single_select),
  124. },
  125. router: true,
  126. })
  127. expect(view.getByText('llave1')).toBeInTheDocument()
  128. })
  129. it('renders links', () => {
  130. const view = renderComponent(ObjectAttribute, {
  131. props: {
  132. object,
  133. attribute: attributesByKey.integer_field,
  134. },
  135. router: true,
  136. })
  137. expect(view.getByRole('link', { name: '600' })).toHaveAttribute(
  138. 'href',
  139. 'https://integer.com/rendered',
  140. )
  141. })
  142. it('renders user relation', () => {
  143. const view = renderComponent(ObjectAttribute, {
  144. props: {
  145. object: {
  146. customer: {
  147. fullname: 'John Doe',
  148. },
  149. },
  150. attribute: {
  151. name: 'customer_id',
  152. dataType: 'user_autocompletion',
  153. dataOption: {
  154. relation: 'User',
  155. belongs_to: 'customer',
  156. },
  157. },
  158. },
  159. router: true,
  160. })
  161. expect(view.getByText('John Doe')).toBeInTheDocument()
  162. })
  163. it('renders user secondary organizations', () => {
  164. const view = renderComponent(ObjectAttribute, {
  165. props: {
  166. object: {
  167. secondaryOrganizations: {
  168. edges: [
  169. {
  170. node: {
  171. name: 'Example',
  172. },
  173. },
  174. {
  175. node: {
  176. name: 'Test',
  177. },
  178. },
  179. ],
  180. totalCount: 1,
  181. },
  182. },
  183. attribute: {
  184. name: 'organization_ids',
  185. dataType: 'autocompletion_ajax',
  186. dataOption: {
  187. relation: 'Organization',
  188. belongs_to: 'secondaryOrganizations',
  189. },
  190. },
  191. },
  192. router: true,
  193. })
  194. expect(view.getByText('Example, Test')).toBeInTheDocument()
  195. })
  196. it('renders textarea in table mode', () => {
  197. const view = renderComponent(ObjectAttribute, {
  198. props: {
  199. attribute: attributesByKey.address,
  200. object,
  201. mode: 'table',
  202. },
  203. router: true,
  204. })
  205. expect(view.getByText('Berlin Street House')).toBeInTheDocument()
  206. })
  207. it('renders textarea in view mode', () => {
  208. const view = renderComponent(ObjectAttribute, {
  209. props: {
  210. attribute: attributesByKey.address,
  211. object,
  212. },
  213. router: true,
  214. })
  215. expect(view.getByText('Berlin')).toHaveTextContent(/^Berlin$/)
  216. expect(view.getByText('Street')).toHaveTextContent(/^Street$/)
  217. expect(view.getByText('House')).toHaveTextContent(/^House$/)
  218. })
  219. })