a11y-color-contrast.cy.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /**
  2. * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
  3. * SPDX-License-Identifier: AGPL-3.0-or-later
  4. */
  5. const themesToTest = ['light', 'dark', 'light-highcontrast', 'dark-highcontrast']
  6. const testCases = {
  7. 'Main text': {
  8. foregroundColors: [
  9. 'color-main-text',
  10. // 'color-text-light', deprecated
  11. // 'color-text-lighter', deprecated
  12. 'color-text-maxcontrast',
  13. ],
  14. backgroundColors: [
  15. 'color-main-background',
  16. 'color-background-hover',
  17. 'color-background-dark',
  18. // 'color-background-darker', this should only be used for elements not for text
  19. ],
  20. },
  21. 'blurred background': {
  22. foregroundColors: [
  23. 'color-main-text',
  24. 'color-text-maxcontrast-blur',
  25. ],
  26. backgroundColors: [
  27. 'color-main-background-blur',
  28. ],
  29. },
  30. Primary: {
  31. foregroundColors: [
  32. 'color-primary-text',
  33. ],
  34. backgroundColors: [
  35. // 'color-primary-default', this should only be used for elements not for text!
  36. // 'color-primary-hover', this should only be used for elements and not for text!
  37. 'color-primary',
  38. ],
  39. },
  40. 'Primary light': {
  41. foregroundColors: [
  42. 'color-primary-light-text',
  43. ],
  44. backgroundColors: [
  45. 'color-primary-light',
  46. 'color-primary-light-hover',
  47. ],
  48. },
  49. 'Primary element': {
  50. foregroundColors: [
  51. 'color-primary-element-text',
  52. 'color-primary-element-text-dark',
  53. ],
  54. backgroundColors: [
  55. 'color-primary-element',
  56. 'color-primary-element-hover',
  57. ],
  58. },
  59. 'Primary element light': {
  60. foregroundColors: [
  61. 'color-primary-element-light-text',
  62. ],
  63. backgroundColors: [
  64. 'color-primary-element-light',
  65. 'color-primary-element-light-hover',
  66. ],
  67. },
  68. 'Servity information texts': {
  69. foregroundColors: [
  70. 'color-error-text',
  71. 'color-warning-text',
  72. 'color-success-text',
  73. 'color-info-text',
  74. ],
  75. backgroundColors: [
  76. 'color-main-background',
  77. 'color-background-hover',
  78. 'color-main-background-blur',
  79. ],
  80. },
  81. }
  82. /**
  83. * Create a wrapper element with color and background set
  84. *
  85. * @param foreground The foreground color (css variable without leading --)
  86. * @param background The background color
  87. */
  88. function createTestCase(foreground: string, background: string) {
  89. const wrapper = document.createElement('div')
  90. wrapper.style.padding = '14px'
  91. wrapper.style.color = `var(--${foreground})`
  92. wrapper.style.backgroundColor = `var(--${background})`
  93. if (background.includes('blur')) {
  94. wrapper.style.backdropFilter = 'var(--filter-background-blur)'
  95. }
  96. const testCase = document.createElement('div')
  97. testCase.innerText = `${foreground} ${background}`
  98. testCase.setAttribute('data-cy-testcase', '')
  99. wrapper.appendChild(testCase)
  100. return wrapper
  101. }
  102. describe('Accessibility of Nextcloud theming colors', () => {
  103. for (const theme of themesToTest) {
  104. context(`Theme: ${theme}`, () => {
  105. before(() => {
  106. cy.createRandomUser().then(($user) => {
  107. // set user theme
  108. cy.runOccCommand(`user:setting -- '${$user.userId}' theming enabled-themes '[\\"${theme}\\"]'`)
  109. cy.login($user)
  110. cy.visit('/')
  111. cy.injectAxe({ axeCorePath: 'node_modules/axe-core/axe.min.js' })
  112. })
  113. })
  114. beforeEach(() => {
  115. cy.document().then(doc => {
  116. // Unset background image and thus use background-color for testing blur background (images do not work with axe-core)
  117. doc.body.style.backgroundImage = 'unset'
  118. const root = doc.querySelector('main')
  119. if (root === null) {
  120. throw new Error('No test root found')
  121. }
  122. root.innerHTML = ''
  123. })
  124. })
  125. for (const [name, { backgroundColors, foregroundColors }] of Object.entries(testCases)) {
  126. context(`Accessibility of CSS color variables for ${name}`, () => {
  127. for (const foreground of foregroundColors) {
  128. for (const background of backgroundColors) {
  129. it(`color contrast of ${foreground} on ${background}`, () => {
  130. cy.document().then(doc => {
  131. const element = createTestCase(foreground, background)
  132. const root = doc.querySelector('main')
  133. // eslint-disable-next-line no-unused-expressions
  134. expect(root).not.to.be.undefined
  135. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  136. root!.appendChild(element)
  137. cy.checkA11y('[data-cy-testcase]', {
  138. runOnly: ['color-contrast'],
  139. })
  140. })
  141. })
  142. }
  143. }
  144. })
  145. }
  146. })
  147. }
  148. })